Java反射机制


前言

学到代理设计模式发现对反射理解有点模糊了,重新温习一下。
参考:
视频:【零基础 快速学Java】韩顺平 零基础30天学会Java
文章:Java基础篇:反射机制详解


一、反射是什么?

(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

个人理解:就是所有使用到的类都会在类加载阶段会加载成class对象(一个类一个class对象),但是有些类我们可能开始是希望它在运行阶段再加载,这样就需要使用到反射机制。


二、Java程序的三个阶段

先来看一张图:
在这里插入图片描述
java程序三个阶段分别是编译、加载和运行阶段,具体如下:

  1. 编译阶段是将.java文件编译成.class字节码文件。
  2. 类加载阶段是通过类加载器把class文件中的成员变量,构造方法,成员方法加载到内存中。
  3. 运行阶段是进行创建对象和调用对象里的方法。

反射体现在类加载阶段


三、类加载三个阶段

1、什么是类加载?

  1. 静态加载: 编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载: 运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性

2、类加载过程

在这里插入图片描述

编译:.java编译成.class文件;
类加载:加载、连接(验证、准备、解析)、初始化;
内存布局:方法区(类的字节码二进制数据),堆区(类的Class对象)。

  1. Loading阶段:的主要目的是将字节码从不同的数据源(可能是class 文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象。
  2. Verification阶段
    ①目的是为了确保Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不
    会危害虚拟机自身的安全;
    ②包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和
    符号引用验证;
    ③可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载
    的时间。
  3. Preparation阶段
    JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、OL、null、false等)。这些变量所使用的内存都将在方法区中进行分配。
  4. Resolution阶段
    虚拟机将常量池内的符号引用替换为直接引用的过程。
  5. Initialization阶段
    ①到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行clinit()方法的过程。
    ②clinit()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
    ③虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。

四、正常与反射机制的类加载

先来看一张图:
在这里插入图片描述

个人理解
①正常类加载过程:图中1、2、3顺序执行过程就是正常类加载过程,编译执行发现需要Student类,所以JVM把Student.class文件加载到JVM内存中,加载到JVM内存后会通过类加载器创建一个Student类的class对象。
②反射机制类加载过程:得到class对象后,通过反编译创建Student类的对象、


五、反射机制的优缺点

1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:
(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题;
(3)反射是解释执行,对速度有影响。


六、反射常用的类

1.Java.lang.Class:

1.getName:获取全类名
2.getSimpleName:获取简单类名
3.getFields:获取所有public修饰的属性,包含本类以及父类的
4.getDeclaredFields:获取本类中所有属性
5.getMethods:获取所有public修饰的方法,包含本类以及父类的
6.getDeclaredMethods:获取本类中所有方法
7.getConstructors:获取本类所有public修饰的构造器
8.getDeclaredConstructors:获取本类中所有构造器
9.getPackage:Package形式返回包信息
10.getSuperClass:Class形式返回父类信息
11.getlnterfaces:Class[形式返回接口信息
12.getAnnotations:Annotation[形式返回注解信息

2.Java.lang.reflect.Constructor:

1. getModifiers:int形式返回修饰符2. getName:返回构造器名(全类名)
3. getParameterTypes:Class[返回参数类型数组

3.Java.lang.reflect.Field:

1.getModifiers:int形式返回修饰符
[说明:默认修饰符是0public1private2protected4,static8, final16], public(1) + static (8) =9
2.getType:Class形式返回类型
3.getName:返回属性名

4.Java.lang.reflect.Method:

1.getModifiers:int形式返回修饰符
[说明:默认修饰符是0public1private2protected4,static8,final16]
2.getReturnType:Class形式获取返回类型3. getName:返回方法名
4.getParameterTypes:Class[]返回参数类型数组

5.Java.lang.reflect.Modifier:

暂无    🐓

七、通过反射创建对象

1.方式一:调用类中的public修饰的无参构造器
2.方式二:调用类中的指定构造器

3.Class类相关方法

  • newlnstance:调用类中的无参构造器,获取对应类的对象
  • getConstructor(Class…clazz):根据参数列表,获取对应的public构造器对
  • getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器对象

4.Constructor类相关方法

  • setAccessible:暴破
  • newlnstance(Object…obj):调用构造器

八、通过反射访问类中的成员、方法

1.访问属性:

  • 1.根据属性名获取Field对象
    Field f =clazz对象.getDeclaredField(属性名);
  • 2.暴破:f.setAccessible(true);//f 是Field
  • 3.访问
    f.set(o,值);//o表示对象
    syso(f.get(o));//o表示对象
  • 4.注意:如果是静态属性,则set和get中的参数o,可以写成null

2.访问方法:

  • 1.根据方法名和参数列表获取Method方法对象:
    Method m = clazz.getDeclaredMethod(方法名,XX.class);//得到本类的所有方法;
  • 2.获取对象:Object o=clazz.newlnstance();
  • 3.暴破:m.setAccessible(true);
  • 4.访问:Object returnValue = m.invoke(o,实参列表);//o就是对象;
  • 5.注意:如果是静态方法,则invoke的参数o,可以写成null。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值