针对最小的功能单元(方法),编写测试代码对其进行正确性测试。
main方法进行单元测试的问题:
Junit单元测试框架
Junit使用步骤
自动化测试
在项目上右键Run All Test
案例
工具类
public class StringUtil {
public static void printNumber(String name) {
System.out.println("名字的长度是:" + name.length());
}
// 求最大索引
public static int getMaxIndex(String data) {
if (data == null) {
return -1;
}
return data.length();
}
}
测试类
public class StringUtilTest {
@Test
public void testPrintNumber() {
StringUtil.printNumber("admin");
// StringUtil.printNumber(null);
}
@Test
public void testGetMaxIndex() {
int r1 = StringUtil.getMaxIndex("admin");
// 断言,看实际期望的和程序输出的是否有出入
Assert.assertEquals("有问题", 4, r1);
}
}
Junit框架的常见注解
在测试方法之前执行的方法——初始化资源
在测试方法之后执行的方法——释放资源
测试类
public class StringUtilTest {
@Before // 每个测试方法执行之前执行一次
public void test1() {
System.out.println("----");
}
@BeforeClass // 所有测试方法执行之前执行一次
public static void test11() {
System.out.println("String测试类开始执行了");
}
@After // 每个测试方法执行之后执行一次
public void test2() {
System.out.println("====");
}
@AfterClass // 所有测试方法执行之前执行一次
public static void test22() {
System.out.println("String测试类执行结束了");
}
@Test
public void testPrintNumber() {
StringUtil.printNumber("admin");
// StringUtil.printNumber(null);
}
@Test
public void testGetMaxIndex() {
int r1 = StringUtil.getMaxIndex("admin");
System.out.println(r1);
// 断言,看实际期望的和程序输出的是否有出入
Assert.assertEquals("有问题", 4, r1);
}
}
学习框架、理解源码/开发框架
java.lang.reflect
概念: 加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)——反序列化/向外界展示已经封装好的内部东西
学什么: 如何获取类的信息并操作他们
步骤:
1)获取Class对象的三种方式
Class c1 = 类名.class
调用Class提供的方法:public static Class forName(String package);
Object提供的方法:public Class getClass(); Class c3 = 对象.getClass();
public class Test1Class {
public static void main(String[] args) throws Exception {
// 方式一
Class c1 = Student.class;
System.out.println(c1.getName()); // 全类名 com.itheima.d2_reflect.Student
System.out.println(c1.getSimpleName()); // 简名 Student
// 方式二
Class c2 = Class.forName("com.itheima.d2_reflect.Student");
System.out.println(c2.getName()); // com.itheima.d2_reflect.Student
// 方式三,通过类的实例对象
Student s = new Student();
Class c3 = s.getClass();
System.out.println(c3.getName()); // com.itheima.d2_reflect.Student
System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true
}
}
2)获取Constructor对象
类
public class Cat {
private String name;
private int age;
private Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
}
获取Constructor对象
public class TestConstructor {
@Test
public void testGetConstructor() {
// 1. 首先要获取类的class对象
Class c = Cat.class;
// Class.forName("com.itheima.d2_reflect.Cat");
// 对象.getClass()
// 2. 获取全部构造器
Constructor[] constructors = c.getConstructors(); // 只能获取public修饰的构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
Constructor[] constructors1 = c.getDeclaredConstructors(); // 获取任何修饰符修饰的构造器
for (Constructor constructor : constructors1) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
@Test
public void testGetOneConstructor() throws Exception {
// 1. 首先要获取类的class对象
Class c = Cat.class;
// Class.forName("com.itheima.d2_reflect.Cat");
// 对象.getClass()
// 2. 获取1个构造器
Constructor constructor1 = c.getDeclaredConstructor(); // 获取无参构造器
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); // 获取任何修饰符修饰的构造器
System.out.println(constructor2.getName() + "===>" + constructor2.getParameterCount());
}
}
作用:
初始化对象返回
@Test
public void testGetOneConstructor() throws Exception {
// 1. 首先要获取类的class对象
Class c = Cat.class;
// Class.forName("com.itheima.d2_reflect.Cat");
// 对象.getClass()
// 2. 获取1个构造器
Constructor constructor1 = c.getDeclaredConstructor(); // 获取无参构造器
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
// 重点!!!
constructor1.setAccessible(true); // 禁止检查访问权限,也就是不管private还是public,都能创建对象,会破坏封装性
Cat cat = (Cat) constructor1.newInstance(); // 调用此构造器,并传入参数,完成对象的初始化
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class); // 获取任何修饰符修饰的构造器
System.out.println(constructor2.getName() + "===>" + constructor2.getParameterCount());
}
3)获取成员变量Field
public Field[] getFields()——获取全部public修饰的成员变量
public Field[] getDeclaredFields()——获取全部成员变量
public Field getField(String name)——根据成员变量的名字,获取某个成员变量,只能获取public修饰的
public Field getDeclaredField(String name)——根据成员变量的名字,获取某个成员变量
作用: 赋值、取值
void set(Object obj, Object value);
Object get(Object obj);
public void setAccessible(boolean flag); // 禁止访问权限
4)获取成员方法Method
同上
作用:执行
public Object invoke(Object obj, Object……args); // 出发某个对象的该方法执行
public void setAccessible(boolean flag); /// 设置true,表示禁止检查访问控制
反射的作用
JAVA代码里的特殊标记
作用: 让其他程序根据在注解信息来决定怎么执行该程序
自定义注解: 自己定义注解
格式:
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
/*
* 自定义注解
*/
public @interface MyTest1 {
// String value(); // 特殊属性,只有这一个属性时,或者后面是有默认值的,用的时候可以不写名字
String aaa();
boolean bbb() default true;
String[] ccc();
}
@MyTest1(aaa = "小鱼0135", ccc = {"嘻嘻", "嘎嘎"})
public class AnnotationTest1 {
@MyTest1(aaa="小君", bbb=false, ccc={"123"})
public void test1(){
}
}
原理:
元注解:修饰注解的注解
/*
* 自定义注解
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest1 {
// String value(); // 特殊属性,只有这一个属性时,或者后面是有默认值的,用的时候可以不写名字
String aaa();
boolean bbb() default true;
String[] ccc();
}
注解的解析
判断类上、方法上、成员变量上是否存在注解,并把注解里面的内容给解析出来
如何解析注解:
要解析谁上面的注解,就要先拿到谁(要解析类上面的注解,应该先获取该类的Class对象,再通过Class对象解析其上面的注解;Class、Method、Field、Constructor都实现了AnnotatedElement接口,他们都有解析注解的能力)
/*
* 注解的解析
* */
public class AnnotationTest3 {
@Test
public void parseClass() {
// 1. 先得到Class对象
Class c = Demo.class;
// 2. 解析类上的注解
// 判断类上是否包含了注解
if(c.isAnnotationPresent(MyTest4.class)) {
MyTest4 myTest4 = (MyTest4) c.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
}
}
应用场景:结合反射等做框架
整理:就是做框架的时候会自定义很多注解,说明怎么执行这段程序(功能),那别人使用这个功能就要完成一些操作,这个时候就要用到反射,拿出类信息、构造器信息、成员变量和方法等信息,执行一些初始化、取值赋值、执行等一些操作。
程序为什么需要代理
对象如果干的事太多,可以通过代理来转移部分职责
代理的样子
对象有什么方法想被代理,代理一定要有对应的方法
代理如何知道有什么方法需要代理
接口:想代理的方法
案例:
BigStar
public class BigStar implements Star{
private String name;
public BigStar(String name) {
this.name = name;
}
// 唱歌行为
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "唱完了!谢谢大噶!";
}
// 跳舞行为
public void dance() {
System.out.println(this.name + "正在跳舞!");
}
}
想要代理的接口类Star
// 指明有哪些方法需要被代理
public interface Star {
String sing(String name);
void dance();
}
代理对象的类
public class ProxyUtil {
// 生成代理对象,并返回
public static Star creatrProxy(BigStar bigStar) {
// Java为产生代理,设计了Proxy类。java.lang.reflect
/* newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)*/
// 参数1:用于指定一个类的加载器
// 参数2:指定生成的代理的样子,也就是方法,接口数组
// 参数3:指定生成的代理对象要干什么事情,InvocationHandler是一个接口,也就是要实现一个匿名内部类,指定对象要要干的事情
Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[]{Star.class}, new InvocationHandler() {
@Override // 回调方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理对象,要调用的方法,调用的方法需要传递的参数
// 代理对象要做的事情
if (method.getName().equals("sing")) {
System.out.println("准备话筒,收钱20万"); // 代理要干的事情
// return method.invoke(bigStar, args);
} else if(method.getName().equals("dance")) {
System.out.println("准备场地,收钱1000万");
// return method.invoke(bigStar, args);
}
return method.invoke(bigStar, args);
}
}); // 产生一个代理对象
return starProxy;
}
}
主程序
public class Test {
public static void main(String[] args) {
BigStar s = new BigStar("杨");
Star starProxy = ProxyUtil.creatrProxy(s);
String rs = starProxy.sing("好日子");
System.out.println(rs);
starProxy.dance();
}
}
一些通用的功能可以通过代理在不修改原代码的情况下,为不同对象添加通用功能