动态编译与静态编译
在聊反射之前先说说静态编译与动态编译,
静态编译:静态链接时指把要调用的函数或过程直接链接到可执行文件
在编译时确定类型,绑定对象,即通过
动态编译:动态编译的可执行文件需要附带一个动态链接库。在执行时,需要调用其动态链接库中的命令。
运行时确定类型,绑定对象
动态创建对象和编译,体现出很大的灵活性,动态编译使用到的就是反射。
使用反射基本上是一种解释操作,我们可以告诉JVM,
我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作
反射
类是java.lang.Class类的实例对象,通过这个类我们可以找到所有的类
三种方式获取类
Class c1 = Code.class;
这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的
Class c2 = code1.getClass();
Class c3 = Class.forName("com.trigl.code");
这三种方式获取的对象都是一个
获取并且使用方法
Class c = Class.forName("com.tengj.reflect.Person"); //先生成class
Object o = c.newInstance(); //newInstance可以初始化一个实例
Method method = c.getMethod("fun", String.class, int.class);//获取方法
method.invoke(o, "tengj", 10); //通过invoke调用该方法,参数第一个为实例对象,后面为具体参数值
获取类的成员变量
class a{
private int n;
}
Class c = a.getClass();
Field field = c.getDeclaredField("n");
获取类的构造方法
public A(String a, int b) {
// code body
}
那么就可以通过:
Constructor constructor = a.getDeclaredConstructor(String.class, int.class);
一个注意的地方
Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译到了运行期就无效了。
public class GenericEssence {
public static void main(String[] args)
{
List list1 = new ArrayList(); // 没有泛型
List<String> list2 = new ArrayList<String>(); // 有泛型
list2.add("hello");
// list2.add(20); // 报错!list2有泛型限制,只能添加String,添加int报错
System.out.println("list2的长度是:" + list2.size()); // 此时list2长度为1
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.println(c1 == c2); // 结果:true,说明类类型完全相同
try {
Method m = c2.getMethod("add", Object.class); // 通过方法反射得到add方法
m.invoke(list2, 20); // 给list2添加一个int型的,上面显示在编译器是会报错的
System.out.println("list2的长度是:" + list2.size()); // 结果:2,说明list2长度增加了,并没有泛型检查
} catch (Exception e) {
e.printStackTrace();
}
}
}