Java单元测试和类加载

回顾:

1 Lambda表达式:相等于匿名内部类,实现代码作为方法的参数传统。函数式接口 变量=(参数列表)->{方法体};注意:  ->操作符 分成两部分 左侧:(参数列表)右侧:  方法体1 左侧的类型可以省略,类型推断2 左侧没有参数,写一个()3 左侧有一个参数,  ()可以省略4 右侧如果只有一条语句,可以省略{},如果有返回值,只有一条语句,return省略,如果有多条语句,必须写{}5 Labmda表达式没有生成内部类6 访问局部变量,加上final函数式接口:只有一个抽象方法Consumer 消费型    有参数没有返回值Supplier 供给型    没有参数有返回值Function 函数型    有参数有返回值Predicate 断言型   有参数 返回值boolean
2 方法引用: 如果方法体中只调用一条语句,可以使用方法引用对象::实例方法System.out::println类名::静态方法 Integer:compare类名::实例方法String::equalsEmployee::getName类名::new   创建对象Employee::new数组引用String[]::new
3 Stream API  流:包含对集合和数组的操作三步1 创建流 Stream.of()Arrays.stream()集合的.stream()Stream.iterate()Stream.generate();2 中间操作filter 排除不满足条件数据limit  限制skip   跳过distinct  去重复 map 映射3 终止操作 forEach();allMatch()anyMatch()noneMath();findFirst();findAny();count();reduce() 归约collect() 收集时间和日期LocalDateLocalTimeLocalDateTimeInstant 时间时刻时间矫正器时间格式化DateTimeFormatter

今天任务

1.单元测试
2.注解
3.类加载器

教学目标

1.掌握单元测试
2.掌握注解
3.理解类加载器

第一节:单元测试

1.1 什么是软件测试

软件测试是程序的一种执行过程,目的是尽可能发现并改正被测试软件中的错误,提高软件的可靠性。

1.2 测试分类

按照是否知道源代码

​ 黑盒测试:不关心具体的逻辑代码,只测功能

​ 白盒测试:测试逻辑代码

​ 灰盒测试

从软件开发的过程

​ 单元测试Unit Testing

​ 集成测试Integrated Testing

​ 系统测试System Testing

根据测试的次数

​ 冒烟测试

​ 压力测试

1.3 Junit单元测试

Junit是一个基于Java语言的单元测试框架。是白盒测试的一种技术。

演示测试1

public class Operation {public int add(int x,int y) {return x^y;}public int sub(int x,int y) {return x-y;}
}public class OperationTest {@Testpublic void testAdd() {Operation operation=new Operation();int result=operation.add(20, 30);System.out.println(result);Assert.assertEquals(50, result);}@Testpublic void testSub() {Operation operation=new Operation();int result=operation.sub(10,5);System.out.println(result);}
}

演示测试2

有一个学生类StudentDao,添加测试类

public class StudentDao {public void add() {System.out.println("添加学生");}public void update() {System.out.println("更新学生");}}  public class StudentDaoTest {@BeforeClasspublic static void setUpBeforeClass() throws Exception {System.out.println("测试类执行之前。。。。。。。。。");}@AfterClasspublic static void tearDownAfterClass() throws Exception {System.out.println("测试类执行之后。。。。。。。。。");}@Beforepublic void setUp() throws Exception {System.out.println("方法之前执行........");}@Afterpublic void tearDown() throws Exception {System.out.println("方法之后执行........");}@Testpublic void test() {System.out.println("测试方法");}@Testpublic void test2() {System.out.println("测试方法2");}@Testpublic void testAdd() {StudentDao studentDao=new StudentDao();studentDao.add();}@Testpublic void testUpdate() {StudentDao studentDao=new StudentDao();studentDao.update();}}

注意:

​ ①测试方法上必须使用@Test进行修饰

​ ②测试方法必须使用public void 进行修饰,不能带任何的参数

​ ③新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开

​ ④测试类所在的包名应该和被测试类所在的包名保持一致

​ ⑤测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖

​ ⑥测试类使用Test作为类名的后缀(不是必须)

​ ⑦测试方法使用test作为方法名的前缀(不是必须)

第二节:注解

注释:给代码添加说明和解释,注释帮助开发人员理解程序。(Comment)

注解:给代码添加说明,这个说明给程序使用。

从 JDK 5.0 开始,Java 增加了对元数据(MetaData) 的支持, 也就是Annotation(注解)。

三个基本的 Annotation:

​ @Override:限定重写父类方法, 该注解只能用于方法

​ @Deprecated:用于表示某个程序元素(类, 方法等)已过时

​ @SuppressWarnings: 抑制编译器警告.

什么是注解

​ Annotation其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

注解技术的要点:

​ 如何定义注解

​ 如何反射注解,并根据反射的注解信息,决定如何去运行类

2.1自定义注解:

​ 定义新的 Annotation 类型使用@interface关键字

​ 声明注解的属性

注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述。
Annotation的属性声明方式:Stringname();
属性默认值声明方式:Stringname() default “xxx”;
特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")
特殊属性value[];
注解属性的类型可以是:String类型基本数据类型Class类型枚举类型注解类型以上类型的一维数组

案例演示1 创建和使用注解

public @interface MyAnnocation {String name();int num() default 10;MyAnnocation2 anno();
}
public @interface MyAnnocation2 {String value();
}public class Demo1 {@MyAnnocation(name="哈哈",num=50,anno=@MyAnnocation2(value = "xxx"))public void show() {System.out.println("xxxxxxx");}
}
2.2 JDK的元 Annotation

元 Annotation指修饰Annotation的Annotation。

@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。

RetentionPolicy.CLASS: 编译器将把注解记录在 class文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
RetentionPolicy.RUNTIME:编译器将把注解记录在 class文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释

@Target:指定注解用于修饰类的哪个成员.@Target 包含了一个名为value,类型为ElementType的成员变量。

@Documented:用于指定被该元 Annotation 修饰的Annotation类将被 javadoc 工具提取成文档。

@Inherited:被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的Annotation,则其子类将自动具有该注解。

案例演示2 使用反射获取注解信息

@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfo {String name();int age() default 20;String gender();
}public class PersonOpe {@PersonInfo(name="李四",age=20,gender="男")public void show(String name,int age,String gen) {System.out.println(name);System.out.println(age);System.out.println(gen);}
}
public class Demo2 {public static void main(String[] args) throws Exception{PersonOpe ope=new PersonOpe();Class<?> class1=PersonOpe.class;Method method = class1.getMethod("show", String.class,int.class,String.class);PersonInfo annotation = method.getAnnotation(PersonInfo.class);String name=annotation.name();int age=annotation.age();String gender=annotation.gender();method.invoke(ope, name,age,gender);}
}

第三节:类加载器

​ Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。

​ 类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,Java运行时系统不需要知道文件与文件系统。

​ JVM中有3个默认的类加载器:

  1. 引导(Bootstrap)类加载器。由原生代码(如C语言)编写,不继承自java.lang.ClassLoader。负责加载核心Java库,存储在<JAVA_HOME>/jre/lib目录中。

  2. 扩展(Extensions)类加载器。用来在<JAVA_HOME>/jre/lib/ext,或java.ext.dirs中指明的目录中加载 Java的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。该类由sun.misc.Launcher$ExtClassLoader实现。

  3. Apps类加载器(也称系统类加载器)。根据 Java应用程序的类路径(java.class.path或CLASSPATH环境变量)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。该类由sun.misc.Launcher$AppClassLoader实现。

    ​ 这三个类装载器存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下使用AppClassLoader装载应用程序的类。

public class Test{Public static void main(String[] arg){ClassLoader c  = Test.class.getClassLoader();  //获取Test类的类加载器System.out.println(c); ClassLoader c1 = c.getParent();  //获取c这个类加载器的父类加载器System.out.println(c1);ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器System.out.println(c2);}
}
3.1类加载过程

​ 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程称为类加载,这里我们需要了解一下类加载的过程,如下:

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SoNgkVA9-1575685440937)(图片\02.png)]

  • 加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
  • 验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
  • 准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
  • 解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
  • 初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。
3.2 双亲委托模式

​ Java装载类使用“全盘负责委托机制”。“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入;“委托机制”是指先委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全方面考虑的,试想如果一个人写了一个恶意的基础类(如java.lang.String)并加载到JVM将会引起严重的后果,但有了全盘负责制,java.lang.String永远是由根装载器来装载,避免以上情况发生 除了JVM默认的三个ClassLoder以外,第三方可以编写自己的类装载器,以实现一些特殊的需求。

为什么要使用这种双亲委托模式呢?

​ 因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。

​ 考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法被加载。

演示错误

创建java.lang包并创建String类。

双亲委派模式工作原理

​ 双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码,类加载器间的关系如下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBburOWz-1575685440938)(图片\01.png)]

​ 双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这不就是传说中的实力坑爹啊。

3.3 使用类加载器加载属性文件

使用类加载器加载属性文件。

案例1:Properties加载属性文件

InputStream is = Test.class.getClassLoader().getResourceAsStream("user.properties");
Properties properties=new Properties();
properties.load(new InputStreamReader(is, "utf-8"));
properties.list(System.out);

案例2:使用ResourceBundle加载属性文件

//不用带扩展名
ResourceBundle bundle = ResourceBundle.getBundle("com.qf.day19.user");
//解决中文乱码问题
System.out.println(new String(bundle.getString("name").getBytes("iso-8859-1"),"utf-8"));
System.out.println(bundle.getString("age"));
System.out.println(new String(bundle.getString("gender").getBytes("iso-8859-1"),"utf-8"));

注意:属性文件默认编码为ISO-88590-1,如果修改为utf-8需要代码中处理乱码问题。

Java单元测试和类加载相关推荐

  1. Java单元测试技巧之PowerMock

    简介: 高德的技术大佬向老师在谈论方法论时说到:"复杂的问题要简单化,简单的问题要深入化." 这句话让我感触颇深,这何尝不是一套编写代码的方法--把一个复杂逻辑拆分为许多简单逻辑, ...

  2. Java单元测试实践-25.在本地使用H2数据库进行单元测试

    Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. 前言 使用 ...

  3. Java反射 - 动态类加载和重载

    可以使用Java在运行时加载和重新加载类,虽然它不像人们希望的那样简单. 本文将解释何时以及如何在Java中加载和重新加载类. ClassLoader Java应用程序中的所有类都使用java.lan ...

  4. 用Java Instrumentation 在类加载时添加记录

    用Java Instrumentation 在类加载时添加记录 发布者:xanadu0214   来源:网络转载   发布日期:2013年11月06日   Java学习交流群:471651004 在分 ...

  5. java 单元测试inject_Mockito中@Mock与@InjectMock

    Mockito是java单元测试中,最常用的mck工具之一,提供了诸多打桩方法和注解.其中有两个比较常用的注解,@Mock和@InjectMock,名字和在代码中使用 的位置都很像,对于初学者,很容易 ...

  6. Java基础:类加载器

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 1. 什么是类加载器 类加载器就是用来加载类的东西!类加载器也是一个类:ClassLoader 类加载 ...

  7. 使用Mockito进行Java单元测试

    Google在3月份推出了一个关于Android MVP架构的官方Sample,除MVP架构本身之外,在这个Sample中配备了完善的单元测试用例,这对学习如何在Android中进行单元测试具有极高的 ...

  8. java中的类加载器有,Java自定义的类加载器,java自定义加载,在java中类加载器有以...

    Java自定义的类加载器,java自定义加载,在java中类加载器有以 在java中类加载器有以下几种java虚拟机自带的加载器 1)根类加载器(Bootstrap,c++实现)2)扩展类加载器(Ex ...

  9. Mock和Java单元测试中的Mock框架Mockito介绍

    什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象.程序员通常创造模拟对象(mock object)来测试其他对象 ...

最新文章

  1. 哪个瞬间让你突然觉得CV技术真有用?
  2. POJ 2516 Minimum Cost 最小费用流
  3. hdu 1147(线段相交)
  4. 计算机视觉与深度学习 | 目标提取(代码实现)
  5. SAP CRM WebClient UI上分销渠道点击展开按钮后执行了哪些逻辑
  6. 织梦 mysql 配置文件_MySQL集群配置
  7. 机械零点、MAM 文件 、 EMT标定原理
  8. .Net在线编辑工具.NET Fiddle
  9. 训练代码_代码简介:是的,有完全免费的代码训练营
  10. 编写一个求方程ax2 + bx + c = 0的根 的程序,用3个函数分别求当b2-4ac大于零、等于零、和小于零时的方程的根。要求从主函数输入a,b,c的值并输出结果。
  11. 哈工大计算机学院历史,历史沿革
  12. linux hadoop etc目录,Hadoop系列——Linux下Hadoop的安装与伪分布式配置
  13. oracle 安装
  14. sql递归查询上级_递归的实际业务场景之MySQL 递归查询
  15. AJAX问题:如果SESSION丢失,会直接报错。
  16. springboot默认数据源如何设置连接数_Spring Boot学习:如何使用Druid数据源
  17. Error:Cannot read packageName from AndroidManifest.xml
  18. 校外国外博士论文去哪里查找下载
  19. 确认OHS版本的方法
  20. mysql数据库读取数据,教你如何从 MySQL 数据库读取数据

热门文章

  1. nagios报警信息,发送到微信端
  2. Eclipse环境设置导出
  3. python怎么和前端连接_如何将前端HTML/JQuery连接到后端Python
  4. 超级攻略!Pandas\NumPy\Matrix用于金融数据准备
  5. 今日北方大部进入降水间歇期 南方仍多低温阴雨雪天气
  6. 【 Apifox】一款前端开发、后端开发、测试人员连连叫好的开发工具
  7. 五款功能强大的国产软件,常常被误认为是外国人开发的
  8. 数据库常见面试题 —— 7.事务的四种特性
  9. 九城入股G10 觊觎研发
  10. arcgis for android(六)定位