1.单元测试
就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。
1.Junit单元测试框架
优点:可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。不需要程序员去分析测试的结果,会自动生成出测试报告。
2.Junit单元测试框架的常用注解
注解 | 说明 |
@Test | 测试类中的方法必须用它修饰才能成为测试方法,才能启动执行 |
@Before | 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次 |
@After | 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次 |
@BeforeClass | 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次 |
@AfterClass | 用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次 |
2.反射
反射就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量,方法,构造器等)
1.加载类,获取类的字节码:Class对象
Class c1 = 类名.class
调用Class通过方法: public static Class forName(String package)
Object提供的方法: public Class getClass(); Class c1 = 对象.getClass();
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Student.class;
String name = c1.getName(); // 全类名
System.out.println("name = " + name);
String simpleName = c1.getSimpleName(); // 简名: Student
System.out.println("simpleName = " + simpleName);
Class<?> c2 = Class.forName("com.hzj.d1reflect.Student"); // 根据全类名获取类
System.out.println(c2 == c1); // true
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c3 == c2); // true
}
2.获取类的构造器
方法 | 说明 |
Constructor<?>[] getConstructors() | 获取全部构造器(只能获取public修饰的) |
Constructor<?>[] getDeclaredConstructors() | 获取全部构造器(主要存在就能拿到) |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 获取某个构造器(只能获取public修饰的) |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取某个构造器(只要存在就能拿到) |
@Test
public void testGetConstructors() {
// 反射第一步:得到这个类的Class对象
Class<Cat> c = Cat.class;
// 获取类的全部构造器
Constructor<?>[] constructors = c.getConstructors();
// 遍历数组中的每个构造器对象
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.getName() + "-----" + constructor.getParameterCount());
}
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName() + "-----" + declaredConstructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws NoSuchMethodException {
Class<Cat> c = Cat.class;
// 获取某个构造器
Constructor<Cat> constructor = c.getConstructor(); // 无参构造器,public的
Constructor<Cat> declaredConstructor = c.getDeclaredConstructor(); // 无参构造器,所有
System.out.println(constructor.getName() + "-------" + constructor.getParameterCount());
// 获取有参构造器
Constructor<Cat> constructor1 = c.getConstructor(String.class, int.class); // public
Constructor<Cat> declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class); // 所有
}
3.获取类构造器的作用:初始化对象返回
Constructor提供的方法 | 说明 |
T newInstance(Object... initargs) | 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
@Test
public void testGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Cat> c = Cat.class;
// 获取某个构造器
Constructor<Cat> constructor = c.getConstructor(); // 无参构造器,public的
Constructor<Cat> declaredConstructor = c.getDeclaredConstructor(); // 无参构造器,所有
System.out.println(constructor.getName() + "-------" + constructor.getParameterCount());
constructor.setAccessible(true); // 禁止检查访问权限
Cat cat = constructor.newInstance();
System.out.println(cat);
// 获取有参构造器
Constructor<Cat> constructor1 = c.getConstructor(String.class, int.class); // public
Constructor<Cat> declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class); // 所有
constructor1.setAccessible(true);
Cat cat1 = constructor1.newInstance("猫", 2);
System.out.println(cat1);
}
4.获取类的成员变量
方法 | 说明 |
public Field[] getFields() | 获取类的全部成员变量(只能获取public修饰的) |
public Field[] getDeclaredFields() | 获取类的全部成员变量(只要存在就能拿到) |
public Field getField(String name) | 获取类的某个成员变量(只能获取public修饰的) |
public Field getDeclaredField(String name) | 获取类的某个成员变量(只要存在就能拿到) |
5.获取到成员变量的作用:赋值,取值
方法 | 说明 |
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 取值 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
@Test
public void testGetFields() throws NoSuchFieldException, IllegalAccessException {
Class<Cat> c = Cat.class;
// 获取类的全部成员变量
Field[] fields = c.getFields();
Field[] declaredFields = c.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field.getName() + "------------" + field.getType());
}
// Field name = c.getField("name");
Field name1 = c.getDeclaredField("name");
System.out.println(name1.getName() + "---------" + name1.getType());
// 赋值
Cat cat = new Cat();
name1.setAccessible(true);
name1.set(cat, "猫猫");
System.out.println(cat);
// 取值
Object name = name1.get(cat);
System.out.println(name);
}
6.获取类的成员方法
方法 | 说明 |
Method[] getMethods() | 获取类的全部成员方法(只能获取public修饰的) |
Method[] getDeclaredMethods() | 获取类的全部成员方法(只要存在就能拿到) |
Method[] getMethod(String name, Class<?>... parameterTypes) | 获取类的某个成员方法(只能获取public修饰的) |
Method[] getDeclaredMethod(String name, Class<?>... parameterType) | 获取类的某个成员方法(只要存在就能拿到) |
7.成员方法的作用:执行
Method提供的方法 | 说明 |
public Object invoke(Object obj, Object... args) | 触发某个对象的改方法执行 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
@Test
public void testGetMethods() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<Cat> c = Cat.class;
// 获取类的全部成员方法
Method[] methods = c.getMethods();
Method[] declaredMethods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + "------" + method.getParameterCount());
}
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName() + "--------" + declaredMethod.getParameterCount());
}
// 获取某个方法对象
Method run = c.getDeclaredMethod("run");
System.out.println(run.getName() + "---------" + run.getParameterCount() + "-------" + run.getReturnType());
Method eat = c.getDeclaredMethod("eat", String.class);
System.out.println(eat.getName() + "---------" + eat.getParameterCount() + "-------" + eat.getReturnType());
Cat cat = new Cat();
run.setAccessible(true);
run.invoke(cat);
eat.setAccessible(true);
eat.invoke(cat, "饭");
}
3.注解(Annotation)
java代码里的特殊标记,让其他程序根据注解信息来决定怎么执行改程序
注解本质是一个接口,Java中所有注解都是继承了Annotation接口的
@注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口
1.自定义注解
public @interface MyTest1 {
String a();
boolean b() default true;
String[] c();
}
@MyTest1(a = "测试", c = {"a", "b"})
public class AnnotationTest1 {
@MyTest1(a = "测试方法", b = false, c = {""})
public void test() {
}
}
特殊属性名: value
如果注解中只要一个value属性或其他属性都有默认值,使用注解时,value名称可以不写
2.元注解
修饰注解的注解
常见元注解
1.@Target
声明被修饰的注解只能在哪些位置使用
@Target(ElementType.TYPE)
TYPE:类接口
FIELD:成员变量
METHODD:成员方法
PARAMETER:方法参数
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
2.@Retention
声明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
SOURCE:只作用在源码阶段,字节码文件中不存在
CLASS(默认):保留到字节码文件阶段,运行阶段不存在
RUNTIME(开发常用):一直保留到运行阶段
3.注解的解析
就是判断类上,方法上,成员变量上是否存在注解,并把注解里的内容给解析出来。
Class,Method,Field,Constructor都实现了AnnotatedElement接口
AnnotatedElement接口提供了解析注解的方法 | 说明 |
public Annotation[] getDeclaredAnnotations() | 获取当前对象上面的注解 |
public T getDeclaredAnnotation(Class<T> annotationClass) | 获取指定的注解对象 |
public boolean isAnnotationPresent(Class<Annotation> annotationClass) | 判断当前对象上是否存在某个注解 |
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
String value();
double aaa() default 100;
String[] bbb();
}
@MyTest4(value = "测试类", aaa = 99, bbb = {"value1", "value2"})
public class Demo {
@MyTest4(value = "测试方法", aaa = 999, bbb = {"value1m", "value2m"})
public void test1() {
}
}
public class AnnotationTest2 {
@Test
public void parseClass() throws NoSuchMethodException {
// 先得到class对象
Class<Demo> c = Demo.class;
Method m = c.getDeclaredMethod("test1");
// 解析类上的注解
// 判断类上是否包含了某个注解
if (c.isAnnotationPresent(MyTest4.class)) {
MyTest4 myTest4 = c.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
if (m.isAnnotationPresent(MyTest4.class)) {
MyTest4 myTest4 = m.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
}
}
4.动态代理
把公共代码提取出来,在特定的方法执行前后执行公共代码
public interface Star {
String sing(String name);
void dance();
}
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 + "跳舞");
}
}
// 创建动态代理类
public class ProxyUtil {
public static Star createProxy(Star star) {
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("准备开始唱歌");
Object invoke = method.invoke(star, args);
System.out.println(invoke);
return invoke;
} else if (method.getName().equals("dance")) {
Object invoke = method.invoke(star);
System.out.println("跳舞结束");
return invoke;
} else {
return method.invoke(star);
}
}
});
return starProxy;
}
}
@Test
public void testProxy() {
BigStar bigStar = new BigStar("杨超越");
Star proxy = ProxyUtil.createProxy(bigStar);
proxy.sing("哇哈哈");
proxy.dance();
}