一、定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
二、常用方法总结
########## | 类 | 属性 | 方法 | 构造方法 | 注解 |
---|---|---|---|---|---|
获得公共,指定名字/类型 单个 | getField(String name) | getMethod(String name, Class…<?> parameterTypes) | getConstructor(Class…<?> parameterTypes) | getAnnotation(Class annotationClass) | |
获得公共,所有 | getClasses() | getFields() | getMethods() | getConstructors() | getAnnotations() |
获得指定名字/类型单个 (包括私有) | getDeclaredField(String name) | getDeclaredMethod(String name, Class…<?> parameterTypes) | getDeclaredConstructor(Class…<?> parameterTypes) | getDeclaredAnnotation(Class annotationClass) | |
获得所有 (包括私有) | getDeclaredClasses() | getDeclaredFields() | getDeclaredMethods() | getDeclaredConstructors() | getDeclaredAnnotations() |
其他 | forName(String className)根据类名返回类的对象 | set(Object obj, Object value)设置obj中对应属性值;get(Object obj)获得obj中对应的属性值 | invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法 | newInstance(Object… initargs)根据传递的参数创建类的对象 | isAnnotation(),isAnnotationPresent(Class<? extends Annotation> annotationClass) |
二、反射使用
1.获取类对象有3种方式
- Class.forName()(常用)
- Hero.class, 需要导入类, 有依赖
- new Hero().getClass(), 能拿到对象,就无需用反射了
在ClassLoader下,一种类只有一个类对象。所以三种结果是一样的
@Test
public void test_reflect() throws ClassNotFoundException {
Object obj = Class.forName("com.learning.reflect.Person");
Class obj2 = Person.class;
Class obj3 = new Person().getClass();
System.out.println(obj == obj2);//true
System.out.println(obj == obj3);//true
}
2. 利用反射创建对象
步骤
1)获取类对象
2)获取构造对象
3)获取对象
以下是使用有参构造器实例对象的例子:
@Test
public void test_reflect_new_object_with_parameter() throws Exception {
//1)获取类对象
Class<?> pClass = Class.forName("com.learning.reflect.Person");
//2)获取构造对象
Constructor<?> con = pClass.getDeclaredConstructor(String.class);// 调用了Person的有参构造器, 参数为String name
//3)获取对象'
Person o = (Person) con.newInstance("Vivi");
System.out.println(o.toString());//Person{name='Vivi', age=0}
}
@Test
public void test_reflect_new_object_with_parameter_pravite() throws Exception {
//1)获取类对象
Class<?> pClass = Class.forName("com.learning.reflect.Person");
//2)获取构造对象
Constructor<?> con = pClass.getDeclaredConstructor(int.class);//调用了Person的有参构造器, 参数为int age
//3)获取对象'
con.setAccessible(true); //如果方法/属性是私有的,则需要设置Accessible为true
Person o = (Person) con.newInstance(18);
System.out.println(o.toString());//Person{name='null', age=18}
}
@Test
public void test_reflect_new_object_no_parameter() throws Exception {
//1)获取类对象
Class<?> pClass = Class.forName("com.learning.reflect.Person");
//2)获取构造对象
Constructor<?> con = pClass.getDeclaredConstructor();//调用了Person的无参构造器
//3)获取对象'
Person o = (Person) con.newInstance();
System.out.println(o.toString());//Person{name='null', age=0}
//与以下写法一样, 如果使用无参构造,则可省略2), 直接用类对象pClass.newInstance()
Person person = (Person) pClass.newInstance();//调用了Person的无参构造器
System.out.println(person.toString());//Person{name='null', age=0}
}
注意:
- 用无参构造实例对象。可省略2), 直接用类对象pClass.newInstance()
- 如果方法/属性是私有的,则需要设置Accessible为true con.setAccessible(true);
3. 利用反射获得并设置属性
@Test
public void test_reflect_set_private_field() throws Exception {
//获得类对象
Class pClass = Class.forName("com.learning.reflect.Person");
//通过无参构造器获得对象
Person person = (Person)pClass.newInstance();//调用了Person的无参构造器
//得到属性
Field pName = pClass.getDeclaredField("name");
//私有属性,需要设置Accessible为true
pName.setAccessible(true);
//设置属性
pName.set(person, "Vivi");
System.out.println(person);//Person{name='Vivi', age=0}
}
4. 获得方法并使用
@Test
public void test_reflect_set_private_method() throws Exception {
//获得类对象
Class pClass = Class.forName("com.learning.reflect.Person");
//通过无参构造器获得对象
Person person = (Person)pClass.newInstance();//调用了Person的无参构造器
//得到方法
Method pMethod = pClass.getDeclaredMethod("play",java.lang.String.class);
//私有方法,需要设置Accessible为true
pMethod.setAccessible(true);
//方法调用
pMethod.invoke(person, "Shanghai");//playing in Shanghai
}
测试的Person类:
public class Person {
private String name;
private int age;
private void play(String city){
System.out.println("playing in " + city);
}
public Person(String name, int age) {
System.out.println("调用了Person的有参构造器, 参数为String name, int age");
this.name = name;
this.age = age;
}
public Person(String name) {
System.out.println("调用了Person的有参构造器, 参数为String name");
this.name = name;
}
private Person(int age) {
System.out.println("调用了Person的有参构造器, 参数为int age");
this.age = age;
}
public Person() {
System.out.println("调用了Person的无参构造器");
}
...set/get/toString...
}