Java中的单元测试,反射和枚举

知识模块
一.Junit单元测试
二.反射
三.枚举





一.Junit单元测试
   a.概述
     Junit是一种Java写的单元测试框架,专门用来测试Java程序,它可以取代main方法
   b.Junit环境搭建
     由于Junit使用的类不属于我们JDK的类库,需要引入第三方jar包才能使用
   c.Junit使用
     /*
     Junit单元测试使用
       我们测试方法只需要在方法上添加一个注解 @Test
       1.我们在不同的方法上加上@Test,每个方法都可以独立运行
       2.如果在类上运行,那么会测试该类的所有方法,如果有一个方法测试失败,那么该类就测试失败
         各个方法 独立测试,相互不影响
      */

import org.junit.Test;

/*
Junit单元测试使用
  我们测试方法只需要在方法上添加一个注解 @Test
  1.我们在不同的方法上加上@Test,每个方法都可以独立运行
  2.如果在类上运行,那么会测试该类的所有方法,如果有一个方法测试失败,那么该类就测试失败
    各个方法 独立测试,相互不影响
 */
public class JunitDemo01 {
    /* public static void main(String[] args) {
         int[] arr = {3, 5, 7,};
         for (int i : arr) {
             System.out.println(i);
         }*/
    @Test
    public void method01() {
        int[] arr = {3, 5, 7,};
        for (int i : arr) {
            System.out.println(i);
        }
    }

    @Test
    public void method02() {
        System.out.println(1 / 0);
    }

    @Test
    public void method03() {
        int[] arr = {3, 7, 5,};
        int sum=0;
        for (int i : arr) {
            sum += i;
        }
        System.out.println(sum);
    }
}
   d.Junit注意事项
       /*
       Junit注意事项:
         @Test 只能用在基于一下模板定义的方法
           public void 方法名(){

           }
           1.权限修饰符必须是public
           2.返回值类型必须为void
           3.形参列表必须为空
           4.该方法不能是静态方法
        */

import org.junit.Test;

/*
Junit注意事项:
  @Test 只能用在基于一下模板定义的方法
    public void 方法名(){

    }
    1.权限修饰符必须是public
    2.返回值类型必须为void
    3.形参列表必须为空
    4.该方法不能是静态方法
 */
public class JunitDemo02 {
    @Test
    private void method01() {
        System.out.println("私有方法");
    }

    @Test
    public int method02() {
        return 3;
    }
    @Test
    public void method03(int i) {
        System.out.println(i);
    }
    @Test
    private static void method04() {
        System.out.println("私有方法");
    }

}
        /*
        调用非public void method(){}的方法
         解决方案:
             先定义一个可以使用2Test注解方法,然后去调用不能使用@Test注解方法来达到测试目的
         */

import org.junit.Test;

/*
调用非public void method(){}的方法
 解决方案:
     先定义一个可以使用2Test注解方法,然后去调用不能使用@Test注解方法来达到测试目的
 */
public class JunitDemo03 {

    @Test
    public void testMethod01() {
        //System.out.println("abc");
        method01();
        System.out.println(method02());
    }

    @Test
    public void testMethod02() {
        method03(15);
    }

    @Test
    public void testMethod03() {
        JunitDemo03.method04();
        method04();
    }

    private void method01() {
        System.out.println("私有方法");
    }


    public int method02() {
        return 3;
    }

    public void method03(int i) {
        System.out.println(i);
    }

    private static void method04() {
        System.out.println("静态方法");
    }
}
二.反射
   a.字节码对象
      当JVM用到一个类的时候,会把这个类加载到内存中,首先在方法区存放类的定义信息
      还要再堆内存中创建一个字节码对象和类文件(字节码文件)一一对应
   b.class类
      参见图解
   c.反射(reflect)概述
      反射其实就是解剖一个类,获取类中的各项信息(构造方法,成员变量,成员方法)
        类比:
            法医解剖人的尸体,人体内有很多器官(心肝脾肺肾),法医获取这些器官
            程序员解剖一个类,类中有构造方法信息,成员变量信息,成员方法信息,程序员获取这些信息

   d.获取字节码对象三种方式
       /*
       反射第一步获取字节码对象,因为只有获取到字节码对象,才能进一步获取类中的信息
        三种方式:
          1.类名.class 代表一个字节码对象
          2.通过Class类的方法,所以字节码对象都是Class类的实例
              static Class<?> forName(String className)
                 返回与带有给定字符串名的类或接口相关联的 Class 对象。
          3.通过Object类中的getClass()方法获取该类的字节码对象
               Class<?> getClass()
                 返回此 Object 的运行时类。
          无论采用哪种方式获取该类的字节码对象,都是获取了同一个字节码对象
        */


/*
解剖Person类
 */
public class Person {
   public String name;
    int age=13;

    public Person() {
    }

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

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

    public void sleep() {
        System.out.println("只有睡得好,精神才能好");
    }

    public String eat(String food) {
        System.out.println("人吃" + food);
        return food;
    }

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

import org.junit.Test;

/*
反射第一步获取字节码对象,因为只有获取到字节码对象,才能进一步获取类中的信息
 三种方式:
   1.类名.class 代表一个字节码对象
   2.通过Class类的方法,所以字节码对象都是Class类的实例
       static Class<?> forName(String className)
          返回与带有给定字符串名的类或接口相关联的 Class 对象。
   3.通过Object类中的getClass()方法获取该类的字节码对象
        Class<?> getClass()
          返回此 Object 的运行时类。
   无论采用哪种方式获取该类的字节码对象,都是获取了同一个字节码对象
 */
public class ReflectDemo01 {
    @Test
    public void testMethod01() {
        System.out.println(Person.class);//class reflect01.Person
    }

    @Test
    public void testMethod02() throws ClassNotFoundException {
        /*Class p = Class.forName("Perosn");
        System.out.println(p);*/
        Class p = Class.forName("reflect01.Person");
        System.out.println(p);//class reflect01.Person
    }

    @Test
    public void testMethod03() {
        Person p = new Person();
        System.out.println(p.getClass());//class reflect01.Person
    }

    @Test
    public void testMethod() throws ClassNotFoundException {
        Class p1 = Person.class;
        Class p2 = Class.forName("reflect01.Person");
        Class p3 = new Person().getClass();
        System.out.println(p1 == p2);//true
        System.out.println(p2 == p3);//true
        System.out.println(p1 == p3);//true
    }
}
   e.反射构造方法
         /*
         反射(解剖出)构造方法
         Class<T>:T代表字节码对象所表示得类
         基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
         只需要将基本类型后面加上.class就表示Class的实例

         Class类中的成员方法
             Constructor<T> getConstructor(Class<?>... parameterTypes)
                   返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公有(public)构造方法。
                   <T>:T代表字节码对象所表示得类

             Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
                   获取类中声明的任意一个构造方法

              T newInstance()
                   只能利用该类的空参构造对象,不能利用有参创建对象

         Constructor类中的方法
                String getName()
                   以字符串形式返回此构造方法的名称。

                T newInstance(Object... initargs)
                   使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

          */


import org.junit.Test;
import reflect01.Person;

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

/*
反射(解剖出)构造方法
Class<T>:T代表字节码对象所表示得类
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
只需要将基本类型后面加上.class就表示Class的实例

Class类中的成员方法
    Constructor<T> getConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公有(public)构造方法。
          <T>:T代表字节码对象所表示得类

    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
          获取类中声明的任意一个构造方法

     T newInstance()
          只能利用该类的空参构造对象,不能利用有参创建对象

Constructor类中的方法
       String getName()
          以字符串形式返回此构造方法的名称。

       T newInstance(Object... initargs)
          使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

 */
public class ReflectDemo01 {
    @Test
    public void testMethod01() throws Exception{
        //1.获取字节码对象
        Class<Person> pCLs = Person.class;

        //2.获取构造方法
        Constructor<Person> cons = pCLs.getConstructor();//由于获取的是空参构造,所以不需要传递任何参数,因此使用getConstructor()方法也不用传递参数

        //3.获取构造方法的信息
        System.out.println(cons.getName());//获取构造方法的名称   reflect01.Person

        //4.利用构造方法创建对象
        Person p = cons.newInstance();//利用空参构造创建对象
                                      //类比:Person p = new Perosn();
        System.out.println(p);//reflect01.Person@f5f2bb7

    }

    @Test
    public void testMethod02() throws Exception{
        //1.获取字节码对象
        Class<Person> pCLs = Person.class;
        //2.直接利用Class类的newInstance()方法创建该类实例
        Person p = pCLs.newInstance();
        System.out.println(p); //reflect01.Person@f5f2bb7
    }

    @Test
    public void testMethod() throws Exception{
        //1.获取字节码对象并获取有参构造
        Constructor<Person> cons = Person.class.getConstructor(String.class, int.class);//获取指定形参为String,int的方法

        //2.利用这个有参构造创建对象
        Person p = cons.newInstance("老王", 30);//类比:Perosn p = new Person("老王",30);
        System.out.println(p);

    }

    /**
     * 暴力反射:获取类中的一些私有属性
     * @throws Exception
     */
    @Test
    public void testMethod04() throws Exception {
        //1.获取字节码对象
        Class<Person> pCLs = Person.class;

        //2.获取构造方法
        //Constructor<Person> cons = pCLs.getConstructor(String.class);
        Constructor<Person> cons = pCLs.getDeclaredConstructor(String.class);

        //2.5由于是将要利用私有构造方法创建对象,在类外无法调用私有构造方法,但是我们可以让java取消权限检查
        cons.setAccessible(true);

        //3.构造方法创建对象
        Person p = cons.newInstance("老李");//类似:Person p = new Person("老李");
        System.out.println(p);
    }
}
   f.反射成员变量(字段)
         /**
          * 反射(解剖出)字段
          *  Class类中的成员方法
          *      Field getField(String name)
          *           返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共public成员字段。
          *
          *      Field getDeclaredField(String name)
          *           返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
          *
          *  Field类中的成员方法
          *       Object get(Object obj)
          *           返回指定对象上此 Field 表示的字段的值。
          */


import org.junit.Test;
import reflect01.Person;

import java.lang.reflect.Field;

/*
 * 反射(解剖出)字段
 *  Class类中的成员方法
 *      Field getField(String name)
 *           返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共public成员字段。
 *
 *      Field getDeclaredField(String name)
 *           返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
 *
 *  Field类中的成员方法
 *       Object get(Object obj)
 *           返回指定对象上此 Field 表示的字段的值。
 */
public class ReflectDemo02 {
    @Test
    public void testMethod01() throws Exception {
        //1.获取Person类的字节码对象
        Class<Person> pCLs = (Class<Person>) Class.forName("reflect01.Person");

        //2.获取字段信息
        Field f = pCLs.getField("name");
        //System.out.println(f);  //public java.lang.String reflect01.Person.name

        //3.获取该字段的值
        Person p = pCLs.newInstance(); //相当于Person p = new Person();
        System.out.println(f.get(p));  //由于成员对象随着对象的存在二存在,所以必须指定获取哪个对象的成员变量的值
    }

    @Test
    public void testMethod02() throws Exception {
        //1.获取Person类的字节码对象
        Class<Person> pCLs = (Class<Person>) Class.forName("reflect01.Person");

        //2.利用getDeclarField方法获取非public修饰的字段
        Field f = pCLs.getDeclaredField("age");

        //2.5通过setAccessiable设置Java的访问权限检查
        f.setAccessible(true);

        //3.获取当前field字段的值
        Person p = pCLs.newInstance();//相当于Person p = new Person();
        System.out.println(f.get(p));//13

        //4.设置当前field字段的值
        f.set(p, 28);

        //5.获取当前field字段的值
        System.out.println(f.get(p));//28


    }
}
   g.反射成员方法
          /*
           * 反射(解剖出)成员方法信息
           *
           * Class类中的成员方法
           *      Method getMethod(String name, Class<?>... parameterTypes)
           *             返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
           *
           *Method类的方法:
           *      Object invoke(Object obj, Object... args)
           *     形参:
           *        Object obj:代表该类的一个对象
           *        orgs:代表传递给方法的实参
           *     返回值:
           *          代表调用的方法的返回值
           *          如果该方法没有返回值,invoke()返回null
           */


import org.junit.Test;
import reflect01.Person;

import java.lang.reflect.Method;

/*
 * 反射(解剖出)成员方法信息
 *
 * Class类中的成员方法
 *      Method getMethod(String name, Class<?>... parameterTypes)
 *             返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
 *
 *Method类的方法:
 *      Object invoke(Object obj, Object... args)
 *     形参:
 *        Object obj:代表该类的一个对象
 *        orgs:代表传递给方法的实参
 *     返回值:
 *          代表调用的方法的返回值
 *          如果该方法没有返回值,invoke()返回null
 */
public class ReflectDemo03 {
    @Test
    public void testMethod01() throws Exception {
        //1.获取字节码对象
        Class<Person> pCLs = (Class<Person>) Class.forName("reflect01.Person");

        //2.获取指定的成员方法
        Method sleepMethod = pCLs.getMethod("sleep");

        //3.通过invoke来调用该方法
        Person p = pCLs.newInstance();
        System.out.println(sleepMethod.invoke(p));//类似: Person p = new Person();
        // p.sleep();
    }

    @Test
    public void testMethod02() throws Exception {
        //1.获取字节码对象
        Class<Person> pCLs = (Class<Person>) Class.forName("reflect01.Person");

        //2.获取eat方法
        Method eatMethod = pCLs.getMethod("eat", String.class);

        //3.调用eat方法
        Person p = pCLs.newInstance();
        Object returnVal = eatMethod.invoke(p, "榴莲");//相当于:Person p = new Person();
                                                            //String food = p.eat("蛋糕");
                                                           //Ststem.out.println(food);
        System.out.println(returnVal);
    }


}
三.枚举
     a.枚举概述
         一一列举
         如果某些变量的取值是固定几个值中其中一个,我们就考虑定义枚举
         星期(一~日)   月份(1~12)  性别(男/女)

     b.模拟java中的枚举
         /*
          *一周(星期一~星期日)
          *  1.我们为一周每天定义一个Week对象,每个Week对象都代表改天
          *
          */
         public class Week {
             /*
              *私有化构造方法目的:只能使用Week类中的这七个对象
              * 而不能在类外在创建该类对象
              */
             private Week() {

             }
             private  String weekName;//代表星期的名称

             private Week(String weekName) {
                 this.weekName=weekName;
             }

             /*
              *public: 保证权限足够大,在类外以及不同的包下都能访问
              *static: 不需要再类外创建对象,可以用过类名直接调用
              * final: final修饰变量,该变量只能被赋值一次,该变量就成为了常量
              * 常量的命名规范:变量名纯大写  XXX_XXX_XXX
              */
           /*  public static final Week MONDAY = new Week();
             public static final Week TUESDAY = new Week();
             public static final  Week WEDNESDAY = new Week();
             public static final  Week THURSDAY = new Week();
             public static final  Week FRIDAY = new Week();
             public static final Week SATURDAY = new Week();
             public static final  Week SUNDAY = new Week();*/

             public static final Week MONDAY = new Week("星期一");
             public static final Week TUESDAY = new Week("星期二");
             public static final  Week WEDNESDAY = new Week("星期三");
             public static final  Week THURSDAY = new Week("星期四");
             public static final  Week FRIDAY = new Week("星期五");
             public static final Week SATURDAY = new Week("星期六");
             public static final  Week SUNDAY = new Week("星期日");

             @Override
             public String toString() {
                 return weekName;
             }
         }


import org.junit.Test;

public class WeekDemo {
    @Test
    public void testMethod01() {
        //Week week = new Week();
        //Week.monday=null;
        System.out.println(Week.MONDAY);
        System.out.println(Week.FRIDAY);
    }
}

/*
 *一周(星期一~星期日)
 *  1.我们为一周每天定义一个Week对象,每个Week对象都代表改天
 *
 */
public class Week {
    /*
     *私有化构造方法目的:只能使用Week类中的这七个对象
     * 而不能在类外在创建该类对象
     */
    private Week() {

    }
    private  String weekName;//代表星期的名称

    private Week(String weekName) {
        this.weekName=weekName;
    }

    /*
     *public: 保证权限足够大,在类外以及不同的包下都能访问
     *static: 不需要再类外创建对象,可以用过类名直接调用
     * final: final修饰变量,该变量只能被赋值一次,该变量就成为了常量
     * 常量的命名规范:变量名纯大写  XXX_XXX_XXX
     */
  /*  public static final Week MONDAY = new Week();
    public static final Week TUESDAY = new Week();
    public static final  Week WEDNESDAY = new Week();
    public static final  Week THURSDAY = new Week();
    public static final  Week FRIDAY = new Week();
    public static final Week SATURDAY = new Week();
    public static final  Week SUNDAY = new Week();*/

    public static final Week MONDAY = new Week("星期一");
    public static final Week TUESDAY = new Week("星期二");
    public static final  Week WEDNESDAY = new Week("星期三");
    public static final  Week THURSDAY = new Week("星期四");
    public static final  Week FRIDAY = new Week("星期五");
    public static final Week SATURDAY = new Week("星期六");
    public static final  Week SUNDAY = new Week("星期日");

    @Override
    public String toString() {
        return weekName;
    }
}
     c.利用enum创建枚举
           /*
            * Java中利用enum关键字定义枚举
            * 格式:
            *    权限修饰符 enum 枚举名称{
            *     枚举变量1,枚举变量2,枚举变量3....;
            *    }
            *
            * JAVA中利用enum定义的枚举和我们自己模拟的枚举原理相同
            */
           public enum Week {
               MONDAY("星期一"),THESDAY("星期二"),WEDNESDAY("星期三"),THURSDAY("星期四"),
               FRIDAY("星期五"),SATURDAY("星期六"),SUNDAY("星期日");
               private String weekName;

               private Week(String weekName) {
                   this.weekName=weekName;
               }

               private Week() {

               }

               @Override
               public String toString() {
                   return weekName;
               }
           }

/*
 * Java中利用enum关键字定义枚举
 * 格式:
 *    权限修饰符 enum 枚举名称{
 *     枚举变量1,枚举变量2,枚举变量3....;
 *    }
 *
 * JAVA中利用enum定义的枚举和我们自己模拟的枚举原理相同
 */
public enum Week {
    MONDAY,THESDAY,WEDNESDAY,THURSDAY,
    FRIDAY,SATURDAY,SUNDAY
}
import org.junit.Test;

public class WeekDemo {
    @Test
    public void testMethod() {
        //Week week = new Week();
        System.out.println(Week.MONDAY);
        System.out.println(Week.FRIDAY);
        System.out.println(Week.MONDAY.getClass());//class enum03.Week
    }
}
     d.枚举中常用的方法
           /*
            *枚举中的常用方法
            * Java中所有用enum定义的枚举默认会继承一个类:java.lang.Enum
            *
            * Class类中的方法
            *      Class<? super T> getSuperclass()
            *         获取该字节码对象的父类字节码对象
            *
            *      Method[] getMethods()
            *         获取该字节码对象中所有public修饰的成员方法
            *
            * 枚举中的常用方法:
            *     public static Week[] values()
            *            获取所有的枚举常量,并把所有的枚举常量封装到一个数组中返回
            *     public static Week.valueOf(String str)
            *     public final String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
            *
            */



/*
 * Java中利用enum关键字定义枚举
 * 格式:
 *    权限修饰符 enum 枚举名称{
 *     枚举变量1,枚举变量2,枚举变量3....;
 *    }
 *
 * JAVA中利用enum定义的枚举和我们自己模拟的枚举原理相同
 */
public enum Week {
    MONDAY,THESDAY,WEDNESDAY,THURSDAY,
    FRIDAY,SATURDAY,SUNDAY
}

import org.junit.Test;

import java.lang.reflect.Method;

/*
 *枚举中的常用方法
 * Java中所有用enum定义的枚举默认会继承一个类:java.lang.Enum
 *
 * Class类中的方法
 *      Class<? super T> getSuperclass()
 *         获取该字节码对象的父类字节码对象
 *
 *      Method[] getMethods()
 *         获取该字节码对象中所有public修饰的成员方法
 *
 * 枚举中的常用方法:
 *     public static Week[] values()
 *            获取所有的枚举常量,并把所有的枚举常量封装到一个数组中返回
 *     public static Week.valueOf(String str)
 *     public final String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
 *
 */
public class WeekDemo {
    @Test
    public void testMethod() {
        System.out.println(Week.class.getSuperclass());//class java.lang.Enum

    }

    @Test
    public void testMethod02() {
        //1.利用字节码对象获取所有的成员方法
        Method[] methods = Week.class.getMethods();

        //2.遍历methods数组
        for (Method method : methods) {
            System.out.println(method);
        }
    }

    @Test
    public void testMethod03() {
        Week[] weeks = Week.values();
        for (Week week : weeks) {
            System.out.println(week);
        }
    }
    @Test
    public void testMethod04() {
        System.out.println(Week.valueOf("MONDAY"));
        System.out.println(Week.valueOf("MONDAY")==Week.MONDAY);//true
    }
    @Test
    public void testMethod05() {
        System.out.println(Week.FRIDAY.name());//跟toString原理相同
        System.out.println(Week.FRIDAY);
        System.out.println(Week.FRIDAY.toString());
    }
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>