Java反射机制知识点总结

1. 反射

在运行状态中,对于任何一个类,都可以知道这个类的所有成员和方法;对于任何一个对象,都可以调用这个变量的所有成员的方法。这种动态获取信息和动态调用对象的方法就是Java的反射。

  • 用途:常用于开发插件和框架,一般在写框架的时候,并不知道实际程序上会有什么样的类,使用反射就可以预先对不同的类做出不同的操作。

  • 能做到的事:

    1. 在程序运行时动态判断一个对象的具体类。
    2. 在程序运行时动态创建一个新的任意类型的对象。
    3. 在程序运行时动态访问一个对象的成员变量和方法。
    4. 绕过泛型的检测。
  • 和泛型的区别:泛型是在编译的时候确认类型,而反射会在运行时动态确认类型以及其他的正确性。由于是动态确认,也有很高的概率出错,所以反射的方法一般都会附带各种各样的Exception。

反射相关类具体描述
Class代表一个Java类的实体
Constructor代表类的构造方法
Field代表类的成员对象
Method代表类的方法

2. 具体用法

首先先设置一个类Student来作为样例,接下来都是以这个类为基础来演示。

public class Student {
    
    //注意每个变量的权限声明
    private String name;
    public String id;

    //注意每个构造方法的权限声明
    public Student(){ }

    private Student(String name){ this.name = name; }

    //注意每个方法的权限声明
    private void setId(String id) { this.id = id; }

    public void setName(String name) { this.name = name; }

    private String getId() { return id; }

    public String getName() { return name; }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                '}';
    }
}

2.1 获取Class类

  1. 直接根据现有的对象获取Class
    Student student = new Student();
    Class stuClass = student.getClass();
    System.out.println(stuClass);
    
  2. 锁定类进行获取Class
    Class stuClass2 = Student.class;
    System.out.println(stuClass2 == stuClass);
    
  3. 根据路径进行获取Class
    try {
    	//注意这里的路径是package相关的路径
        Class stuClass3 = Class.forName("reflection.Student");
        System.out.println(stuClass3 == stuClass);
    }catch (Exception e){
        e.printStackTrace();
    }
    

运行结果:
class reflection.Student
true
true

2.2 访问类的构造方法和创建一个新对象

调用方法返回类型具体描述
getConstructors()Constructor[]获取所有public构造方法
getDeclaredConstructors()Constructor[]获取所有构造方法
getConstructor(Class<?>... parameterTypes)Constructor获取单个public构造方法,参数代表构造函数中参数的类型
传入null表示调用无参数的构造函数
getDeclaredConstructor(Class<?>... parameterTypes)Constructor获取单个无视访问权限的构造方法

Class stuClass = Student.class;

//获取复数构造方法
Constructor[] constructors = stuClass.getConstructors();   //获取所有public构造方法
for (Constructor c: constructors){
    System.out.println(c);
}

System.out.println("------------------------------------------");

//获取复数构造方法
Constructor[] constructors1 = stuClass.getDeclaredConstructors();   //获取所有构造方法
for (Constructor c: constructors1){
    System.out.println(c);
}

System.out.println("-------------------------------------------");

//获取单个构造方法
Constructor constructor = stuClass.getConstructor(null);  //获取无参构造方法
System.out.println(constructor);
//创建一个实例
Object o = constructor.newInstance();
if (o instanceof Student) System.out.println((Student)o);

System.out.println("-------------------------------------------");

//获取单个私有构造方法
Constructor constructor1 = stuClass.getDeclaredConstructor(String.class);  //获取第一个参数是String的构造方法
System.out.println(constructor1);
constructor1.setAccessible(true);  //强制访问,设置之后就可以访问私有方法了
Object o2 = constructor1.newInstance("aaa");
if (o2 instanceof Student) System.out.println((Student)o2);

运行结果:
public reflection.Student()
------------------------------------------
public reflection.Student()
private reflection.Student(java.lang.String)
-------------------------------------------
public reflection.Student()
Student{name=‘null’, id=‘null’}
-------------------------------------------
private reflection.Student(java.lang.String)
Student{name=‘aaa’, id=‘null’}

2.3 访问类的成员变量

调用方法返回类型具体描述
getFields()Field[]获取所有public成员变量
getDeclaredFields()Field[]获取所有成员变量
getField(String name)Field获取单个public成员变量,参数代表变量名
getDeclaredField(String name)Field获取单个成员变量,参数代表变量名
Class stuClass = Student.class;

//获取所有public变量
Field[] fields = stuClass.getFields();
for (Field field: fields){
    System.out.println(field);
}

System.out.println("-------------------------------------------");

//获取所有变量
Field[] fields1 = stuClass.getDeclaredFields();
for (Field field: fields1){
    System.out.println(field);
}

System.out.println("-------------------------------------------");

//获取指定public变量
Field field = stuClass.getField("id");
Object object = stuClass.newInstance();
field.set(object, "123");
System.out.println(object);

System.out.println("-------------------------------------------");

//获取指定变量
Field field1 = stuClass.getDeclaredField(null);
Object object1 = stuClass.newInstance();
field1.setAccessible(true);  //解除私有设定
field1.set(object1, "123");
System.out.println(object1);

运行结果:
public java.lang.String reflection.Student.id
-------------------------------------------
private java.lang.String reflection.Student.name
public java.lang.String reflection.Student.id
-------------------------------------------
Student{name=‘null’, id=‘123’}
-------------------------------------------
Student{name=‘123’, id=‘null’}

2.4 访问类的成员方法

调用方法返回类型具体描述
getMethods()Method[]获取所有public成员方法
getDeclaredMethods()Method[]获取所有成员方法
getMethod(String name, Class<?>... parameterTypes)Method获取单个public成员方法,参数代表方法名和参数类型列表
getDeclaredMethod(String name, Class<?>... parameterTypes)Method获取单个成员方法,参数代表方法名和参数类型列表
Class stuClass = Student.class;

//获取所有public方法
Method[] methods = stuClass.getMethods();
for (Method method: methods){
    System.out.println(method);
}

System.out.println("-------------------------------------------");

//获取所有方法
Method[] methods1 = stuClass.getDeclaredMethods();
for (Method method: methods1){
    System.out.println(method);
}

System.out.println("-------------------------------------------");

//获取指定名字的public方法
Method method = stuClass.getMethod("getName", null);
Object object3 = stuClass.newInstance();
System.out.println(method.invoke(object3, null));

System.out.println("-------------------------------------------");

//获取指定名字的方法
Method method1 = stuClass.getDeclaredMethod("setName", String.class);
Object object4 = stuClass.newInstance();
method1.invoke(object4, "123");
System.out.println(object4);

运行结果:
-------------------------------------------
public java.lang.String reflection.Student.toString()
public java.lang.String reflection.Student.getName()
public void reflection.Student.setName(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-------------------------------------------
public java.lang.String reflection.Student.toString()
public java.lang.String reflection.Student.getName()
public void reflection.Student.setName(java.lang.String)
private java.lang.String reflection.Student.getId()
private void reflection.Student.setId(java.lang.String)
-------------------------------------------
null
-------------------------------------------
Student{name=‘123’, id=‘null’}

2.5 绕过泛型的检测

由于泛型只在编译阶段起作用,而反射则是在运行阶段起作用,用反射就可以绕过泛型的检测机制,做到例如在集合中添加不同类型的数据。

ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);

Class listClass = list.getClass(); //得到 list 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(list, "aaa");

//遍历集合
for(Object obj : list){
    System.out.println(obj);
}

运行结果:
100
200
aaa

参考材料

Java基础之—反射(非常重要) - sinat_38259539的博客 - CSDN博客
https://blog.csdn.net/sinat_38259539/article/details/71799078

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值