一、单元测试
1.1 介绍
单元测试:针对最小的功能单元,编写测试代码对其进行正确性测试。
为了测试更加方便,有一些第三方的公司或者组织提供了很好用的测试框架,给开发者使用。Junit是第三方公司开源出来的,用于对代码进行单元测试的工具(IDEA已经集成了junit框架)。相比于在main方法中测试有如下几个优点。
- 能灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
- 不需要程序员分析测试结果,会自动生成测试报告

先准备一个类:
1 2 3 4 5 6
| public class StringUtil { public static void printNumber(String name){ System.out.println("名字长度:"+name.length()); } }
|
为之写一个测试类:
1 2 3 4 5 6 7 8 9 10
| import org.junit.Test; public class StringUtilTest { @Test public void testPrintNumber(){ StringUtil.printNumber("admin"); StringUtil.printNumber(null); }
}
|
1.2 单元测试断言
断言:程序员可以预测程序的运行结果,检查程序的运行结果是否与预期一致。
在StringUtil类中新增一个测试方法
1 2 3 4 5 6
| public static int getMaxIndex(String data){ if(data == null){ return -1; } return data.length(); }
|
接下来,我们在StringUtilTest类中写一个测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class StringUtilTest{ @Test public void testGetMaxIndex(){ int index1 = StringUtil.getMaxIndex(null); System.out.println(index1); int index2 = StringUtil.getMaxIndex("admin"); System.out.println(index2); Assert.assertEquals("方法内部有Bug",4,index2); } }
|
运行测试方法,结果如下图所示,表示我们预期值与实际值不一致

1.3 Junit框架的常用注解

下面进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class StringUtilTest{ @Before public void test1(){ System.out.println("--> test1 Before 执行了"); } @BeforeClass public static void test11(){ System.out.println("--> test11 BeforeClass 执行了"); } @After public void test2(){ System.out.println("--> test2 After 执行了"); } @AfterCalss public static void test22(){ System.out.println("--> test22 AfterCalss 执行了"); } }
|
应用场景:
假设我想在每个测试方法中使用Socket对象,并且用完之后,需要把Socket关闭。代码就可以按照下面的结构来设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class StringUtilTest{ private static Socket socket; @Before public void test1(){ System.out.println("--> test1 Before 执行了"); } @BeforeClass public static void test11(){ System.out.println("--> test11 BeforeClass 执行了"); socket = new Socket(); } @After public void test2(){ System.out.println("--> test2 After 执行了"); } @AfterCalss public static void test22(){ System.out.println("--> test22 AfterCalss 执行了"); socket.close(); } }
|
二、反射
反射技术:指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。
- 加载类,获取字节码对象 class对象
- 获取类的构造器:constructor对象
- 获取类的成员变量:Filed对象
- 获取类的成员方法:Method对象
2.1 获取类的字节码
将字节码加载到内存,我们需要获取到的字节码对象。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import javaday01.Student; public class Test1Class { public static void main(String[] args) throws Exception { Class c1 = Student.class; System.out.println(c1.getName()); System.out.println(c1.getSimpleName());
Class c2 = Class.forName("javaday01.Student"); System.out.println(c1 == c2);
Student s = new Student(); Class c3 = s.getClass(); System.out.println(c2==c3); } }
|
2.2 获取类的构造器
上一节我们已经可以获取到类的字节码对象了。接下来,我们学习一下通过字节码对象获取构造器,并使用构造器创建对象。

写一个类Cat
1 2 3 4 5 6 7 8 9 10 11
| package javaday01;
public class Cat { private String name; private int age;
public Cat(){} public Cat(String name, int age){}
}
|
- getDeclaredConstructors()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package javaday01;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class Test2Constructor { @Test public void testGetConstructor(){ Class c = Cat.class; Constructor[] constructors = c.getDeclaredConstructors(); for(Constructor constructor : constructors){ System.out.println(constructor.getName()+"--->参数个数: "+constructor.getParameterCount()); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package javaday01;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class Test2Constructor { @Test public void testGetConstructor() throws Exception{ Class c = Cat.class;
Constructor constructor1 = c.getConstructor(); System.out.println(constructor1.getName()+"---> 参数个数:"+constructor1.getParameterCount());
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); System.out.println(constructor2.getName()+"---> 参数个数:"+constructor2.getParameterCount());
}
}
|
2.3 反射获取构造器的作用
构造器的作用:初始化对象并返回。

由于构造器是private修饰的,先需要调用setAccessible(true)
表示禁止检查访问控制,然后再调用newInstance(实参列表)
就可以执行构造器,完成对象的初始化了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package javaday01;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class Test2Constructor { @Test public void testGetConstructor() throws Exception{ Class c = Cat.class;
Constructor constructor1 = c.getConstructor(); System.out.println(constructor1.getName()+"---> 参数个数:"+constructor1.getParameterCount()); constructor1.setAccessible(true); Cat cat = (Cat) constructor1.newInstance(); System.out.println(cat);
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); System.out.println(constructor2.getName()+"---> 参数个数:"+constructor2.getParameterCount()); constructor2.setAccessible(true); Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 12); System.out.println(cat2);
}
}
|
2.4 反射获取成员变量&使用

Cat类有如下成员变量:

执行一下代码获取成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package javaday01;
import org.junit.Test;
import java.lang.reflect.Field;
public class Test3Field { @Test public void testGetFiled() throws Exception{ Class c = Cat.class; Field[] fields = c.getDeclaredFields(); for (Field filed : fields){ System.out.println(filed.getName() + "---> " + filed.getType()); } Field fName = c.getDeclaredField("name"); System.out.println(fName.getName() + "---> "+ fName.getType());
Field fAge = c.getDeclaredField("age"); System.out.println(fAge.getName() + "---> "+ fAge.getType());
} }
|
给成员变量赋值和获取值的方法

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package javaday01;
import org.junit.Test;
import java.lang.reflect.Field;
public class Test3Field { @Test public void testGetFiled() throws Exception{ Class c = Cat.class; Field[] fields = c.getDeclaredFields(); for (Field filed : fields){ System.out.println(filed.getName() + "---> " + filed.getType()); } Field fName = c.getDeclaredField("name"); System.out.println(fName.getName() + "---> "+ fName.getType());
Field fAge = c.getDeclaredField("age"); System.out.println(fAge.getName() + "---> "+ fAge.getType());
Cat cat = new Cat(); fName.setAccessible(true); fName.set(cat, "加菲猫"); System.out.println(cat);
String name = (String) fName.get(cat); System.out.println(name);
} }
|

2.5 反射获取成员方法
在Java中反射包中,每一个成员方法用Method对象来表示,通过Class类提供的方法可以获取类中的成员方法对象。如下下图所示

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package javaday01;
import java.lang.reflect.Method;
public class Test3Method { public static void main(String[] args) { Class c = Cat.class; Method[] methods = c.getDeclaredMethods();
for (Method method:methods){ System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType()); }
}
}
|
执行上面的代码,运行结果如下图所示:打印输出每一个成员方法的名称、参数格式、返回值类型

在Method类中提供了方法,可以将方法自己执行起来。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package javaday01;
import java.lang.reflect.Method;
public class Test3Method { public static void main(String[] args) throws Exception { Class c = Cat.class; Method[] methods = c.getDeclaredMethods();
for (Method method:methods){ System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType()); }
Method run = c.getDeclaredMethod("run"); Cat cat = new Cat(); run.setAccessible(true); Object rs1 = run.invoke(cat); System.out.println(rs1);
Method eat = c.getDeclaredMethod("eat",String.class); eat.setAccessible(true); Object rs2 = eat.invoke(cat,"鱼儿"); System.out.println(rs2);
}
}
|

2.6 反射的应用
反射的核心作用是用来获取类的各个组成部分并执行他们

让我们写一个框架,能够将任意一个对象的属性名和属性值写到文件中去。不管这个对象有多少个属性,也不管这个对象的属性名是否相同。
1 2 3 4 5 6 7 8 9
| 1.先写好两个类,一个Student类和Teacher类 2.写一个ObjectFrame类代表框本架 在ObjectFrame类中定义一个saveObject(Object obj)方法,用于将任意对象存到文件中去 参数:Object obj: 就表示要存入文件中的对象 3.编写方法内部的代码,往文件中存储对象的属性名和属性值 1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。 2)接着就通过反射获取类的成员变量信息了(变量名、变量值) 3)把变量名和变量值写到文件中去
|
写一个ObjectFrame表示自己设计的框架,代码如下图所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package javaday01;
import java.io.FileOutputStream; import java.io.PrintStream; import java.lang.reflect.Field;
public class ObjectFrame { public static void saveObject(Object obj) throws Exception{ PrintStream ps = new PrintStream(new FileOutputStream("D:\\learn_java\\javaday01\\src\\data.txt", true)); Class c = obj.getClass(); ps.println("---------"+c.getSimpleName()+"---------"); Field[] fields = c.getDeclaredFields();
for(Field field : fields){ String name = field.getName(); ps.println(name); } ps.close();
} }
|
使用自己设计的框架,往文件中写入Student对象的信息和Teacher对象的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package javaday01;
import org.junit.Test;
public class Test5Framw { @Test public void save() throws Exception{ Student s1 = new Student(45, "jack"); Teacher t1 = new Teacher("wendy", 30000); ObjectFrame.saveObject(s1); ObjectFrame.saveObject(t1);
}
}
|
三、注解
3.1 定义
Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。
- 注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。