反射机制
反射是一种机制,利用该机制可以在程序运行过程中,对类进行解剖,并获得操作类中的方法,属性,构造成员等。
反射就直接操作class字节码,获得方法,属性,构造成员。
反射是在生成字节码文件之后,对字节码文件进行的操作。
1、获取Class对象的三种方式
//创建测试类试Student
public class Student{
//属性
//行为
}
方式1、通过类名.class获取
//格式:类名.class 属性
//常用场景:反射获取方式,确定方法的形参列表类型
public void test01(){
Class<Student> cls = Student.class;
}
方式2、通过Object类的成员方法getClass()方法获取
public void test02(){
Student stu = new Student();
showInfo(stu);
}
public void showInfo(Object obj){
// 方式二 : 使用对象名调用 getClass() 方法.
// 格式 : 对象名.getClass() 方法.
// 使用场景 : 在方法内部, 确定传入形参的真实类型
Class<?> cls = obj.getClass();
System.out.println("cls="+cls)
}
方式3、通过Class.forName(“全限定类名”)方法获取
public void test3() throws ClassNotFoundException {
// 方式三 : 使用 Class 调用静态方法 forName(全限定类名); `包名+类名`
// 使用场景 : 加载外部的配置文件时使用
Class<?> cls = Class.forName("cn.itcast.test2.Student");
System.out.println("cls = " + cls);
}
在获取类对象之后,介绍几个Class类中的常用方法
获取Class中Constructor的相关方法
1.Constructor getConstructor(Class...parameterType);
//根据参数类型获取构造方法对象,只能获得public修饰的构造方法。
//如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
2.Constructor getDeclaredConstructor(Class...parameter);
//根据参数类型获取构造方法对象,包括private修饰的构造方法。
//如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
3. Constructor[] getConstructors() ;
//获取所有的public修饰的构造方法
4. Constructor[] getDeclaredConstructors();
//获取所有构造方法,包括privat修饰的
Constructor类中的常用方法
1. T newInstance(Object... initargs)
//根据指定参数创建对象。
2. void setAccessible(true)
//暴力反射,设置为可以直接访问私有类型的构造方法。
示例
学生类
public class Student {
// 属性
private String name;
private int age;
private char gender;
// 公开构造方法 :
public Student(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 私有构造方法 :
private Student(String name, int age) {
this.name = name;
this.age = age;
}
// 公开无参构造方法
public Student() {
}
// 行为
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
示例方法1
public void testConstructor1() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 getConstructor 方法
Constructor<?> constructor = cls.getConstructor(String.class, int.class, char.class);
// 3. 调用 Constructor 对象的 newInstance 方法, 创建对象
Object obj = constructor.newInstance("柳岩", 18, '女');
// 4. 查看创建的对象
System.out.println("obj = " + obj);
}
```
#### 示例方法2
```
public void testDeclaredConstructor2() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 getDeclaredConstructor 方法
Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);
// 3. 暴力反射 (设置可访问权限)
constructor.setAccessible(true);
// 4. 调用 Constructor 对象的 newInstance 方法, 创建对象
Object obj = constructor.newInstance("柳岩", 18);
// 5. 查看创建的对象
System.out.println("obj = " + obj);
}
Class类中与Method相关方法
1. Method getMethod("方法名", 方法的参数类型... 类型) ;
//根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
2. Method getDeclaredMethod("方法名", 方法的参数类型... 类型);
//根据方法名和参数类型获得一个方法对象,包括private修饰的
3. Method[] getMethods() (了解);
//获取所有的public修饰的成员方法,包括父类中。
4. Method[] getDeclaredMethods() (了解);
//获取当前类中所有的方法,包含私有的,不包括父类中。
method类中的常用方法
1. Object invoke(Object obj, Object... args) ;
//根据参数args调用对象obj的该成员方法
//如果obj=null,则表示该方法是静态方法
2. void setAccessible(boolean flag) ;
//暴力反射,设置为可以直接调用私有修饰的成员方法
示例代码1
@Test
public void testMethod1() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 getMethod 方法
Method eat = cls.getMethod("eat", String.class);
// 3. 调用 invoke 方法
Object obj = cls.getDeclaredConstructor().newInstance();
eat.invoke(obj, "牛肉");
}
示例代码2
@Test
public void testDeclaredMethod2() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 declaredMethod 方法
Method sleep = cls.getDeclaredMethod("fallInLove");
// 3. 暴力反射 (设置可访问权限)
sleep.setAccessible(true);
// 4. 调用 invoke 执行
Object obj = cls.getDeclaredConstructor().newInstance();
sleep.invoke(obj);
}
Class类中与Field相关方法
1. Field getDeclaredField(String name) ;
// 根据属性名获得属性对象,包括private修饰的
2. Field getField(String name) ;
// 根据属性名获得属性对象,只能获取public修1饰的
3. Field[] getFields() ;
// 获取所有的public修饰的属性对象,返回数组。
4. Field[] getDeclaredFields() ;
// 获取所有的属性对象,包括private修饰的,返回数组。
Field类中常用方法
void set(Object obj, Object value) ;
Object get(Object obj) ;
void setAccessible(true);
//暴力反射,设置为可以直接访问私有类型的属性。
Class getType();
//获取属性的类型,返回Class对象
示例代码1
public void testField1() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 getField 方法
Field description = cls.getField("description");
// 3. 设置属性
Object obj = cls.getDeclaredConstructor().newInstance();
description.set(obj, "这就是那个神奇的学生.");
// 4. 获取属性
Object desc = description.get(obj);
System.out.println("desc = " + desc);
}
输出结果 :
desc = 这就是那个神奇的学生.
代码示例2
@Test
public void testDeclaredField2() throws Exception {
// 1. 获取 Student 类表示的 Class 对象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 调用 getDeclaredField 方法
Field name = cls.getDeclaredField("name");
// 3. 暴力反射
name.setAccessible(true);
// 4. 设置属性
Object obj = cls.getDeclaredConstructor().newInstance();
name.set(obj, "渣渣辉");
// 5. 查看
System.out.println(obj);
}
输出结果 :
Student{name='渣渣辉', age=0, gender= }