反射
反射概念汇总
反射是为了解决在运行期间,对某个实例一无所知的情况下,如何调用其方法(反射是为了获得某个实例的信息)反射是为了获得某个实例的信息。
如果能够在运行时拿到Class对象,就可以生成java对象并调用,这就是java反射的本质。
java的反射机制允许你在运行时检查类的信息。
java的反射机制是指程序在运行期间可以拿到一个对象的所有信息。
反射是一开始我们并不知道我要初始化的类对象是什么,自然无法使用new关键字来new对象。
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
一些概念的汇总
- 正常情况下,在编译之后就已经确定了类的类型,在jvm启动后被加载到jvm中。而反射:在编译和jvm启动后未确定类型,而是当程序执行到这里时才加载类。
- 动态加载:有些类可以到用时在动态加载到jvm中,减少jvm的启动时间,更重要的是可以动态的加载需要的对象。动态加载可以最大限度的体现java的灵活性,并降低类耦合性:多态
- java是编译型语言,绝大多数对象在编译期间就确定了类型,反射:动态编译,在jvm已经运行的情况下动态加载并操作类型。
- 因为Java代码是先通过编译器将Java代码编译成.class的二进制字节码文件的,因此我们需要使用new来实例化对象。但是这样的话,若需要更换实例,就需修改源代码。若利用反射,则可将类信息放在xml配置文件中,那么更换时只需修改xml文件即可(在框架中大量使用)
为什么需要使用反射?
1. 减少耦合性
正常情况下,如果我们在一个类中需要一个类的实例,那么需要通过new关键字来实例化。那么,如果这时这个类的实例需要使用另一种类型的,就只能修改源代码了。这时就可以使用反射来解决这个问题,反射可以在运行时(即编译之后且jvm启动之后)动态的加载类信息,从而通过加载的类信息实例化对象,当然,类信息我们可以事先定义在xml中,然后由程序加载。显然,这就是spring ioc的实现方式。
Spring的控制反转和反射
Spring在启动的时候加载bean xml 中定义的class注册到一个map中,用到时直接取,然后利用newInstance实例化。
在编译时并不能确定要使用的类型的情况下使用反射。
如果你编写的程序必须要与编译时未知的类一起工作,如有可能,仅仅使用反射机制来实例化对象。
获取Class实例的三种方法
-
Class cls = String.class
-
String s = "Hello"; Class cls = s.getClass();
-
Class cls = Class.forName("java.lang.String");
访问字段
Filed f = cls.getDeclaredField("name");
f.get(p); // 获取指定实例对应的字段值
f.setAccessible(true); // 设置这个字段即使是private也可以访问。
f.set(p, "xiaopeng"); // 为指定对象的这个字段设置值。
调用方法
Method m = cls.getMethod()
m.getName(); //获取方法名字
m.getReturnType(); //获取方法返回值类型
m.invoke(Object instance, Object... parameters); //调用这个class指定的某个实例的这个方法。
调用构造方法
-
根据Class生成实例: class.newInstance();这个方式只能调用该类的public的无参数的构造方法。
-
Constructor cons1 = Integer.class.getConstructor(int.class);
-
cons1.newInstance(123);
获取继承关系
-
cls.getSuperClass() ;// 获取父类的class
-
获取直接实现的接口 cls.getInterfaces()
动态代理
不编写实现类,直接在运行期间创建某个interface的实例