概念

  • 反射机制是在运行状态中:
    对于任意一个类,都能够知道这个类的所有属性和方法。
    对于任意一个对象,都能够调用它的任意一个方法和属性。

提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

获得反射入口的三种方式(获得类)

Class.forName(全类名)(推荐使用)

1
2
3
4
5
6
try {
Class<?> classStu = Class.forName("reflect.Student");
System.out.println(classStu);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

类名.class

1
2
Class<?> classStu2 = Student.class;
System.out.println(classStu2);

对象.getClass()

1
2
3
Student stu = new Student();
Class<?> classStu3 = stu.getClass();
System.out.println(classStu3);

通过反射获取类的相关信息

获取所有的公共的方法

  • 方法范围是本类以及父类、接口中的所有公有的方法
  • 符合访问修饰的规律
1
2
3
4
Method[] methods = classStu.getMethods();
for(Method method : methods) {
System.out.println(method);
}

获取该类的所有接口

1
2
3
4
Class<?>[] interfaces = classStu.getInterfaces();
for(Class<?> inter : interfaces) {
System.out.println(inter);
}

获取该类的父类

1
2
Class<?> superClass = classStu.getSuperclass();
System.out.println(superClass);

获取该类的所有的构造方法

1
2
3
4
Constructor<?>[] constructors = classStu.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}

获取所有公共属性

  • 属性范围是本类以及父类中的所有公有的属性
1
2
3
4
Field[] fields = classStu.getFields();
for (Field field : fields) {
System.out.println(field);
}

获取当前类的所有方法

  • 包含私有方法(忽略访问修饰符)
  • 不包括父类方法,但包含接口的实现方法
1
2
3
4
Method[] declaredMethods = classStu.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}

获取当前类的所有属性

  • 包含私有属性
  • 不包含父类属性
1
2
3
4
Field[] declaredFields = classStu.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}

获取当前反射所代表类(接口)的对象(实例)

  • 相当于new了一个对象
1
2
3
Object newInstance = classStu.newInstance();
Student stu = (Student)newInstance;
stu.breathe();

通过反射获取对象的实例,并操作对象(实例)

操作属性

  • 使用场景:没有set构造器
1
2
3
4
5
Student stu = (Student)classStu.newInstance();
Field idFieAge = classStu.getDeclaredField("age");
idFieAge.setAccessible(true);//修改访问权限(private)
idFieAge.set(stu, 1);//相当于stu.setAge(1);
System.out.println(stu.getAge());

操作函数

  • 无参私有函数
1
2
3
4
Student stu = (Student)classStu.newInstance();
Method method = classStu.getDeclaredMethod("sleep", null);//(函数名,参数)
method.setAccessible(true);//private函数
method.invoke(stu, null);//null表示无参数
  • 有参公有函数
1
2
3
Student stu = (Student)classStu.newInstance();
Method method = classStu.getDeclaredMethod("habby", String.class);//参数类型
method.invoke(stu, "篮球");

注:在反射中,基本类型(int)和基本类型的包装类(Integer)是不同的类型

操作构造函数

  • 可以直接new出一个对象
1
2
3
Constructor<?> constructor = classStu.getConstructor(null);
Student stu = (Student)constructor.newInstance();
System.out.println(stu);

动态加载类名和方法

  • class.txt
1
2
classname=reflect.Student
methodname=staticMethod
  • 动态调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Properties prop = new Properties();
prop.load(new FileReader("class.txt"));

String classname = prop.getProperty("classname");
String methodname = prop.getProperty("methodname");

Class<?> classStu = null;
//反射入口
try {
classStu = Class.forName(classname);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

Method method = classStu.getMethod(methodname);
method.setAccessible(true);
method.invoke(classStu.newInstance());

通过反射越过泛型检查

  • 在Integer列表中加入String
1
2
3
4
5
6
7
8
9
ArrayList<Integer> list = new ArrayList();
list.add(123);
list.add(22);

Class<?> classStu = list.getClass();

Method method = classStu.getMethod("add", Object.class);
method.invoke(list, "ssss");
System.out.println(list);
  • 结果

    [123, 22, ssss]

注:虽然可以通过反射访问等访问修饰符不允许访问的属性和方法,也可以忽略掉泛型检查,但不推荐使用,可能会引起程序的混乱

通过反射实现万能set方法

  • obj:对象
  • propertyName:属性名
  • value:属性值
1
2
3
4
5
6
7
8
public static void setProperty(Object obj, String propertyName, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {

Class<?> clazz = obj.getClass();
Field field = clazz.getDeclaredField(propertyName);
field.setAccessible(true);
field.set(obj, value);

}