Java教程

java反射笔记

本文主要是介绍java反射笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

参考视频:
https://www.bilibili.com/video/BV1g84y1F7df?spm_id_from=333.999.0.0

java反射

  • 反射是框架的基石。
  • 反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。

请添加图片描述

堆区

1、存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

2、jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 。

栈区:

1、每个线程包含一个栈区,栈中只保存基础数据类型的值和对象以及基础数据的引用

2、每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。

3、栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

方法区:

1、又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

2、方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

反射机制

在反射中可以将方法视为对象

Class cls = Class.forName(classFullPath);
Object o = cls.newInstance();

<1>加载类,返回Class类型的对象cls

<2>通过cls得到加载的类的对象实例

Method method1 = cls.getMethod(methodName);
method1.invoke(o);

通过method1调用方法:即通过方法对象实现调用方法

传统方法:对象.方法

反射机制:方法.invoke(对象)

反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。

反射在设计模式和框架底层都会用到加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象) ,这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射

java.lang.Class对象表示某个类加载后在堆中的对象

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

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

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

优点

​ 可以动态的创建和使用对象(也是框架底层的核心),使用灵活,没有反射机制,框架技术就失去底层支撑

缺点

​ 使用反射基本是解释执行,对执行速度有影响

反射调用优化:

Method / constructor/Field都有setAccessible()方法,其作用是启动和禁用访问安全检查的开关,ture表示反射对象使用时取消访问检查,提高反射的效率。false表示反射对象执行访问检查

Class类

请添加图片描述

  • Class类的对象不是new出来的,而是系统创建出来的。
  • 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
  • 每个类都知道自己由哪个Class对象实例生成的
  • 进行类加载时会执行ClassLoader方法

获取Class对象六个方法:

<1>

前提:已知一个类的全名,且在该路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,实例

Class cls = Class.forName("java.lang.Cat")

<2>

前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高实例:

Class cls2 = Cat.class;

应用场景:多用于参数传递,比如通过反射得到对应构造器对象.

<3>

前提:已知某个类的实例,调用该实例的getClass(方法获取Class对象,实例:

Class clazz =对象.getClass();//运行类型

应用场景:通过创建好的对象,获取Class对象.

<4>

//4.通过类加载器[4种]来获取到类的CLass对象
//(1)先得到类加载器car
CLassLoader classLoader = car.getCLass() . getClassLoader();
//(2)通过类加载器得到CLass对象
CLass cls4 = classLoader.LoadCLass(cLassAllPath) ;
System.out.printLn(cLs4);

<5>

​ 基本数据(int, char,boolean,float,double,byte,long,.short)按如下方式得到Class类
对象
Class cls =基本数据类型.class

<6>

​ 基本数据类型对应的包装类,可以通过.type得到Class类对象
Class cls =包装类.TYPE

哪些类有Class对象:

​ 1、外部类、成员内部类,静态内部类,局部内部类,匿名内部类

​ 2、interface:接口

​ 3、数组

​ 4、enum:枚举类

​ 5、annotation:注解

​ 6、基本数据类型

​ 7、void

类加载

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

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

类加载时机:

  • 创建对象时(new
  • 子类被加载时
  • 调用类中静态成员
  • 通过反射

请添加图片描述

类加载阶段:

加载阶段

​ JVM在该阶段的主要目的是将字节码从不同数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

链接阶段-验证:

	1. 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
	2. 包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号验证
            		3. 可以考虑用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

链接阶段-准备

  1. jvm会在该阶段对静态变量,分配内存并初始化(对应数据类型的默认初始值,如0,null)。这些变量所使用的内存都将在方法区中进行分配

    //属性-成员变量-字段
    //类加载的链接阶段-准备属性是如何处理
    pubLic int n1 = 10;
    pubtic static int n2 = 20;
    pubLic static final int n3 = 30;
    
    1. n1是实例属性,不是静态变量,因此在准备阶段,是不会分配内存
    2. n2是静态变量,分配内存n2是默认初始化0 ,而不是20
    3. n3是static final 是常量,他和静态变量不一样,因为一旦赋值不变n3=30

链接阶段-解析

虚拟机将常量池内的符号引用替换为直接引用的过程

Initialization(初始化)

  1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程
  2. ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
  3. 虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只有一个线程去执行这个类的()方法,其他线程都要阻塞等待,直到活动线程执行()方法完毕

反射获取类的结构信息

请添加图片描述

请添加图片描述
刚好是二进制各个位置的1
请添加图片描述

请添加图片描述

反射创建类

方式一、调用类中的public修饰的无参构造器

方式二、调用类中指定的构造器

newInstance:调用类中的无参构造器,获取类的对象(public)

getConstructor(Class…clazz)根据参数列表获取对应的public构造器对象

Constructor<?> cst = cls.getConstructor(String.class);
Object obj = cst.newInstance("sdsada");

getDecalaredConstructor(Class…clazz)根据参数列表,获取对应的所有构造器的对象,包括私有

Constructor<?> cst = cls.getDecalaredConstructor(String.class);
cst.setAccessible(true);
Object obj = cst.newInstance("sdsada");

使用反射可以访问private构造器,暴力破解

Controller类相关方法**

setAccessible爆破

newInstance(Object …obj)调用构造器

通过反射访问类中成员

1、根据属性名获取Field对象

FIled f - cls.getDeclaredField(属性名);

2、暴力破解

f.setAccessible(true);

请添加图片描述

这篇关于java反射笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!