单元测试,反射,注解

本文详细介绍了Java中的单元测试,重点讲解了JUnit框架的使用,包括测试类的编写和测试方法的注解。接着深入探讨了Java反射机制,阐述了如何获取类的字节码对象、构造器、成员变量和方法对象,并展示了反射在编写通用框架中的应用。最后,文章讨论了注解的概念,包括元注解、注解解析,并给出了利用注解和反射构建通用框架的示例。
摘要由CSDN通过智能技术生成

1.junit单元测试

 单元测试:是指对程序中的最小功能单位进行检查和验证,以确认自己编写的程序是否符合预期。

junit单元测试框架是第三方组织开发的一个测试工具。

  • 测试代码与主程序是分离的,不影响主程序的业务逻辑
  • 上一个测试单元出现问题,对下一个测试单元没有影响
  • 可以生成的是报告,测试成功是绿色,测试失败是红色

使用步骤:

  1. 导jar包:将JUnit的jar包导入到项目中
  2. 编写测试类:在测试类中编写测试方法,测试方法上需要添加一个@Test注解  
  3. 运行测试方法:查看是红色,还是绿色。 
public class StringUtil{
    public static void test1(String name){
        System.out.println("名字长度:"+name.length());
    }

    public static int test2(String name){
        if(name==null){
            return -1;
        }
        int length = name.length();
        return length;
    }
}

 

public class StringUtilTest {
    //1.写一个测试方法,测试StringUtil类中的test1方法是否正确
    @Test
    public void test1(){
        StringUtil.test1("穆斯林");
    }

    //2.写一个测试方法,测试StringUtil类中的test2方法的返回值是否符合预期
    @Test
    public void test2(){
        int result = StringUtil.test2("穆斯林");
        //断言:预期的值是3,验证result结果是否是3.
        Assert.assertEquals(3,result);
    }
}

Junit常用注解:

public class MyTest {
    //1.测试方法
    @Test
    public void test1(){
        System.out.println("test1");
    }
    @Test
    public void test2(){
        System.out.println("test2");
    }

    //2.用来修饰实例方法,在每一个测试方法前执行一次。
    @Before
    public void before(){
        System.out.println("===before===");
    }

    //3.用来修饰实例方法,在每一个测试方法后执行一次。
    @After
    public void after(){
        System.out.println("===after===");
    }

    //4.用来修饰静态方法,在所有测试方法前只执行一次。
    @BeforeClass
    public static void BeforeClass(){
        System.out.println("===BeforeClass===");
    }

    //4.用来修饰静态方法,在所有测试方法后只执行一次。
    @AfterClass
    public static void afterClass(){
        System.out.println("===AfterClass===");
    }
}

2.反射

反射是Java语言的一个重要特性,它允许开发者编写程序去获取一个类的各个组成部分。

 

 反射可以获取到字节码的各个组成部分,并对他们进行使用。

类的各个组成部分其实都是对象(Field,Method,Constructor)

                反射获取类的字节码对象

  • 任何一个类的字节码对象,它的类型都是Class类型。
  • 获取类的字节码有三种方式。
  • 1.Class aClass=Class.forName(包名.类名);
  • 2.Class aClass=类名.class;
  • 3,Class aClass=对象.getClass();
public class Student {
    public String name;
    private int age;
    //空参数的构造器
    public Student(){

    }

    //有参数的构造器
    private Student(String name, int age){
        this.name=name;
        this.age=age;
    }

    public void test1(){
        System.out.println("test1");
    }

    public void test2(String name){
        System.out.println("test2..."+name);
    }

    private int test3(int a,int b){
        return a+b;
    }


    public void study(){
        System.out.println("学生在努力学习");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Teacher {
    public void teach(){
        System.out.println("老师正在激情的讲课");
    }

    public void eat(){
        System.out.println("老师一会要去食堂吃炒河粉");
    }
}

 

                反射获取构造器对象

  1. 获取类的字节码(Class对象)
  2. 调用Class对象的getConstructor()获取构造器(Constructor对象)
  3. 调用Constructor对象的newInstance()方法,创建类的对象
/*
反射获取构造器对象,并使用构造器创建对象
 */
public class Demo2 {
    public static void main(String[] args) throws Exception {
        //1.获取Student类的字节码
        Class<Student> aClass = Student.class;

        //2.获取Student类所有公有的构造器对象
        Constructor<?>[] arrs = aClass.getConstructors();
        for (Constructor<?> arr : arrs) {
            System.out.println(arr);
        }

        //3.获取Student类中所有的构造器对象(包括私有)
        Constructor<?>[] arrss = aClass.getDeclaredConstructors();
        for (Constructor<?> ar : arrss) {
            System.out.println(ar);
        }

        System.out.println("==============================");

        //4.获取单个公有的构造器对象
        Constructor<Student> con1 = aClass.getConstructor();
        System.out.println(con1);
            //执行con1代表的空参构造方法
        Student student1 = con1.newInstance();
        System.out.println(student1);

        //5.获取单个私有的构造器对象
        Constructor<Student> con2 = aClass.getDeclaredConstructor(String.class,int.class);
        System.out.println(con2);
            //取消权限检查(暴力反射)
        con2.setAccessible(true);
            //执行con2代表的有参构造方法
        Student obj2 = con2.newInstance("小明", 20);

        System.out.println(obj2);
    }
}

 

                反射获取成员变量对象

  1. 先获取类的字节码(Class对象)。
  2. 调用Class对象的getField("变量名")方法获取Field对象
  3. 调用Field对象的set/get方法,给成员变量赋值/获取值
//成员变量的反射,并使用
public class Demo3 {
    public static void main(String[] args) throws Exception {
        //1.获取Student类的字节码
        Class<?> aClass = Class.forName("com.itheima.d2_reflect.Student");

        //2.获取Student类所有公有的成员变量对象
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //3.获取Student类中所有的成员变量对象(包括私有)
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println("-------------------------------------------");

            //创建学生对象
        Constructor<?> constructor = aClass.getConstructor();
        Object obj = constructor.newInstance();

        //4.获取单个公有的成员变量对象
        Field name = aClass.getField("name");
            //给name这个成员变量设置值。
        name.set(obj,"小明");
            //获取name这个成员变量的值。
        Object o1 = name.get(obj);
        System.out.println(o1);

        //5.获取单个私有的成员变量对象
        Field age = aClass.getDeclaredField("age");
            //因为age是私有的,不能直接使用,需要暴力反射后再使用
        age.setAccessible(true);
        age.set(obj,23);
        Object o2 = age.get(obj);
        System.out.println(o2);
    }
}

 

                反射获取方法对象

  1. 先获取类的字节码(Class对象)
  2. 调用Class对象的方法获取Method对象
  3. 调用Method对象的inovke(对象.实际参数)方法,执行方法
/*
通过反射获取成员方法对象(Method对象)
 */
public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取Student类的字节码
        Student student=new Student();
        Class<? extends Student> aClass = student.getClass();

        //2.获取Student类所有公有的成员方法对象
        Method[] methods1 = aClass.getMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }
        System.out.println("-------------------------------------");

        //3.获取Student类中所有的成员方法对象(包括私有)
        Method[] methods2 = aClass.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method);
        }

        System.out.println("-------------------------------------");

        Constructor<? extends Student> constructor = aClass.getConstructor();
        Student s = constructor.newInstance();
        //4.获取单个公有的成员方法对象
        Method m1 = aClass.getMethod("test1");
        System.out.println(m1);
        m1.invoke(s);

        Method m2 = aClass.getMethod("test2", String.class);
        System.out.println(m2);
        m2.invoke(s,"hahah");

        System.out.println("-------------------------------------");

        //5.获取单个私有的成员方法对象
        Method m3 = aClass.getDeclaredMethod("test3", int.class, int.class);
        System.out.println(m3);
                //暴力反射
        m3.setAccessible(true);
        Object result = m3.invoke(s, 25, 36);

        System.out.println(result);
    }
}

 

                反射的引用:编写通用框架

  1. 定义配置文件,约定每一个配置表示的含义
  2. 使用Properties对象读取配置文件,获取类名和方法名
  3. 根据类名获取类的字节码对象(Class对象)
  4. 在根据方法名,获取要执行的方法对象(Method对象)
  5. 执行方法

 

public class Demo5 {
    public static void main(String[] args) throws Exception {
        //第一步:读取配置文件
        //这是一个双列集合,键和值都是Stirng类型
        Properties prop = new Properties();
        //读取配置文件中的键和值,存储到Properties集合中
        prop.load(new FileReader("reflect\\src\\com\\itheima\\d2_reflect\\config.properties"));

        //第二步:获取键对应的值
        String methodName = prop.getProperty("methodName"); //获取方法名
        String className = prop.getProperty("className"); //获取类名

        //第三步:通过反射加载要执行的类、要执行的方法
        //假设类名是com.itheima.Student
        Class<?> clazz = Class.forName(className);
        Method m = clazz.getDeclaredMethod(methodName);
        m.setAccessible(true);

        //第四步:执行目标方法
        //执行目标方法,依赖于一个对象,可以通过字节码创建对象
        Object obj = clazz.getConstructor().newInstance();
        m.invoke(obj);
    }
}

3.注解:

Java注解又称Java标注。通过Java注解可以给类,方法,变量添加一些标注数据。

程序可以读取代码上的标注数据,从而做出不同的处理。

 

自定义注解

public @interface 注解名{

        public 属性类型 属性名() default 默认值;

}

元注解:(两个)

  • @Target:约束自定义注解只能在哪些地方使用
  • @Retention:声明注解的生命周期

 

 注解解析:

                就是通过反射读取代码上的注解信息,然后做出针对性的处理。

                所有的类的成分Class,Method,Field,Constructor,都实现了AnnotatedElement接口,他们都拥有解析注解的方法。

                任何一个注解都是Annotation的子类对象

 

 

 注解+反射编写通用框架

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值