JAVA进阶知识点总结 13-单元测试 反射 注解

1  单元测试Junit
2  反射
3  注解

Junit单元测试

概述

  • JUnit是一个Java语言的单元测试
  • 单元:一个方法就是一个单元
  • 测试: 测方法中的代码逻辑是否正确

作用

  • 替代main方法
    一个类只能有一个main方法 如果有N个功能要单独测试的话,需要写N个类由N个main方法进行不同的测试
    如果使用单元测试会让程序功能的测试更加简单

实现方式

  • JUnit的使用步骤
    • 1.导JUnit单元测试的jar包 (idea开发工具已经集成了junit的jar包)
    • 2.在类中要测试的方法上添加 @Test
    • 3.测试执行
  • JUnit的细节整理
    • 1.方法必须得是公共的
    • 2.返回值必须得是void
    • 3.方法不能有任何的参数
  • 常见注解
    • @Test: 单元方法测试
    • @Before:在每个测试方法之前都会运行一次
    • @After:在每个测试方法运行以后运行的方法
  • 了解注解
    • 静态方法可以使用
    • @BeforeClass
    • @AfterClass
      ps:会在 @Before之前执行 会在 @After之后执行

反射

在这里插入图片描述

概述

  • 反射是一种行为,利用该行为可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法成员

    类:
    构造方法
    成员方法
    成员变量

    一个类的执行流程:
    hello.java —编译–>hello.class —加载内存–>jvm创建了Class对象用来记录数据—>运行
    Student.java —编译–>Student.class—加载内存–>jvm创建了Class对象用来记录数据—>运行
    Person.java —编译–>Person.class—加载内存–>jvm创建了Class对象用来记录数据—>运行

    如何拿到类中的数据:
    Class(字节码对象): 接收一切类的字节码文件
    Constructor(构造器对象): 接收类中的一切构造方法
    Method(方法对象): 接收类中的一切成员方法
    Field(变量对象): 接收类中的一切成员变量

作用

  • 通过反射可以获取到每个类的字节码对象,拿到其中的构造方法,成员方法和成员变量

ps应用场景: 后期我们要学的ssm框架底层用到了很多的反射行为,为了后面能够更加理解框架,这里需要同学们对反射机制熟练化

核心实现

获取字节码对象的三种方式(面试题–重要)
在这里插入图片描述

  • 方式1:通过类名.class获取
  • 方式2:通过Object类的成员方法getClass()方法获取
  • 方式3:通过Class.forName(“全限定名”)方法获取
    ps全限定名: 就是包名 + 类名

相关API(Class, Constructor,Method,Field)

  1. Class对象相关方法

    • String getName() 获取全限定名,包含 包名+类名

    • String getSimpleName() 获得简单类名,只是类名,没有包名

    • Object newInstance() 创建此 Class 对象所表示的类的一个实例。要求:类必须有公共的无参数构造方法

在这里插入图片描述

  1. 操作构造方法(Constructor)

    • Constructor getConstructor(Class… parameterTypes)
      根据参数类型获取构造方法对象,只能获得public修饰的构造方法。

    • Constructor getDeclaredConstructor(Class… parameterTypes)
      根据参数类型获取构造方法对象,包括private修饰的构造方法。

    在这里插入图片描述

    • T newInstance(Object… initargs)
      根据构造器中的指定参数创建对象。

    • void setAccessible(true)
      暴力反射,设置为可以直接访问私有类型的构造方法
      在这里插入图片描述

    • Constructor[] getConstructors() (了解)
      获取所有的public修饰的构造方法

    • Constructor[] getDeclaredConstructors() (了解)
      获取所有构造方法,包括privat修饰的
      在这里插入图片描述

  2. 操作方法(Method)

Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法。

- Method getMethod("方法名", 方法的参数类型... 类型)
  根据方法名和参数类型获得一个方法对象,只能是获取public修饰的

- Method getDeclaredMethod("方法名", 方法的参数类型... 类型)
  根据方法名和参数类型获得一个方法对象,包括private修饰的

在这里插入图片描述

- Object invoke(Object obj, Object... args)  核心方法 
  使用反射的方式让一个方法执行 
  obj  :   要执行该方法的对象 
  args  :  方法运行过程中需要的参数

在这里插入图片描述

- void setAccessible(boolean flag)
  暴力反射,设置为true可以直接调用私有修饰的成员方法 

- Method[] getMethods() (了解)
  获取所有的public修饰的成员方法,包括父类中。

- Method[] getDeclaredMethods() (了解)
  获取当前类中所有的方法,包含私有的,不包括父类中。
  1. 操作属性(Field)

Field是属性类,类中的每一个属性(成员变量)都是Field的对象,通过Field对象可以给对应的成员变量赋值和取 值。

- Field getField(String name)
  根据属性名获得属性对象,只能获取public修饰的

- Field getDeclaredField(String name)
  根据属性名获得属性对象,包括private修饰的

- Field[] getFields()(了解)
  获取所有的public修饰的属性对象,返回数组。

- Field[] getDeclaredFields()(了解)
  获取所有的属性对象,包括private修饰的,返回数组

- getType()  (了解)
  获取字段类型

- set(字段所属的对象,要赋的值)
  给字段赋值的,如果是私有的还是要先暴力破解

Student类


package cn.itcast.b_reflect;

public class Student {

    // 公共无参的
    public Student(){

    }

    // 公共的有参构造器
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    // 私有有参构造器
    private Student(String name){
        this.name = name;
    }

    // 成员属性
    private String name;
    private Integer age;


    // 成员方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    private void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    // 公共无参的
    public String run1(){
        System.out.println("run1...");
        return "我是返回值";
    }
    // 公共有参的
    public void run2(String value){
        System.out.println("run2..."+value);
    }
    // 私有有参的
    private void run3(String value){
        System.out.println("私有run3..."+value);
    }

}

获取各种方法

package cn.itcast.b_reflect;

import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// 获取各种方法 让方法执行
public class MethodDemo {

    @Test  //获取各种方法
    public void test1() throws ClassNotFoundException, NoSuchMethodException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共的无参方法    Method getMethod("方法名", 方法的参数类型... 类型)
        // 参数1:要获取的方法名
        // 参数2: 方法参数的类型(Class类型)
        Method method1 = clazz.getMethod("getName");
        System.out.println(method1);

        System.out.println("--------------------------------------");
        // 获取公共的有参方法
        Method method2 = clazz.getMethod("setName", String.class);
        System.out.println(method2);

        // 获取私有的有参方法
        Method method3 = clazz.getDeclaredMethod("setAge", Integer.class);
        System.out.println(method3);
    }


    @Test  //让各种方法执行
    public void test2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共无参的
        Method method = clazz.getMethod("run1");  //run1
        // 让方法执行
        // 参数1:本身应该执行这个方法的对象
        // 参数2:方法运行过程中需要的传递的参数
        Student student =(Student)clazz.newInstance();
        // 方法执行可以有返回值
        String returnValue =(String)method.invoke(student);
        System.out.println(returnValue);

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

        // 获取公共有参的方法执行
        Method method2 = clazz.getMethod("run2", String.class); //run2
        method2.invoke(clazz.newInstance(),"迪丽热巴");

        System.out.println("-----------------------------------------");
        // 获取私有有参的方法执行
        Method method3 = clazz.getDeclaredMethod("run3", String.class);  //run3
        // 暴力破解
        method3.setAccessible(true);
        method3.invoke(clazz.newInstance(), "jack");
    }


    @Test//获取所有的方法
    public void test3() throws ClassNotFoundException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 所有公共方法 包含父类的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

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

        // 所有方法(公共和私有) 不包含父类的
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }
}

获取所有的属性

package cn.itcast.b_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

// 获取各种属性 给属性赋值
public class FieldDemo {

    @Test  //获取各种属性
    public void test1() throws ClassNotFoundException, NoSuchFieldException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共的字段
        // 参数:属性名
        Field nameField = clazz.getField("name");
        System.out.println(nameField);
        // 获取私有的字段
        Field ageField = clazz.getDeclaredField("age");
        System.out.println(ageField);
    }

    @Test  //各种属性赋值
    public void test2() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        Field nameField = clazz.getDeclaredField("name");
        // 暴力破解
        nameField.setAccessible(true);
        // 赋值
        // 参数一:所属的对象
        // 参数二:要赋的值
        Student o =(Student)clazz.newInstance();
        nameField.set(o,"迪丽热巴");
        Field ageField = clazz.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(o,18);
        System.out.println(o);

    }

    @Test
    public void test3() throws ClassNotFoundException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取所有公共的字段
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

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

        // 获取所有字段(公共和私有)
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
            // 获取字段类型
            System.out.println(declaredField.getType());
        }
    }

}

反射明确的点:框架

1 获取字节码对象的方式
2 如何根据字节码对象获取各种构造器让各种构造器创建对象
3 如何根据字节码对象获取各种方法让各种方法执行
4 如何根据字节码对象获取各种字段给各种字段赋值

注解

概述:

  • 在java中由一个 @+一堆英文单词组成的集合 就是注解

  • 它可以声明在类、字段、方法、局部变量、方法参数上等,用来对程序进行限制说明的

    注释:给程序员看的
    注解:给程序去看的 声明不同的注解可以让程序做不同的功能
    注解的学习明确:
    1 明确java或者框架提供的注解都有什么功能
    2 明确提供的注解能定义在哪个位置上 (类上 字段上 方法上 局部变量上)

jdk中的注解

  • @Override
    限制该方法是重写的方法
  • @Deprecated
    声明该方法不推荐使用

扩展:自定义注解(理解

  • 格式:

    • public @interface 注解名称{
      类型 属性名();

      }
      注解本质上就是一个特殊的接口
      注解中的方法叫做属性.
  • 属性:

    • 基本类型 (byte,short,int,long,float,double,boolean,char)

    • String

    • Class

    • Annotation

    • 以上类型的一维数组

      常见注解

@英文字符 底层:要不就是没属性 要不属性全部有默认值

@英文字符(属性名1=属性值1,属性名2 = 属性值2) 底层:注解设置属性 没有给默认值 需要使用的时候设置

@英文字符(“abcd”) 底层:注解的属性中只有一个 且名称叫value

  • 注意事项:
    • 注解一旦有了属性,使用注解时,必须给属性赋值

    • 注解名称如果为value,那么属性名称可以省去不写

      自定义注解小结:
      1.自定义注解格式: public @interface 注解名称{}
      2.注解可以使用在类,方法,接口,成员变量,局部变量…
      3.注解中的方法不叫方法,叫属性
      4.当注解中有属性时,使用该注解时,必须给注解中的属性赋值
      5.当只给value属性赋值时,value属性名可以省去不写

元注解

定义在注解之上的注解被称为元注解

  • @Target 定义该注解作用在什么上面 常用值为:
    • METHOD:方法
    • TYPE:类 接口
    • FIELD:字段
  • @Retention 定义该注解保留到那个代码阶段(存活时期) 值为:
    • SOURCE:注解只在源码上保留
    • CLASS:注解在源码和字节码上保留
    • RUNTIME:注解在所有的阶段都保留 (常用)

解析注解

反射机制

  • method.isAnnotationPresent(注解.class):判断方法上是否有指定的注解
  • method.getAnnotation(注解.class);获取方法上指定的注解

案例2-自定@MyTest注解,实现单元测试的功能

需求分析:
	定义一个类,在类中提供多个方法,在部分方法上添加自定义的 @MyTest 注解,让带有@MyTest的注解方法执行.
技术分析:
	自定义注解 @MyTest
步骤分析:
	1.定义@MyTest注解,声明该注解只能使用在方法上,生成注解的存活时期为运行时期
	2.定义一个类,在类中提供多个方法,在部分方法上添加MyTest注解
	3.让带有@MyTest的方法执行

================================================

// 获取类的Class字节码对象 (3种方式)
public class ClassDemo {

    @Test  //获取类的Class字节码对象方式一  类名.class
    public void test1(){
        Class aaa=Student.class;
        System.out.println(aaa);
    }

    @Test  //获取类的Class字节码对象方式二  当前类对象的getClass方法
    public void test2(){
        /*Class bbb = new Student().getClass();
        System.out.println(bbb);*/
    }

    @Test //获取类的Class字节码对象方式三   Class.forName(全限定名)
         // 全限定名==包名+类名==cn.itcast.b_reflect.Student
    public void test3() throws ClassNotFoundException {
        Class ccc = Class.forName("cn.itcast.b_reflect.Student");
        System.out.println(ccc);
    }

    // 关于Class的一些自身方法
    @Test
    public void test4() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 获取类的全限定名
        Class clazz = Class.forName("cn.itcast.b_reflect.Student");
        String className = clazz.getName();
        System.out.println(className);
        // 获取类的简单名字
        String simpleName = clazz.getSimpleName();
        System.out.println(simpleName);
        System.out.println("-------------------------");
        // 不获取构造器的方式创建该类的对象
        //  底层找的还是无参构造器来创建对象的
        //  局限性:如果该类没有无参构造器 该方法作废 还是得获取构造器来创建对象
        Student student =(Student)clazz.newInstance();
        System.out.println(student);
    }

==================================================

 // 最终目标:获取各种构造器 创建对象
public class ConstructorDemo {

    @Test  //获取各种构造器
    public void test1() throws ClassNotFoundException, NoSuchMethodException {

        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共无参的构造器--不写参数获取无参的构造器  getConstructor:获取的是公共的
        Constructor constructor1 = clazz.getConstructor();
        System.out.println(constructor1);
        System.out.println("---------------------------------------");
        // 获取公共有参的构造器--写参数  getConstructor:获取的是公共的
        Constructor constructor2 = clazz.getConstructor(String.class, Integer.class);
        System.out.println(constructor2);
        System.out.println("---------------------------------------");
        // 获取私有有参的构造器 --写参数  getDeclaredConstructor:获取公共的和私有的都可以
        Constructor constructor3 = clazz.getDeclaredConstructor(String.class);
        System.out.println(constructor3);
    }

    @Test  //根据各种构造器创建对象
    public void test2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 公共无参的构造器创建对象  简写:clazz.newInstance()
        Constructor constructor = clazz.getConstructor();
        Student student =(Student)constructor.newInstance();
        System.out.println(student);
        // 公共有参的构造器创建对象
        Constructor constructor1 = clazz.getConstructor(String.class, Integer.class);
        Student student2 =(Student)constructor1.newInstance("迪丽热巴", 18);
        System.out.println(student2);
        // 私有有参的构造器创建对象
        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
        // 暴力破解私有构造器
        declaredConstructor.setAccessible(true);

        Student student3 =(Student)declaredConstructor.newInstance("迪丽热巴");
        System.out.println(student3);
    }


    @Test  //获取所有构造器
    public void test3() throws ClassNotFoundException {
        // 获取所有的公共构造器
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("-------------------------------");
        // 获取所有的构造器(公共的+私有的)
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

    }

==================================================

// 获取各种方法 让方法执行
public class MethodDemo {

    @Test  //获取各种方法
    public void test1() throws ClassNotFoundException, NoSuchMethodException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共的无参方法    Method getMethod("方法名", 方法的参数类型... 类型)
        // 参数1:要获取的方法名
        // 参数2: 方法参数的类型(Class类型)
        Method method1 = clazz.getMethod("getName");
        System.out.println(method1);

        System.out.println("--------------------------------------");
        // 获取公共的有参方法
        Method method2 = clazz.getMethod("setName", String.class);
        System.out.println(method2);

        // 获取私有的有参方法
        Method method3 = clazz.getDeclaredMethod("setAge", Integer.class);
        System.out.println(method3);
    }


    @Test  //让各种方法执行
    public void test2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 获取公共无参的
        Method method = clazz.getMethod("run1");  //run1
        // 让方法执行
        // 参数1:本身应该执行这个方法的对象
        // 参数2:方法运行过程中需要的传递的参数
        Student student =(Student)clazz.newInstance();
        // 方法执行可以有返回值
        String returnValue =(String)method.invoke(student);
        System.out.println(returnValue);

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

        // 获取公共有参的方法执行
        Method method2 = clazz.getMethod("run2", String.class); //run2
        method2.invoke(clazz.newInstance(),"迪丽热巴");

        System.out.println("-----------------------------------------");
        // 获取私有有参的方法执行
        Method method3 = clazz.getDeclaredMethod("run3", String.class);  //run3
        // 暴力破解
        method3.setAccessible(true);
        method3.invoke(clazz.newInstance(), "jack");
    }


    @Test//获取所有的方法
    public void test3() throws ClassNotFoundException {
        Class clazz=Class.forName("cn.itcast.b_reflect.Student");
        // 所有公共方法 包含父类的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

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

        // 所有方法(公共和私有) 不包含父类的
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }
}

==================================================
// 获取各种属性 给属性赋值
public class FieldDemo {

@Test  //获取各种属性
public void test1() throws ClassNotFoundException, NoSuchFieldException {
    Class clazz=Class.forName("cn.itcast.b_reflect.Student");
    // 获取公共的字段
    // 参数:属性名
    Field nameField = clazz.getField("name");
    System.out.println(nameField);
    // 获取私有的字段
    Field ageField = clazz.getDeclaredField("age");
    System.out.println(ageField);
}

@Test  //各种属性赋值
public void test2() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
    Class clazz=Class.forName("cn.itcast.b_reflect.Student");
    Field nameField = clazz.getDeclaredField("name");
    // 暴力破解
    nameField.setAccessible(true);
    // 赋值
    // 参数一:所属的对象
    // 参数二:要赋的值
    Student o =(Student)clazz.newInstance();
    nameField.set(o,"迪丽热巴");
    Field ageField = clazz.getDeclaredField("age");
    ageField.setAccessible(true);
    ageField.set(o,18);
    System.out.println(o);

}

@Test
public void test3() throws ClassNotFoundException {
    Class clazz=Class.forName("cn.itcast.b_reflect.Student");
    // 获取所有公共的字段
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
        System.out.println(field);
    }

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

    // 获取所有字段(公共和私有)
    Field[] declaredFields = clazz.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField);
        // 获取字段类型
        System.out.println(declaredField.getType());
    }
}

==================================================
public class Student {

// 公共无参的
public Student(){

}

// 公共的有参构造器
public Student(String name, Integer age) {
    this.name = name;
    this.age = age;
}

// 私有有参构造器
private Student(String name){
    this.name = name;
}

// 成员属性
private String name;
private Integer age;


// 成员方法
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

private void setAge(Integer age) {
    this.age = age;
}

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}


// 公共无参的
public String run1(){
    System.out.println("run1...");
    return "我是返回值";
}
// 公共有参的
public void run2(String value){
    System.out.println("run2..."+value);
}
// 私有有参的
private void run3(String value){
    System.out.println("私有run3..."+value);
}

}

==================================================

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值