一、java的反射机制
反射的定义:
反射机制可以将一个类的实例化操作。 方法的调用,属性的调用等操作由编码期决定改为在运行期决定。
Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成instances、变更fields内容或唤起methods。
反射的作用:
大大的提高了代码的灵活性。
反射的利弊:
1: 适度使用反射机制可以提高代码复用及灵活性。
2: 由于反射会有额外的性能开销,所以过度使用会降低系统性能。 二、Class类
定义:
Class的每个实例称为类的类对象。它是反射机制中的最重要的一个类。
过程:
1加载:(三种)
当我们需要使用一个类时,首先JVM会加载该类的class文件,
注:
这时JVM就会实例化一个Class的实例,用来表示加载的这个类的信息。
由于JVM加载一个类只进行一次, 所以每个被JVM加载的类都有且只有唯一 的一个Class的实例用于表示它。
通过Class的实例可以获取其表示的类的一系列信息: 比如类的名字,有哪些 属性,哪些构造方法,哪些方法等。
(加载的三种方式)获取一个类的类对象的三种方法:
方法一:每个类都有一个静态属性:class,可以直接返回其类对象,
例如:想获取表示String类的类对象:
Class cls = String.class;
方法二:通过Class的静态方法forName加载该类并得到其类对象
Class cls = Class.forName("java.lang.String")
方法三:还可以通过类加载器ClassLoader加载(更灵活)
//加载指定名称(包括包名)的二进制类型,供用户调用的接口
public Class<?> loadClass(String name);
//加载指定名称(包括包名)的二进制类型,
protected synchronized Class<?> loadClass(String name, boolean resolve);
protected Class<?> findClass(String name)
//定义类型,一般在findClass方法中读取到对应字节码后调用,可以看出不可继承
说明:JVM已经实现了对应的具体功能,解析对应的字节码,产生对应的内部数据
结构放置到方法区,所以无需覆写,直接调用就可以了)
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError{}
2实例化: Object obj = cls.newInstance();
其提供了一个方法newInstance可以调用其表示的类的无参构造方法将其实例化(必须 有无参构造方法,否则会抛出异常)
eg:
//1加载Person
Class cls = Class.forName(“reflect.Person”);
//2通过Class实例化其表示的类
Object obj = cls.newInstance();
等价与
Person p = new Person();
三、 通过反射调用方法
eg:利用反射机制调用sayHello方法
1 . 实例化
1.1 加载Person类
1.2. 通过Class实例化Person
2. 调用sayHello方法
2.1. 通过Class获取Person的sayHello方法(Method实例)
2.2. 通过Method调用其表示的方法
//1 Person o = new Person();
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
//2 o.sayHello();
Method method = cls.getDeclaredMethod("sayHello");
method.invoke(o, null);
* Method类
* Method的每一个实例,用于表示一个类中的一个方法
* 通常通过Class获取,通过它可以得知其表示的方法更多的
* 详细信息:访问修饰符,返回值类型,参数,名字等。
* 并且可以通过invoke方法调用该方法。该方法要求传入
* 两个参数,第一个为当前方法所属对象,第二个为调用该
* 方法时需要传入的实参(如果有,没有则直接传入null)
四、 调用有参方法
1:Person p = new Person();
2:p.sayName(“小明”,22);
//1获得Class类
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
* 2 获取sayName(String,int)
* Class的getDeclaredMethod方法的第一个参数为方法名
* 第二个参数是一个Class数组,数组每个元素表示要获取的
* 方法中的一个参数类型。注意,参数类型在数组中的顺序
* 必须和该方法定义的参数顺序一致。
*/
Method method = cls.getDeclaredMethod("sayName", new Class[]{String.class,int.class}
);
/*
* invoke方法在执行时,第二个参数为Object数组,数组中
* 每个元素是调用该方法是传入的实际参数。
*/
method.invoke(o, new Object[]{"小明",22});
五、使用反射机制在类外面调用该类的获取构造方法
Class类提供了四个public方法,用于获取某个类的构造方法。
1. Constructor getConstructor(Class[] params)
根据构造函数的参数,返回一个具体的具有public属性的构造函数
2. Constructor getConstructors()
返回所有具有public属性的构造函数数组
3. Constructor getDeclaredConstructor(Class[] params)
根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
4. Constructor getDeclaredConstructors()
返回该类中所有的构造函数数组(不分public和非public属性)
六、反射调用有参方法过程:
1:加载(有三种方法)
静态属性:Class cls = String.class;
静态方法: Class cls = Class.forName("java.lang.String") (常用:参数为类名)
类加载器:ClassLoader
2:实例化
调用表示类的无参构造方法:Object o = cls.newInstance();
3:获取一个 Method实例
通过Class获取:(Method的每一个实例,用于表示一个类中的一个方法)
Method method = cls.getDeclaredMethod
("sayName", new Class[]{String.class,int.class});
第一个参数为方法名(无参方法只方法名)
第二个参数为Object数组,数组中每个元素是调用该方法是传入的实际参数。
4:通过invoke方法调用该方法
method.setAccessible();
method.invoke(o, new Object[]{"小明",22});
第一个为当前方法所属对象,
第二个为调用该方法时需要传入的实参(如果有,没有则直 接传入null)
(//设置为true后就可以访问该私有方法
method.setAccessible(true);)
获取类的成员方法
1. Method getMethod(String name, Class[] params)
根据方法名和参数,返回一个具体的具有public属性的方法
2. Method[] getMethods()
返回所有具有public属性的方法数组
3. Method getDeclaredMethod(String name, Class[] params)
根据方法名和参数,返回一个具体的方法(不分public和非public属性)
4. Method[] getDeclaredMethods()
返回该类中的所有的方法数组(不分public和非public属性)
获取类的成员变量(成员属性)
存在四种获取成员属性的方法:
1. Field getField(String name)
根据变量名,返回一个具体的具有public属性的成员变量
2. Field[] getFields()
返回具有public属性的成员变量的数组
3. Field getDeclaredField(String name)
根据变量名,返回一个成员变量(不分public和非public属性)
4. Field[] getDelcaredFields()
返回所有成员变量组成的数组(不分public和非public属性)
使用反射机制在类外面调用该类的私有方法
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
//获取dosome方法
Method method = cls.getDeclaredMethod("dosome");
//设置为true后就可以访问该私有方法
method.setAccessible(true);
method.invoke(o, null);