概述
Java反射机制:在运行状态中,能够知道任意类的所有属性和方法,能够调用任意对象的所有属性和方法
和"反"对应的就是"正",所谓的"正"就是指我们正常new出一个对象进行相应操作。那么如果我们不知道要使用的类是什么怎么办?比如JDBC中加载不同的数据库驱动程序、Spring框架中注入各种Bean,同一个业务要操作很多不同的类,没办法把所有的对象new出来,这时候就要使用反射创建一个实例,然后再操作
常用操作
先写一个类
public class Student {
@Getter
@Setter
private String name;
@Getter
@Setter
private int id;
public Student() {
System.out.println("无参构造器");
}
private Student(String name) {
this.name = name;
System.out.println("name:" + name);
}
public Student(String name, int id) {
this.name = name;
this.id = id;
System.out.println("name:" + name + "id" + id);
}
private void eat(String name) {
System.out.println(name + " eat chuanchuan");
}
public void study(){
System.out.println("study");
}
}
获取Class对象
为什么要获取Class对象呢?因为所有的操作都是要先根据Class对象创建一个实例出来
-
使用Class.forName(“类全名”),因为类可能不存在,所以会抛出ClassNotFoundException异常
Class c1 = Class.forName(“java.lang.String”);
-
通过类名.Class获取,最安全、性能最高,只适合在编译前就知道要操作的类名的场景
Class c1 = String.class
-
通过对象的getClass()获取,适用于传过来一个Object的对象,但是不知道具体是什么类
String str = new String("Hello"); Class c3 = str.getClass();
创建对象
有两种方法:
-
通过Class的newInstance()方法,只能使用无参构造方法
Class<?> studentClass = Student.class; Student student = (Student) studentClass.newInstance();
-
通过Constructor对象的newInstance()方法,可以选择构造方法,但是不能选择私有构造方法,否则会报NoSuchMethodException异常
Constructor<?> constructor1 = studentClass.getConstructor(); Constructor<?> constructor2 = studentClass.getConstructor(String.class); Student s1 = (Student) constructor1.newInstance(); Student s2 = (Student) constructor2.newInstance("zcs");
最后一行代码会报错,因为Student(String name)是私有的,那么如何获取私有的呢?看一下常用API
方法名 作用 getConstructors() 获取public构造方法 getDeclaredConstructors() 获取所有构造方法 getConstructor(Class<?>…) 获取指定参数的public构造方法 getDeclaredConstructor(Class<?>…) 获取指定参数的构造方法(可以是private) 把Constructor换成Field和Method就是对属性和方法的操作,区别就是返回值不同
例如Method method=class.getDeclaredMethod()
还有就是对于获取私有类型的方法(带Declraed的),需要设置setAccessible(true),具体见下文
// 私有构造方法
Constructor<?> constructor3 = studentClass.getDeclaredConstructor(String.class);
constructor3.setAccessible(true);
Student s3 = (Student) constructor3.newInstance("zcs");
// 私有属性
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);
System.out.println(name.get(s3));
// 私有方法,第一个参数是方法名,第二个是参数类型
Method method = studentClass.getDeclaredMethod("eat",String.class);
method.setAccessible(true);
// 第一个参数是实例,第二个是具体参数
method.invoke(s3,"zcs");