单元测试,反射,注解,动态代理

1.单元测试

就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。

1.Junit单元测试框架

优点:可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。不需要程序员去分析测试的结果,会自动生成出测试报告。

2.Junit单元测试框架的常用注解

注解说明
@Test测试类中的方法必须用它修饰才能成为测试方法,才能启动执行
@Before用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次
@After用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次
@AfterClass用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次

2.反射

反射就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量,方法,构造器等)

1.加载类,获取类的字节码:Class对象

Class c1 = 类名.class

调用Class通过方法: public static Class forName(String package)

Object提供的方法: public Class getClass(); Class c1 = 对象.getClass();

    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Student.class;
        String name = c1.getName();  // 全类名
        System.out.println("name = " + name);
        String simpleName = c1.getSimpleName(); // 简名: Student
        System.out.println("simpleName = " + simpleName);

        Class<?> c2 = Class.forName("com.hzj.d1reflect.Student"); // 根据全类名获取类
        System.out.println(c2 == c1); // true

        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c3 == c2); // true
    }

2.获取类的构造器

方法说明
Constructor<?>[] getConstructors()获取全部构造器(只能获取public修饰的)
Constructor<?>[] getDeclaredConstructors()获取全部构造器(主要存在就能拿到)
Constructor<T> getConstructor(Class<?>... parameterTypes)获取某个构造器(只能获取public修饰的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)获取某个构造器(只要存在就能拿到)
    @Test
    public void testGetConstructors() {
        // 反射第一步:得到这个类的Class对象
        Class<Cat> c = Cat.class;
        // 获取类的全部构造器
        Constructor<?>[] constructors = c.getConstructors();
        // 遍历数组中的每个构造器对象
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getName() + "-----" + constructor.getParameterCount());
        }
        Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName() + "-----" + declaredConstructor.getParameterCount());
        }
    }

    @Test
    public void testGetConstructor() throws NoSuchMethodException {
        Class<Cat> c = Cat.class;
        // 获取某个构造器
        Constructor<Cat> constructor = c.getConstructor(); // 无参构造器,public的
        Constructor<Cat> declaredConstructor = c.getDeclaredConstructor(); // 无参构造器,所有
        System.out.println(constructor.getName() + "-------" + constructor.getParameterCount());

        // 获取有参构造器
        Constructor<Cat> constructor1 = c.getConstructor(String.class, int.class); // public
        Constructor<Cat> declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class); // 所有
    }

3.获取类构造器的作用:初始化对象返回

Constructor提供的方法说明
T newInstance(Object... initargs)调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
    @Test
    public void testGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<Cat> c = Cat.class;
        // 获取某个构造器
        Constructor<Cat> constructor = c.getConstructor(); // 无参构造器,public的
        Constructor<Cat> declaredConstructor = c.getDeclaredConstructor(); // 无参构造器,所有
        System.out.println(constructor.getName() + "-------" + constructor.getParameterCount());

        constructor.setAccessible(true); // 禁止检查访问权限
        Cat cat = constructor.newInstance();
        System.out.println(cat);

        // 获取有参构造器
        Constructor<Cat> constructor1 = c.getConstructor(String.class, int.class); // public
        Constructor<Cat> declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class); // 所有

        constructor1.setAccessible(true);
        Cat cat1 = constructor1.newInstance("猫", 2);
        System.out.println(cat1);
    }

4.获取类的成员变量

方法说明
public Field[] getFields()获取类的全部成员变量(只能获取public修饰的)
public Field[] getDeclaredFields()获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name)获取类的某个成员变量(只能获取public修饰的)
public Field getDeclaredField(String name)获取类的某个成员变量(只要存在就能拿到)

5.获取到成员变量的作用:赋值,取值

方法说明
void set(Object obj, Object value)赋值
Object get(Object obj)取值
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
@Test
    public void testGetFields() throws NoSuchFieldException, IllegalAccessException {
        Class<Cat> c = Cat.class;
        // 获取类的全部成员变量
        Field[] fields = c.getFields();
        Field[] declaredFields = c.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field.getName() + "------------" + field.getType());
        }

//        Field name = c.getField("name");
        Field name1 = c.getDeclaredField("name");
        System.out.println(name1.getName() + "---------" + name1.getType());

        // 赋值
        Cat cat = new Cat();
        name1.setAccessible(true);
        name1.set(cat, "猫猫");
        System.out.println(cat);
        // 取值
        Object name = name1.get(cat);
        System.out.println(name);
    }

6.获取类的成员方法

方法说明
Method[] getMethods()获取类的全部成员方法(只能获取public修饰的)
Method[] getDeclaredMethods()获取类的全部成员方法(只要存在就能拿到)
Method[] getMethod(String name, Class<?>... parameterTypes)获取类的某个成员方法(只能获取public修饰的)
Method[] getDeclaredMethod(String name, Class<?>... parameterType)获取类的某个成员方法(只要存在就能拿到)

7.成员方法的作用:执行

Method提供的方法说明
public Object invoke(Object obj, Object... args)触发某个对象的改方法执行
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
@Test
    public void testGetMethods() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<Cat> c = Cat.class;

        // 获取类的全部成员方法
        Method[] methods = c.getMethods();
        Method[] declaredMethods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "------" + method.getParameterCount());
        }
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName() + "--------" + declaredMethod.getParameterCount());
        }

        // 获取某个方法对象
        Method run = c.getDeclaredMethod("run");
        System.out.println(run.getName() + "---------" + run.getParameterCount() + "-------" + run.getReturnType());

        Method eat = c.getDeclaredMethod("eat", String.class);
        System.out.println(eat.getName() + "---------" + eat.getParameterCount() + "-------" + eat.getReturnType());

        Cat cat = new Cat();
        run.setAccessible(true);
        run.invoke(cat);

        eat.setAccessible(true);
        eat.invoke(cat, "饭");
    }

3.注解(Annotation)

java代码里的特殊标记,让其他程序根据注解信息来决定怎么执行改程序

注解本质是一个接口,Java中所有注解都是继承了Annotation接口的

@注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口

1.自定义注解

public @interface MyTest1 {
    String a();
    boolean b() default true;
    String[] c();
}
@MyTest1(a = "测试", c = {"a", "b"})
public class AnnotationTest1 {
    @MyTest1(a = "测试方法", b = false, c = {""})
    public void test() {

    }
}

特殊属性名: value

如果注解中只要一个value属性或其他属性都有默认值,使用注解时,value名称可以不写

2.元注解

修饰注解的注解

常见元注解

1.@Target

声明被修饰的注解只能在哪些位置使用

@Target(ElementType.TYPE)

TYPE:类接口

FIELD:成员变量

METHODD:成员方法

PARAMETER:方法参数

CONSTRUCTOR:构造器

LOCAL_VARIABLE:局部变量

2.@Retention

声明注解的保留周期

@Retention(RetentionPolicy.RUNTIME)

SOURCE:只作用在源码阶段,字节码文件中不存在

CLASS(默认):保留到字节码文件阶段,运行阶段不存在

RUNTIME(开发常用):一直保留到运行阶段

3.注解的解析

就是判断类上,方法上,成员变量上是否存在注解,并把注解里的内容给解析出来。

Class,Method,Field,Constructor都实现了AnnotatedElement接口

AnnotatedElement接口提供了解析注解的方法说明
public Annotation[] getDeclaredAnnotations()获取当前对象上面的注解
public T getDeclaredAnnotation(Class<T> annotationClass)获取指定的注解对象
public boolean isAnnotationPresent(Class<Annotation> annotationClass)判断当前对象上是否存在某个注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
    String value();
    double aaa() default 100;
    String[] bbb();
}
@MyTest4(value = "测试类", aaa = 99, bbb = {"value1", "value2"})
public class Demo {

    @MyTest4(value = "测试方法", aaa = 999, bbb = {"value1m", "value2m"})
    public void test1() {

    }
}
public class AnnotationTest2 {
    @Test
    public void parseClass() throws NoSuchMethodException {
        // 先得到class对象
        Class<Demo> c = Demo.class;
        Method m = c.getDeclaredMethod("test1");
        // 解析类上的注解
        // 判断类上是否包含了某个注解
        if (c.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4 = c.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
        if (m.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4 = m.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}

4.动态代理

把公共代码提取出来,在特定的方法执行前后执行公共代码

public interface Star {

    String sing(String name);

    void dance();
}
public class BigStar implements Star{   // 实现接口,接口里面有需要代理的方法
    private String name;

    public BigStar(String name) {
        this.name = name;
    }

    public String sing(String name) {
        System.out.println(this.name + "正在唱:" + name);
        return "唱完了";
    }

    public void dance() {
        System.out.println(this.name + "跳舞");
    }
}
// 创建动态代理类
public class ProxyUtil {
    public static Star createProxy(Star star) {
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("sing")) {
                    System.out.println("准备开始唱歌");
                    Object invoke = method.invoke(star, args);
                    System.out.println(invoke);
                    return invoke;
                } else if (method.getName().equals("dance")) {
                    Object invoke = method.invoke(star);
                    System.out.println("跳舞结束");
                    return invoke;
                } else {
                    return method.invoke(star);
                }
            }
        });
        return starProxy;
    }
}
    @Test
    public void testProxy() {
        BigStar bigStar = new BigStar("杨超越");
        Star proxy = ProxyUtil.createProxy(bigStar);
        proxy.sing("哇哈哈");
        proxy.dance();
    }

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值