首页 > 编程语言 >Java反射机制详解

Java反射机制详解

时间:2023-01-04 20:11:06浏览次数:45  
标签:反射 Java 配置文件 对象 详解 classfullpath java Class

 

时间:2022/11/03

 

一. 引出

在学习反射的时候,大家可能会纠结反射技术有什么作用,下面我们通过这里需求来说明反射是如何解决现有技术不能解决的问题的:

根据配置文件re.properties指定的信息,创建Cat对象并调用方法hi(这样的需求经常出现在框架的配置文件中,即通过外部配置文件,在不修改源码的情况下来控制程序,符合设计模式中的ocp原则(开闭原则:不修改源码,扩容功能)

我们首先定义一个Cat实体类:

 1 package reflection;
 2 
 3 public class Cat {
 4     private String name;
 5 
 6     public Cat(){
 7 
 8     }
 9 
10     public Cat(String name){
11         this.name = name;
12     }
13 
14     public String getName() {
15         return name;
16     }
17 
18     public void setName(String name) {
19         this.name = name;
20     }
21 
22     public void hi(){
23         System.out.println("我是一只小猫");
24     }
25 
26 
27 }

然后定义一个配置文件re.properties:

1 classfullpath = reflection.Cat
2 method = hi

然后在ReflectionQuestion类的main方法中编写实现逻辑,如下所示,我们可以通过Properties类来获取配置文件中对应字段的内容,但是由于此时获取的内容是String类型的,所以我们无法通过传统new的方式来生成一个对象,这里就说明通过传统的方式无法解决上面这个问题,所以我们这里用到了反射机制,我们可以将类的全路径传入Class类的forName方法来获取这个类的Class对象(这里的Class是一个类,可能比较绕),通过类的Class对象就可以获取到这个类的实例、方法和成员变量等(这里的方法和成员变量都是对象,体现了Java中万物皆对象的思想)。

 1 package reflection;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.IOException;
 7 import java.lang.reflect.Method;
 8 import java.util.Properties;
 9 
10 public class ReflectionQuestion {
11 
12     public static void main(String[] args) throws Exception {
13         // 1.使用Properties类,可以读写配置文件
14 //        System.out.println(new File(".").getAbsolutePath());  // 查看当前路径
15         Properties properties = new Properties();
16         properties.load(new FileInputStream("src/reflection/re.properties"));
17         String classfullpath = properties.get("classfullpath").toString();
18         String methodName = properties.get("method").toString();
19 //        classfullpath: reflection.Cat
20 //        method: hi
21         System.out.println("classfullpath: " + classfullpath);
22         System.out.println("method: " + methodName);
23 
24         // 2.使用传统方式创建对象,行不通,因为上面通过配置文件得到的classfullpath是一个string,而不是一个类名
25 //        new classfullpath();
26 
27         // 3.使用反射机制解决
28         // 3.1 加载类,返回一个Class类型的对象
29         Class cls = Class.forName(classfullpath);
30         // 3.2 通过cls得到reflection.Cat类的对象实例,在这里当然可以通过强制类型转换将Object类型转为Cat类型,但是这样做没有意义,
31         // 因为按照上面的问题,你是通过配置文件读取的classfullpath,在这里你并不知道classfullpath: reflection.Cat,你在这里只知道要调用
32         // 配置文件中classfullpath类的method方法,具体classfullpath具体是哪一个类,method是哪一个方法,你都不知道
33         Object o = cls.newInstance();
34         // 3.3 通过cls得到配置文件中要求的methodName方法,在这里也就是hi方法
35         // 在反射中,可以把方法视为对象,即万物皆对象
36         Method method = cls.getMethod(methodName);
37         // 3.4 铜鼓method对象调用方法
38         System.out.println("===================");
39         method.invoke(o);   // 传统方式:对象.方法()  在反射中:方法.invoke(对象)
40 
41 
42     }
43 }

上面这个示例对反射存在的意义进行了说明,现在很多框架的底层都使用了反射机制。通过反射机制,程序可以在执行期借助Reflection API获取任何类的内部信息(比如成员变量、构造器、成员方法等),并能操作对象的属性以及方法。

Java反射机制原理图:

 

 

在上图的第二阶段,即加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象就可以得到类的结构。这个Class对象就像一面镜子,透过这个镜子可以看到类的结构,所以,形象的称之为:反射。

Java反射机制可以完成:

1. 在运行时判断任意一个对象所属的类。

2. 在运行时构造任意一个类的对象。

3. 在运行时得到任意一个类所具有的成员变量和方法。

4. 在运行时调用任意一个对象的成员变量和方法。

5. 生成动态代理。

与反射相关的主要类(在java.lang.reflection包中):

1. java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象。

2. java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法。

3. java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量。

4. java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器。

反射机制还可以关闭访问检查,提高反射效率:Method和Field、Constructor对象都有setAccessible()方法,该方法的作用是启动和禁用访问安全检查。通过传入true,可以访问 private 构造器/方法/属性。

 

 

 

由于Class类是在类加载阶段被创建的,所以需要了解一下类加载的时机,主要有如下几个:

1. 当创建对象时(new)-静态加载

2. 当子类被加载时,父类也被加载-静态加载

3. 调用类中的静态成员时-静态加载

4. 通过反射-动态加载

下面我们对反射中各个类的主要方法及其作用进行说明:

1. java.lang.Class类:

 

2. java.lang.reflect.Field类:

 

3. java.lang.reflect.Method类:

 

4. java.lang.reflect.Constructor类

 

标签:反射,Java,配置文件,对象,详解,classfullpath,java,Class
From: https://www.cnblogs.com/machi12/p/16856748.html

相关文章

  • resin报错:java.lang.IllegalStateException: block Block
    java.lang.IllegalStateException:blockBlock启动resin时报错主要的提示信息就是下面这个java.lang.IllegalStateException:blockBlock[Table[mnode:2,d:\XXXX\resi......
  • 第2章:Java基本语法
    1、关键字和保留字关键字(keyword)的定义和特点:定义:被Java语言赋予了特殊含义,用做专门用途的字符串(或单词)。特点:关键字中所有字母都为小写字母。官方发布的所有关键字:......
  • Java 复习篇2---jdk
    jdk文件:bin该路径下存放了各种工具命令,其中重要的有javac和Javaconf:改路径下存放了相关配置文件include:该路径下存放了一些平台特定的头文件jmods;该路径下存放......
  • Java复习篇3---基础概念
    关键字关键字:被Java赋予了特定含义的英文单词关键字的字母全是小写常用的代码编辑器,针对关键字会有特殊的颜色标记,非常直观例如:class:用于(创建\定义)一个类,后面紧......
  • Java流程控制
    1.Scanner对象  2.顺序结构  3.选择结构if单选择结构 if双选择结构 if多选择结构 嵌套的if结构 switch多选择结构  4......
  • java 基础 -- Comparable 和 Comparator
    packagecom.example.javareview.comparable;importjava.util.*;/***一、说明:Java中的对象,正常情况下,只能进行比较:==或!=。不能使用>或<的*......
  • java基础toString()方法
    1.Object()类下的toSting()方法Java默认的toString方法来自Object类 在Java中每个类都直接或者间接继承Object类,toString()方法同样是来自于Object类在没有重写toString......
  • JAVA-上转型对象,下转型对象
    packagecom.example.barry;//父类publicclassparents{publicparents(){}publicvoidsay(){System.out.println("我是家长");}publicvoi......
  • APP测试 - Monkey遍历命令详解
    1、启动monkey#对手机点击1000次,不限制应用adbshellmonkey1000#限制在设置的应用中,点击1000次adbshellmonkey-pcom.cleanmaster.mguard1000#设置点击事件......
  • 消息队列:第三章:在Java中使用消息队列
    在项目中导入依赖坐标<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-activemq</artifactId>......