一、单元测试
1.1 概述、Junit框架快速入门
单元测试:就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。
优点:①可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。 ②不需要程序员去分析测试的结果,会自动生成测试报告出来。 ③拥有更强大的测试能力。
使用步骤:
1.将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
2.编写测试类、测试类方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
3.必须在测试方法上使用@Test注解(标注该方法是一个测试方法)
4.在测试方法中,编写程序调用被测试的方法即可。
5.选中测试方法,右键选择“JUnit运行” ,如果测试通过则是绿色;如果测试失败,则是红色
1.2 Junit框架的常见注解
Junit 4.xxxx版本
Junit 5.xxxx版本
Demo
public class Utils {
public int getMax(int a,int b){
return a > b ? a:b;
}
public int getMin(int[] arr){
if (arr == null){
throw new RuntimeException("数组不能为空");
}
int min = arr[0];
for (int i = 0; i < arr.length; i++) {
min = Math.min(arr[i], min);
}
return min;
}
}
public class Test1 {
//作用
static Utils u;
@BeforeClass
public static void beforeclass(){
u = new Utils();
System.out.println("执行了beforeclass方法");
}
@Before
public void before(){
System.out.println("执行了before方法");
}
@Test
public void getMaxTest(){
int max = u.getMax(10, 20);
System.out.println(max);
}
@Test
public void arrTest(){
int[] arr = {11,333,22,2,45};
int min = u.getMin(arr);
System.out.println(min);
//断言
//Assert.assertEquals(22,min);
}
@After
public void after(){
System.out.println("执行了after方法");
}
@AfterClass
public static void afterClas(){
System.out.println("afterClas");
}
}
二、反射
反射就是:以编程的方式获取类中的各种成分(成员变量、方法、构造器等)。
第一步,获取类对象,这里有三种获取的方式:
方式一:Class c1 = Class.forName(“全类名”); 方式二:Class c2 = 类名.class 方式三:Class c3 = 对象.getClass();推荐使用方式一
//类名. Class clz1 = Student.class; //对象名. Student s = new Student(); Class clz2 = s.getClass(); //Class.ForName Class clz3 = Class.forName("com/itheima/demo03_获取class对象/Student.java");//对应类路径
public static void main(String[] args) throws Exception { Class clz = Class.forName("com.itheima.demo04_获取构造器.Student"); //获取构造器,单个 Constructor con = clz.getConstructor(); Constructor con4 = clz.getDeclaredConstructor();//获取全部的,不管私有 //无参构造器,而且是公有的 System.out.println(con); //返回所有的构造器 Constructor[] con2 = clz.getDeclaredConstructors(); Annotation[] con5 = clz.getDeclaredAnnotations(); //System.out.println(con2); //System.out.println(con5); //初始化一个对象返回 Constructor con3 = clz.getConstructor(String.class, int.class); //需要进行暴力反射 con3.setAccessible(true); Student o =(Student) con3.newInstance("张三", 22); System.out.println(o); }
利用反射技术获取成员变量的方式 获取类中成员变量对象的方法
getDeclaredFields()——>获取所有存在的成员变量
getField(String name)——>获取一个public成员变量
getDeclaredField(String name)——>获取一个public成员变量
反射得到成员变量可以做什么?
依然是在某个对象中取值和赋值。 void set(Object obj, Object value): Object get(Object obj)
如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值 setAccessible(boolean)
demo
public static void main(String[] args) throws Exception { Class clz = Class.forName("com.itheima.demo05_获取成员变量.Student"); //1.获取构造器 Constructor con = clz.getConstructor(); con.setAccessible(true); Object stu = con.newInstance(); //用什么成员就获取 Field name = clz.getDeclaredField("name"); Field age = clz.getDeclaredField("age"); name.setAccessible(true); age.setAccessible(true); //赋值 name.set(stu,"张三"); age.set(stu,22); //获取到对应字段 System.out.println(name.get(stu)); System.out.println(age.get(stu)); //获取到整个对象字段 System.out.println(stu); }
获取类的成员方法并且使用
demo
public static void main(String[] args)throws Exception { Class<?> clz = Class.forName("com.itheima.demo06_获取成员方法.Student"); //1.获取构造器 Constructor<?> con = clz.getConstructor(); con.setAccessible(true); //创建出一个对象 Object stu = con.newInstance(); //获取上面成员变量就获取 Field name = clz.getDeclaredField("name"); Field age = clz.getDeclaredField("age"); name.setAccessible(true); name.set(stu,"张三"); age.setAccessible(true); age.set(stu,22); //获取什么方法,就调用 Method test = clz.getDeclaredMethod("test", String.class); test.setAccessible(true); test.invoke(stu,"张三");//返回值的内容,传入的东西,如果是无参就写方法名 System.out.println(stu);//方法执行的内容,没有返回值的直接输出就行 Method getName = clz.getDeclaredMethod("getName"); Method getAge = clz.getDeclaredMethod("getAge"); getName.setAccessible(true); getAge.setAccessible(true); Object o = getName.invoke(stu); Object o1 = getAge.invoke(stu); System.out.println(o); System.out.println(o1); }
反射的作用
可以得到一个类的全部成分然后操作。 可以破坏封装性。(很突出)
更重要的用途是适合:做Java的开发框架,基本上主流框架都会基于反射设计一些通用技术功能
综合案例
三个实体类狗、学生、老师,实现调用对象
package com.itheima.demo07_综合案例;
public class Dog {
private String name;
private String type;
private String color;
public Dog() {
}
public Dog(String name, String type, String color) {
this.name = name;
this.type = type;
this.color = color;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return type
*/
public String getType() {
return type;
}
/**
* 设置
* @param type
*/
public void setType(String type) {
this.type = type;
}
/**
* 获取
* @return color
*/
public String getColor() {
return color;
}
/**
* 设置
* @param color
*/
public void setColor(String color) {
this.color = color;
}
public String toString() {
return "Dog{name = " + name + ", type = " + type + ", color = " + color + "}";
}
}
public static void main(String[] args)throws Exception {
Student s1 = new Student("张三" , 23 , 6668 , "广州");
Teacher t1 = new Teacher("0001" , "Mylo" , "男" , 234567 );
Dog d1 = new Dog("小哈" , "哈士奇" , "黑白");
PrintStream ps = new PrintStream("day14_junit_reflect_annotation_proxy\\file\\t.txt");
ArrayList list = new ArrayList<>();
Collections.addAll(list,s1,t1,d1);
for (Object o : list) {
Class<?> clz = o.getClass();
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
ps.println(field.getName()+"="+field.get(o));
}
}
ps.close();}
三、注解
3.1 基本内容和自定义注解
概述:就是Java代码里的特殊标记,比如:@Override、@FunctionalInterface、@Test。
作用的地方:Java程序中的类上、构造器上、方法上、成员变量上、参数、等都可以用注解进行标记。
作用:对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。 例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。
自定义注解
格式:
public @interface 注解名称 { public 属性类型 属性名() default 默认值 ; }
其中属性类型可以有:基本数据类型 String Class 注解 枚举 以上类型的一维数组
自定义注解的使用:@注解名(属性名1=值1, 属性名2=值2)
value值的属性,如果只有一个可以省略value,但是多个value属性、且多个属性没有默认值
必须要写value。
3.2 元注解
概述:修饰注解的注解
分类: @Target: 约束自定义注解只能在哪些地方使用, @Retention:申明注解的生命周期
@Target中可使用的值定义在ElementType枚举类中,常用值如下
TYPE,类,接口 FIELD, 成员变量 METHOD, 成员方法 PARAMETER, 方法参数 CONSTRUCTOR, 构造器 LOCAL_VARIABLE, 局部变量
@Retention中可使用的值定义在@Retention中可使用的值定义在RetentionPolicy枚举类中,常用值如下RetentionPolicy枚举类中,常用值如下
SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在
CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
保存时间(生命周期)
3.3 注解解析和应用场景
注解的解析:就是判断是否存在注解,存在注解就解析注解的内容
应用场景:模拟Junit框架
需求,自定义注解,定义若一个方法,获取在方法上或者类上注解的value值
demo
@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Book { public String value(); double price() default 100; String[] authors(); }
@Book(value = "平凡的世界",authors = {"路遥","孙少安"}) public class BookStore { @Book(value = "白鹿原",price = 22,authors = {"小文","小吴"}) public void show(){ } }
public static void main(String[] args)throws Exception {
//获取类上面的
Class clz = Class.forName("com.itheima.demo09_注解的使用.BookStore");
if (clz.isAnnotationPresent(Book.class)){
Book annotation =(Book) clz.getDeclaredAnnotation(Book.class);
String bookName = annotation.value();
double price = annotation.price();
String[] authors = annotation.authors();
System.out.println("书名:"+bookName+",价格:"+price+",作者:"+ Arrays.toString(authors));
}else {
System.out.println("注解不存在!");
}
//获取在方法上面的
Method show = clz.getDeclaredMethod("show");
if (show.isAnnotationPresent(Book.class)){
Book book = show.getDeclaredAnnotation(Book.class);
String bookName = book.value();
double price = book.price();
String[] authors = book.authors();
System.out.println("书名:"+bookName+",价格:"+price+",作者:"+ Arrays.toString(authors));
}
}
四、动态代理
概述:代理思想就是被代理者没有能力,或者不愿意去完成某件事情,需要找个人(代理)代替自己去完成这件事。
作用:动态代理主要是对被代理对象的行为进行代理。 对功能进行增强。
实现的步骤
必须定义接口,里面定义一些行为,用来约束被代理对象和代理对象都要完成的事情。
定义一个实现类实现接口,这个实现类的对象代表被代理的对象。
定义一个测试类,在里面创建被代理对象,然后为其创建一个代理对象返回。(重点)
代理对象中,真正触发被代理对象的行为。
通过返回的代理对象进行方法的调用,观察动态代理的执行流程。
demo
定义一个接口,规定一些行为
public interface Show { public void sing(); public void dance(); int getMax(int a,int b); }
定义一个实体类去实现接口,实现类的对象代表被管理对象
public class Singer implements Show{ @Override public void sing() { System.out.println("哥哥在唱歌啦~"); } @Override public void dance() { System.out.println("梳着中分穿着背带裤玩着篮球的哥哥在跳舞"); } @Override public int getMax(int a, int b) { int max = Math.max(a, b); return max; } }
测试类
public class Test {
public static void main(String[] args) {
//被代理对象
Singer s = new Singer();
//创建代理对象
Show o =(Show) Proxy.newProxyInstance(Test.class.getClassLoader()
, s.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("天不生我蔡徐坤,坤道万古如长夜");
Object result = method.invoke(s, args);
System.out.println("钱来!!!!");
return result;
}
}
);
o.sing();
o.dance();
int max = o.getMax(10, 20);
System.out.println(max);
}
}