1.概念
- 反射机制是在
运行状态
中:
对于任意一个类,都能够知道这个类的所有属性和方法。
对于任意一个对象,都能够调用它的任意一个方法和属性。
2.提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的的成员变量和方法
- 在运行时调用任意一个对象的方法
- 生成动态代理
3.获得反射入口的三种方式(获得类)
1).Class.forName(全类名)(推荐使用)
try {
Class<?> classStu = Class.forName("reflect.Student");
System.out.println(classStu);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
2).类名.class
Class<?> classStu2 = Student.class;
System.out.println(classStu2);
3).对象.getClass()
Student stu = new Student();
Class<?> classStu3 = stu.getClass();
System.out.println(classStu3);
4.通过反射获取类的相关信息
1).获取所有的公共的方法
- 方法范围是本类以及父类、接口中的所有公有的方法
- 符合访问修饰的规律
Method[] methods = classStu.getMethods();
for(Method method : methods) {
System.out.println(method);
}
2).获取该类的所有接口
Class<?>[] interfaces = classStu.getInterfaces();
for(Class<?> inter : interfaces) {
System.out.println(inter);
}
3).获取该类的父类
Class<?> superClass = classStu.getSuperclass();
System.out.println(superClass);
4).获取该类的所有的构造方法
Constructor<?>[] constructors = classStu.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
5).获取所有公共属性
- 属性范围是本类以及父类中的所有公有的属性
Field[] fields = classStu.getFields();
for (Field field : fields) {
System.out.println(field);
}
6).获取当前类的所有方法
- 包含私有方法(忽略访问修饰符)
- 不包括父类方法,但包含接口的实现方法
Method[] declaredMethods = classStu.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
7).获取当前类的所有属性
- 包含私有属性
- 不包含父类属性
Field[] declaredFields = classStu.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
8).获取当前反射所代表类(接口)的对象(实例)
- 相当于new了一个对象
Object newInstance = classStu.newInstance();
Student stu = (Student)newInstance;
stu.breathe();
5.通过反射获取对象的实例,并操作对象(实例)
1).操作属性
- 使用场景:没有set构造器
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());
2).操作函数
- 无参私有函数
Student stu = (Student)classStu.newInstance();
Method method = classStu.getDeclaredMethod("sleep", null);//(函数名,参数)
method.setAccessible(true);//private函数
method.invoke(stu, null);//null表示无参数
- 有参公有函数
Student stu = (Student)classStu.newInstance();
Method method = classStu.getDeclaredMethod("habby", String.class);//参数类型
method.invoke(stu, "篮球");
注:在反射中,基本类型(int)和基本类型的包装类(Integer)是不同的类型
3).操作构造函数
- 可以直接new出一个对象
Constructor<?> constructor = classStu.getConstructor(null);
Student stu = (Student)constructor.newInstance();
System.out.println(stu);
6.动态加载类名和方法
- class.txt
classname=reflect.Student
methodname=staticMethod
- 动态调用
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());
7.通过反射越过泛型检查
- 在Integer列表中加入String
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);
注:虽然可以通过反射访问private等访问修饰符不允许访问的属性和方法,也可以忽略掉泛型检查,但不推荐使用,可能会引起程序的混乱
8.通过反射实现万能set方法
- obj:对象
- propertyName:属性名
- value:属性值
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);
}