Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说大厂难进?清华学霸整理的Java反射机制笔记,让你面试一面即中,希望能够帮助你!!!。
今日分享开始啦,请大家多多指教~
需求如下:
根据配置文件re.properties中的指定信息,创建Cat对象并调用方法hi
配置文件中代码:classfullpath=com.hspedu.Cat,method=hi
这样的需求在学习框架时非常多,通过外部文件配置,在不修改源码情况下控制程序
符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)
代码如下:
1.使用Properties类读写配置文件
2.使用传统方式创建对象行不通,需要使用 反射机制
此时我们发现,我们只需要将re.properties中的 method=hi 改成 method=cry,就会调用cry(),不需要修改源码,反射机制非常强大!
2.1 Java Reflection
反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如:成员变量,构造器,成员方法等),并能操作对象的属性及方法。反射在设计模式和框架的底层都会用到。
加载完类之后,在堆内存中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以形象称之为:反射。
2.2 反射机制原理图
2.3 反射机制可以完成的功能
2.4 反射相关的主要类
这些类在 java.lang.reflection包下:
代码展示如下:
2.5 反射优点和缺点
优点:可以动态地创建和使用对象(就是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
缺点:使用反射基本是解释执行,对执行速度有影响
2.6 反射调用优化——关闭访问检查
代码展示如下:
3.1 基本介绍
3.2 Class类的常用方法
代码展示如下:
代码展示如下:
6.1 基本说明
反射机制是Java实现动态语言的关键,也就是通过反射实现类的动态加载。
6.2 类加载时机
6.3 类加载过程图
6.4 类加载三个阶段完成任务
6.4.1 加载阶段
6.4.2 连接阶段——验证
1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
2.包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证[举例说明]
3.可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
6.4.3 连接阶段——准备
1. JVM 会在该阶段对静态变量, 分配内存并默认初始化(对应数据类型的默认初始值,如0、OL、null. false 等)。这些变量所使用的内存都将在方法区中进行分配。
2.举例说明: ClassLoad02.java
6.4.4 连接阶段——解析
虚拟机将常量池内的符号引用替换为直接引用的过程。
6.4.5 Initialization(初始化)
1.到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行。
< clinit>()方法的过程。
2. <clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,井进行合井。[举例说明ClassLoad03.java]
3.虚拟机会保证一个类的 <clinit> ()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类, 那么只会有一一个线程去执行这个类的<clinit> 0方法,其他线程都需要阻塞等待,直到活动线程执行<clinit> 0方法完毕[debug源码]
代码展示如下:
1.加载B类,并生成对应的Class类对象
2.连接 num = 0;
3.初始化阶段:依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并。
7.1 java.lang.Class类
com.hspedu.reflection ReflectionUtilsjava
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形式返回父类信息
1.getinterfacs:以Class[]形式返回接口信息
12.getAnnotations:以Annotation[]形式返回注解信息
7.2 java.lang.reflect.Field类
1. getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public 是1,private 是2,protected 是4 ,static是8,final 是16] , public(1) + static (8) = 9
2. getType:以Class形式返回类型
3. getName:返回属性名
7.3 java.lang.reflect.Method类
1. getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final 是16]
2. getReturnType:以Class形式获取返回类型
3. getName:返回方法名
4. getParameterTypes:以Class[]返回参数类型数组
7.4 java.lang.reflect.Constructor类
1. getModifiers:以int形式返回修饰符
2. getName:返回构造器名 (全类名)
3. getParameterTypes:以Class[返回参数类型数组
代码展示如下:
1.方式一: 调用类中的public修饰的无参构造器
2.方式二:调用类中的指定构造器
3. Class类相关方法
4. Constructor类相关方法
测试 1:通过反射创建某类的对象,要求该类中必须有 public 的无参构造
测试 2:通过调用某个特定构造器的方式,实现创建某类的对象
1. 先获取到User类的Class对象
2. 通过public的无参构造器创建实例
3. 通过public的有参构造器创建实例
4. 通过非public的有参构造器创建实例
9.1 访问属性
1.根据属性名获取Field对象
Field f = clazz对象.getDeclaredField(属性名);
2.暴破: f.setAccessible(true); //f是Field
3.访问
4.注意:如果是静态属性,则set和get中的参数o,可以写成null
代码展示如下:
1. 得到Student类对应的 Class对象
2. 创建对象
3. 使用反射得到age 属性对象
4. 使用反射操作name 属性
9.2 访问方法
1.根据方法名和参数列表获取Method方法对象: Method m =
clazz.getDeclaredMethod(方法名,XX.class); //得到本类的所有方法
2.获取对象: Object o= clazz.newInstance();
3.暴破: m.setAccessible(true);
4.访问: Object returnValue = m.invoke(o,实参列表);//o就是对象
5.注意:如果是静态方法,则invoke的参数o,可以写成null!
代码展示如下:
1. 得到Boss类对应的Class对象
2. 创建对象
3. 调用public的hi方法
4. 调用private static 方法
5. 在反射中,如果方法有返回值,统一返回Object , 但是它运行类型和方法定义的返回类型一致。
练习一
通过反射修改私有成员变量com.hspedu.homework Homework01.java
1.定义PrivateTest类,有私有name属性,并且属性值为hellokitty
2.提供getName的公有方法
3.创建Private Test的类, 利用Class类得到私有的name属性,修改私有的name属性值,并调用getName()的方法打印name属性值
代码展示如下:
定义PrivateTest类,有私有name属性,并且属性值为hellokitty
提供getName的公有方法
创建PrivateTest的类,利用Class类得到私有的name属性,修改私有的name属性值,并调用getName()的方法打印name属性值
1. 得到 PrivateTest类对应的Class对象
2. 创建对象实例
3. 得到name属性对象
4. 暴破name
5. 得到getName方法对象
6. 因为getName() 是public,所有直接调用
练习二
利用反射和File完成以下功能Homework02.java
1.利用Class类的forName方法得到File类的class 对象
2.在控制台打印File类的所有构造器
3.通过newInstance的方法创建File对象, 并创建E:\mynew.txt文件
提示创建文件的正常写法如下:
File file = new File(" d:\aa.txt");//内存
file.createNewFile();//方法,才能真正地创建文件
代码展示如下:
利用Class类的forName方法得到File类的class 对象
在控制台打印File类的所有构造器
通过newInstance的方法创建File对象,并创建D:\mynew.txt文件
1. Class类的forName方法得到File类的class 对象
2. 得到所有的构造器
3. 指定的得到 public java.io.File(java.lang.String)
4. 得到createNewFile 的方法对象
今日份分享已结束,请大家多多包涵和指点!
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。