java的反射机制我也是刚刚了解。只能算初学。这里写下这些纯是为了以后查看方便。所以没什么心得,纯粹是一些知识整理,和我做的一点总结的代码。
反射,说起来挺高端。其实内容却是很简单的。由于类加载进内存中的时候,属性方法等都已经储存在了内存中。所以既然已经存在,就可以通过一定方式将其取出。所以反射机制就出现了,就是通过类Class来调用其特定的反射api就可以取出其所有的属性,方法等等。不多说看代码吧。
//获取父类
private String getSuperClass(Class c){
Class superC=c.getSuperclass();
if(null!=superC){
String name=superC.getName();
return name;
}
return null;
}
//获取属性的类型和名字
private String[] getFields(Class c){
Field[] fields=c.getFields();
if(null!=fields){
String[] names = new String[fields.length];
for(int i=0;i<fields.length;i++){
String name=fields[i].getName();
String type=fields[i].getType().getName();
String modifier=Modifier.toString(fields[i].getModifiers());
names[i]=modifier+" "+type+" "+name;
}
return names;
}
return null;
}
等等包括构造器,所有方法实现的接口等等都可以获得。这里就不全部显示了。全部的代码已上传。通过全部代码可以像java代码一样显示出来,例如显示javax.swing.JFrame类。结果如下图:
是不是很有意思呢,不要要看到源码只要取得他的一个对象通过getClass就可以得到他的基本结构。如果再详细的话甚至连存在于此元素上的所有注释都可以显示出来。发射机制在java中的使用非常的广泛,例如数据库操作的ORM框架,反射一般配合着动态加载来使用,这样可以降低代码直接的耦合性,做到高内聚低耦合让代码的维护与添加功能变得更加简单。
对于类的动态加载。其实就是一代码:Class.forName();而这句话有什么用处呢。基本的创建对象我们再熟悉不过了。A a = new A(); a.xxx();这就是常见的静态编译静态绑定。而何为动态绑定呢,如下:
Class c = Class.forName("A的全路径"); Object object = c.newInstance("构造参数"); A a=(A)object; a.xxx()
大家可能很疑惑,这究竟有什么用,反而把一段简单的创建对象代码变得复杂。因为不好说清楚,所以这里就不多说了,若你研究过MVC框架或者IOC模式,想必你就非常理解动态编译的作用。对于动态创建对象,调用方法都很简单,就是两句话:newInstance(...)和method.invoke(对象,参数..)十分简单。下面写出一个自己写的一个简易ORM框架,通过动态编译来实现低耦合。让代码根据不同的类自动生成SQL语言,而不必在用硬编码写入数据库控制代码中。首先ORM框架有一个需要遵守的规则。也就是JAVA操作数据库的基本规则,首先一个表对应一个类,表的表名对应类名,表的字段名对应类的属性名,并且类的属性要有其自己的get与set方法,基于这个规定。我的数据库表对应的类如下:
public class Student {
private int Id;
private String Name;
public int getId() {
return Id;
}
public void setId(int id) {
this.Id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
this.Name = name;
}
}
我所写的简易将对象存入数据库的方法如下:
public static String getSaveSql(Object object){
String sql="insert into ";
Class c=object.getClass();
Method[] methods = c.getMethods();
String name = c.getName();
name=name.substring(name.lastIndexOf(".")+1, name.length());
sql+=name+"(";
List<String> mlist = new ArrayList<String>();
List<Object> vlist = new ArrayList<Object>();
for(Method m:methods){
String methodName = m.getName();
if(methodName.startsWith("get")&&!methodName.startsWith("getClass")){
mlist.add(methodName.substring(3,methodName.length()));
try{
Object ob =m.invoke(object, null);
if(ob instanceof String){
vlist.add("'"+ob+"'");
}else{
vlist.add(ob);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
String values ="values(";
for(int i=0;i<mlist.size();i++){
if(i!=mlist.size()-1){
sql+=mlist.get(i)+",";
values+=vlist.get(i).toString()+",";
}else{
sql+=mlist.get(i)+")";
values+=vlist.get(i).toString()+")";
}
}
sql+=values;
//通过Connection执行sql语句.................略
return sql;
}
经测试可以生成对应的SQL语句。然后从数据库中提取出一个相应对象方法如下由于没有写连接数据库的代码,所以如下所示只是一个测试,代码并不完整,但是也基本说明问题了:
public static Object getLoadSql(int id,Class c){
Object object=null;
try {
object = c.newInstance();
Method[] methods = c.getMethods();
String sql="select * from ";
String name=c.getName();
name=name.substring(name.lastIndexOf(".")+1, name.length());
sql+=name+" where id="+id;
//获取Connection执行sql语句返回ResultSet..........略
for(Method m:methods){
String methodName = m.getName();
if(methodName.startsWith("set")){
String SqlName=methodName.substring(3,methodName.length());
//然后通过字段名获取相应值xx再通过m.invoke(object, xx)存入即可...........代码略
}
}
} catch (Exception e) {
e.printStackTrace();
}
//通过ResultSet和上述
return object;
}
这些只不过是反射的一些基本操作,反射的用途十分广泛,尤其是在解决代码耦合方面,由于我也是初学只能说这么多了。更多的只能再去慢慢探索。
2014/7/31:
在android中,反射有个非常重要的功能:获取非API中提供的类的对象,由于android的开源,导致我们完全可以不只是利用API来进行开发,系统内部的一些运行时的static对象,我们都可以通过反射直接拿到,做出一些特殊的举动(例如,注入)。我们也可以用反射得到系统中的一些不暴露的类的对象,例如Android电池信息的获取等。