反射的基础应用——反射+注解模拟测试框架(Junit)

5 篇文章 0 订阅
1 篇文章 0 订阅

反射基础

1.反射定义

所谓反射,其实相当于类照镜子,是一种自省机制;可以使得程序在运行期间动态获取一个类中的成分;在类加载时,任何一个Java类都存在一个java.lang.Class的对象;反射即将类中的成分反射成为对应的类型(属性,方法,构造器,注解等)对象。

2.获取Class对象

		//加载一个 指定的类并获取该类的Class对象
		//类路径
        Class clazz = Class.forName("User");
        //类名
        clazz = User.class;
        //对象
        clazz = new User().getClass();

3.获取Class中的属性

		//1.通过反射获取类中的成分-属性
        //获取由public修饰的属性
        Field[] fields = clazz.getFields();
        //获取所有的属性,忽略访问修饰符
        Field[] field = clazz.getDeclaredFields();
        for(Field f:field){
        System.out.println(f.getModifiers()+"---"+f.getType()+"---"+f.getName());
        //修改属性可见性
        // f.setAccessible(true);
        }

        //获取类中指定的属性名的Field对象
        Field f = clazz.getDeclaredField("score");
        f.setAccessible(true);
        //创建该类型的对象
        Object obj = clazz.newInstance();
        f.set(obj,158);

        double d = f.getDouble(obj);
        System.out.println(d);

4.获取Class中的方法

	try {
            Class clazz = Class.forName("User");
            Object obj = clazz.newInstance();

            //获取类中的方法
            Method[] ms = clazz.getDeclaredMethods();
            for (Method method:ms) {
                System.out.println(method);
            }
            //根据方法名和方法中的参数类型,获取一个方法对象
            Method m = clazz.getMethod("showInfo", String.class, int.class);
            //执行方法
            Object returnVal = m.invoke(obj, "aa", 10);
            System.out.println(returnVal);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

5.获取Class中的构造器

		//加载类(Cat为一个实体类)
        Class clazz = Cat.class;

//        Object obj = clazz.newInstance();
        //获取所有的public构造器
        Constructor[] constructors = clazz.getConstructors();
        for(Constructor c:constructors){
            System.out.println(c);
        }

        //获取指定的构造器
        Constructor c = clazz.getConstructor(int.class);
        //执行构造器的初始化方法,创建对象
        Object obj = c.newInstance(10);
        System.out.println(obj);

6.获取Class中的注解

//Mapper注解
@Retention(RetentionPolicy.RUNTIME)
@Target({
        ElementType.TYPE,
        ElementType.METHOD,
        ElementType.FIELD
        })
public @interface Mapper {
}

//Table注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {

    String value();

    String schema();
}


@Mapper
@Table(value = "tb_blog",schema = "test")
public class Blog{

    private int bid;
    private String title;
    private String content;
    private String[] tipes;
    private Timestamp time;

    @Mapper
    public void setBid(int bid) {
        this.bid = bid;
    }

    public String[] getTipes() {
        return tipes;
    }

    public void setTipes(String[] tipes) {
        this.tipes = tipes;
    }
}

public class TestAnnotations {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {

        Class<Blog> clz = Blog.class;
        //获取类上的注解
        Annotation[] annos = clz.getAnnotations();
        for(Annotation a:annos){
            System.out.println(a);
        }
        //获取其中一个注解
        Table table = clz.getAnnotation(Table.class);
        System.out.println(table.schema());

        //获取指定的Method对象
        Method m = clz.getMethod("setBid", int.class);
        //获取方法上指定类型的注解
        Mapper mapper = m.getAnnotation(Mapper.class);
        //判断方法对象上是否存在指定类型的注解
        System.out.println(m.isAnnotationPresent(Mapper.class));

        //获取指定名称的属性对象(全局变量)
        Field f = clz.getDeclaredField("bid");
        //判断属性上存在指定的注释
        System.out.println(f.isAnnotationPresent(Mapper.class));
    }
}

反射+注解模拟测试框架(Junit)

注解类:

package com.example;

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

/**
 * @author bxwl
 * @create 2020-07-27 16:22
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}

测试实体类:

package com.example;

import com.softeem.day43.User;
import com.softeem.day43.reglect2.Blog;

/**
 * @author bxwl
 * @create 2020-07-27 16:16
 */
public class UserTest {

    @Test
    public void testInsert(){
        User u = null;
        System.out.println(u.getUserName());
    }

    @Test
    public void testQuery(){
        Blog b = new Blog();
        b.setTipes(new String[]{"技术","java","多线程"});
        String[] tips = b.getTipes();
        System.out.println(tips[3]);
    }

    @Test
    public void TestDivide(){
        System.out.println(10/0);
    }

    @Test
    public void TestAdd(){
        System.out.println(2+2);
    }
}
package com.example;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * @author bxwl
 * @create 2020-07-27 16:26
 */
public class MyJunit {

    public static void main(String[] args) {
        BufferedWriter bw = null;
        //记录方法总数
        int methodCount = 0;
        //记录错误方法总数
        int expCount = 0;
        try {
        	//基于文件的输出缓冲流用于存储生成的错误信息
            bw = new BufferedWriter(new FileWriter("D:\\新建文件夹\\java\\test\\log.txt"));
            //获取类的Class对象
            Class<UserTest> clz = UserTest.class;
            //创建目标类型的实例对象
            UserTest obj = clz.newInstance();
            Method[] methods = clz.getMethods();
            //获取测试方法总数
            for(Method m:methods){
                if(m.isAnnotationPresent(Test.class)) {
                    methodCount++;
                }
            }
            bw.write("测试方法总数:"+methodCount);
            bw.newLine();
            bw.write("---------------------");
            bw.newLine();

            for(Method method:methods){
                try {
                    //如果方法上面包含了Test注解则作为测试方法进行测试
                    if(method.isAnnotationPresent(Test.class)){
                        method.invoke(obj);
                    }
                } catch (Exception e) {
                    //异常方法计数器递增
                    expCount++;
                    bw.write(method.getName()+"出现异常!");
                    bw.newLine();
                    bw.write("类型:"+e.getCause().getClass());
                    bw.newLine();
                    bw.write("原因:"+e.getCause().getMessage());
                    bw.newLine();
                }
            }
            bw.write("-------------------------------");
            bw.newLine();
            bw.write("已测试方法数:"+methodCount+",其中异常方法:"+expCount);
            bw.flush();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(bw != null)bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

生成的测试日志:
在这里插入图片描述

总结

1.优缺点:
优点:反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类;反射是其它一些常用语言,如C、C++、Fortran 或者Pascal等都不具备的。
缺点:效率低,反射执行所需要的时间长。

2.应用场景
(1)逆向代码 ,如反编译
(2)与注解相结合的框架
(3) 动态生成类框架
(4)单纯的反射机制应用框架

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值