【JAVA基础】反射机制

本文深入讲解Java反射机制的概念、用途及实现方式。介绍了反射的基本作用,包括调用私有方法、实现序列化与反序列化等。同时,还探讨了Class类、ClassLoader类加载器以及反射在native层面的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制

一、什么是java反射

反射使程序代码能够接入装载到JVM中的类的内部信息,允许在编写与执行时,而不是源代码中选定的类协作的代码,是以开发效率换运行效率的一种手段。这使反射称为构建灵活应用的主要工具。

反射的作用:
1、调用一些私有方法,实现黑科技。比如双卡短信发送、设置状态栏颜色、自动挂电话等。
2、实现序列化与反序列化,比如PO的ORM,Json解析等
3、实现跨平台兼容,比如jdk中的SocketImpl的实现
4、通过xml或注解,实现依赖注入,注解处理,动态代理,单元测试等功能。比如Retrofit、Spring或者Dagger

二、class类

1、class是一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Field,描述构造类的Constructor等属性
2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
3、对于每个类而言。jre都为其保留一个不变的class类型的对象。一个class对象包含了特定某个类的有关信息
4、class对象只能由系统建立对象
5、一个类在jvm中只会有一个class实例

反射机制获取类的三种方法

1、通过类名
2、通过getClass()
3、通过全类名获取

/** 
 * 反射机制获取类有三种方法 
 */  
@Test  
public void testGetClass() throws ClassNotFoundException {  
    Class clazz = null;  

    //1 直接通过类名.Class的方式得到  
    clazz = Person.class;  
    System.out.println("通过类名: " + clazz);  

    //2 通过对象的getClass()方法获取,这个使用的少(一般是传的是Object,不知道是什么类型的时候才用)  
    Object obj = new Person();  
    clazz = obj.getClass();  
    System.out.println("通过getClass(): " + clazz);  

    //3 通过全类名获取,用的比较多,但可能抛出ClassNotFoundException异常  
    clazz = Class.forName("com.java.reflection.Person");  
    System.out.println("通过全类名获取: " + clazz);  
}  
利用newInstance创建对象:调用的类必须有无参的构造器

无参构造器:Person{name=’null’,age=0}

/** 
 * Class类的newInstance()方法,创建类的一个对象。 
 */  
@Test  
public void testNewInstance()  
        throws ClassNotFoundException, IllegalAccessException, InstantiationException {  

    Class clazz = Class.forName("com.java.reflection.Person");  

    //使用Class类的newInstance()方法创建类的一个对象  
    //实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)  
    //一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器  
    Object obj = clazz.newInstance();  
    System.out.println(obj);  
}  
三、ClassLoader类加载器

类加载器是用来把类装载进jvm的。jvm规范定义了两种类型的类装载器:启动类家载器和用户自定义加载器。jvm在运行时会产生3个类加载器组成的初始化加载器层次结构,如下图所示:
类加载器
类加载器详解:http://blog.youkuaiyun.com/ochangwen/article/details/51473120

/** 
 * ClassLoader类装载器 
 */  
@Test  
public void testClassLoader1() throws ClassNotFoundException, IOException {  
    //1、获取一个系统的类加载器  
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();  
    System.out.println("系统的类加载器-->" + classLoader);  

    //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))  
    classLoader = classLoader.getParent();  
    System.out.println("扩展类加载器-->" + classLoader);  

    //3、获取扩展类加载器的父类加载器  
    //输出为Null,无法被Java程序直接引用  
    classLoader = classLoader.getParent();  
    System.out.println("启动类加载器-->" + classLoader);  

    //  

    //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器  
    classLoader = Class.forName("com.java.reflection.Person").getClassLoader();  
    System.out.println("当前类由哪个类加载器进行加载-->"+classLoader);  

    //5、测试JDK提供的Object类由哪个类加载器负责加载的  
    classLoader = Class.forName("java.lang.Object").getClassLoader();  
    System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader);  
}  
四、反射在native的实现

反射在java中可以直接调用,不过最终调用的认识native方法,以下为主流反射操作的实现
1、Class.forName
Class.forName可以通过寻找Class对象,比如Class.forName(“java.lang.String”)。
在JDK的源码实现中,可以发现最终调用的是native方法forName0(),它在JVM中调用的实际是findClassFromClassLoader(),原理与ClassLoader的流程一样。
2、getDeclareFields的实现
在jdk源码中,可以知道class.getDeclaredFields()方法实际调用的是native方法getDeclaredFields0(),它在JVM主要实现步骤如下:
(1)根据class结构体信息,获取field_count与fields[]字段,这个字段早已在load过程中被放入了
(2)根据field_count的大小分配内存、创建数组
(3)将数组进行forEach循环,通过fields[]中的信息依次创建Object对象
(4)返回数组指针
3、Method.invoke的实现
以下为无同步、无异常的情况下调用的步骤:
(1)创建Frame
(2)如果对象flag为native,交给native_handler进行处理
(3)在frame中执行java代码
(4)弹出Frame
(5)返回执行结果的指针
4、class.newInstance的实现
(1)检测权限、预分配空间大小等参数
(2)创建Object对象,并分配空间
(3)通过Method.invoke调用构造函数(())
(4)返回Object指针

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值