1.什么是反射( reflect)
JAVA反射机制是运行状态中,对于任意一个类都能够知道这个类的所有属性个方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息及动态调用对象的方法的功能称为java语言的反射机制。
简单说:在运行状态下,通过class文件对象,去使用构造方法,成员变量和成员方法
注意:在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用
2.创建Class文件的三种方式
Class.forName("类全名");
对象名.getClass();
类名.class
推荐使用:Class.forName("类全名");
3.获取构造方法并创建对象
概述:
java.lang.reflect.Constructor:构造方法管理器,通过该对象的newInstance方法能有创建构造方法
步骤
1、获取Class对象2、通过调用getDeclaredConstructor或者getConstructor 方法创建构造器(Constructor)对象,如果构造方法没有形式参数写nullpublic Constructor getDeclaredConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法可以获取私有构造方法public Constructor getConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法不能获取私有构造方法3、如果获取到的是私有的构造方法的构造器对象,需要调用构造器对象的setAccessible(true)方法4、通过构造器对象的 newInstance(实际参数1, 实际参数2)创建对象,如果没有实际参数写null
举例
1、通过
private Person(String name, int age)创建对象
Class clazz = Class.forName("com.itcast.Person");
//必须通过类全名获取
Constructor con = clazz.get
Declared
Constructor(String.class, int.class);
//形式参数列表对应的.class列表
con.setAccessible(true);
//此处不设置,无法创建该对象,因为构造方法是私有的
Object obj = con.newInstance("zhangsan",120); //调用newInstance(实际参数列表)创建对象
2、通过public Person()创建对象
Class clazz = Class.forName("com.itcast.Person");
//必须通过类全名获取
Constructor con = clazz.getDeclaredConstructor(null);
//因为没有形式参数,所以写null
con.setAccessible(true);
//此处不设置,无法创建该对象,因为构造方法是私有的
Object obj = con.newInstance();
//因为不需要实际参数,所以调用无参的
newInstance方法
4.获取属性并调用
概述:
java.lang.reflect.Field:属性管理器对象,可以对该类的对象的属性值进行修改和获取
1、获取Class对象
2、通过调用getDeclaredField("属性名")或通过调用getField("属性名") 获取属性管理器
3、如果获取的是私有的属性,调用属性管理器的
setAccessible(true)
方法
4、调用属性管理器的set(该类的对象,值) 来设置属性值
调用属性管理器的get(该类的对象)来获取属性值
举例
Person p1 = new Person();
Person p2= new Person();
Class clazz = Class.forName("Person"); //第一步获取Class对象
Field field = clazz.getDeclaredField("name");
//第二步通过调用getDeclaredField("属性名")或通过调用getField("属性名") 获取属性管理器
field.setAccessible(true); //第三步如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
field.set(p1, "张三"); //第四步用属性管理器的set(该类的对象,值) 来设置属性值
field.setAccessible(true); //第三步如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
field.set(p1, "张三"); //第四步用属性管理器的set(该类的对象,值) 来设置属性值
field.set(p2, "李四");
System.out.println(field.get(p1)); //第四步调用属性管理器的get(该类的对象)来获取属性值
System.out.println(field.get(p2));
System.out.println(field.get(p1)); //第四步调用属性管理器的get(该类的对象)来获取属性值
System.out.println(field.get(p2));
5.获取成员方法并调用
概述:
java.lang.reflect.Method:方法管理器,可以执行该类的对象的方法
步骤
1、获取Class对象
2、通过调用getDeclaredMethod("方法名",形式参数1.class, 形式参数2.class..)或通过调用geMethod("方法名",形式参数1.class, 形式参数2.class..) 获取属性管理器,如果没有形式参数写null
3、如果获取的是私有的方法,调用方法管理器的
setAccessible(true)
方法
4、通过属性管理器的invoke(该类的对象,实际参数)来执行方法,如果没有实际参数写null
案例
Person p1 = new Person("张三",13);
Person p2= new Person("李四",14);
Class clazz = Class.forName("Person");
/*
* 调用setName方法
*/
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.setAccessible(true); //如果getName方法是私有的,此处必须写
setName.invoke(p1, "张三改");
/*
* 调用getName方法
*/
Method getName = clazz.getDeclaredMethod("getName", null); //获取Person类的getName方法对应的方法管
getName.setAccessible(true); //如果getName方法是私有的,此处必须写
Object object = getName.invoke(p1, null); //执行p1对象的getName方法,并且将返回值赋值给object
System.out.println(object);
Person p2= new Person("李四",14);
Class clazz = Class.forName("Person");
/*
* 调用setName方法
*/
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.setAccessible(true); //如果getName方法是私有的,此处必须写
setName.invoke(p1, "张三改");
/*
* 调用getName方法
*/
Method getName = clazz.getDeclaredMethod("getName", null); //获取Person类的getName方法对应的方法管
getName.setAccessible(true); //如果getName方法是私有的,此处必须写
Object object = getName.invoke(p1, null); //执行p1对象的getName方法,并且将返回值赋值给object
System.out.println(object);
6.反射练习
1:
通过反射修改成员变量的值,包括私有
2:
通过反射运行配置文件
在JAVA项目下新建配置文件config,内容为:
class=Person
name=jack
JAVA代码:
Properties p = new Properties();
p.load(new FileReader("config"));
String className = (String)p.get("class");
String name = (String)p.get("name");
Class clazz = Class.forName(className);
//创建对象
Constructor constructor = clazz.getConstructor(null);
Object instance = constructor.newInstance();
//通过setName设置name属性
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(instance,name );
//通过getName设置name属性
Method method = clazz.getDeclaredMethod("getName",null);
Object object = method.invoke(instance, null);
System.out.println(object);
p.load(new FileReader("config"));
String className = (String)p.get("class");
String name = (String)p.get("name");
Class clazz = Class.forName(className);
//创建对象
Constructor constructor = clazz.getConstructor(null);
Object instance = constructor.newInstance();
//通过setName设置name属性
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(instance,name );
//通过getName设置name属性
Method method = clazz.getDeclaredMethod("getName",null);
Object object = method.invoke(instance, null);
System.out.println(object);
3:
通过反射给
ArrayList<Integer>
中添加
String
类型的数据
ArrayList
list = new ArrayList
();
list.add(123);
Class clazz = Class.forName("java.util.ArrayList");//必须通过类全名获取
Method method = clazz.getDeclaredMethod("add", Object.class);
method.setAccessible(true);
method.invoke(list, "ss");
for(Object obj: list){
System.out.println(obj);
}
list.add(123);
Class clazz = Class.forName("java.util.ArrayList");//必须通过类全名获取
Method method = clazz.getDeclaredMethod("add", Object.class);
method.setAccessible(true);
method.invoke(list, "ss");
for(Object obj: list){
System.out.println(obj);
}