
Junit(属于白盒测试)
Junit的使用

javadoc设置

导入Junit依赖的环境

Calculator类
java
package Calculator;
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int sub(int a, int b) {
return a - b;
}
}
CalculatorTest类
java
package com.mm.test01;
import Calculator.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
//加入@Before后,这个方法会在测试方法执行前先执行
//一般在@Before修饰的方法中加入申请资源的代码:申请数据库资源、IO资源、网络资源
@Before
public void init() {
System.out.println("方法执行开始了");
}
//加入@After后,这个方法会在测试方法执行后执行
//一般在@After修饰的方法中加入释放资源的代码:释放数据库资源、IO资源、网络资源
@After
public void close() {
System.out.println("方法执行结束了");
}
@Test
public void testadd() {
Calculator cal = new Calculator();
int result = cal.add(1, 3);
System.out.println(result);
//加入断言:判断预测结果与运行结果是否一致
Assert.assertEquals(4, result);
}
@Test
public void testadd2() {
Calculator cal = new Calculator();
int result = cal.add(1, 4);
System.out.println(result);
}
}


注解
自定义注解
Calculator类(使用注解)
java
package Calculator;
import com.mm.anno.MyAnnotation;
import com.mm.anno.MyAnnotation2;
//因为定义自定义注解时定义了配置参数,所以必须给配置参数赋值
//如果只有一个参数,且这个参数名字为value,那 value= 可以省略不写
@MyAnnotation({"abc", "def"})
//如果给配置参数设置默认值,那使用的时候无需传值
@MyAnnotation2
public class Calculator {
public static void main(String[] args) {
}
}
MyAnnotation1
java
package com.mm.anno;
public @interface MyAnnotation {
/**
* value:成员变量的名字(注意:如果仅有一个成员变量,名字尽量叫value)
*String[ ]:成员变量的类型(无参数方法的类型:基本数据类型(8种)、String、枚举、注解、以及以上类型的数组)
*/
String[] value();
}
MyAnnotation2
java
package com.mm.anno;
public @interface MyAnnotation2 {
//给配置参数设置默认值
String value() default "abc";
}
MyAnnotation3
java
package com.mm.anno;
public @interface MyAnnotation3
//注解内部是可以不定义配置参数的,内部没有定义配置参数的注解,叫标记
{
}
元注解
Retention
(用于声明被修饰的注解的生命周期)
java
package com.mm.anno;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//使注解只在源文件中有效(即源文件保留,在.class字节码文件中不会保留注解信息)
//@Retention(RetentionPolicy.SOURCE)
//反编译查看字节码文件,字节码文件中带有MyAnnotation这个注解
//@Retention(RetentionPolicy.CLASS)
//使注解在运行时有效。当运行java程序时,JVM会保留注解,加载在内存中,程序可以通过反射获取该注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String[] value();
}
Target
java
package com.mm.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
//指定被修饰的注解能用于修饰哪些程序元素
//此处MyAnnotation注解可以用于修饰类、属性、构造器、方法
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface MyAnnotation {
String[] value();
}

枚举
自定义枚举类
枚举类:属性限制不变,对象也限制不变
-
自定义枚举类的上层父类:
-
Object
-
注释掉toString方法后,打印对象输出的是地址
-
java
package com.mm.enum01;
/**
* 定义枚举类:季节
*/
public class season {
//属性使用final修饰不能改变
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//用构造器对属性进行赋值操作
//构造器私有化,外界不能调用这个构造器,只能Season内部调用
private season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//提供枚举类的有限的、确定的对象
//对象使用final修饰,SPRING不能重新new对象
public static final season SPRING = new season("春天", "春暖花开");
//额外因素
public String getSeasonDesc() {
return seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
@Override
public String toString() {
return "test{" +
"seasonDesc='" + seasonDesc + '\'' +
", seasonName='" + seasonName + '\'' +
'}';
}
}
自定义枚举类改成enum枚举类

用enum关键字定义枚举类
-
用enum关键字创建的枚举类的上层父类
-
java.lang.Enum
-
注释掉toString方法后,打印对象输出的不是地址,而是对象名
-
java
package com.mm.enum01;
/**
* 用enum关键字定义枚举类
* enum枚举类要求对象(常量)必须放在最开始的位置
*/
public enum season {
//多个对象之间用逗号隔开,最后一个用;结束
SPRING("春天", "春暖花开"),
SUMMER("夏天", "烈日炎炎"),
WINTER("冬天", "冰天雪地");
//属性使用final修饰不能改变
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//用构造器对属性进行赋值操作
//构造器私有化,外界不能调用这个构造器,只能Season内部调用
private season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//额外因素
public String getSeasonDesc() {
return seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
@Override
public String toString() {
return "test{" +
"seasonDesc='" + seasonDesc + '\'' +
", seasonName='" + seasonName + '\'' +
'}';
}
}
枚举类底层没有属性
构造器、toString、get方法都删掉。只留下对象名/常量名 +,/;
java
package com.mm.enum01;
/**
* enum枚举类要求对象(常量)必须放在最开始的位置
*/
public enum season {
//多个对象之间用逗号隔开,最后一个用;结束
//这个枚举类底层没有属性,构造器、toString、get方法都删掉
SPRING, //原本该写为SPRING(),现在连()都省略了
SUMMER,
WINTER;
}
用enum关键字创建的枚举类
这个枚举类可以直接拿过来使用,3个常用方法
java
package com.mm.enum01;
public class test {
public static void main(String[] args) {
//用enum关键字创建的枚举类的上层父类:java.lang.Enum
//这个枚举类可以直接拿过来使用
//toString:获取对象名
season spring = season.SPRING;
System.out.println(spring);
//values:返回枚举类对象的数组
season[] values = season.values();
//遍历
for (season s : values) {
System.out.println(s);
}
//valueOf:通过对象名获取这个对象
//注意:对象的名字必须传正确,否则报异常
season spring1 = season.valueOf("SPRING");
System.out.println(spring1);
}
}
枚举类实现接口
所有枚举对象调用show方法走的都是同一个方法
TestInterface接口
java
package com.mm.enum01;
public interface TestInterface {
void show();
}
枚举类season
java
package com.mm.enum01;
//枚举类实现接口
public enum season implements TestInterface {
SPRING,
SUMMER,
WINTER;
//需要重写接口内的抽象方法
@Override
public void show() {
System.out.println("重写接口内的抽象方法");
}
}
test类
java
package com.mm.enum01;
public class test {
public static void main(String[] args) {
season spring = season.SPRING;
spring.show();
season summer = season.SUMMER;
summer.show();
//所有枚举对象调用show方法走的都是同一个方法
}
}
不同枚举对象调用show方法走的是不同方法
仅需重写枚举类
java
package com.mm.enum01;
//枚举类实现接口
public enum season implements TestInterface {
SPRING {
@Override
public void show() {
System.out.println("春天");
}
},
SUMMER {
@Override
public void show() {
System.out.println("夏天");
}
},
WINTER {
@Override
public void show() {
System.out.println("冬天");
}
};
}
枚举的应用
枚举Gender类
java
package com.mm.enum01;
public enum Gender {
男,
女;
}
Person类
java
package com.mm.enum01;
public class Person {
private int age;
private String name;
private Gender sex;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
test类
java
package com.mm.enum01;
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setAge(19);
p.setName("lili");
p.setSex(Gender.男);//传入枚举类对象,在入口处对参数进行了限制
System.out.println(p);
}
}
test02类
java
package com.mm.enum01;
public class test02 {
public static void main(String[] args) {
//switch(表达式)表达式返回结果是个等值,等值的类型可以是int、byte、short、char、String、枚举中任意一种类型
Gender sex = Gender.男;
switch (sex) {
case 女:
System.out.println("女生");
break;
case 男:
System.out.println("男生");
break;
}
}
}


反射
美团实例
美团接口
java
package com.mm.Reflect;
//接口的制定方:美团外卖
public interface Mtwm {
//在线支付功能:
void payonline();
}
微信支付类(实现美团接口)
java
package com.mm.Reflect;
public class Wechat implements Mtwm {
@Override
public void payonline() {
//具体实现微信支付功能
System.out.println("使用微信支付成功");
}
}
支付宝支付类(实现美团接口)
java
package com.mm.Reflect;
public class AliPay implements Mtwm {
@Override
public void payonline() {
//具体的支付宝支付
System.out.println("支付宝付款成功");
}
}
银行卡支付类
java
package com.mm.Reflect;
public class BankCard implements Mtwm {
@Override
public void payonline() {
//银行卡具体功能
System.out.println("银行卡支付成功");
}
}
test类(普通写法)
java
package com.mm.Reflect;
public class test {
public static void main(String[] args) {
//定义一个字符串,模拟前台的支付方式
String str = "支付宝";
if ("微信".equals(str)) {//为啥不用str.equals("微信")?避免空指针异常
//微信支付
// new Wechat().payonline();//被下一句替代
pay(new Wechat());
}
if ("支付宝".equals(str)) {
//支付宝支付
// new AliPay().payonline();//被下一句替代
pay(new AliPay());
}
if ("银行卡".equals(str)) {
pay(new BankCard());
}
}
//微信支付
public static void pay(Wechat wc) {
wc.payonline();
}
//支付宝支付
public static void pay(AliPay al) {
al.payonline();
}
//银行卡支付
public static void pay(BankCard bk) {
bk.payonline();
}
}
假设后续还有多种支付方式,添加类和方法太麻烦了
为了提高代码的拓展性---->面向对象特性:多态
方法的形参是接口,具体传入的是接口的实现类的对象--->多态的一种形式
test类(多态)
java
package com.mm.Reflect;
public class test {
public static void main(String[] args) {
//定义一个字符串,模拟前台的支付方式
String str = "支付宝";
if ("微信".equals(str)) {//为啥不用str.equals("微信")?避免空指针异常
//微信支付
// new Wechat().payonline();//被下一句替代
pay(new Wechat());
}
if ("支付宝".equals(str)) {
//支付宝支付
// new AliPay().payonline();//被下一句替代
pay(new AliPay());
}
if ("银行卡".equals(str)) {
pay(new BankCard());
}
}
//方法的形参是接口,具体传入的是接口的实现类的对象--->多态的一种形式
public static void pay(Mtwm m) {
m.payonline();
}
}
多态确实可以提高代码的拓展性,但拓展性没有达到最好
上面的if分支,还是需要手动删除或者添加
解决方法:反射机制
test(反射)
java
package com.mm.Reflect;
import java.lang.reflect.Method;
public class test {
public static void main(String[] args) throws Exception {
//定义一个字符串,模拟前台的支付方式
//字符串:是微信支付类的全限定路径
String str = "com.mm.Reflect.Wechat";
//下面的代码就是利用反射:
Class cls = Class.forName(str);//cls-->Class类具体的对象,Alipay/微信pay字节码信息
Object o = cls.newInstance();
Method method = cls.getMethod("payonline");
method.invoke(o);
}
}
反射(面向对象思维)

获取字节码信息的四种方式
Person类(父类)
java
package com.mm.Reflect;
//作为一个父类
public class Person {
//属性
private int age;
public String name;
//方法
private void eat() {
System.out.println("Person--eat");
}
public void sleep() {
System.out.println("Person--sleep");
}
}
test类(获取Person字节码信息)
java
package com.mm.Reflect;
public class test {
public static void main(String[] args) throws Exception {
//案例:以Person的字节码信息为案例
//方式1:通过getClass方式获取
Person p = new Person();
Class c1 = p.getClass();
System.out.println(c1);
//方式2:通过内置class属性
Class c2 = Person.class;
System.out.println(c2);
//注意:方式1和方式2不常用
//方式3:调用Class类提供的静态方法forName(用得最多)
Class c3 = Class.forName("com.mm.Reflect.Person");
//方式4:利用类的加载器
ClassLoader loader = test.class.getClassLoader();
Class c4 = loader.loadClass("com.mm.Reflect.Person");
System.out.println(c1 == c2);//True
System.out.println(c1 == c3);//True
System.out.println(c1 == c4);//True
}
}
可以作为Class类的实例的种类
Person类(父类)
java
package com.mm.Reflect;
//作为一个父类
public class Person {
//属性
private int age;
public String name;
//方法
private void eat() {
System.out.println("Person--eat");
}
public void sleep() {
System.out.println("Person--sleep");
}
}
test类
java
package com.mm.Reflect;
public class test {
public static void main(String[] args) throws Exception {
//可以作为Class类的实例的种类
//1、类
Class c1 = Person.class;
//2、接口
Class c2 = Comparable.class;
//3、注解
Class c3 = Override.class;
//4、数组
int[] arr1 = {1, 2, 3};
Class c4 = arr1.getClass();
int[] arr2 = {5, 6, 7};
Class c5 = arr2.getClass();
//同一个维度,同一个元素类型,得到的字节码就是同一个
System.out.println(c4 == c5);//True
//5、基本数据类型
Class c6 = int.class;
//6、void方法返回值
Class c7 = void.class;
}
}
获取运行时类的完整结构
Person类
java
package com.mm.Reflect;
import java.io.Serializable;
//作为一个父类,实现序列化Serializable的接口
public class Person implements Serializable {
//属性
private int age;
public String name;
//方法
private void eat() {
System.out.println("Person--eat");
}
public void sleep() {
System.out.println("Person--sleep");
}
}
Student类(子类)
java
package com.mm.Reflect;
//作为子类,实现自定义接口MyInterface
@MyAnnotation(value = "hello")
public class Student extends Person implements MyInterface {
//属性
private int sno;//学号
double height;//身高(default修饰)
protected double weight;
public double score;//成绩
//方法
@MyAnnotation(value = "hiMethod")
public String showInfo() {
return "我是三好学生";
}
public String showInfo(int a, int b) {
return "重载方法,三好学生";
}
private void work() {
System.out.println("我会工作");
}
void happy() {
System.out.println("happy");
}
protected int getSno() {
return sno;
}
//构造器
public Student() {
System.out.println("无参构造器");
}
public Student(double weight, double height) {
this.weight = weight;
this.height = height;
}
private Student(int sno) {
this.sno = sno;
}
Student(int sno, double weight) {//default修饰的构造器
this.sno = sno;
this.weight = weight;
}
protected Student(int sno, double height, double weight) {
this.sno = sno;
}
@Override
@MyAnnotation(value = "hellomyMethod")
public void myMethod() {
System.out.println("重写的myMethod方法");
}
@Override
public String toString() {
return "Student{" +
"height=" + height +
", sno=" + sno +
", weight=" + weight +
", score=" + score +
'}';
}
}
MyAnnotation接口
java
package com.mm.Reflect;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();//属性
}
获取构造器和创建对象
java
package com.mm.Reflect;
import java.lang.reflect.Constructor;
public class test {
public static void main(String[] args) throws Exception {
//获取字节码信息
Class cls = Student.class;
//通过字节码信息获取构造器
//getConstructors只能获取当前运行时类的被public修饰的构造器,返回值是一个数组
Constructor[] c1 = cls.getConstructors();
for (Constructor c : c1) {
System.out.println(c);
}
//getDeclaredConstructors能获取当前运行时类的全部修饰符的构造器,返回值是一个数组
Constructor[] c2 = cls.getDeclaredConstructors();
for (Constructor c : c2) {
System.out.println(c);
}
//获取指定的构造器
//不传参数,得到空构造器
Constructor con1 = cls.getConstructor();
System.out.println(con1);
//获取两个参数的有参构造器
Constructor con2 = cls.getConstructor(double.class, double.class);
//getDeclaredConstructor:获取private修饰的有参构造器
Constructor con3 = cls.getDeclaredConstructor(int.class);
System.out.println(con3);
//创建对象
Object o1 = con1.newInstance();
System.out.println(o1);
Object o2 = con2.newInstance(180.5, 170.5);
System.out.println(o2);
}
}
获取属性和对属性进行赋值
java
package com.mm.Reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class test {
public static void main(String[] args) throws Exception {
//获取字节码信息
Class cls = Student.class;
//通过字节码信息获取属性
//getFields:获取运行时类和其父类中被public修饰的属性,返回值是一个数组
Field[] fields = cls.getFields();
for (Field f : fields) {
System.out.println(f);
}
//getDeclaredFields:获取当前运行时类的全部修饰符的属性
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
//getField:获取指定的public修饰的属性
Field score = cls.getField("score");
System.out.println(score);
//getDeclaredField:获取指定的private修饰的属性
Field sno = cls.getDeclaredField("sno");
System.out.println(sno);
//获取属性的具体结构
//获取属性的修饰符:返回结果是修饰符对应的数字
int modifiers = sno.getModifiers();
// System.out.println(modifiers);//2
//将对应数字转为修饰符
System.out.println(Modifier.toString(modifiers));
//获取属性的数据类型:
Class type = sno.getType();
System.out.println(type);
System.out.println(type.getName());
//获取属性的名字:
String name = sno.getName();
System.out.println(name);
//给属性赋值
Field sco = cls.getField("score");
//创建一个cls类的obj对象(给属性赋值必须有对象)
Object obj = cls.newInstance();
//给o2对象设置sco属性,值为98
sco.set(obj, 98);
System.out.println(obj);
}
}
Student类
java
package com.mm.Reflect;
//作为子类,实现自定义接口MyInterface
@MyAnnotation(value = "hello")
public class Student extends Person implements MyInterface {
//属性
private int sno;//学号
double height;//身高(default修饰)
protected double weight;
public double score;//成绩
//方法
@MyAnnotation(value = "hiMethod")
public String showInfo() {
return "我是三好学生";
}
public String showInfo(int a, int b) {
return "有参数的方法,三好学生";
}
private void work() {
System.out.println("我会工作");
}
void happy() {
System.out.println("happy");
}
protected int getSno() {
return sno;
}
//构造器
public Student() {
System.out.println("无参构造器");
}
public Student(double weight, double height) {
this.weight = weight;
this.height = height;
}
private Student(int sno) {
this.sno = sno;
}
Student(int sno, double weight) {//default修饰的构造器
this.sno = sno;
this.weight = weight;
}
protected Student(int sno, double height, double weight) {
this.sno = sno;
}
@Override
@MyAnnotation(value = "hellomyMethod")
public void myMethod() throws RuntimeException {
System.out.println("重写的myMethod方法");
}
@Override
public String toString() {
return "Student{" +
"height=" + height +
", sno=" + sno +
", weight=" + weight +
", score=" + score +
'}';
}
}
获取方法和调用方法
test类
java
package com.mm.Reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
public class test {
public static void main(String[] args) throws Exception {
//获取字节码信息
Class cls = Student.class;
//通过字节码信息获取方法
//getMethods:获取运行时类和其所以父类中被public修饰的方法
Method[] methods = cls.getMethods();
for (Method m : methods) {
System.out.println(m);
}
//getDeclaredMethods:获取当前运行时类的全部修饰符的方法
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
//获取指定方法
//获取被public修饰的无参数指定方法
Method method1 = cls.getMethod("showInfo");
System.out.println(method1);
//获取被public修饰的有参数指定方法
Method method2 = cls.getMethod("showInfo", int.class, int.class);
System.out.println(method2);
//获取被private修饰的指定方法
Method method3 = cls.getDeclaredMethod("work");
System.out.println(method3);
//获取方法的具体结构
//名字
System.out.println(method1.getName());
//修饰符
//返回结果是修饰符对应的数字
int modifiers = method1.getModifiers();
// System.out.println(modifiers);//1
System.out.println(Modifier.toString(modifiers));
//返回值
Class returnType = method3.getReturnType();
System.out.println(returnType);
//获取参数列表,返回值是一个列表
Parameter[] parameters = method3.getParameters();
for (Parameter p : parameters) {
System.out.println(p);//此处无输出内容,因为无参数
}
//注解
Method myMethod = cls.getMethod("myMethod");
Annotation[] annotations = myMethod.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
//只能获取一个注解,因为@Override注解的生命周期只在编译期
}
//获取异常,返回值是一个列表
Class[] exceptionTypes = myMethod.getExceptionTypes();
for (Class c : exceptionTypes) {
System.out.println(c);
}
//调用方法
Object o2 = cls.newInstance();
//调用o2对象的myMethod方法
System.out.println(myMethod.invoke(o2));
System.out.println(method2.invoke(o2, 12, 25));
}
}
获取类的接口,所在包,注解
test类
java
package com.mm.Reflect;
import java.lang.annotation.Annotation;
public class test {
public static void main(String[] args) throws Exception {
//获取字节码信息
Class cls = Student.class;
//通过字节码信息获取接口
Class[] interfaces = cls.getInterfaces();
for (Class c : interfaces) {
System.out.println(c);
}
//获取父类接口:
// 先得到父类的字节码信息
Class superclass = cls.getSuperclass();
// 再得到父类接口
Class[] interfaces2 = superclass.getInterfaces();
for (Class c2 : interfaces2) {
System.out.println(c2);
}
//获取类所在类的包
Package aPackage = cls.getPackage();
System.out.println(aPackage);//package com.mm.Reflect
System.out.println(aPackage.getName());//com.mm.Reflect
//获取类的注解
Annotation[] annotations = cls.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
}
}