day14 Junit、反射、注解、动态代理

一、单元测试

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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值