概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
换句话说:
- 指的是可以于运行时加载,探知和使用编译期间完全未知的类.
- 反射(Reflection)是java被视为动态语言的一个关键特性;
- 反射机制指的是程序在运行时能够获取任何类的内部所有信息;
- 加载完类之后, 在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象), 这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射。
- 说白了反射就是把java类中的各种成分映射成一个个的Java对象
JVM类加载过程
反射与class对象息息相关。
Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
获取Class对象的三种方式
对象的getClass()方法
1 | Class class = (new Object()).getClass(); |
类的.class(最安全/性能最好)属性
1 | Class class = Object.class; |
运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用)
1 | Class class = Class.forName("com.object.Object"); |
创建对象
- 创建对象,利用newInstance()
1 | Class c = Class.forName("Employee"); //创建此Class 对象所表示的类的一个新实例 |
以上的代码等同于
创建对象
1 Employee employee = new Employee(); //调用了Employee的无参数构造方法.
newInstance():
- 弱类型。低效率。只能调用无参构造,即默认的构造函数
- 抛出所有由被调用构造函数抛出的异常
- 要求被调用的构造函数是可见的,也即必须是public类型的。
new():
- 强类型。相对高效。能调用任何public构造。
- 创建对象,利用getConstructor() 和 getDeclaredConstructor()
1 | class Solution { |
运行结果:1
2
3hello1
hello2
true
- getConstructor()和getDeclaredConstructor()区别
getDeclaredConstructor(Class<?>… parameterTypes)
- 这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
- getDeclaredConstructors()的返回结果就没有参数类型的过滤了。
getConstructor(Class<?>… parameterTypes)
- 这个方法返回的是上面那个方法返回结果的子集,只返回制定参数类型访问权限是public的构造器。
- getConstructors()的返回结果同样也没有参数类型的过滤。
Class类
Class对象概述
- Class其实就是类的类型
- 字符串类型就是String,整形类型就是Integer,String和Integer类型就是Class
常用的Class方法
方法名 | 释义 |
---|---|
getName() | 返回String形式的该类的名称 |
getClassLoader() | 返回该Class对象对应的类的类加载器 |
getSuperClass() | 返回某子类所对应的直接父类所对应的Class对象 |
getComponentType() | 如果当前类表示一个数组,则返回表示该数组组件的 Class 对象,否则返回 null |
getConstructor(Class[]) | 返回当前 Class 对象表示的类的指定的公有构造子对象 |
getConstructors() | 返回当前 Class 对象表示的类的所有公有构造子对象数组 |
getDeclaredConstructor(Class[]) | 返回当前 Class 对象表示的类的指定已说明的一个构造子对象 |
getDeclaredConstructors() | 返回当前 Class 对象表示的类的所有已说明的构造子对象数组 |
getDeclaredField(String) | 返回当前 Class 对象表示的类或接口的指定已说明的一个域对象 |
getDeclaredFields() | 返回当前 Class 对象表示的类或接口的所有已说明的域对象数组 |
getDeclaredMethod(String, Class[]) | 返回当前 Class 对象表示的类或接口的指定已说明的一个方法对象 |
getDeclaredMethods() | 返回 Class 对象表示的类或接口的所有已说明的方法数组 |
getField(String) | 返回当前 Class 对象表示的类或接口的指定的公有成员域对象 |
getFields() | 返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组 |
getInterfaces() | 返回当前对象表示的类或接口实现的接口 |
getMethod(String, Class[]) | 返回当前 Class 对象表示的类或接口的指定的公有成员方法对象 |
getMethods() | 返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承的方法 |
getModifiers() | 返回该类或接口的 Java 语言修改器代码 |
getResource(String) | 按指定名查找资源 |
getResourceAsStream(String) | 用给定名查找资源 |
getSigners() | 获取类标记 |
isArray() | 判定此Class对象所对应的是否是一个数组对象 |
isInstance(Object) | 此方法是 Java 语言 instanceof 操作的动态等价方法 |
isInterface() | 判定指定的 Class 对象是否表示一个接口类型 |
isPrimitive() | 判定指定的 Class 对象是否表示一个 Java 的基类型 |
isAssignableFrom(Class) | 判定 Class 对象表示的类或接口是否同参数指定的 Class 表示的类或接口相同,或是其父类 |
newInstance() | 根据某个Class对象产生其对应类的实例,它调用的是此类的默认构造方法(没有默认无参构造器会报错) |
toString() | 将对象转换为字符串 |
Field类
Field对象概述
- Java.lang.reflect.Field类,是用于表示类中、接口中属性对象的类。
- 可以操作类中私有,以及公有等全部属性和属性的信息。
Field对象常用方法
方法名 | 释义 |
---|---|
getName() | 获得属性名称 |
getType() | 获得属性类型 |
get(Object obj) | 获得obj对象中这个属性的值 |
set(Object obj,Object value) | 向obj对象中这个属性赋值value |
setAccessible() | 启用/禁用访问控制权限 |
Method类
Method对象概述
- java.lang.reflect.Method类,提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
- 代表类中的一个方法的定义,一个Method由修饰符,返回值,方法名称,参数列表组合而成。
Method对象常用方法
方法名 | 释义 |
---|---|
getName() | 获得方法名 |
getModifiers() | 获得修饰符 |
getReturnTypes() | 返回值类型。返回class |
getParameterTypes() | 返回Class[],参数类型的数组 |
invoke(Object obj,Object..args) | 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法 |
示例代码
通过一个对象获得完整的包名和类名
1 | package Reflect; |
- 运行结果
1 | Reflect.Demo |
实例化Class类对象
1 | package Reflect; |
- 运行结果
1 | 类名称 Reflect.Demo |
获取成员变量并调用
1 |
|
- 运行结果
1 |
|
通过Class调用其他类中的构造函数
1 | package Reflect; |
- 运行结果
1 | [null 0] |
返回一个类实现的接口
1 | package Reflect; |
- 运行结果
1 | 实现的接口 Reflect.China |
取得其他类中的父类
1 | package Reflect; |
- 运行结果
1 | 继承的父类为: java.lang.Object |
获得其他类中的全部构造函数
1 | package Reflect; |
- 运行结果
1 | 构造方法: public Reflect.Person(){} |
调用其他类中的方法
1 | package Reflect; |
- 运行结果
1 | hello ,china |
调用其他类的set和get方法
1 | package Reflect; |
- 运行结果
1 | 男 |
通过反射取得并修改数组的信息
1 | import java.lang.reflect.*; |
- 运行结果
1 | 数组类型: int |
通过反射修改数组大小
1 | class Hello{ |
- 运行结果
1 | 数组长度为: 15 |
反射main方法
1 | package fanshe.main; |
- 运行结果
1 | main方法执行了。。。 |
通过反射运行配置文件内容
- 配置文件(pro.txt)
配置文件 1
2className = cn.fanshe.Student
methodName = show
1 |
|
- 运行结果
1 | is show() |
通过反射越过泛型检查
- 泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的
1 |
|
- 运行结果
1 | aaa |