目录
定义:
用途:
反射基本信息:
反射相关的类(important):
Class类(反射机制的起源 )
Class类中的相关方法:
常用获得类相关的方法(重要)
常用获得类中属性相关的方法(重要)
获得类中注解相关的方法(了解)
获得类中构造器相关的方法(重要)
获得该类所有构造方法(重要)
反射示例:
获得Class对象的三种方式
反射的使用:
反射--创建对象
反射--调用私有的构造方法
反射--私有属性
反射--私有方法
反射优点和缺点
优点:
缺点:
重点总结:
结语:
定义:
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
用途:
(1)在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
(2)反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无 论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的 就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
反射基本信息:
Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。
反射相关的类(important):
类名 | 用途 |
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量/类的属性 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Class类(反射机制的起源 )
代表类的实体,在运行的Java应用程序中表示类和接口. Class的官方文档:Class文档
Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件 ,被编译后的Java文件.class也被JVM解析为一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个java文件就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类 .(如果觉得抽象没关系看下面演示后再看这个就明白了😎😎😎)
Class类中的相关方法:
常用获得类相关的方法(重要)
方法 | 用途 |
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
常用获得类中属性相关的方法(重要)
Field的官方文档:Field官方文档
方法 | 用途 |
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
获得类中注解相关的方法(了解)
方法 | 用途 |
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
获得类中构造器相关的方法(重要)
Constructor的官方文档:Constructor官方文档
方法 | 用途 |
getConstructor(Class... parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class... parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
获得该类所有构造方法(重要)
Method的官方文档:Method官方文档
方法 | 用途 |
getMethod(String name, Class... parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class... parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
反射示例:
获得Class对象的三种方式
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息👍👍👍。
第一种:
使用类对象的 getClass() 方法
第二种:
使用 .class 方法。 说明:仅适合在编译前就已经明确要操作的Class
第三种:
使用 Class.forName("类的全路径名"); 静态方法。 前提:已明确类的全路径名。
注意这里是类的全路径,如果有包需要加包的路径例如(domo1.Student).
要声明异常。
其中第三种使用的最多如果大家要记得话就记下第三种。
class Student{
public int age = 10;
private String name = "gobeyye";
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student();
//第一种
Class c1= s1.getClass();
//第二种
Class c2 = Student.class;
//第三种
Class c3 = null;
try{
c3 = Class.forName("Student");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
System.out.println(c1 == c2);
System.out.println(c1 == c3);
System.out.println(c2 == c3);
}
}
上面的代码运行结果如下:
都为true且在==的比较情况下,这说明:一个类在 JVM 中只会有一个 Class 实例。
反射的使用:
注意:所有和反射相关的包都在 import java.lang.reflect 包下面。
我们主要运用反射来进行创建类的实例和调用被private修饰的构造方法,方法和成员变量。
为了方便理解下面给出Student类的实现图片💕💕💕。
反射--创建对象
具体创建过程如下,这个不用记忆有用到的时候查资料知道怎么用即可。
下面有些方法是上面表格给出的如果不太了解的话可以向上翻。
public static void reflectNewInstance(){
try{
Class<?> classStudent = Class.forName("Student");
Object objectStudent = classStudent.newInstance();
Student student = (Student)objectStudent;
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectNewInstance();
}
结果如下:可以发现我们成功通过反射创建了一个Student对象。
不要怕抛了这么多异常,这个编译器有快捷键的不需要我们自己写。如下图我们把鼠标放到报错处等弹出如下界面是按下Alt + Shift + Enter键即可快速catch异常。
反射--调用私有的构造方法
具体过程如下:
和上面一样看着异常很多我们可以直接使用快捷键快速完成,不用记忆这个一般都是在项目里面才会用到,比赛不会有这些东西考试大概率也不会。
eclaredConstructorStudent.setAccessible(true);
这个代码在后续演示中会经常看到因为基本上用到private修饰的东西要用反射来调用的话都要把它设置为true这个方法可以查阅方法库双击shift即可查看。
至于
String.class,int.class
后面为什么要加.class这是语法规定。
public static void reflectPrivateConstructor(){
try{
Class<?> classStudent = Class.forName("Student");
Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class,int.class);
declaredConstructorStudent.setAccessible(true);
Object objectStudent = declaredConstructorStudent.newInstance("go",20);
Student student = (Student)objectStudent;
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateConstructor();
}
结果如下:上面这所以会打印Student(String,name)可以看看我前面给出的Student类的图,加上这个是为了证明private的带参数的构造方法被成功调用,显然可以被调用👍👍👍。
反射--私有属性
改变被private修饰的成员变量的值。
后续在私有属性这里会经常调用到set方法,为了防止友友们疑惑这里声明这个set是人家自带的。
具体演示如下:
classStudent.getDeclaredField("name");
传入要设置成员变量的标识符。
public static void reflectPrivateField(){
try{
Student student = new Student();
Class<?> classStudent = Class.forName("Student");
Field field = classStudent.getDeclaredField("name");
field.setAccessible(true);
field.set(student,"gobey");
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateField();
}
结果如下:
可以发现在用println打印student时我们name成员变量的值成功被修改👌👌👌。
反射--私有方法
具体演示如下:
在这个方法中我们第一个参数传入的是我们要调用的方法名称,后面的参数是我们方法的参数,由于我们function方法只有一个String参数故我们传入一个String类型即可但是一定要记得后面要加一个.class后缀这是语法。
invoke就是用来调用对应方法的。对应源码如下图:
代码如下:
public static void reflectPrivateMethod(){
try{
Class<?> classStudent = Class.forName("Student");
Method methodStudent = classStudent.getDeclaredMethod("function", String.class);
methodStudent.setAccessible(true);
Object objectStudent = classStudent.newInstance();
Student student = (Student)objectStudent;
methodStudent.invoke(student,"hehehehe");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateMethod();
}
对应结果如下:可以看到被private修饰的方法成功被调用。
到这里我们反射常用的四个方式已经全部演示完毕,希望友友们自己可以试着实现一下,这个不是很难的👍👍👍。
反射优点和缺点
优点:
1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力。
3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
1. 使用反射会有效率问题。会导致程序效率降低。
2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
重点总结:
1. 反射的意义。
2. 反射重要的几个类: Class类 、Field类、 Method类、 Constructor类。
3. 学会合理利用反射,一定要在安全环境下使用。
结语:
其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。文章来源:https://www.toymoban.com/news/detail-853490.html
文章来源地址https://www.toymoban.com/news/detail-853490.html
到了这里,关于【详解】Java反射机制(打穿封装)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!