反射

动态编译与静态编译

在聊反射之前先说说静态编译与动态编译,
静态编译:静态链接时指把要调用的函数或过程直接链接到可执行文件
  在编译时确定类型,绑定对象,即通过
动态编译:动态编译的可执行文件需要附带一个动态链接库。在执行时,需要调用其动态链接库中的命令。
运行时确定类型,绑定对象

动态创建对象和编译,体现出很大的灵活性,动态编译使用到的就是反射。
使用反射基本上是一种解释操作,我们可以告诉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();
        }
    }
     
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容