摘要:本文学习了什么是反射,以及如何使用反射。
环境
Windows 10 企业版 LTSC 21H2 Java 1.8
1 简介 反射被视为动态语言的关键,反射机制允许程序在执行期借助于API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。
这个Class类型的对象就像一面镜子,可以透过这个镜子看到类的结构,所以形象的称之为反射。
2 原理 2.1 Class 2.1.1 定义 Class是用来描述类的类,封装了当前对象所对应的类的信息,通过Class可以得到一个类中所有被加载的结构。
将书看做一个对象,一本书有名称,作者,字数等,使用Book类描述所有书的信息。根据万物皆对象,可以将类看做一个对象,一个类中有属性,方法,构造器等,使用Class类描述所有类的信息。
Class类是一特殊的类,对于每个类而言,虚拟机都为其保留一个不变的Class类的对象。Class类的对象只能由虚拟机创建,一个类只能有一个Class类的对象。
支持Class实例的类型:类,接口,枚举,注解,数组,基本数据类型(包含Void类但不存在Null类)。
2.1.2 方法 类的信息:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static Class<?> forName(String className);public T newInstance () ;public String getName () ;public Package getPackage () ;public native int getModifiers () ;public ClassLoader getClassLoader () ;public InputStream getResourceAsStream (String name) ;
属性和方法:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public Field getField (String name) ;public Field getDeclaredField (String name) ;public Field[] getFields();public Field[] getDeclaredFields();public Method getMethod (String name, Class<?>... parameterTypes) ;public Method getDeclaredMethod (String name, Class<?>... parameterTypes) ;public Method[] getMethods();public Method[] getDeclaredMethods();public Constructor<T> getConstructor (Class<?>... parameterTypes) ;public Constructor<T> getDeclaredConstructor (Class<?>... parameterTypes) ;public Constructor<?>[] getConstructors();public Constructor<?>[] getDeclaredConstructors();
继承和实现:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public Annotation[] getAnnotations();public Annotation[] getDeclaredAnnotations();public <A extends Annotation > A getAnnotation (Class<A> annotationClass) ;public <A extends Annotation > A getDeclaredAnnotation (Class<A> annotationClass) ;public Class<?>[] getInterfaces();public Type[] getGenericInterfaces();public native Class<? super T> getSuperclass();public Type getGenericSuperclass () ;
2.1.3 获取 Class没有公共构造方法,Class对象是在加载类时由虚拟机创建的。
获取Class类的实例有四种方式:
直接调用运行时类的.class属性:java 1 Class clazz = String.class;
通过调用运行时类的对象的getClass()方法:java 1 Class clazz = "www.demo.com" .getClass();
调用Class的forName()方法:java 1 Class clazz = Class.forName("refl.Person" );
使用ClassLoader的loadClass()方法:java 1 2 ClassLoader cl = this .getClass().getClassLoader();Class clazz = cl.loadClass("refl.Person" );
使用Class的forName()方法和使用ClassLoader的loadClass()方法都能获取指定类的Class实例,也都会进行类的加载,都能将class字节码文件加载到虚拟机中。
其区别是:
在调用Class的forName()方法时,会进行类的加载以外,也会进行类的初始化,初始化静态成员变量和执行静态代码块,但不会执行构造方法创建对象。只有在调用了newInstance()方法后,才会调用空参的构造方法创建对象。
在调用ClassLoader的loadClass()方法时,只会进行类的加载,不会进行类的初始化,也不会执行构造方法创建对象。
2.2 ClassLoader 2.2.1 类的加载过程 当程序主动使用了某个类时,该类还未被加载到内存中,那么系统会通过下面三个步骤对该类进行初始化:
类的加载:将类的class文件读入内存,并为之创建一个Class对象。由类加载器完成。
类的连接:将类的二进制数据合并到JRE中。
类的初始化:JVM负责对类进行初始化。
2.2.2 类的初始化 类的主动引用一定会发生类的初始化,类的被动引用不会发生类的初始化。
类的主动引用场景:
当虚拟机启动,先初始化main方法所在的类。
使用new关键字创建了一个类的对象。
调用类的静态成员(除了final常量)和静态方法。
使用java.lang.reflect包的方法对类进行反射调用。
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类。
类的被动引用场景:
当访问一个静态域时,只有真正声明这个域的类才会被初始化。
当通过子类引用父类的静态变量,不会导致子类初始化。
通过数组定义类引用,不会触发此类的初始化。
引用常量不会触发此类的初始化,常量在连接阶段就存入调用类的常量池中了。
2.2.3 类加载器的作用 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。
2.2.4 类加载器的分类 类加载器分为三种:
引导类加载器:用C++编写的,是JVM自带的类装载器,负责Java平台核心库,用来装载核心类库。无法直接获取。
扩展类加载器:负责jre/lib/ext目录下的Jar包或–D java.ext.dirs指定目录下的Jar包装入工作库。
系统类加载器:负责java –classpath或–D java.class.path所指的目录下的类与Jar包装入工作,最常用的加载器。
2.2.5 常用方法 常用方法:
java 1 2 3 4 5 6 7 8 9 10 public Class<?> loadClass(String name);public static ClassLoader getSystemClassLoader () ;public final ClassLoader getParent () ;public static InputStream getSystemResourceAsStream (String name) ;public InputStream getResourceAsStream (String name) ;
2.2.6 获取类加载器 获取系统类加载器(可以获取):
java 1 ClassLoader.getSystemClassLoader();
获取扩展类加载器(可以获取):
java 1 ClassLoader.getSystemClassLoader().getParent();
获取引导类加载器(不可以获取):
java 1 ClassLoader.getSystemClassLoader().getParent().getParent();
2.2.7 测试类加载器 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void main (String[] args) { ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(appClassLoader); ClassLoader extClassLoader = appClassLoader.getParent(); System.out.println(extClassLoader); ClassLoader bootClassLoader = extClassLoader.getParent(); System.out.println(bootClassLoader); System.out.println(ClassLoaderTest.class.getClassLoader()); System.out.println(String.class.getClassLoader()); }
结果:
log 1 2 3 4 5 sun.misc.Launcher$AppClassLoader@18b4aac2 sun.misc.Launcher$ExtClassLoader@6d9c638 null sun.misc.Launcher$AppClassLoader@18b4aac2 null
2.2.8 测试加载资源 示例:
java 1 2 3 4 InputStream is3 = ClassLoader.getSystemClassLoader().getResourceAsStream("com/test/test.txt" );InputStream is4 = ClassLoader.getSystemResourceAsStream("com/test/test.txt" );
3 使用 3.1 定义类和接口 定义接口:
java 1 2 3 4 public interface Home <H> { public String address = "" ; public String location () ; }
定义父类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public abstract class People <P> { public People () { System.out.println("do >>> People()" ); } private Integer age; public String name; public Integer getAge () { return age; } public void setAge (Integer age) { this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public String talk (String topic) { System.out.println("do >>> talk() " + topic); return name; } @Override public String toString () { String ageStr = "age=" + age; String nameStr = "name=" + name; return "People{" + ageStr + ", " + nameStr + "}" ; } }
定义子类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class Student extends People <Integer> implements Serializable , Home<String> { public String teacher; private Integer grade; public Student () { System.out.println("do >>> Student()" ); } private Student (Integer grade) { System.out.println("do >>> Student(grade)" ); this .grade = grade; } public String getTeacher () { return teacher; } public void setTeacher (String teacher) { this .teacher = teacher; } public Integer getGrade () { return grade; } public void setGrade (Integer grade) { this .grade = grade; } @Deprecated private Integer exam (String name) throws ArithmeticException { System.out.println("do >>> exam() " + name); return 98 ; } @Override public String location () { return address; } @Override public String toString () { String teacherStr = "teacher=" + teacher; String gradeStr = "grade=" + grade; return "Student{" + teacherStr + ", " + gradeStr + "}" ; } }
3.2 测试类的信息 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Demo { public static void main (String[] args) throws Exception { Class<?> cla = Class.forName("test.Student" ); Student student = (Student) cla.newInstance(); System.out.println("student.toString() >>> " + student); System.out.println("cla.getName() >>> " + cla.getName()); System.out.println("cla.getPackage() >>> " + cla.getPackage()); System.out.println("cla.getModifiers() >>> " + cla.getModifiers()); System.out.println("cla.getModifiers() >>> " + Modifier.toString(cla.getModifiers())); System.out.println("cla.getClassLoader() >>> " + cla.getClassLoader()); } }
结果:
log 1 2 3 4 5 6 7 8 do >>> People() do >>> Student() student.toString() >>> Student{teacher=null, grade=null} cla.getName() >>> test.Student cla.getPackage() >>> package test cla.getModifiers() >>> 1 cla.getModifiers() >>> public cla.getClassLoader() >>> sun.misc.Launcher$AppClassLoader@18b4aac2
3.3 测试类的继承和实现 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Demo { public static void main (String[] args) throws Exception { System.out.println("cla.getSuperclass() >>> " + cla.getSuperclass().getName()); Type genericSuperclass = cla.getGenericSuperclass(); System.out.println("cla.getGenericSuperclass() >>> " + genericSuperclass.getTypeName()); ParameterizedType paramType = (ParameterizedType) genericSuperclass; Type[] actualTypeArguments = paramType.getActualTypeArguments(); for (Type type : actualTypeArguments) { System.out.println("cla.getGenericSuperclass().getActualTypeArguments() >>> " + type.getTypeName()); } Class<?>[] interfaces = cla.getInterfaces(); for (Class<?> interfaceClass : interfaces) { System.out.println("cla.getInterfaces() >>> " + interfaceClass.getName()); } Type[] genericInterfaces = cla.getGenericInterfaces(); for (Type genericInterface : genericInterfaces) { System.out.println("cla.getGenericInterfaces() >>> " + genericInterface.getTypeName()); } } }
结果:
log 1 2 3 4 5 6 7 cla.getSuperclass() >>> test.People cla.getGenericSuperclass() >>> test.People<java.lang.Integer> cla.getGenericSuperclass().getActualTypeArguments() >>> java.lang.Integer cla.getInterfaces() >>> java.io.Serializable cla.getInterfaces() >>> test.Home cla.getGenericInterfaces() >>> java.io.Serializable cla.getGenericInterfaces() >>> test.Home<java.lang.String>
3.4 测试类的属性 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Demo { public static void main (String[] args) throws Exception { Field[] fields = cla.getFields(); for (Field field : fields) { System.out.println("cla.getFields() >>> " + field); } Field[] declaredFields = cla.getDeclaredFields(); for (Field field : declaredFields) { System.out.println("cla.getDeclaredFields() >>> " + field); } System.out.println("cla.getField(name) >>> " + cla.getField("name" )); Field grade = cla.getDeclaredField("grade" ); System.out.println("cla.getDeclaredField(grade) >>> " + grade); System.out.println("grade.getModifiers() >>> " + Modifier.toString(grade.getModifiers())); System.out.println("grade.getType() >>> " + grade.getType().getTypeName()); System.out.println("grade.getName() >>> " + grade.getName()); grade.setAccessible(true ); grade.set(student, 100 ); System.out.println("grade.get(student) >>> " + grade.get(student)); } }
结果:
log 1 2 3 4 5 6 7 8 cla.getFields() >>> public ... cla.getDeclaredFields() >>> ... cla.getField(name) >>> public java.lang.String test.People.name cla.getDeclaredField(grade) >>> private java.lang.Integer test.Student.grade grade.getModifiers() >>> private grade.getType() >>> java.lang.Integer grade.getName() >>> grade grade.get(student) >>> 100
3.5 测试类的方法 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class Demo { public static void main (String[] args) throws Exception { Method[] methods = cla.getMethods(); for (Method method : methods) { System.out.println("cla.getMethods() >>> " + method); } Method[] declaredMethods = cla.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println("cla.getDeclaredMethods() >>> " + method); } System.out.println("cla.getMethod(talk, String.class) >>> " + cla.getMethod("talk" , String.class)); Method exam = cla.getDeclaredMethod("exam" , String.class); System.out.println("cla.getDeclaredMethod(exam, String.class) >>> " + exam); Annotation[] annotations = exam.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("exam.getAnnotations() >>> " + annotation); } System.out.println("exam.getModifiers() >>> " + Modifier.toString(exam.getModifiers())); System.out.println("exam.getReturnType() >>> " + exam.getReturnType().getTypeName()); System.out.println("exam.getName() >>> " + exam.getName()); Parameter[] parameters = exam.getParameters(); for (Parameter parameter : parameters) { System.out.println("exam.getParameters() >>> " + parameter); } Class[] exceptionTypes = exam.getExceptionTypes(); for (Class exceptionType : exceptionTypes) { System.out.println("exam.getExceptionTypes() >>> " + exceptionType.getTypeName()); } exam.setAccessible(true ); Object result = exam.invoke(student, "Tom" ); System.out.println("exam.invoke(student, Tom) >>> " + result); } }
结果:
log 1 2 3 4 5 6 7 8 9 10 11 12 cla.getMethods() >>> public ... cla.getDeclaredMethods() >>> ... cla.getMethod(talk, String.class) >>> public java.lang.String test.People.talk(java.lang.String) cla.getDeclaredMethod(exam, String.class) >>> private java.lang.Integer test.Student.exam(java.lang.String) throws java.lang.ArithmeticException exam.getAnnotations() >>> @java.lang.Deprecated() exam.getModifiers() >>> private exam.getReturnType() >>> java.lang.Integer exam.getName() >>> exam exam.getParameters() >>> java.lang.String name exam.getExceptionTypes() >>> java.lang.ArithmeticException do >>> exam() Tom exam.invoke(student, Tom) >>> 98
3.6 测试类的构造方法 示例:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Demo { public static void main (String[] args) throws Exception { Constructor<?>[] constructors = cla.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("cla.getConstructors() >>> " + constructor); } Constructor<?>[] declaredConstructors = cla.getDeclaredConstructors(); for (Constructor<?> constructor : declaredConstructors) { System.out.println("cla.getDeclaredConstructors() >>> " + constructor); } System.out.println("cla.getConstructor() >>> " + cla.getConstructor()); Constructor<?> constructor = cla.getDeclaredConstructor(Integer.class); System.out.println("cla.getDeclaredConstructor() >>> " + constructor); constructor.setAccessible(true ); student = (Student) constructor.newInstance(10 ); System.out.println("student >>> " + student); } }
结果:
log 1 2 3 4 5 6 7 8 cla.getConstructors() >>> public test.Student() cla.getDeclaredConstructors() >>> public test.Student() cla.getDeclaredConstructors() >>> private test.Student(java.lang.Integer) cla.getConstructor() >>> public test.Student() cla.getDeclaredConstructor() >>> private test.Student(java.lang.Integer) do >>> People() do >>> Student(grade) student >>> Student{teacher=null, grade=10}
条