1 junit单元测试
测试分类:
- 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
- 白盒测试:需要写代码的。关注程序具体的执行流程。
Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三方工具,需要导入jar包后使用
注意:
- 要进行Junit单元测试的方法必须是: 无参无返回值的非静态方法。
- 需要进行Junit的方法, 上边必须写: @Test注解, 这类方法叫: 测试方法,一般写的是正常的业务逻辑。
- @Before作用: 被它修饰方法的方法, 会在 测试方法 之前, 自动调用,一般用来对某些对象进行初始化, 或者加载驱动等操作。
- @After作用: 被它修饰方法的方法, 会在 测试方法 之后, 自动调用,一般是用来释放资源的。
2 类加载器
类加载:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化。
类的加载:
- 就是指将class文件读入内存,并为之创建一个 java.lang.Class 对象
- 任何类被使用时,系统都会为之建立一个java.lang.Class 对象
类的连接:
- 验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
- 准备阶段:负责为类的类变量(静态成员变量)分配内存,并设置默认初始化值
- 解析阶段:将类的二进制数据中的符号引用替换为直接引用
类的初始化:
- 在该阶段,主要就是对类变量进行初始化
类的初始化步骤:
- 假如类还未被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还未被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
- 注意:在执行第2个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
类的初始化时机
- 创建类的实例
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
问:什么时候才会加载类的字节码文件进内存:
答:当系统第一次使用该类内容,但是该类的字节码文件中不存在的时候,就会加载。
类加载器的作用:负责将.class文件加载到内存中,并为之生成对应的 java.lang.Class 对象。
JVM的类加载机制:
- 全盘负责:就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
- 父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
- 缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区
Java中的内置类加载器:
- Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null ,并且没有父null
- Platform class loader:平台类加载器可以看到所有平台类,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
- System class loader:它也被称为应用程序类加载器,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
- 类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGmL8MKe-1666165917949)(D:\智慧笔囊\java\assets\1666078734819.png)]
ClassLoader的方法:
方法名 | 说明 |
---|---|
static ClassLoader getSystemClassLoader() | 返回用于委派的系统类加载器 |
ClassLoader getParent() | 返回父类加载器进行委派 |
类加载器运行顺序是自下而上运行:bootstrap–>ext–>app
检查顺序是自上而检查:app–>ext–>bootstarp
3 反射
**概述:**是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展。
获取字节码对象的方式:
方式1: 类名.class属性 一般当做锁对象使用.
Class clazz1 = Student.class;
方式2: 对象名.getClass()方法 一般用来判断两个对象是否是同一个类型的对象.
//?表示泛型的通配符, 即: 可以用来表示任意的数据类型
//? extends Student: 向下限定, 这里的?必须是 Student类或者其子类对象
//? super Student: 向上限定, 这里的?必须是 Student类或者其父类
Class<? extends Student> clazz2 = new Student().getClass();
方式3: Class.forName(“全类名”); 一般需要结合反射使用
Class<?> clazz3 = Class.forName(“com.itheima.pojo.Student”);
注意: 一个.java文件, 对应一个.class文件, 即: 一个java文件只有一个 字节码文件对象
获取构造方法:(以下全部都是Class类中的方法)
- public Constructor getConstructor(Class… params); 根据传入的参数类型, 获取其对应的构造方法对象(即: 构造器对象), 只能获取公共的构造方法
Constructor<?> con = clazz.getConstructor(String.class, int.class);
- public Constructor[] getConstructors(); 获取指定类中所有的构造方法对象(即: 构造器对象), 只能获取公共的构造方法
onstructor<?>[] cons = clazz.getConstructors();
- public Constructor getDeclaredConstructor(Class… params); 根据传入的参数类型, 获取其对应的构造方法对象(包括私有)
Constructor<?> con = clazz.getDeclaredConstructor(String.class, int.class);
- public Constructor[] getDeclaredConstructors(); 获取指定类中所有的构造方法对象(包括私有)
Constructor<?>[] cons = clazz.getDeclaredConstructors();
创建对象:(以下全部都是Class类中的方法)
- public T newInstance(); 根据类的空参构造直接创建对象.
Student s1 = (Student) clazz.newInstance();
(Constructor 构造器类中的成员方法):
- public T newInstance(Object… values); 根据类的构造方法直接创建对象, 并设置值
Constructor<?> con = clazz.getDeclaredConstructor();
//3.2 根据构造器对象, 来创建学生类的对象.
Student s1 = (Student) con.newInstance(“刘亦菲”);
- public void setAccessible(boolean flag); 暴力反射, 如果传true, 说明取消访问检查.
如果构造方法为私有的,无法传入值,可以通过暴力反射来取消访问权限。
获取成员变量:(使用类似于获取构造方法)
-
public Field getField(String name); 根据传入的变量名, 获取其对应的成员变量对象, 只能获取公共的.
-
public Field[] getFields(); 获取指定类中所有的成员变量对象, 只能获取公共的.
-
public Field getDeclaredField(String name); 根据传入的变量名, 获取其对应的成员变量对象(包括私有)
-
public Field[] getDeclaredFields(); 获取指定类中所有的成员变量对象(包括私有)
目的:就是普通的使用变量, 或者修改某些私有的变量
Field类中的成员方法:
- public void set(Object obj, Object value); //设置obj对象的指定属性为指定的值(value)
- public void setAccessible(boolean flag) //暴力反射
获取成员方法:(以下全部都是Class类中的方法)
-
public Method getMethod(String name, Class… params); 根据传入的方法名, 获取其对应的成员方法对象, 只能获取公共的.
-
public Method[] getMethods(); 获取指定类中所有的成员方法对象, 只能获取公共的.
-
public Method getDeclaredMethod(String name, Class… params); 根据传入的方法名, 获取其对应的成员方法对象(包括私有)
-
public Method[] getDeclaredMethods(); 获取指定类中所有的成员方法对象(包括私有)
目的: 就是为了调用该方法, 且反射能越过泛型检查, 一些在编译期搞不定的事儿挪到运行时就可以搞定
Method的成员方法:
- public Object invoke(Object obj, Object… args) 执行指定对象(obj)的指定方法(method).
目的:就是为了调用该方法, 且反射能越过泛型检查, 一些在编译期搞不定的事儿挪到运行时就可以搞定.
Property概述:
- 它是一个双列集合, 是Hashtable的子类, 它的键和值都是String类型的.
- 它是唯一一个可以直接和IO流相结合使用的集合类.
成员方法:
- public void setProperty(String key, String value); 类似于Map#put()
- public String getProperty(String key); 类似于Map#get()
- public void load(InputStream is); 可以直接从流中获取数据.
- public void load(Reader r);
- public void store(OutputStream os, String comments); 可以直接把集合中的数据写到流中.
- public void store(Writer w, String comments); 可以直接从流中获取数据.
- public void load(Reader r);
- public void store(OutputStream os, String comments); 可以直接把集合中的数据写到流中.
- public void store(Writer w, String comments);