每日总结Day13

单元测试&反射&注解


目录

单元测试&反射&注解

文章目录

一、单元测试

二、反射

2.1获取字节码对象

2.2获取类的构造器

2.3获取类的成员变量

2.4获取类的成员方法

2.5反射案例

三、注解

3.1自定义注解

3.2元注解

3.3注解解析

总结


一、单元测试

测试的方法必须是公共的,无参的,无返回值

@Test:测试类中的方法必须用它修饰才能成为测试方法,才能启动执行

@Before:用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次

@After:用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次

@BeforeClass:(必须修饰的是静态方法)用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次

@AfterClass:(必须修饰的是静态方法)用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次

代码如下(示例):

public class StringUtilTest {
    @BeforeClass
    public static void beforeClassPrint(){
        System.out.println("测试类开始");
    }
    @AfterClass
    public static void afterClassPrint(){
        System.out.println("测试类结束");
    }
    @Before
    public  void beforePrint(){
        System.out.println("测试开始");
    }
    @After
    public  void afterPrint(){
        System.out.println("测试结束");
    }
    @Test
    public void testPrintNumber(){
        StringUtil.printNumber("helloworld!");
    }
    @Test
    public void testGetMaxIndex(){
        int index = new StringUtil().getMaxIndex("黑马程序员");
        Assert.assertEquals("有问题",4,index);
        System.out.println(index);
    }
}
public class StringUtil {

    //获取字符串长度
    public static void printNumber(String name) {
        System.out.println("名字长度:" + name.length());
    }

    //获取字符串的最大索引
    public int getMaxIndex(String data) {
        if (data == null) {
            return -1;
        }
        return data.length()-1;
    }
}

二、反射

2.1获取字节码对象

反射的第一步是什么
    获取Class类对象,如此才可以解析类的全部成分

获取Class对象的三种方式
    1. 直接使用类名.class获取:Class c1 = 类名.class
    2. 调用Class提供的方法:Class c2 = Class.forName("全类名")
    3. 调用Object提供的方法:Class c3 = 对象.getClass()

代码如下(示例):

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class class1 = Cat.class;
        Class class2 = Class.forName("com.itheima.b_反射.Cat");
        Class class3 = new Cat().getClass();
        System.out.println(class1 == class2);
        System.out.println(class1 == class3);
    }
}

2.2获取类的构造器

获取构造器[下面是Class的方法]
    Constructor<?>[] getConstructors()  获取所有的公共构造器(只能获取public修饰的)
    Constructor<?>[] getDeclaredConstructors()  获取全部构造器(只要存在就能拿到)
    Constructor<T> getConstructor(Class<?>... parameterTypes)   获取某个公共构造器(只能获取public修饰的)
    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)   获取某个构造器(只要存在就能拿到)

使用构造器(创建对象)[下面是Constructor的方法]
    T newInstance(Object... initArgs)   调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
    public void  setAccessible(boolean flag)    设置为true,表示禁止检查访问控制(暴力反射)

注意
    使如果想使用private修饰构造器反射创建对象,需要暴力反射(禁止JVM检查构造方法的访问权限)

代码如下(示例):

public static void main(String[] args) throws Exception {
        Class<Cat> aClass = Cat.class;
        Constructor[] constructors1 = aClass.getConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println(constructor);
        }
        System.out.println("-------------------------------");
        Constructor[] constructors2 = aClass.getDeclaredConstructors();
        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }
        System.out.println("-------------------------------");
        Constructor<Cat> constructor3 = aClass.getConstructor(String.class);
        System.out.println(constructor3);
        System.out.println("-------------------------------");
        Constructor<Cat> constructor4 = aClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor4);
        System.out.println("-------------------------------");
        Cat cat = constructor3.newInstance("小花");
        System.out.println(cat);
        System.out.println("-------------------------------");
        constructor4.setAccessible(true);
        Cat cat1 = constructor4.newInstance("加菲", 4);
        System.out.println(cat1);
    }

2.3获取类的成员变量

获取成员变量[Class提供]
    public Field[] getFields()  获取类的所有公共成员变量(只能获取public修饰的)
    public Field[] getDeclaredFields()  获取类的全部成员变量(只要存在就能拿到)
    public Field getField(String name)  获取类的某个公共成员变量(只能获取public修饰的)
    public Field getDeclaredField(String name)  获取类的某个成员变量(只要存在就能拿到)
使用成员变量(赋值和取值) [Field提供]
    public void set(Object obj, Object value): 赋值
    public Object get(Object obj):  取值
    public void  setAccessible(boolean flag):   设置为true,表示禁止检查访问控制(暴力反射)
注意
    使如果想使用private修饰的变量,需要暴力反射

代码如下(示例):

public static void main(String[] args) throws Exception {
        Class<Cat> aClass = Cat.class;
        Cat cat = new Cat();
        Field[] fields1 = aClass.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }
        System.out.println("===========================");
        Field[] fields2 = aClass.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }
        System.out.println("===========================");
        Field field1 = aClass.getField("a");
        System.out.println(field1);
        System.out.println("===========================");
        Field field2 = aClass.getDeclaredField("name");
        System.out.println(field2);
        System.out.println("===========================");
        field1.set(cat,10);
        System.out.println(cat.a);
        System.out.println("===========================");
        Field field = aClass.getDeclaredField("age");
        field.setAccessible(true);
        field.set(cat,20);
        System.out.println(cat.getAge());
        System.out.println(field.get(cat));
        System.out.println("===========================");
        field2.setAccessible(true);
        field2.set(cat,"小花");
        System.out.println(cat.getName());
        System.out.println("===========================");
        System.out.println(field1.get(cat));
        System.out.println(field2.get(cat));
    }

2.4获取类的成员方法

获取成员方法[Class提供]
    Method[] getMethods()   获取类的全部公共成员方法(只能获取public修饰的)
    Method[] getDeclaredMethods()   获取类的全部成员方法(只要存在就能拿到)
    Method getMethod(String name, Class<?>... parameterTypes)   获取类的某个公共成员方法(只能获取public修饰的)
    Method getDeclaredMethod(String name, Class<?>... parameterTypes)   获取类的某个成员方法(只要存在就能拿到)
使用成员方法(执行方法)[Method提供]
    public Object invoke(Object obj, Object... args)    触发某个对象的该方法执行。
    public void  setAccessible(boolean flag)    设置为true,表示禁止检查访问控制(暴力反射)
注意
    使如果想使用private修饰的成员方法,需要暴力反射

代码如下(示例):

public static void main(String[] args) throws Exception {
        Class<Cat> aClass = Cat.class;
        Method[] methods1 = aClass.getMethods();
        for (Method method : methods1) {
            System.out.println(method.getName()+"---"+method.getReturnType()+"---"+method.getParameterCount());
        }
        System.out.println("=======================================================================================");
        Method[] methods2 = aClass.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method.getName()+"---"+method.getReturnType()+"---"+method.getParameterCount());
        }
        System.out.println("=======================================================================================");
        Method method1 = aClass.getMethod("eat");
        System.out.println(method1.getName()+"---"+method1.getReturnType());
        System.out.println("=======================================================================================");
        Method method2 = aClass.getDeclaredMethod("eat", String.class);
        System.out.println(method2.getName()+"---"+method2.getReturnType());
        System.out.println("=======================================================================================");
        Cat cat = new Cat();
        Object invoke = method1.invoke(cat);
        System.out.println(invoke);
        System.out.println("=======================================================================================");
        method2.setAccessible(true);
        Object invoke1 = method2.invoke(cat, "shi");
        System.out.println(invoke1);
    }

2.5反射案例

反射案例
    对于任意一个对象,该框架都可以把对象的字段名和对应的值,然后打印在控制台

代码如下(示例):

public class Demo5 {
    public static void main(String[] args) throws Exception {
        //1. 准备两个对象
        Student student = new Student("柳岩", 40, '女', 167.5, "女星");
        Teacher teacher = new Teacher("播妞", 6000);
        //2.调用方法
        print(student);
        print(teacher);
    }
    public static void print(Object obj) throws Exception {
        Class aClass = obj.getClass();
        System.out.println("=============="+aClass.getSimpleName()+"====================");
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            System.out.println(field.getName()+"="+field.get(obj));
        }
    }
}
class Student{
    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;
}
class Teacher {
    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
    private String name;
    private double salary;
}

三、注解

让其他程序根据注解信息决定怎么执行该程序

3.1自定义注解

@interface 注解名{
    数据类型 属性名();
    数据类型 属性名() default 默认值;
}

注意:

- 注解使用时候,若属性没有设置默认值,我们需要给该属性设置值

- 若使用注解的时候,只有一个属性需要赋值且属性名为value的时候,属性名可以省略

- 使用注解的时候,若某个属性的类型为数组类型,但是赋值时只有一个值,"{}"是可以省略的

3.2元注解

@Target:声明被修饰的注解只能再哪些位置使用

1、TYPE:类,接口

2、FIELD:成员变量

3、METHID:成员方法

4、PARAMETER:方法参数

5、CONSTRUCTOR:构造器

6、LOCAL_VARIABLE:局部变量

@Retention:声明注解的保留阶段

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

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

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

3.3注解解析

isAnnotationPresent(注解.class)

getAnnotation(注解.class)

通过class、method、field都可以调用

案例:

定位到指定包中所有带@ClassNameCheck注解的类然后判断类名是否是以Heima开头如果不是就抛异常

下面分析一下步骤

定义一个ClassNameCheckParser在类中定义一个checkClassName方法,用来完成功能

获取项目中指定包下的所有类(此功能已经在工具类中提供好了方法,可以直接使用)

遍历得到每一个类,然后判断类上是否有@ClassNameCheck注解

如果有注解,则获取到类名进行判断,如果不符合规范,则放到一个准备好的集合中

等到遍历结束,查看集合中是否有元素;有就说明存在不符合规范的类名;打印结果,抛出异常

代码如下(示例):

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

@Target(value = {ElementType.TYPE})

@Retention(value = RetentionPolicy.RUNTIME)
public @interface ClassNameCheck {

    String author() default "小明";
    String value();
}
import com.itheima.c_annotation.ClassNameCheck;

@ClassNameCheck(value = "老师类")
public class HeimaTeacher {

    private String name;
    private Integer age;

    public String sayHello() {
        return "hello";
    }


}
import com.itheima.c_annotation.ClassNameCheck;

@ClassNameCheck(value = "学生类", author = "李四")
public class Student {

    //@ClassNameCheck
    private String name;
    private Integer age;

    //@ClassNameCheck
    public String sayHello() {
        return "hello";
    }

}
public class ClassNameCheckParser {

    public static void checkClassName(){
        Set<Class> classes = ClassUtil.getClasses("com.itheima.c_annotation.example");
        for (Class aClass : classes) {
            if(aClass.isAnnotationPresent(ClassNameCheck.class)){
                if(!aClass.getSimpleName().startsWith("Heima")){
                    ClassNameCheck annotation =(ClassNameCheck) aClass.getDeclaredAnnotation(ClassNameCheck.class);
                    System.out.println("类"+aClass.getSimpleName()+"的类名不符合规范,作者:"+annotation.author()+" 作用是:"+annotation.value());
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
            ClassNameCheckParser.checkClassName();
    }
}




总结

以上就是今天学习的内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值