反射和注解

1.1 类加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。如果不出意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化。

类的加载:

  • 就是指将class文件读入内存,并为之创建一个java.lang.Class对象
  • 任何类被使用时,系统都会为之建立一个java.lang.Class对象

类的连接:

  • 验证阶段:用于检验被加载的类是否具有正确的内部结构,并和其他类协调一致
  • 准备阶段:负责为类的类变量分配内存,并设置默认初始化值
  • 解析阶段:将类的二进制数据中的符号引用替换为直接引用

类的初始化:

  • 在该阶段,主要就是对类变量进行初始化

类的初始化步骤

  • 假如类还未被加载和连接,则程序先加载并连接该类
  • 假如该类的直接父类还未被初始化,则先初始化其直接父类
  • 假如类中有初始化语句,则系统一次执行这些初始化语句

注意:在执行第二个步骤时,系统对直接父类的初始化步骤也遵循初始化步骤1-3

类的初始化时机:

  • 创建类的实例
  • 调用类的类方法
  • 访问类或者接口的类变量,或者为该类变量赋值
  • 使用反射方式来强制创建每个类或者接口对应的java.lang.Class对象
  • 初始化每个类的子类
  • 直接使用java.exe命令来运行某个主类

1.2 类加载器

类加载器的作用:负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象

虽然我们不用过分关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

JVM的类加载机制

  • 全盘负责:就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个加载器来载入
  • 父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
  • 缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区

ClassLoader:负责加载类的对象

  • Java运行时具有以下内置类加载器:
  • Bootstrap class loader: 它是虚拟机的内置类加载器,通常表示为 null ,并且没有父级。
  • Platform class loader: 平台类加载器可以看到所有 平台类 ,它们可以用作 ClassLoader实例的父 ClassLoader 。 平台类包括Java SE平台API,它们的实现类以及特定于JDK的运行时类。
  • System class loader:它也称为 应用程序类加载器 ,与平台类加载器不同。 系统类加载器通常用于在应用程序类路径,模块路径和JDK特定工具上定义类。 *平台类加载器是系统类加载器的父级或祖先,内置类加载器时平台类加载器的父级或祖先

  • ClassLoader中的两个方法

  • static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
  • ClassLoader getParent():返回父类加载器进行委派
package com.Study;

/**
 * @ClassName ClassLoaderDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 16:17
 * @Version 1.0
 */
public class ClassLoaderDemo {
    public static void main(String[] args) {
        //static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
        ClassLoader scl = ClassLoader.getSystemClassLoader();
        System.out.println(scl);//AppClassLoader

        //ClassLoader getParent():返回父类加载器进行委派
        ClassLoader p = scl.getParent();
        System.out.println(p);//PlatformClassLoader

        ClassLoader p1 = p.getParent();
        System.out.println(p1);//null
    }
}

2.1 反射描述

Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译器就完成确定,在运行期仍然可以扩展

2.2 获取Class类的对象

我们想要通过反射去使用一个类,首先我们要获取到类的字节码文件对象,也就是类型为Class类型的对象

这里我们提供三种方式获取Class类型的对象

  • 使用类的class属性来获取该类对应的Class对象。举例:Student.class将会返回Student类对应的Class对象
  • 调用对象的getClass()方法,返回该对象所属类对应的Class对象 ​ 该方法时Object类中的方法,所有的Java对象都可调用该方法
  • 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
package com.Study02;

/**
 * @ClassName RefelectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 16:33
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //使用类的class属性来获取该类对应的Class对象
        Class c1 = Student.class;//最简易
        System.out.println(c1);

        Class c2 = Student.class;
        System.out.println(c1.equals(c2));
        System.out.println("---------------");

        //调用对象的getClass()方法,返回该对象所属类对应的Class对象
        Student s=new Student();
        Class c3 = s.getClass();
        System.out.println(c1.equals(c3));
        System.out.println("---------------");

        //使用Class类中的静态方法
        Class c4 = Class.forName("com.Study02.Student");//最常用
        System.out.println(c1.equals(c4));

    }
}

package com.Study02;

/**
 * @ClassName Student
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 16:33
 * @Version 1.0
 */
public class Student {
    //三个成员变量:一个私有、一个默认、一个公共
    private String name;
    int age;
    public String address;

    //构造方法:一个私有、一个默认、一个公共
    public Student() {
    }

    private Student(String name) {
        this.name = name;
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    //成员方法:一个私有,四个公共
    private void function() {
        System.out.println("function");
    }

    public void method1() {
        System.out.println("method");
    }

    public void method2(String s) {
        System.out.println("method:" + s);
    }

    public String method3(String s, int i) {
        return s + ',' + i;
    }

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

2.3 反射获取构造方法并使用

package com.Study03;

import com.Study02.Student;
import com.sun.security.jgss.GSSUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 16:50
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取Class对象
        Class c = Class.forName("com.Study02.Student");//得到了该类的字节码文件c
        // getConstructors() 返回一个包含Constructor构造器对象的数组,Constructor构造器对象反映了此Class对象所表示的类的所有公共构造函数。
        Constructor[] cons = c.getConstructors();//所有的公共构造方法的数组
        for(Constructor con:cons){
            System.out.println(con);
        }
        System.out.println("---------------");

        //getDeclaredConstructors() 返回一个反映由该Class对象表示的类声明的所有构造函数的Constructor对象的数组
        Constructor[] cons1 = c.getDeclaredConstructors();//所有构造方法的数组
        for (Constructor con:cons1){
            System.out.println(con);
        }
        System.out.println("---------------");

        //getConstructor(类... parameterTypes) 返回一个Constructor对象,该对象反映由Class对象表示的类的指定的公共构造函数
        //getDeclaredConstructor(类... parameterTypes) 返回一个Constructor对象,该对象反映由此Class对象表示的类或接口的指定构造函数。
        //参数表示的意思是:你要获取的构造方法的参数个数和数据类型对应的字节码文件对象
        Constructor con = c.getConstructor();//通过c获取单个无参构造方法对象con
//        Student s=new Student();
//        System.out.println(s);
        //Constructor提供了一个类的单个构造函数的信息和访问权限
        //T newInstance(Object... initargs) 使用此Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
        Object obj = con.newInstance();//通过无参构造方法对象con的newInstance()创建了一个对象
        System.out.println(obj);
    }
}

Class类中用于获取构造方法的方法

  • Constructor<?>[] getConstructors():返回所有的公共构造方法对象的数组
  • Constructor<?>[] getDeclaredConstructors():返回所有的构造方法对象的数组
  • Constructor<t>[] getConstructor(Class<?>... parameterTypes)</t>:返回单个公共构造方法对象
  • Constructor<t>[]getDeclaredConstructor(Class<?>... parameterTypes)</t>:返回单个构造方法对象

Constructor类中用于创建对象的方法

  • T newInstance(Object... initargs):根据指定的构造方法创建对象

2.4 反射获取构造方法并使用练习

练习一

通过反射实现如下操作

  • Student s=new Student(“王昭君”,25,”西安”);
  • System.out.println(s);
package com.Study04;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 17:22
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class c = Class.forName("com.Study02.Student");

        //public Student(String name, int age, String address)
        Constructor con = c.getConstructor(String.class, int.class, String.class);
        //基本数据类型也可以通过.class得到对应的Class类型

        Object obj = con.newInstance("王昭君", 25, "西安");
        System.out.println(obj);
    }
}

基本数据类型也可以通过.class得到对应的Class类型

练习二

  • Student s=new Student(“王昭君”);
  • System.out.println(s);
package com.Study05;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/10 22:13
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class c = Class.forName("com.Study02.Student");

        //private Student(String name)
        Constructor con = c.getDeclaredConstructor(String.class);

        //私有构造方法这里无法创建对象
        //使用暴力反射方式:
        //public void setAccessible(boolean flag):值为true,取消访问检查
        con.setAccessible(true);
        //此时就可创建对象了

        Object obj = con.newInstance("王昭君");//java.lang.IllegalAccessException
        System.out.println(obj);

    }
}

当构造方法为私有时,无法创建对象

使用暴力反射方式: public void setAccessible(boolean flag):当值为true时,取消访问检查

此时就可创建对象了

2.5 反射获取成员变量并使用

Class类中获取成员变量的方法:

  • Field[] getFields():返回所有公共成员变量对象的数组
  • Field[] getDeclaredFields():返回所有成员变量对象的数组
  • Field getField(String name):返回单个公共成员变量对象
  • Field getDeclaredField(String name):返回单个成员变量对象

成员变量的使用:

  • 获取Class对象
  • 获取Field字段
  • 获取构造方法创建对象
  • *使用Field类中方法 set(Object obj,Object value) 给obj对象的成员变量赋值为value
package com.Study06;

import com.Study02.Student;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/11 12:33
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取Class对象
        Class c = Class.forName("com.Study02.Student");
        //getFields() 返回一个包含Field字段对象的数组,Field字段对象反映此Class类对象所表示的类或接口的所有可访问公共字段。
        //getDeclaredFields() 返回Field字段对象的数组,反映由此Class类对象表示的类或接口声明的所有字段。
        Field[] f = c.getFields();
        for (Field field:f){
            System.out.println(field);
        }
        System.out.println("--------------");
        Field[] f2 = c.getDeclaredFields();
        for (Field field1:f2){
            System.out.println(field1);
        }
        System.out.println("--------------");

//        Student s=new Student();
//        s.address="西安";
        //getField(String name) 返回Field字段对象,该对象反映此Class类对象表示的类或接口的指定公共成员字段。
        //getDeclaredField(String name) 返回Field字段对象,该对象反映此Class类对象表示的类或接口的指定声明字段。
        Field addressField = c.getField("address");
        //获取无参构造方法创建对象
        Constructor con = c.getConstructor();
        Object obj = con.newInstance();

        //void set(Object obj, Object value) 将指定对象参数上此Field字段对象表示的字段设置为指定的新值。
        addressField.set(obj,"西安");//给obj的成员变量addressField赋值为"西安"
        System.out.println(obj);
    }
}

2.6 反射获取成员变量并使用练习

通过反射实现如下操作:

  • Student s=new Student();
  • s.name=”王昭君”;
  • s.age=25;
  • s.address=”西安”;
  • System.out.println(s);
package com.Study07;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/11 12:56
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取Class对象
        Class c = Class.forName("com.Study02.Student");

        Field addressField = c.getField("address");
        Field nameField = c.getDeclaredField("name");
        Field ageField = c.getDeclaredField("age");
        nameField.setAccessible(true);
        ageField.setAccessible(true);

        Constructor con = c.getConstructor();

        Object obj = con.newInstance();

        nameField.set(obj,"王昭君");
        ageField.set(obj,25);
        addressField.set(obj,"西安");

        System.out.println(obj);

    }
}

2.7 反射获取成员方法并使用

Class类中用于获取成员方法的方法:

  • Method getMethods():返回所有公共成员方法对象的数组,包括继承的
  • Method getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
  • Method getMethod(String name,Class<?>...paraneterTypes):返回单个公共成员方法对象
  • Method getDeclaredMethod(String name,Class<?>...paraneterTypes):返回单个成员方法对象

成员方法的使用:

  • 获取Class对象
  • 获取成员方法
  • 获取构造方法创建对象
  • *使用Method类中的方法 Object invoke(Object obj, Object... args) 调用成员方法
package com.Study08;

import com.Study02.Student;

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

/**
 * @ClassName ReflectDemo
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/11 13:09
 * @Version 1.0
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class c = Class.forName("com.Study02.Student");

        // getMethods() 返回一个包含方法对象的数组,方法对象反映此Class类对象所表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超接口继承的类
        // getDeclaredMethods() 返回一个包含方法对象的数组,方法对象反映此Class类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。
        Method[] ms = c.getDeclaredMethods();
        for (Method method:ms){
            System.out.println(ms);
        }
        System.out.println("-----------");
//        Method[] ms2 = c.getDeclaredMethods();
//        for (Method method:ms2){
//            System.out.println(ms2);
//        }

        //Method getMethod(String name, 类... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法。
        //Method getDeclaredMethod(String name, 类... parameterTypes)返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 类对象。
        //public void method1()
        Method m = c.getMethod("method1");
//        Student s=new Student();
//        s.method1();
        //获取无参构造对象
        Constructor con = c.getConstructor();

        Object obj = con.newInstance();

        //Method提供有关类和接口上单一方法的信息和访问权限
        //Object invoke(Object obj, Object... args) 在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
        //Object:返回值类型 obj:调用方法的对象 args:方法需要的参数
        m.invoke(obj);

        //public void method2(String s) {
        //        System.out.println("method:" + s);
        //    }
        Method m2 = c.getMethod("method2", String.class);

        m2.invoke(obj,"sss");

        //public String method3(String s, int i) {
        //        return s + ',' + i;
        //    }
        Method m3 = c.getDeclaredMethod("method3", String.class, int.class);
        Object d = m3.invoke(obj, "ddd", 2);
        System.out.println(d);

        //private void function() {
        //        System.out.println("function");
        //    }
        Method f = c.getDeclaredMethod("function");
        f.setAccessible(true);
        f.invoke(obj);

    }
}

2.8 反射练习

练习一

有一个 ArrayList<integer></integer>集合,在这个集合中添加一个字符串数据

package com.Test01;

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

/**
 * @ClassName ReflectTest
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/12 18:32
 * @Version 1.0
 */
public class ReflectTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList arrayList=new ArrayList<>();
//        arrayList.add(10);
//        arrayList.add(20);

        Class c = arrayList.getClass();
        Method m = c.getMethod("add", Object.class);
        m.invoke(arrayList,"Hello");
        m.invoke(arrayList,"Java");
        m.invoke(arrayList,"World");
        System.out.println(arrayList);
    }
}

反射可以越过泛型检查获取到原始方法所需要的参数类型

练习二

通过配置文件运行类中的方法

package com.Test02;

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @ClassName ReflectTest
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/12 18:42
 * @Version 1.0
 */
public class ReflectTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        Student s=new Student();
//        s.study();
//        Teacher t=new Teacher();
//        t.teach();
        /*
        * class.txt
        * className=xxx
        * methodName=xxx
        * */
        //加载数据
        Properties prop=new Properties();
        //对象序列化流
        FileReader fr=new FileReader("myReflect\\src\\com\\Test02\\class.txt");
        prop.load(fr);
        fr.close();
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");
        //通过反射使用
        Class c = Class.forName(className);
        Constructor con = c.getConstructor();
        Object obj = con.newInstance();
        Method m = c.getMethod(methodName);//Study
        m.invoke(obj);
    }
}

关于Properties的介绍:

  • 是一个Map体系的集合类
  • Properties可以保存到流中或从流中加载
public class PropertiesDemo {
    public static void main(String[] args) {
        Properties prop=new Properties();

        prop.put("Class","Student");
        prop.put("Method","study");
        prop.put("Method1","play");

        Set KeySet = prop.keySet();

        for (Object key: KeySet){
            Object value = prop.get(key);
            System.out.println(key+","+value);
        }
    }
}

Properties作为集合的特有方法

方法名 说明

设置集合的键和值,都是String类型,底层调用Hashtable方法put

使用此属性列表中指定的键搜索属性

从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

3.1 注解概述

注解:Annotation

  • Annotation是JDK5.0引入的新技术
  • Annotation作用:
  • 不是程序本身,可以对程序做出解释(这一点和comment注释没区别)
  • 可以被其他程序(如编译器等)读取
  • Annotation格式:
  • 注解是以”@注释名”在代码中存在的,还可以添加一些参数值,例如: @SuppressWarnings(value=”unchecked”)
  • Annotation用处:
  • 可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问

3.2 内置注解

  • @Override:定义在 java.lang.Override中,此注解只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法的声明
  • @Deprecated:定义在java.lang.Deprecated中,此注解可以用于修饰方法、属性、类,表示不鼓励程序员使用,通常是因为它很危险或者存在更好的选择
  • @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
  • 与前两个注解有所不同,你需要添加一个参数才能正确使用,这些参数都是定义好了的,只需要我们选择性使用
    • @SuppressWarnings(“all”)
    • @SuppressWarnings(“unchecked”)
    • @SuppressWarnings(value={“unchecked”,”deprecation”})

3.3 元注解

  • 元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
  • 这些类型和他们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited)
  • @Target:用于描述注解的使用范围(即被描述的注解可以用在什么地方)
  • @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE

3.4 自定义注解

  • 使用 @interface自定义注解,自动继承了java.lang.annotation.Annotation接口
  • @interface用来声明一个注释,格式: public @interface &#x6CE8;&#x89E3;&#x540D;{&#x5B9A;&#x4E49;&#x5185;&#x5BB9;}
  • 其中每一个方法实际上是声明了一个配置参数
  • 方法的名称就是参数的名称
  • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
  • 可以通过default来声明参数的默认值
  • 如果只有一个参数成员,一般参数名为calue
  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
public class AnnotationDemo {
    @myAnnotation(/*name="hello"*/)
    public void testMethod(){}

    @myAnnotation1("省略value")
    public void testMethods(){}
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation{
    //注解的参数:参数类型+参数名()
    String name() default "";//如果没有默认值,在使用注解时必须为注解赋值
    int age() default 0;
    int id() default -1;//如果默认值为-1,代表不存在
    String[] companies() default {"阿里巴巴","Tencent","字节跳动"};
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface  myAnnotation1{
    String value();//如果参数名为value,在赋值时可以不写value=xxx
}

4.1 测试分类

  • 黑盒测试:不需要写代码,给输入值,看程序能否输出期望值
  • 白盒测试:需要写代码。关注程序具体的执行流程

4.2 Junit的使用步骤

  • 定义一个测试类(测试用例)
  • 建议:
    • 测试类名:被测试的类后加Test CalculatorTest
    • 包名:xxx.xxx.xxx.test com.myJunit.test
  • 定义测试方法:可以独立运行
  • 建议:
    • 方法名:test测试的方法名 testAdd()
    • 返回值:void
    • 参数列表建议空参
  • 给方法加注解@Test
  • 导入Junit的依赖环境
package com.test;

import com.myJunit.Calculator;
import org.junit.Assert;
import org.junit.Test;

/**
 * @ClassName CalculatorTest
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/16 23:38
 * @Version 1.0
 */
public class CalculatorTest {
    //测试add方法
    @Test
    public void testAdd() {
        //System.out.println("我被执行了");
        Calculator c = new Calculator();

        int result = c.add(1, 2);
//        System.out.println(result);
        //如果add方法中改为-,虽然运行成功,但是与实际不符,因此在Test中使用断言进行测试
        //断言:断言结果为3
        Assert.assertEquals(3, result);
    }

    //测试sub方法
    @Test
    public void testSub(){
        Calculator c = new Calculator();
        int result =c.sub(3,2);
        Assert.assertEquals(1,result);
    }
}

4.3 Junit结果判定

  • 红色:失败
  • 绿色:成功
  • 一般我们使用断言操作来处理结果 Assert.assertEquals(3,result);

4.4 @Before和@After

补充:

  • @Before:修饰的方法会在测试方法之前自动被执行
  • @After:修饰的方法会在测试方法之后自动被执行
package com.test;

import com.myJunit.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @ClassName CalculatorTest
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/16 23:38
 * @Version 1.0
 */
public class CalculatorTest {
    //初始化方法
    //用于资源申请,所有测试方法在执行之前都会执行该方法
    @Before
    public void init(){
        System.out.println("init...");
    }

    //释放资源方法
    //在所有测试方法执行完后,都会自动执行该方法
    @After
    public void close(){
        System.out.println("close...");
    }

    //测试sub方法
    @Test
    public void testSub(){
        Calculator c = new Calculator();
        int result =c.sub(3,2);
        System.out.println("testSub...");
        Assert.assertEquals(1,result);
    }
}

init...

testSub...

close...

Original: https://www.cnblogs.com/hackertyper/p/16472226.html
Author: 风吹头蛋凉OvO
Title: 反射和注解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/575124/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 最长上升子序列

    给定一个长度为 (N) 的数列(A),求数值严格单调递增的子序列的长度最长是多少。 第一行包含整数 (N)。 第二行包含 (N) 个整数,表示完整序列。 输出一个整数,表示最大长度…

    Java 2023年6月7日
    078
  • Mybatis系列全解(六):Mybatis最硬核的API你知道几个?

    封面:洛小汐作者:潘潘 2020 年的大疫情,把世界撕成几片。 时至今日,依旧人心惶惶。 很庆幸,身处这安稳国, 兼得一份安稳工。 · 东家常讲的一个词: 深秋心态 。 大势时,不…

    Java 2023年6月13日
    055
  • nginx rewrite基本用法

    rewrite支持使用 if,set,正则,文件和目录判断 正则表达式匹配: 符号 说明 = 等值的比较 ~ 与指定正则表达式模式匹配,区分字符大小写 ~* 与指定正则表达式模式匹…

    Java 2023年5月30日
    078
  • js简单实现拦截访问指定网页

    最近闲的无事,写个脚本玩玩,实现拦截访问指定网址 要想实现这个功能,就要自定义一个浏览器插件 最简单的浏览器插件有两个文件,分别是 manifest.json和 **.js。首先新…

    Java 2023年6月8日
    0100
  • Sharepoint 高级筛选

    先看看效果吧………….. 默认情况下:不做任何筛选. 添加一个筛选条件: 条件:如果是int类型那么可以有> < = 等…

    Java 2023年6月7日
    0110
  • Java面向对象基础

    变量与局部变量的区别: 定义的位置不同 局部变量:定义的位置是在方法内部或者是方法构造中成员变量:成员变量定义在class里面方法外面默认值 局部变量:无默认值成员变量:字面值与数…

    Java 2023年6月5日
    054
  • maven插件实现项目一键“run maven、debug maven”等命令 => 插件名:“maven helper”

    插件名:”maven helper” 1、在IDEA中下载插件 2、使用 总结:通过 “maven helper” 插件即可通过命令…

    Java 2023年6月9日
    088
  • 二十一、XML

    二十一、XML 21.1 XML介绍 21.1.1 一个问题引入 XML 思考:前面的反射可以加载配置文件里的信息,获取类的字节码对象从而动态创建对象和调用方法,但是如果需要创建多…

    Java 2023年6月5日
    076
  • Vue学习之——–深入理解Vuex、原理详解、实战应用(2022/9/1)

    @ 1.概念 2.何时使用? 3.搭建vuex环境 3.1 创建文件: src/store/index.js 3.2 在 main.js中创建vm时传入 store配置项 4.基本…

    Java 2023年6月14日
    0115
  • Java实现按行读取大文件

    非频繁操作如下: String file = "F:" + File.separator + "a.txt"; FileInputStrea…

    Java 2023年5月29日
    079
  • WPF 对Border 边框进行投影

    画一个 Border 对边框进行投影 <Window x:Class="WpfApp1.MainWindow" xmlns="http://sc…

    Java 2023年6月14日
    081
  • 动态代理

    动态代理。 讲到动态代理,就有对应的静态代理 静态代理的实现,方式1 继承目标类,生成一个子类。代理类和目标类是父子的关系。 然后在子类中进行逻辑的扩展,完成了静态代理。 方式2 …

    Java 2023年6月5日
    085
  • 三万字+八十图,详解Redis五十二问!太全面了

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis——不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的…

    Java 2023年6月5日
    091
  • 分享一下 Idea 的 scope 功能

    分享一下 Idea 的 scope 功能 事情的起因是我在使用 idea 的 call hierarchy功能时,觉得它没有像 find usage那样有排除功能,并且如果点击了 …

    Java 2023年6月5日
    075
  • springboot系列十三、springboot集成swaggerUI

    一、Swagger介绍 Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因: Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速…

    Java 2023年5月30日
    083
  • Spring Security OAuth正式终止维护,已从官网下架

    Spring Security团队正式宣布 Spring Security OAuth终止维护。 目前官网的主页已经高亮提醒彻底停止维护。 旧的 Spring Security O…

    Java 2023年5月30日
    087
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球