Junit单元测试、反射——框架设计的灵魂、注解

1 篇文章 0 订阅

一、Junit单元测试

  1. 测试分类∶
    ①黑盒测试∶不需要写代码,给输入值,看程序是否能够输出期望的值。
    ②白盒测试:需要写代码的。关注程序具体的执行流程。
    Junit单元测试就是白盒测试中的一种。

  2. Junit使用∶白盒测试
    步骤∶

①定义一个测试类(测试用例)
建议∶测试类名∶被测试的类名Test,包名∶xxx.xxx.xx.test

②定义测试方法:可以独立运行
建议∶
方法名: test测试的方法名
返回值: void
参数列表:空参

③给方法加@Test,可使方法独立运行
④导入Junit依赖环境

  1. 判定结果︰
    红色:失败
    绿色∶成功,无输出
    —般我们会使用断言操作来处理结果:Assert.assertEquals(期望的结果,运算的结果);

  2. 补充∶
    @Before:修饰的方法会在测试方法之前被自动执行
    @After:修饰的方法会在测试方法执行之后自动被执行

二、反射:框架设计的灵魂

  1. 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码。
  2. 反射:将类的各个组成部分封装为其他对象,这就是反射机制。

在这里插入图片描述
好处:
① 可以在程序运行过程中,操作这些对象。
② 可以解耦,提高程序的可扩展性。

1. 获取Class对象的方法

①Class. forName( “全类名”) :将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类。

②类名.class :通过类名的属性class获取
多用于参数的传递

③对象.getClass() : getClass()方法在Object类中定义着。
多用于对象的获取字节码的方式

结论:
同一个字节码文件( *.class)在一次程序运行过程中, 只会被加载一次, 不论通过哪一种方式获取的Class对象都是同一个。

2. Class对象功能:获取功能

①获取成员变量们

  • Field[ ] getFields():获取所有public修饰的的成员变量;

  • Field getField(String name):获取指定名称的public修饰的的成员变量;

  • Field[ ] getDeclaredFields()::获取所有的成员变量,不考虑修饰符;

  • Field getDeclaredField(String name)

②获取构造方法们

  • Constructor<?>[ ] getConstructors()
  • Constructor< T> getConstructor(类<?>… parameterTypes)
  • Constructor< T> getDeclaredConstructor(类<?>… parameterTypes)
  • Constructor<?>[ ] getDeclaredConstructors()

③获取成员方法们:

  • Method[ ] getMethods()
  • Method getMethod(String name, 类<?>… parameterTypes)
  • Method[ ] getDeclaredMethods()
  • Method getDeclaredMethod(String name,类<?>… parameterTypes)

④获取类名

  • String getName():获取全类名。

3. Field :成员变量

操作:
①设置值

  • void set(object obj, object value)

②获取值

  • get(Object obj)

③忽略访问权限修饰符的安全检查

  • setAccessible(true) :暴力反射

4. Constructor :构造方法

创建对象:

  • T newInstance(Object… initargs)
    如果使用空参数构造方法创建对象,操作可以简化: Class对象的newInstance方法

5. Method :方法对象

①执行方法:

  • Object invoke(Object obj, Object… args)

②获取方法名称:

  • String getName() :获取方法名(包含所继承的Object类的所有方法)

6. 案例

“框架类”:可以帮助我们创建任意类的对象,并且执行其中任意方法

实现
  1. 配置文件:pro.properties
className=domain.Person//类名
methodName=eat//方法名
  1. 反射
步骤:
  1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  2. 在程序中加载读取配置文件
  3. 使用反射技术来加载类文件进内存
  4. 创建对象
  5. 执行方法
package reflect;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //可以创建任意类的对象,可以执行任意方法
        //前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
        
        //1.加载配置文件
        //1.1创建Properties对象
        Properties pro = new Properties();//Properties的对象可以将以Properties结尾的配置文件用load方法读取到内存中,形成一个集合
        
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();//获取字节码文件对应的类加载器
        InputStream is = classLoader.getResourceAsStream("pro.Properties");
        pro.load(is);

        //2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //3.加载该类进内存
        Class cls = Class.forName(className);

        //4.创建对象
        Object obj = cls.newInstance();

        //5.获取方法对象
        Method method = cls.getMethod(methodName);

        //6.执行方法
        method.invoke(obj);
    }
}

三、注解

  1. 概念:说明程序的。给计算机看的。
  2. 注释:用文字描述程序的。给程序员看的。
  3. 定义:注解(Annotation)也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
  4. 概念描述:
  • JDK1.5后的新特性
  • 说明程序的
  • 使用注释:@注解名称
  1. 作用分类:
  • 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
  • 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
  • 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

(1)JDK中预定义的一些注解

  1. @Override :检测被该注解标注的方法是否是继承自父类(接口)的
  2. @Deprecated :该注解标注的内容,表示已过时
  3. @SuppressWarnings :压制警告,一般传递参数all @SuppressWarnings(“all”)

(2)自定义注解

1.格式:元注解

public @interface 注解名称{}

2.本质:注解本质上就是一 个接口,该接口默认继承Annotation接口

public interface MyAnno extends java.lang.annotation.Annotation {}

3.属性:接口中抽象方法
要求:
①属性的返回值类型有下列取值:

  • 基本数据类型
  • string
  • 枚举
  • 注解
  • 以上类型的数组
package annotation;

public @interface MyAnnotation {
    //返回值类型
    public String show() default "zhang";//抽象方法

    int age();
    String show2();

    Person per();

    MyAnnotation2 anno2();

    String[] strs();
}

②定义了属性,在使用时需要给属性赋值

  • 如果定义属性时,使用default关键字给属性默认初始化值, 则使用注解时,可以不进行属性的赋值。
  • 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略, 直接定义值即可。
  • 数组赋值时,值使用{ }包裹。如果数组中只有一个值, 则{ }省略

4.元注解:用于描述注解的注解

  • @Target:描述注解能够作用的位置
    ElementType的取值:
    ①TYPE:可以作用于类上
    ②METHOD:可以作用于方法上
    ③FIELD:可以作用于成员变量上
  • @Retention:描述注解被保留的阶段

例:@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到

①SOURCE:不会保留到class字节码文件中,不被JVM读取到
②CLASS:会保留到class字节码文件中,不被JVM读取到
③RUNTIME

  • @Documented:描述注解是否被抽取到api文档中

  • @Inherited:描述注解是否被子类继承

(3)在程序使用(解析)注解:获取注解中定义的属性值

  1. 获取注解定义的位置的对象 (Class,Method,Field)
  2. 获取指定的注解:getAnnotation(Class)//其实就是在内存中生成了一个该注解接口的子类实现对象
  3. 调用注解中的抽象方法获取配置的属性值

自定义注解:Pro.java

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 描述需要执行的类名和方法名
 */
@Target({ElementType.TYPE})//作用在类上
@Retention(RetentionPolicy.RUNTIME)//保留在RUNTIME阶段
public @interface Pro {
    String className();
    String methodName();
}

Demo1.java:

package annotation;

public class Demo1 {
    public void show1() {
        System.out.println("demo1...show1...");
    }
}

package annotation;

import java.lang.reflect.Method;

/**
 * 框架类:可以帮助我们创建任意类的对象,并且执行其中任意方法
 */
@Pro(className = "annotation.Demo1",methodName = "show1")
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //1.解析注释
        //1.1获取该类的字节码文件对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //2.获取注解对象
        Pro annotation = reflectTestClass.getAnnotation(Pro.class);//其实就是在内存中生成了一个该注解接口的子类实现对象
        /**
         * public class ProImpl implements Pro {
         *     public String className() {
         *         return "annotation.Demo1";
         *     }
         *     public String methodName() {
         *         return "show1";
         *     }
         * }
         */
        //3.调用注解对象中定义的抽象方法,获得返回值
        String className = annotation.className();
        String methodName = annotation.methodName();
        System.out.println(className);
        System.out.println(methodName);

        //3.加载该类进内存
        Class cls = Class.forName(className);

        //4.创建对象
        Object obj = cls.newInstance();

        //5.获取方法对象
        Method method = cls.getMethod(methodName);

        //6.执行方法
        method.invoke(obj);
    }
}

小结:
l. 以后大多数时候,我们会使用注解,而不是自定义注解
2.注解给谁用?
①编译器
②给解析程序用
3.注解不是程序的一部分,可以理解为注解就是一个标签

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值