前言
都知道反射技术很厉害,对我们开发过程中的帮忙也特别大。而且在阅读源码的过程中也不难发现里面有很多地方都用到了反射。今天把最近了解到的反射技术简单记录一下。
反射(ReFlect)
-
概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
简单来讲就是:可以访问、检测和修改它本身状态或行为的一种能力。
-
作用
反编译:将 class 文件反编译成 Java 文件。
访问对象:访问 Java 对象中的属性、方法、构造方法等。
-
核心的类
java.lang.Class
- 类,某个具体的类或接口
java.lang.reflect.Constructor
- 反射构造方法
java.lang.reflect.Field
- 反射属性
java.lang.reflect.Method
- 反射方法
java.lang.reflect.Modifier
- 访问修饰符的信息
Class
:Class对象是一个特殊的对象,是用来创建其它Java的实例,Class对象就是Java类编译后生成的.class文件,它包含了与类有关的信息。
Field
:Filed字段提供有关和动态访问的信息,类或接口的单个字段。反射的字段可能是类字段或实例字段。
Method
:Method方法提供了关于单个方法的信息和访问在类或接口上。反射的方法可能是类方法或者是一个实例方法(包括一个抽象的方法)。
Constructor
:Constructor提供了关于某类的构造方法的所需信息。
Modifier
: 获取修饰符的类型
-
核心API
getClass()
- 获取类
getAnnotation(xx.class)
- 获取注解
getConstructor(Class[])
- 根据构造函数的参数,返回一个具体的具有public属性的构造函数
getConstructors()
返回所有具有public属性的构造函数数组
getDeclaredConstructor(Class[] params)
根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
getDeclaredConstructors()
返回该类中所有的构造函数数组(不分public和非public属性)
getMethod()
- 获取方法 [1.获取当前类的方法 2.获取public的方法]
invoke(obj,yy)
- 执行方法 [method.invoke(对象,参数)]
getDeclaredMethods()
- 获取所有方法 [1.获取当前类和父类的方法 2.获取任何修饰的方法]
getDeclaredFields()
- 获取所有属性
annotationType()
- 获取注解的类型
setAccessible(true)
- 设置私有变量/方法的访问权限
set(class, obj)
- 赋值
-
使用
- 1.获取反射类的三种方式
// 方式一
Class<?> c1 = Class.forName("com.test.java.Test");
// 方式二
Class c2 = Test.class;
//方式三
Test test = new Test();
Class<?> c3 = test.getClass();
System.out.println(c1 + "\n" + c2 + "\n" + c3);
Log:
c1 ==> class com.test.java.Test
c2 ==> class com.test.java.Test
c3 ==> class com.test.java.Test
方式一:Class.forName
会让ClassLoader装载类,并进行类的初始化
方式二:xxx.class
ClassLoader 装载入内存,不对类进行类的初始化操作
方式三:xxx.getClass
返回类对象运行时真正所指的对象,所属类型的Class对象
区别主要在于是否进行初始化和是否在实例中获取.
- 2.获取反射类的构造函数
Class clazz = Test.class;
//方式一:
Constructor con1 = clazz.getConstructor(float.class);
System.out.println(con1);
//方式二:
Constructor[] con2 = clazz.getConstructors();
for (Constructor con : con2) {
System.out.println(con);
}
//方式三:
Constructor con3 = clazz.getDeclaredConstructor(float.class, String.class);
System.out.println(con3);
//方式四:
Constructor[] con4 = clazz.getDeclaredConstructors();
for (Constructor con : con4) {
System.out.println(con);
}
Log:
con1 ==> public com.test.java.Test(float)
con2 ==> public com.test.java.Test(float,java.lang.String)
con2 ==> public com.test.java.Test(float)
con2 ==> public com.test.java.Test()
con3 ==> public com.test.java.Test(float,java.lang.String)
con4 ==> public com.test.java.Test(float,java.lang.String)
con4 ==> public com.test.javaTest(float)
con4 ==> public com.test.java.Test()
方式一:getConstructor(Class[] params)
根据构造函数的参数
,返回一个具体的具有public属性的构造函数
方式二:getConstructors()
返回所有具有public
属性的构造函数数组
方式三:getDeclaredConstructor(Class[] params)
根据构造函数的参数,返回一个具体的构造函数不分public和非public属性
方式四:getDeclaredConstructors()
返回该类中所有的构造函数数组不分public和非public属性
- 3.获取反射类的对象
// 方式一:无参构造创建对象
Test t1 = Test.class.newInstance();
// 方式二:有参构造创建对象
Test t2 = (Test) con1.newInstance(100f);
System.out.println(t1 + "\n" + t2);
Log:
t1 ==> com.test.java.Test@2503dbd3
t2 ==> com.test.java.Test@4b67cf4d
newInstance()
方法返回的是一个泛型T,需要强转成相应的反射类。
反射创建对象,可以使用Class.newInstance()
和 Constructor.newInstance()
两种方式
方式一必须要求反射类中存在一个无参的构造方法,并且有访问权限。
方式二适应各种类型的构造方法,无论是否有参数都可以调用,需要提供 setAccessible()
控制访问验证即可。
- 4.获取反射类的其他成员 (方法、属性)
public class Test {
private float mHight = 100f;
// 构造函数
public Test() {
System.out.println("Test中打印:测试反射");
}
private void logHight() {
System.out.println("Test中打印mHight = " + mHight);
}
public void logHight(float mHight) {
this.mHight = mHight;
System.out.println("Test中打印赋值的mHight = " + mHight);
}
}
// 获取反射类
Class<Test> clazz = Test.class;
// 获取反射类的对象
Test test = clazz.newInstance();
// 获取Test类中private申明的mHight变量
Field field = clazz.getDeclaredField("mHight");
// 允许访问私有成员变量
field.setAccessible(true);
System.out.println("field ==> " + field);
// 获取Test类中private申明的logHight()方法
Method method1 = clazz.getDeclaredMethod("logHight");
// 设置私有变量/方法的访问权限
method1.setAccessible(true);
// 打印method1
System.out.println("method1 ==> " + method1);
// 执行该方法
method1.invoke(test);
// 获取Test类中public申明的有参logHight()方法
Method method2 = clazz.getDeclaredMethod("logHight", float.class);
// 打印method1
System.out.println("method2 ==> " + method2);
// 执行该方法
method2.invoke(test, 200f);
Log:
Test中打印:测试反射
field ==> private float com.test.java.Test.mHight
method1 ==> private void com.test.java.Test.logHight()
Test中打印mHight = 100.0
method2 ==> public void com.test.java.Test.logHight(float)
Test中打印赋值的mHight = 200.0
被public
修饰的方法可以直接通过clazz.getMetho()
获取,
而被非public
修饰的方法(private,protected 等)
则需要clazz.getDeclaredMethods()
获取,并且需要使用method.setAccessible(true)
来打开权限。
而获取变量的方式则和获取方法的方式基本一致。
以上就是对反射机制ReFlect的使用总结以及简单使用。
网友评论