反射的本质就是:在运行时,把 Java 类中的各种成分映射成一个个的 Java 对象。**
0.反射和类加载关系
类加载过程如下:
-
编译,Java 编译器将 .java 编译产生 .class 二进制文件。
-
加载,JVM 中的类加载器解析.class 文件内的信息。
类加载器会根据类的全限定名来获取此类的二进制字节流,生成代表这个类的 java.lang.Class 对象。
-
加载结束后,JVM 开始进行连接阶段(包含验证、准备、初始化)。经过这一系列操作,类的变量会被初始化。
-
初始化
反射就是上述第二步,**Java 中,无论生成某个类的多少个对象,这些对象都会对应于同一个 Class 对象。**使用反射可获取class,然后进行各种操作。
- JVM 加载方法的时候,遇到 new User(),JVM 会根据 User 的全限定名去加载 User.class 。
- JVM 会去本地磁盘查找 User.class 文件并加载 JVM 内存中。
- JVM 通过调用类加载器自动创建这个类对应的 Class 对象,并且存储在 JVM 的方法区。注意:一个类有且只有一个 Class 对象。
1.获取Class对象的方法
3种:
-
forName
Class c1 = Class.forName("xxx.xxx.xxx");
-
通过类获取Class
Class c2 = Boolean.class;
-
通过对象 getClass
Boolean bool = new Boolean(); Class c3 = bool.getClass();
2.获取Class对象的信息
setAccessible() //是一个通用的方法,可获取到对应信息的超级权限,若当前信息有private等权限控制,该方法可拿到操作权限
构造方法
-
获取constructors数组
cla.getConstructors()
-
获取constructor
getConstructor(Class<?>... parameterTypes)
-
获取非public的构造函数
getDeclaredConstructor(Class<?>... parameterTypes)
使用对象创建实例方式见下
属性
-
获取属性数组
getFields()
-
获取指定Field
getField(String name)
-
获取非public的属性
getDeclaredField(String name)
-
设置属性
set(Object,param)
方法
-
获取方法数组
getMethods()
-
获取指定数组
getMethod(String name, Class<?>... parameterTypes)
-
获取非public数组
getDeclaredMethod(String name, Class<?>... parameterTypes)
-
指定对象调用方法
invoke(Object)
3.反射操作实例对象
判断是否为类的实例两种方式:
- 用 instanceof 关键字
- 用 Class 对象的 isInstance 方法(它是一个 Native 方法)
ArrayList arrayList = new ArrayList();
Boolean isList1 = arrayList instanceof List
Boolean isList2 = List.class.isInstance(arrayList)
创建实例
- 用 Class 对象的 newInstance 方法,没有无参构造函数无法创建,需使用第2种。
- 用 Constructor 对象的 newInstance 方法。
demo:
public class TestReObject {
private int id;
private String name;
public TestReObject(){
}
public TestReObject(int id,String name){
this.id = id;
this.name = name;
}
}
String classString = "reflect.TestReObject";
Class cla = Class.forName(classString);
TestReObject reObject = (TestReObject) cla.newInstance();
Constructor constructor = cla.getConstructor(int.class,String.class);
TestReObject str2 = (TestReObject) constructor.newInstance(12,"abc");
PS
demo
public class AboutReflect {
public static void main(String[] args) {
try {
//获取class对象
Class cla = Class.forName("Base.ObjectTest");
//class对象创建实例对象方式一
ObjectTest objectTest = (ObjectTest) cla.newInstance();
//class对象创建实例对象方式二
Constructor constructor = cla.getConstructor(int.class, String.class);
ObjectTest objectTest1 = (ObjectTest) constructor.newInstance(12, "abc");
//获取 constructor数组及指定constructor
Constructor[] constructors = cla.getConstructors();
Constructor constructor0 = cla.getConstructor();
Constructor constructor1 = cla.getConstructor(int.class,String.class);
//可以获取非public的构造函数
Constructor constructor2 = cla.getDeclaredConstructor(int.class);
System.out.println(constructor2.getParameterCount());
for(Constructor cons:constructors){
System.out.println(cons.getParameterCount());
}
//获取属性
Field[] fields = cla.getFields();
System.out.println("field数量:"+fields.length);
//获取属性的注解,拿到超级权限,然后注入到指定对象
Field fieldId = cla.getDeclaredField("id");
fieldId.setAccessible(true);
fieldId.set(objectTest,fieldId.getAnnotation(TestAnnotation.class).id());
System.out.println(objectTest.toString());
//获取方法 并使用指定对象访问
Method method = cla.getDeclaredMethod("print",int.class,String.class);
method.invoke(objectTest,996,"icu");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ObjectTest {
@TestAnnotation(id=123)
private long id;
private String name;
public ObjectTest() {
}
public ObjectTest(int id, String name) {
this.id = id;
this.name = name;
}
protected ObjectTest(int id){
this.id = id;
}
public void print(int id,String name){
System.out.println(id+"==="+name);
}
@Override
public String toString() {
return "ObjectTest{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
int id() default 1;
}