Java 的反射(Reflection)机制是在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。因此,通过它我们就能够修改部分类型信息,而这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制
Java 的反射机制可以形象的理解为安检的机器或者是照妖镜,因为它和安检机器和照妖镜一样都能够显露出事物内部的属性
注意:
Java 的反射是在运行期间获取类型的信息,是在运行时的一种机制
疑问: Java 已经有了封装为什么还要有反射呢?这貌似不就破坏了封装的特性吗?
解答: 这里截取了 Oracle 官方文档的一些话来回答这个问题
毕竟,没有最好,只有更好!反射机制就可以让我们不断地变得更好
这里介绍几点关于反射的用途,例如:
Person p=new Student();
这句代码中,p 在编译时类型为 Person,但在运行时类型为 Student。程序需要在运行时发现对象和类的真实信息,而通过使用反射,程序就能够正确判断出该对象和类是属于哪些类
Java 类的成员包括以下三类:成员变量、成员方法、构造方法。反射相关的类就是和这几个成员相关
下面将介绍一些关于这几类相关的方法,但是并不全。想查询全部相关方法,可以去帮助文档了解
方法 | 说明 |
---|---|
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
方法 | 说明 |
---|---|
getFiled(String name) | 获得某个公有的属性对象 |
getFileds() | 获得所有公有的属性对象 |
getDeclaredFiled(String name) | 获得某个属性对象 |
getDeclaredFileds() | 获得所有属性对象 |
方法 | 说明 |
---|---|
getMethod(String name,Class...<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name,Class...<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
方法 | 说明 |
---|---|
getConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructor() | 获得该类型所有的构造方法 |
Class 类代表类的实体,在运行的 Java 应用程序中表示类和接口
Java 文件被编译后,会生成 .class
字节码文件,而字节码文件最终又被加载到了 JVM 中(具体加载到了 JVM 的方法区),之后 JVM 就会将要使用的字节码文件解析为一个对象,而这个对象就是 java.lang.Class
,它存储在 JVM 的堆中。
因此,当程序运行时,每个 Java 文件最终就变成了 Class 类对象的一个实例。我们通过 Java 的反射机制应用到这个实例,就可以去获得甚至去添加、改变这个类的属性和行为,使得这个类成为一个动态的类
注意:
java.lang
包中以下均为对下面的 Student 类来获取 Class 对象进行示例(可以先跳过这段代码)
package demo;
public class Student{
// 私有属性 name
private String name = "lb";
// 公有属性 age
public int age = 18;
// 不带参数的构造方法
public Student(){
System.out.println("Student()");
}
private Student(String name,int age) {
this.name = name; this.age = age;
System.out.println("Student(String,name)");
}
private void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' +
", age=" + age +
'}';
}
}
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的 Class 对象,然后通过 Class 对象的核心方法,达到反射的目的。
Class.forName("类的全路径名");
静态方法获取try{
Class c1=Class.forName("demo.Student");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
要处理异常是因为,Class 的 forName 方法中抛出了 ClassNotFoundException
异常,防止输入的字符串不能找到对应的类
Class c2=Student.class;
该方式说明了任何一个类都有一个隐藏的静态成员变量 class
getClass()
方法获取Student student=new Student();
Class c3=student.getClass();
注意:
一个类对应一个 Class 对象,可以通过对上述三个获取的 Class 对象进行引用值的比较来证明
接下来将以上述的 Student 类为例,来对它进行反射的操作示例
注意:
所有和反射相关的包都在 java.lang.reflect
包下,使用前需要导包
补充:
将此对象的 accessible 标志设置为指示的布尔值
实际上 setAccessible
是启用和禁用访问安全检查的开关,并不是为 true 就能访问,为 false 就不能访问。由于 JDK 的安全检查耗时较多,所以通过 setAccessible(true)
的方式关闭安全检查就可以达到提升反射速度的目的
示例:
public class ReflectClassDemo {
// 创建对象
public static void reflectNewInstance(){
Class<?> c=null;
try {
// 获取 Class 对象
c=Class.forName("demo.Student");
// 通过获取的对象来创建 Student 的对象
Student student=(Student) c.newInstance();
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 反射私有构造方法
public static void reflectPrivateConstructor(){
Class<?> c=null;
try {
// 获取 Class 的对象
c=Class.forName("demo.Student");
// 获取 Student 中私有的构造方法
Constructor<?> constructor=c.getDeclaredConstructor(String.class,int.class);
// 设置为 true 后可以修改访问权限
constructor.setAccessible(true);
// 通过获取的私有构造方法来创建 Student 对象
Student student=(Student) constructor.newInstance("张三",18);
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 反射私有属性
public static void reflectPrivateFiled(){
Class c=null;
try {
// 获取对象
c=Class.forName("demo.Student");
// 获取私有属性
Field filed=(Field) c.getDeclaredField("name");
filed.setAccessible(true);
// 通过获取的对象实例化
Student student=(Student) c.newInstance();
// 修改 student 这个对象的 filed 字段,将其值修改为 张三
filed.set(student,"张三");
String name=(String) filed.get(student);
System.out.println("反射私有属性修改了 name: "+name);
} catch (ClassNotFoundException | NoSuchFieldException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 反射私有方法
public static void reflectPrivateMethod(){
Class c=null;
try {
// 获取对象
c=Class.forName("demo.Student");
// 获取私有方法
Method method=c.getDeclaredMethod("function", String.class);
// 通过获取到对象实例化
Student student=(Student) c.newInstance();
method.setAccessible(true);
// 给实例化对象的私有方法 function 赋值
method.invoke(student,"给私有方法 function 传参数");
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
优点:
缺点:
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_51367845/article/details/122014096
内容来源于网络,如有侵权,请联系作者删除!