一、反射
概念:反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)
作用:
- 得到一个类的全部成分然后操作。
- 破坏封装性,可以访问私有的对象
- 绕过范型约束,比如定义了一个String 类型的 ArrayList, 通过反射,可以添加 其它类型的数据。
反射第一步:加载类,获取类的 Class 对象
获取 Class 对象的三种方式
- Class c1 = 类名.class
- 调用 Class 提供方法:public static Class forName(String package);
- Object 提供的方法:public Class getClass(); Class c3 = 对象.getClass();
1. 获取类对象
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
// 1. Class c1 = 类名.class
Class c1 = Student.class;
System.out.println(c1.getSimpleName()); // 输出 类名
System.out.println(c1); // 输出 class 包名.类名
// 2. 调用 Class 提供方法:public static Class forName(String package);
Class c2 = Class.forName("reflect.Student");
System.out.println(c2); //输出 class 包名.类名
// 3. Object 提供的方法:public Class getClass();
Student student = new Student();
Class c3 = student.getClass();
System.out.println(c2); //输出 class 包名.类名
}
}
2. 获取构造器
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException {
// 获取构造器信息并进行操作
// 获取多个构造器
Constructor[] cons = c1.getDeclaredConstructors();
for (Constructor con : cons) {
// reflect.Student(0) 无参 、 reflect.Student(2) 2个参数构造
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
}
// 获取单个构造器
Constructor con1 = c1.getDeclaredConstructor();// 无参构造
System.out.println(con1.getName() + "(" + con1.getParameterCount() + ")"); // reflect.Student(0)
}
// 指定获取单个有参构造器(Integer 类型和 String 类型的构造器)
Constructor con1 = c1.getDeclaredConstructor(Integer.class, String.class);// 有参构造
System.out.println(con1.getName() + "(" + con1.getParameterCount() + ")"); // reflect.Student(2)
}
3. 获取成员变量
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
// 反射类第一步:获取类的信息
Class c1 = Student.class;
Field field = c1.getDeclaredField("name"); // name 是成员变量名称
Field field1 = c1.getDeclaredField("age"); // aeg 是成员变量名称
System.out.println(field.getName() + "(" + field.getType().getName() + ")"); // name(java.lang.String)
System.out.println(field1.getName() + "(" + field1.getType().getName() + ")"); // age(java.lang.Integer)
//获取成员变量目的还是取值和赋值
Field ageField = c1.getDeclaredField("age");
Student stu = new Student("张安");
ageField.setAccessible(true); // 私有属性不能直接访问,需要绕过访问权限直接访问
ageField.set(stu, 19);
System.out.println(stu); // Student{age=19, name='张安'}
Integer age = (Integer) ageField.get(stu); // 等价于 stu.getAge()
System.out.println(age); // 19
}
}
4 获取方法
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
// 反射类第一步:获取类的信息
Class c1 = Student.class;
// 获取单个成员变量方法
Method m0 = c1.getDeclaredMethod("eat"); // 获取无参参方法
Method m1 = c1.getDeclaredMethod("eat", String.class); // 获取有参方法
System.out.println(m0.getName() + "(" + m0.getParameterCount() + ")"); // eat(0)
System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")"); // eat(1)
Student s1 = new Student(20, "小红");
m0.setAccessible(true); // 绕过访问权限,直接访问
Object res1 = m0.invoke(s1);// 唤醒对象的 eat 无参 方法,相当于 student.eat();
System.out.println(res1);
Object res2 = m1.invoke(s1, "皮蛋"); // 有参方法
System.out.println(res2);
}
}