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

Java的反射机制

时间:2024-01-31 09:37:58浏览次数:29  
标签:反射 Java 初始化 对象 class Constructor 机制 Class 加载

​ java反射机制的核心是在程序运行时启动动态加载并获取类的信息,从而操作类或对象的属性和方法,本质是jvm得到class对象后,再通过class对象进行反编译,从而获取对象的各种语言信息。

​ java属于先编译再执行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态的加载某些类,这些类因为之前引用不到,所以没有被jvm加载。通过反射,可以在运行时动态的创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

Class类

​ 对象照镜子后可以得到的信息:某个类的属性、方法和构造器,某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留了一个不变的Class类型的对象。一个Class对象包含了特定某个结构的相关信息。

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整的得到一个类中所有被加载的结构
  • Class类是Reflection的根源,真对任何你想动态加载、运行的类、唯有先获得相应的Class对象

反射机制的常用类

  • Java.lang.Class
    • 代表一个类
  • Java.lang.reflect.Constructor;
    • 代表类的构造方法
  • Java.lang.reflect.Field;
    • 代表成员变量
  • Java.lang.reflect.Method;
    • 代表类的方法
  • Java.lang.reflect.Modifier;

如何获得Class的三种方法

  1. 通过Class对象中的getClass来获取
  2. 任何数据类型,都有一个静态的class属性
  3. 通过class类的静态方法forName(String className)来获取
//第一种方法获取Class对象
Student stu1 = new Student(); //这个是new产生的Student对象,一个Class对象
Class stuClass = stu1.getClass();//获取class对象
System.out.println(stuClass.getName());

//第二种方法获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stu2Class);
//获取父类
Class<?> superclass = stuClass2.getSuperclass();

//第三种方法获取class对象 (常用方法)
try{
    Class stuClass3 = Class.forName(***反射的类) //代包名的路径和要反射的类
   	System.out.println(stuClass3 == stuClass2);    
}catch(ClassNotFoundException e){
    e.printStackTrace();
}

在运行期间,一个类只会产生一个Class对象

创建实例

​ 使用Class对象的newInstance()方法来创建Class对象实例

Class<?> c = String.class;
Object str = c.newInstance();

​ 先通过Class对象获取指定的Constructor(构造器)对象,再调用Constructor(构造器)对象的newInstance()方法来创建对象,这种方法可以指定的构造器构造实例类型

//通过String的Class对象
Class<?> str = String.class;
//通过Class对象获取指定的Constructor构造器对象
Constructor constructor = str.getConstructor(String.class);
//根据构造器来创建实例
Object obj = constructor.newInstance("Hello World");

通过反射获取构造方法并使用

批量获取的方法

public Constructor[] getConstructors():"所有公用的"构造方法
piblic Constructor[] getDeclaredConstructors():获取所有的构造方法

获取单个的方法,并调用

public Constructor getConstructor(Class... parameterTypes):获取单个的"共有的"构造方法
public Constructor getDeclaredConstructors(Class... parameterTypes):获取"某个构造方法"

调用构造方法

Constructor->newInstance(Object... initargs)

newInstance是 Constructor类的方法(管理构造函数的类)

构造方法的使用顺序

//1.加载Class对象
Class clazz = Class.forName("com.rzt.Student");

//2.创建构造方法 
//因为是无参的构造方法
Constructor con = clazz.getConstructor(String.class,int.class);

//3.调用构造方法
Object obj = con.newInstance("男",20);

Java内存分析

Java内存

    • 存放new的内存对象和数组
    • 可以被所有的线程共享,不会存放别的对象引用
    • 存放基本变量类型(会包含这个基本类型的具体数值)
    • 引用对象的变量(会存放这个引用在堆里面的具体地址)
  • 方法区
    • 可以被所有线程共享
    • 包含了所有class和static变量

​ 当程序主动使某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来进行该类的初始化

  1. 类的加载(Load)
    1. 将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
  2. 类的链接(Link)
    1. 将类的二进制数组数据合并到JRE中
  3. 类的初始化
    1. JVM负责对类进行初始化

类的加载与ClassLoader的理解

  • 加载
    • 将class文件字节码内容加载到内存中,并将这些静态数据转换为方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
  • 链接
    • 将java类的二进制代码合并到jvm的运行状态之中过程
    • 验证:确保加载类信息符合jvm规范,没有安全方面问题(控制台报错)
    • 准备:正式为类变量分配内存并设置类变量默认初始化值的阶段,这些内存都将在方法区中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
  • 初始化
    • 执行类构造器clinit方法的过程。类构造器clinit方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。
    • 当初始化一个类的时候,如果发现其父类方法还没有进行初始化,则需要先触发其父类的初始化。
    • 虚拟机会保证一个类的clinit方法在多线程环境中被正确加锁和同步

什么时候会发生类初始化

  • 类的主动引用(一定会发生类的初始化)
    • 当虚拟机启动,先初始化main方法所在的类
    • new一个类的对象
    • 调用类的静态成员(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
  • 类的被动引用(不好发生初始化)
    • 当访问一个静态域时,只有真正的声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致类的初始化。
    • 通过数组定义类引用,不会触发类的初始化
    • 引用常量不会触发类的初始化(常量在连接阶段就存入调用类的常量池中了)

类加载器的作用

  • 类加载的作用
    • 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
  • 类缓存
    • 标准的JavaSE类加载器可以安要求查找类,但是一旦某个类被加载代类加载器中,它将持续一段时间(缓存),不过JVM垃圾回收机制可以收回这些Class对象

标签:反射,Java,初始化,对象,class,Constructor,机制,Class,加载
From: https://www.cnblogs.com/MineLSG/p/17998527

相关文章

  • JavaBean
    ......
  • Java学习日记 Day15 科目三终于考过了/(ㄒoㄒ)/~~
    昨天鸽了一天,备战科三来着/(ㄒoㄒ)/~~算法:①修建二叉搜索树:思路还是比较清晰的,如果当前节点小于给定的最低值,那就把当前节点换成他的右子叶,相反换成左子叶。然后递归对左右子树进行操作。②将有序数组转换为二叉搜索树:最简单的做法就一直增加左子树。但我们可以选择数组的中间......
  • SpringBoot自定义注解+反射实现 excel 导入的数据组装及字段校验
    本次给大家带来的SpringBoot中通过自定义注解+反射实现excel导入数据组装及字段校验的实现方式。这种实现方式其实是很普通、常规的方法,但很多同学在开发过程中,可能却不太容易想到他。当然我也是众多同学中的一员。1背景在前段时间的开发工作中,接手了一个很简单,很普通的开发任务。......
  • Java 编程指南:入门,语法与学习方法
    Java是什么?Java是一种流行的编程语言,诞生于1995年。由Oracle公司拥有,运行在超过30亿台设备上。Java可以用于:移动应用程序(尤其是Android应用)桌面应用程序网络应用程序网络服务器和应用程序服务器游戏数据库连接等等!为什么使用Java?Java拥有以下优势:跨平......
  • JAVA基础-数组
    数组(array)是一种容器,用来存储同种数据类型的多个值。总结:数组容器在存储数据的时候,需要结合数据类型考虑。例如:int类型的数组容器(booleanbyteshortdouble)建议:容器的类型,和存储的数据类型保持一致数组的定义格式⚫格式一:数据类型[]变量名⚫范例:int[]array⚫格......
  • Java学习(day2)
    整数拓展inti=10;inti2=010;//八进制0inti3=0x10;//十六进制0x浮点数拓展floatf=0.1f;//0.1doubled=1.0/10;//0.1f!=d浮点数有舍入误差最好不用浮点数进行比较字符拓展charc1='a';charc2='中';System.out.println(c1);System.out......
  • 深入理解Java双列结合Map
    在Java编程中,集合框架提供了多种数据结构来存储和操作数据.其中,双列集合Map是一种非常有用且广泛使用的数据结构,本文我将深入探讨Java中的双列集合Map,介绍其特点、常用方法和使用场景.一、什么是双列集合Map?双列集合Map是一种用于存储键值对(Key-ValuePair)的数据结构.......
  • [RoarCTF 2019]Easy Java
    [RoarCTF2019]EasyJava打开是一个登录页面,通过爆破得到admin/admin888为账号密码此时刷新页面点击下面的help发现有help.docx文件变更为POST可下载文件打开docx并未发现flag信息查看了师傅们的WP之后才知道,涉及到Java的题目,我们首先读取初始化配置信息/WEB-INF/web.xm......
  • java打包将静态文件一起打
    java打包将静态文件一起打Java打包将静态文件一起打概述在Java开发中,我们常常需要将静态文件(如html、css、js等)一同打包到生成的jar文件中,以便于在项目部署时一并发布。本文将介绍如何实现这一过程,并提供详细的操作步骤和代码示例。流程下表展示了实现Java打包将静态文件一起......
  • Java实现Rabbitmq群发消息
    1.Rabbitmq简介RabbitMQ是一个实现了AMQP(AdvancedMessageQueuingProtocol)高级消息队列协议的消息队列服务,用Erlang语言。是面向消息的中间件。你可以把它想像成一个邮局:你把信件放入邮箱,邮递员就会把信件投递到你的收件人处。在这个比喻中,RabbitMQ是一个邮箱、邮局、邮递员......