一、反射
1.1 反射机制
概述:将类的各个组成部分封装成其他对象,在代码运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
好处:
1. 可以在程序运行的过程中,操作这些对象;
2. 可以解耦,提高程序的可扩展性。
用途:在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。
反射机制的相关类:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
![](https://img2020.cnblogs.com/blog/1225870/202008/1225870-20200827173338018-1340083500.png)
1.2 获取Class对象的方式
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
* 多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着。
* 多用于对象的获取字节码的方式
小贴士:上述三种获取Class对象的方式,刚好对应java代码经历的三个阶段。
1.3 Class对象功能
1. 获取成员变量
* Field[] getFields() :获取所有public修饰的成员变量
* Field getField(String name) 获取指定名称的 public修饰的成员变量
* Field getDeclaredField(String name) 获取指定名称的成员变量,不考虑修饰符
2. 获取构造方法
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)
3. 获取成员方法
* Method[] getMethods()
* Method getMethod(String name, 类<?>... parameterTypes)
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)
* String getName()
1.4 Field成员变量
操作:
1. 设置值
* void set(Object obj, Object value)
2. 获取值
* get(Object obj)
3. 当给私有属性get/set时,需忽略访问权限修饰符的安全检查
* setAccessible(true):暴力反射
1.5 Constructor构造方法
创建对象:
* T newInstance(Object... initargs)
如果使用空参数构造方法创建对象时,操作可以简化:Class对象.newInstance方法
1.6 Method方法对象
* Object invoke(Object obj, Object... args)
* String getName:获取方法名
二、Junit单元测试
2.1 测试分类
1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。2. 白盒测试:需要写代码的。关注程序具体的执行流程。
2.2 Junit使用(白盒测试的一种)
步骤:1. 定义一个测试类(测试用例)
* 测试类名:被测试的类名Test
* 包名:xxx.xxx.xx.test
* 方法名:test测试的方法名 testAdd()
* 返回值:void
* 参数列表:空参
4. 导入junit依赖环境
* 一般我们会使用断言操作来处理结果:Assert.assertEquals('期望的结果','运算的结果');
补充:
* @Before注解: 修饰的方法会在测试方法之前自动被执行
* @After注解: 修饰的方法会在测试方法执行之后自动被执行
三、注解
3.1 概述
小贴士:它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。格式:@注解名称
3.2 注解的作用
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
3.3 JDK中预定义的一些注解
* @Deprecated:该注解标注的内容,表示已过时
* @SuppressWarnings:压制警告
* 一般传递参数all @SuppressWarnings("all")
3.4 自定义注解
3.4.1 格式
元注解
public @interface 注解名称{
属性列表;
}
3.4.2 本质
注解本质上就是一个接口,该接口默认继承Annotation接口。
如:public interface MyAnno extends java.lang.annotation.Annotation {...}
3.4.3 属性
* 要求:
1. 属性的返回值类型有下列取值
* 基本数据类型
* String
* 枚举
* 注解
* 以上类型的数组
* 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
* 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
* 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
3.4.4 元注解
元注解:用于描述注解的注解
* @Target:描述注解能够作用的位置
* ElementType取值:
* TYPE:可以作用于类上
* METHOD:可以作用于方法上
* FIELD:可以作用于成员变量上
* @Retention:描述注解被保留的阶段
* RetentionPolicy取值:
*CLASS:编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。
* RUNTIME:编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
* SOURCE:被修饰的注解只能存在源码中,字节码class没有。编译器要丢弃的注释。
* @Documented:描述注解是否被抽取到api文档中
* @Inherited:描述注解是否被子类继承
面试题:描述一下JVM加载class文件的原理机制?
JVM中类的装载是由ClassLoader和它的子类来实现的。
Java ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件的类。