Java学习——反射
Java学习——反射
摘要:本文主要讲述了什么是反射,使用反射有什么好处,以及如何使用反射。
部分内容来自以下博客:
https://www.cnblogs.com/tech-bird/p/3525336.html
https://www.cnblogs.com/jiaoyiping/p/6130355.html
什么是反射
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
Class类
Class类是什么
Class是用来描述类的类,封装了当前对象所对应的类的信息。
一个类中有属性,方法,构造器等,比如说有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述类,这就是Class,它应该有类名,属性,方法,构造器等。
Class类是一个对象照镜子的结果,对象可以看到自己有哪些属性,方法,构造器,实现了哪些接口等等。
对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。
Class对象只能由系统建立对象,一个类(而不是一个对象)在JVM中只会有一个Class实例。
通过Class可以完整地得到一个类中的所有被加载的结构。
Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象。
Java中的哪些类型可以有Class类的实例
类,接口,枚举,注解,数组,基本数据类型,void。
常用方法
static Class<?> forName(String className):返回指定类名的Class对象。
T newInstance():返回该Class对象对应的类的一个实例。
Field[] getFields():获取所有的公共属性。
Field[] getDeclaredFields():获取所有的属性。
Field getField(String name):获取指定名称的公共属性。
Field getDeclaredField(String name):获取指定名称的属性。
Method[] getMethods():获取所有的公共方法。
Method[] getDeclaredMethods():获取所有的方法。
Method getMethod(String name, Class<?>... parameterTypes):返回指定名称、参数列表的公共方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回指定名称、参数列表的方法。
Constructor<?>[] getConstructors():获取所有的公共构造方法。
Constructor<?>[] getDeclaredConstructors():获取所有的构造方法。
Constructor<T> getConstructor(Class<?>... parameterTypes):获取指定参数列表的公共构造方法。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):获取指定参数列表的构造方法。
<A extends Annotation> A getAnnotation(Class<A> annotationClass):获取指定类型的公共注解。
<A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass):获取指定类型的注解。
Annotation[] getAnnotations():获取所有的公共注解。
Annotation[] getDeclaredAnnotations():获取所有的注解。
Class<?>[] getInterfaces():获取实现的所有接口。
Type[] getGenericInterfaces():获取带泛型的接口。
Class<? super T> getSuperclass():获取继承的父类。
Type getGenericSuperclass():获取带泛型的父类。
String getName():返回全类名。
Package getPackage():返回包名。
int getModifiers():返回修饰符。
ClassLoader getClassLoader():返回类加载器。
InputStream getResourceAsStream(String name):返回读取的文件流。
如何获取Class类的实例
Class没有公共构造方法。
Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
Java程序经过编译以后,生成关于类的字节码文件。在解释运行时,需要将类的字节码文件加载到内存中(通过JVM的类的加载器实现的加载)。此时加载到内存中的类,我们就称作运行时类,此类本身就充当了java.lang.Class的一个实例。
反过来讲:一个Class的实例就对应着一个加载到内存中的运行时类。
获取Class类的实例有四种方式:
1)直接调用运行时类的.class属性
Class clazz = String.class;
2)通过调用运行时类的对象的getClass()方法
Class clazz = "www.atguigu.com".getClass();
3)调用Class的静态方法forName()获取
Class clazz = Class.forName("refl.Person");
4)使用类的加载器
ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("refl.Person");
使用forName()和loadClass()的区别
相同:
使用Class的静态方法forName()和使用ClassLoader的成员方法loadClass()都能获取指定类的Class实例。
也都会进行类的加载,即将.class文件读取到JVM中。
不同:
在调用Class的静态方法forName()时,除了会进行类的加载(即将.class文件加载到JVM中)以外,还会进行类的初始化(即初始化静态成员变量和执行静态代码块)。但调用forName()方法并不会执行构造方法创建对象,只要在调用了成员方法newInstance()以后,才会调用空参的构造方法创建对象。
当调用ClassLoader的成员方法loadClass()时,只进行类的加载(即将.class文件加载到JVM中),不会进行类的初始化(即初始化静态成员变量和执行静态代码块),也不会执行构造方法。
ClassLoader类
类的加载过程
当程序主动使用了某个类时,该类还未被加载到内存中,那么系统会通过下面三个步骤对该类进行初始化。:
1)类的加载:将类的class文件读入内存,并为之创建一个Class对象。由类加载器完成。
2)类的连接:将类的二进制数据合并到JRE中。
3)类的初始化:JVM负责对类进行初始化。
何时会进行类的初始化
1)类的主动引用一定会发生类的初始化:
当虚拟机启动,先初始化main方法所在的类。
使用new关键字创建了一个类的对象。
调用类的静态成员(除了final常量)和静态方法。
使用java.lang.reflect包的方法对类进行反射调用。
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类。
2)类的被动引用不会发生类的初始化
当访问一个静态域时,只有真正声明这个域的类才会被初始化。
当通过子类引用父类的静态变量,不会导致子类初始化。
通过数组定义类引用,不会触发此类的初始化。
引用常量不会触发此类的初始化,常量在链接阶段就存入调用类的常量池中了。
类加载器的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类加载器的分类
引导类加载器:用C++编写的,是JVM自带的类装载器,负责Java平台核心库,用来装载核心类库。无法直接获取。
扩展类加载器:负责jre/lib/ext目录下的JAR包或–D java.ext.dirs指定目录下的JAR包装入工作库。
系统类加载器:负责java –classpath或–D java.class.path所指的目录下的类与JAR包装入工作,最常用的加载器。
常用方法
Class<?> loadClass(String name):将Class文件加载到内存时,并不会执行类的初始化。
static ClassLoader getSystemClassLoader():获取系统类加载器。
ClassLoader getParent():获取当前类加载器的上级类加载器。
static InputStream getSystemResourceAsStream(String name):和getResourceAsStream用法类似。
InputStream getResourceAsStream(String name):默认则是从ClassPath根下获取,path不能以'/'开头,最终是由ClassLoader获取资源。
如何获取类加载器
获取系统类加载器(可以获取): ClassLoader.getSystemClassLoader();
获取扩展类加载器(可以获取): ClassLoader.getSystemClassLoader().getParent();
获取引导类加载器(不可以获取): ClassLoader.getSystemClassLoader().getParent().getParent();
测试类加载器
测试代码如下:
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());
// JDK提供的类使用的是引导类加载器
System.out.println(String.class.getClassLoader());
}
运行结果如下:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@6d9c638
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
测试加载资源
测试代码如下:
// InputStream is1 = ClassLoader.getSystemClassLoader().getResourceAsStream("test.txt");// null
// InputStream is2 = ClassLoader.getSystemClassLoader().getResourceAsStream("/com/test/test.txt");// null
InputStream is3 = ClassLoader.getSystemClassLoader().getResourceAsStream("com/test/test.txt");
InputStream is4 = ClassLoader.getSystemResourceAsStream("com/test/test.txt");
使用反射
获取类的信息
// 根据类名获取类的Class实例
Class<?> cla = Class.forName("test.Student");
// 获取全类名
System.out.println("cla.getName() >>> " + cla.getName());// cla.getName() >>> test.Student
// 获取包名
System.out.println("cla.getPackage() >>> " + cla.getPackage());// cla.getPackage() >>> package test
// 获取访问修饰符
System.out.println("cla.getModifiers() >>> " + cla.getModifiers());// cla.getModifiers() >>> 0
// 获取翻译后的访问修饰符
System.out.println("cla.getModifiers() >>> " + Modifier.toString(cla.getModifiers()));// cla.getModifiers() >>>
// 获取加载器
System.out.println("cla.getClassLoader() >>> " + cla.getClassLoader());// cla.getClassLoader() >>> sun.misc.Launcher$AppClassLoader@18b4aac2
// 获取父类
Class<?> superclass = cla.getSuperclass();
System.out.println("cla.getSuperclass() >>> " + superclass);// cla.getSuperclass() >>> class test.People
// 获取带泛型的父类
Type genericSuperclass = cla.getGenericSuperclass();
System.out.println("cla.getGenericSuperclass() >>> " + genericSuperclass);
// 获取带泛型的父类的泛型类型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = paramType.getActualTypeArguments();
for (Type type : actualTypeArguments) {
System.out.println("genericSuperclass.getActualTypeArguments() >>> " + type.getTypeName());
}
// 获取接口
Class<?>[] interfaces = cla.getInterfaces();
for (Class<?> interfaceClass : interfaces) {
System.out.println("cla.getInterfaces() >>> " + interfaceClass);
// cla.getInterfaces() >>> interface test.School
// cla.getInterfaces() >>> interface test.Home
}
// 获取带泛型的接口
Type[] genericInterfaces = cla.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
System.out.println("cla.getGenericInterfaces() >>> " + genericInterface);
// cla.getGenericInterfaces() >>> test.School<J>
// cla.getGenericInterfaces() >>> test.Home<K>
}
// 使用反射创建类的实例
Student student = (Student) cla.newInstance();// >>> Student()
System.out.println("student.toString() >>> " + student);// student.toString() >>> [age:0][grade:0.0][sex:null]
获取类的属性
// 获取所有的公共属性,包括父类的公共属性
Field[] fields = cla.getFields();
for (Field field : fields) {
System.out.println("cla.getFields() >>> " + field);
// cla.getFields() >>> public int test.Student.age
// cla.getFields() >>> public java.lang.String test.People.name
}
// 获取已声明的所有属性,包括非公共属性,但不包括父类的属性
Field[] declaredFields = cla.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println("cla.getDeclaredFields() >>> " + field);
// cla.getDeclaredFields() >>> public int test.Student.age
// cla.getDeclaredFields() >>> double test.Student.grade
// cla.getDeclaredFields() >>> private java.lang.String test.Student.sex
}
// 获取指定名称的属性
// Field sex = cla.getField("sex");
Field sex = cla.getDeclaredField("sex");
System.out.println("cla.getDeclaredField() >>> " + sex);// cla.getDeclaredField() >>> private java.lang.String test.Student.sex
// 获取访问修饰符
System.out.println("sex.getModifiers() >>> " + Modifier.toString(sex.getModifiers()));// sex.getModifiers() >>> private
// 获取类型
System.out.println("sex.getType() >>> " + sex.getType().getName());// sex.getType() >>> java.lang.String
// 获取名称
System.out.println("sex.getName() >>> " + sex.getName());// sex.getName() >>> sex
// 获取和修改属性值,非公共属性需要执行setAccessible()方法
sex.setAccessible(true);
System.out.println("sex.get() >>> " + sex.get(student));// sex.get() >>> null
sex.set(student, "男");
System.out.println("student.getSex() >>> " + student.getSex());// student.getSex() >>> 男
获取类的方法
// 获取所有的公共方法,包括父类的公共方法和接口的公共方法
Method[] methods = cla.getMethods();
for (Method method : methods) {
System.out.println("cla.getMethods() >>> " + method);
// cla.getMethods() >>> public int test.Student.getAge()
// cla.getMethods() >>> public void test.Student.setAge(int)
// cla.getMethods() >>> public double test.Student.getGrade()
// cla.getMethods() >>> public void test.Student.setGrade(double)
// cla.getMethods() >>> public java.lang.String test.Student.getSex()
// cla.getMethods() >>> public void test.Student.setSex(java.lang.String)
// cla.getMethods() >>> public java.lang.String test.Student.toString()
// cla.getMethods() >>> public void test.Student.showSchool(java.lang.Object)
// cla.getMethods() >>> public void test.Student.showHome(java.lang.Object)
// cla.getMethods() >>> public java.lang.String test.People.getName()
// cla.getMethods() >>> public void test.People.setName(java.lang.String)
// cla.getMethods() >>> public boolean java.lang.Object.equals(java.lang.Object)
// cla.getMethods() >>> public native int java.lang.Object.hashCode()
// cla.getMethods() >>> public final native java.lang.Class java.lang.Object.getClass()
// cla.getMethods() >>> public final native void java.lang.Object.notify()
// cla.getMethods() >>> public final native void java.lang.Object.notifyAll()
// cla.getMethods() >>> public final void java.lang.Object.wait() throws java.lang.InterruptedException
// cla.getMethods() >>> public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
// cla.getMethods() >>> public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
// cla.getMethods() >>> public java.lang.String test.Student.testStudent(java.lang.String) throws java.lang.NullPointerException,java.lang.ArithmeticException
}
// 获取已声明的所有方法,包括非公共方法和重写的方法,但不包括父类的方法
Method[] declaredMethods = cla.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println("cla.getDeclaredMethods() >>> " + method);
// cla.getDeclaredMethods() >>> public int test.Student.getAge()
// cla.getDeclaredMethods() >>> public void test.Student.setAge(int)
// cla.getDeclaredMethods() >>> public double test.Student.getGrade()
// cla.getDeclaredMethods() >>> public void test.Student.setGrade(double)
// cla.getDeclaredMethods() >>> public java.lang.String test.Student.getSex()
// cla.getDeclaredMethods() >>> public void test.Student.setSex(java.lang.String)
// cla.getDeclaredMethods() >>> public java.lang.String test.Student.toString()
// cla.getDeclaredMethods() >>> public void test.Student.showSchool(java.lang.Object)
// cla.getDeclaredMethods() >>> public void test.Student.showHome(java.lang.Object)
// cla.getDeclaredMethods() >>> public java.lang.String test.Student.testStudent(java.lang.String) throws java.lang.NullPointerException,java.lang.ArithmeticException
// cla.getDeclaredMethods() >>> private void test.Student.doTestStudent()
}
// 获取指定名称和参数类型的方法
// Method testStudent = cla.getMethod("testStudent", String.class);
Method testStudent = cla.getDeclaredMethod("testStudent", String.class);
System.out.println("cla.getDeclaredMethod() >>> " + testStudent);// cla.getDeclaredMethod() >>> public java.lang.String test.Student.testStudent(java.lang.String) throws java.lang.NullPointerException,java.lang.ArithmeticException
// 获取注解
Annotation[] annotations = testStudent.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("testStudent.getAnnotations() >>> " + annotation);
// testStudent.getAnnotations() >>> @java.lang.Deprecated()
}
// 获取访问修饰符
System.out.println("testStudent.getModifiers() >>> " + Modifier.toString(testStudent.getModifiers()));// testStudent.getModifiers() >>> public
// 获取返回值类型
System.out.println("testStudent.getReturnType() >>> " + testStudent.getReturnType().getName());// testStudent.getReturnType() >>> java.lang.String
// 获取名称
System.out.println("testStudent.getName() >>> " + testStudent.getName());// testStudent.getName() >>> testStudent
// 获取参数
Parameter[] parameters = testStudent.getParameters();
for (Parameter parameter : parameters) {
System.out.println("testStudent.getParameters() >>> " + parameter.getName());
// testStudent.getParameters() >>> name
}
// 获取参数列表
Class[] parameterTypes = testStudent.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println("testStudent.getParameterTypes() >>> " + parameterType.getName());
// testStudent.getParameterTypes() >>> java.lang.String
}
// 获取异常
Class[] exceptionTypes = testStudent.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println("testStudent.getExceptionTypes() >>> " + exceptionType.getName());
// testStudent.getExceptionTypes() >>> java.lang.NullPointerException
// testStudent.getExceptionTypes() >>> java.lang.ArithmeticException
}
// 调用方法,非公共属性需要执行setAccessible()方法
Object testStudentResult = testStudent.invoke(student, "abc");// >>> testStudent()
System.out.println("testStudent.invoke() >>> " + testStudentResult);// testStudent.invoke() >>> abc
Method doTestStudent = cla.getDeclaredMethod("doTestStudent");
// Object doTestStudentResult = doTestStudent.invoke(student);// java.lang.IllegalAccessException
doTestStudent.setAccessible(true);
Object doTestStudentResult = doTestStudent.invoke(student);// >>> doTestStudent()
System.out.println("doTestStudent.invoke() >>> " + doTestStudentResult);// doTestStudent.invoke() >>> null
获取类的构造方法
// 获取所有的公共构造方法
Constructor<?>[] constructors = cla.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("cla.getConstructors() >>> " + constructor);
// cla.getConstructors() >>> public test.Student()
// cla.getConstructors() >>> public test.Student(java.lang.String)
}
// 获取所有的构造方法,包括非公共构造方法
Constructor<?>[] declaredConstructors = cla.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println("cla.getDeclaredConstructors() >>> " + constructor);
// cla.getDeclaredConstructors() >>> public test.Student()
// cla.getDeclaredConstructors() >>> public test.Student(java.lang.String)
// cla.getDeclaredConstructors() >>> private test.Student(int,double,java.lang.String)
}
// 获取参数类型的构造方法
// Constructor<?> peopleConstructor = cla.getConstructor(String.class);
Constructor<?> studentConstructor = cla.getDeclaredConstructor(int.class, double.class, String.class);
System.out.println("cla.getDeclaredConstructor() >>> " + studentConstructor);// cla.getDeclaredConstructor() >>> private test.Student(int,double,java.lang.String)
// 调用方法,非公共属性需要执行setAccessible()方法
// student = (Student) studentConstructor.newInstance(10, 3.5, "女");// java.lang.IllegalAccessException
studentConstructor.setAccessible(true);
student = (Student) studentConstructor.newInstance(10, 3.5, "女");
System.out.println("student.toString() >>> " + student);// student.toString() >>> [age:10][grade:3.5][sex:女]
Java学习——反射的更多相关文章
- java学习——反射机制
/* * JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法: * 对于任意一个对象,都能够调用它的任意一个方法和属性: * 这种动态获取的信息以及动 ...
- [Java学习]反射机制(待续226)
反射机制相关的类.反射机制的作用 获取Class类型对象的三种方式
- Java学习之反射机制及应用场景
前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框 ...
- java学习之 反射
以前学习java只是学习了基本语法操作,各种常用方法的使用,随着慢慢学习,很多大神都觉得要想成为大神,就必须把java的反射给理解透,这样我就带着好奇的心去学习到底反射是什么玩意,所以就上网找资料学习 ...
- java学习之反射机制
java语言区别于C,C++等准静态语言的最大特点就是java的反射机制.静态语言的最直接定义就是不能在运行时改变程序结构或变量的类型.按照这样的定义,python,ruby是动态语言,C,C++,J ...
- JAVA的反射机制学习笔记(二)
上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...
- java学习——java中的反射学习笔记
Java--reflect 一.Class类的使用 什么是Class类? 1:在面向对象的世界中,万事万物皆对象. java语言中,静态的成员,普通数据类型类是不是对象呢? 是,对象!是类的对象! 类 ...
- Java学习:注解,反射,动态编译
狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Java学习:注解,反射,动态编译 Annotation 注解 什么是注解 ? Annotat ...
- Java学习笔记54(反射详解)
反射概念: java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法 对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制 实际作用: 已经完成 ...
随机推荐
- SpringMVC入门 -- 参数绑定
一.REST与RESTful 1.简介 (1)REST(Representational State Transfer):表现层状态转移,一种软件架构风格,不是标准.REST描述的是在网络中clien ...
- 2-1-动态方法:ByTagName()
动态方法:ByTagName() <ul id="list"> <li></li> <li></li> <li&g ...
- 在 sql server 中批量删除表
通过查询系统表,可以批量获得 drop 语句,执行即可... select 'drop table '+name+';' from sys.tables
- Java 数学操作类
数学操作类 Math类 数学计算操作类 类属性值 Math.E ^ Math.PI 圆周率 类方法 Math类中,一切方法都是 static 型,因为Math类中没有普通属性. round() 方法 ...
- YYLable 的使用 以及注意点
NSString *title = @"不得不说 YYKit第三方框架确实很牛,YYLabel在富文本显示和操作方面相当强大,尤其是其异步渲染,让界面要多流畅有多流畅,这里我们介绍下简单的使 ...
- iOS中的NSOperation线程
1.除NSThread之外的第二种多线程的编程方法 2.采用NSOperation(线程操作,通常用他的子类)和NSOperationQueue(线程队列)搭配来做多线程开发,采用NSOperat ...
- nuget 包管理器
nuget 是.Net平台上的包管理器, 对于包的发布(打包 package)和消费(下载依赖管理)都有很好的支持, 本文仅仅关注消费端, =======================nuget项目 ...
- Angular 学习笔记(二)
控制器: 就像 JavaScript 里的构造函数一般,用来增强作用域(scope),当一个控制器通过 ng-controller 指令来添加到 DOM 中时, ng 会调用该控制器的构造函数来生成一 ...
- MySQL 部署分布式架构 MyCAT (二)
安装 MyCAT 安装 java 环境(db1) yum install -y java 下载 Mycat-server-1.6.5-release-20180122220033-linux.tar. ...
- Event事件、进程池与线程池、协程
目录 Event事件 进程池与线程池 多线程爬取梨视频 协程 协程目的 gevent TCP服务端socket套接字实现协程 Event事件 用来控制线程的执行 出现e.wait(),就会把这个线程设 ...