JAVA反射机制是在运行状态中
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
1)获取Class对象的三种方式
//Object类中的getObject()方法
Person person = new Person();
Class c1 = person.getClass();
System.out.println(c1);
//类名.class 获取到字节码文件对象
Class c2 = Person.class;
System.out.println(c2);
//通过Class类中的方法
Class c3 = Class.forName("cn.it.ref.Person");
System.out.println(c3);
System.out.println(c1==c2);//T
System.out.println(c1==c3);//T
System.out.println(c3==c2);//T
2)通过反射获取构造方法并使用
@Test
public void func1() throws Exception{
Class c1 = Class.forName("cn.it.ref.Person");
// 获取所有的public 修饰的构造方法
/*Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}*/
//获取public修饰, 指定参数类型所对应的构造方法。
//不传参数得到无参构造方法
//获取指定的构造方法,空参数的构造方法
Constructor constructor = c1.getConstructor();
System.out.println(constructor);//public cn.it.ref.Person()
//运行空参数构造方法,Constructor类方法 newInstance()运行获取到的构造方法
Object obj = constructor.newInstance();
System.out.println(obj);//Person [name=null, age=null]
Constructor constructor2 = c1.getConstructor(String.class,Integer.class);
System.out.println(constructor2);//public cn.it.ref.Person(java.lang.String,java.lang.Integer)
Object obj1 = constructor2.newInstance("jackson",20);
System.out.println(obj1);//Person [name=jackson, age=20]
//前提: 类有空参的公共构造方法,构造方法权限必须public
Object obj2 = c1.newInstance();
System.out.println(obj2);//Person [name=null, age=null]
//反射获取私有的构造方法运行
Constructor declaredConstructor = c1.getDeclaredConstructor(Integer.class,String.class);
//Constructor类,父类AccessibleObject,定义方法setAccessible(boolean b)
declaredConstructor.setAccessible(true);
Object newInstance = declaredConstructor.newInstance(21,"john");
System.out.println(newInstance);//Person [name=john, age=21]
}
3)反射获取成员变量并改值
@Test
public void func2() throws Exception{
Class c = Class.forName("cn.it.ref.Person");
Object obj = c.newInstance();
//获取成员变量 Class类的方法 getFields() class文件中的所有公共的成员变量
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);//public java.lang.String cn.it.ref.Person.name
}
//获取指定的成员变量 String name
Field field = c.getField("name");
field.set(obj, "jackson");
System.out.println(obj);//Person [name=jackson, age=null]
}
4)反射获取成员方法并运行
@Test
public void func3() throws Exception{
Class c = Class.forName("cn.it.ref.Person");
Object obj = c.newInstance();
// Method[] getMethods()获取的是class文件中的所有公共成员方法,包括继承的
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
Method method = c.getMethod("method1");
//obj 指的是调这个方法的对象。
//args 指的是调用这个方法所要用到的参数列表。
//返回值Object就是方法的返回对象。如果方法没有返回值 ,返回的是null.
method.invoke(obj);//method1
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法
Method method1 = c.getMethod("method1", String.class);
method1.invoke(obj, "123456");//method1..123456
}
5)用反射的方法绕过编译,得到Class文件对象,直接调用add方法
反射泛型擦除 java中的泛型是 伪泛型
伪泛型:在编译后的.class文件里面是没有泛型的。类型为Object
@Test
public void func4() throws Exception{
List<String> list = new ArrayList<String>();
list.add("jack");
//反射方式,获取出集合ArrayList类的class文件对象
Class c = list.getClass();
//获取ArrayList.class文件中的方法add
Method method = c.getMethod("add", Object.class);
method.invoke(list, "lucy");
method.invoke(list, 21);
method.invoke(list, 22);
System.out.println(list);
}
6)反射配置文件
pro.properties:
#className=cn.it.ref.Worker
#classMethod=work
className=cn.it.ref.Student
classMethod=student
@Test
public void func5() throws Exception{
//IO流读取配置文件
FileReader fr = new FileReader("src/pro.properties");
//创建集合对象
Properties properties = new Properties();
//调用集合方法load,传递流对象
properties.load(fr);
//关闭流
fr.close();
//通过键获取值
String className = properties.getProperty("className");
String classMethod = properties.getProperty("classMethod");
//反射获取指定类的class文件对象
Class c = Class.forName(className);
Object newInstance = c.newInstance();
//获取指定的方法名
Method method = c.getMethod(classMethod);
method.invoke(newInstance);
}