Java高级技术
单元测试:Junit单元测试框架
针对于最小的功能单元:方法
,编写测试代码对于其进行正确性测试
自动测试全部方法
样例:
package junittest;
public class StringUtil {
public static int getLength(String str) {
if (str == null||"".equals(str)){
return -1;
}
return str.length();
}
public static int getMaxIndex(String str){
if (str == null||"".equals(str)){
return -1;
}
return str.length();
}
}
public class StringUtilTest {
@Test
public void testGetLength(){
StringUtil.getLength("abc");
StringUtil.getLength("");
// StringUtil.getLength(null);
}
@Test
public void testGetMaxIndex(){
System.out.println(StringUtil.getMaxIndex("abc"));//实际上应该为2
System.out.println(StringUtil.getMaxIndex(""));
System.out.println(StringUtil.getMaxIndex(null));
// TODO:进行断言测试
Assert.assertEquals("测试结果与预期目标不一致",2,StringUtil.getMaxIndex("abc"));
}
}
反射(reflection)
用于加载类,并且允许已变成的方式 解剖类中的各种成分(成员变量,方法,构造器)
第一步:获取Class类对象
// TODO:掌握反射:获取类的Class对象(获取类本身)
// 通过类名获取Class
Class c1 = Student.class;
// 通过对象获取Class
Class c2 = new Student().getClass();
第二步:获取类中的成分并进行操作
类中的成分:(Constructor构造器,Field成员变量,Method成员方法)
反射中建议调用getDeclaredXxx方法,获取的都是声明的成员变量和方法,包括私有的,不包括继承的
@Test
public void testGetClassInfo(){
// TODO:获取类的信息
Student s = new Student("张三", 20, "清华大学");
Class c = s.getClass();
System.out.println(c.getName());
System.out.println(c.getSimpleName());//获取类名
//获取对应的构造器(getConstructors()获取所有构造器,其中返回的是该对象的公开的构造器的数组)
System.out.println(Arrays.toString(c.getConstructors()));
System.out.println(Arrays.toString(c.getMethods()));
}
@Test
public void testGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 获取类的构造器
Class c = Student.class;
//获取所有的公开的构造器,并返回为一个数组 (getConstructors()获取所有构造器,其中返回的是该对象的公开的构造器的数组)
System.out.println(Arrays.toString(c.getConstructors()));
//获取所有的构造器,包括私有的,并返回为一个数组 (getDeclaredConstructors()获取所有构造器,其中返回的是该对象的所有构造器的数组)
System.out.println(Arrays.toString(c.getDeclaredConstructors()));
// TODO:获取对应的无参构造器
Constructor dc1 = c.getDeclaredConstructor();
// TODO:获取对应的有参构造器
// c.getConstructor(String.class,int.class,String.class);
// TODO:获取构造器的作用是创建对象
// 如果构造器是私有的,那么我们就需要通过反射机制来创建对象
dc1.setAccessible(true);//临时将构造器的权限设置为公开的
Student s = (Student) dc1.newInstance();
// Student s= new Student();
System.out.println(s);
}
@Test
public void testGetField() throws NoSuchFieldException, IllegalAccessException {
Class c = Student.class;
// 获取成员变量(getFields()获取所有成员变量,其中返回的是该对象的公开成员变量的数组)
System.out.println(Arrays.toString(c.getDeclaredFields()));
// 获取单个成员变量,通过字段名
System.out.println(c.getDeclaredField("name"));
// TODO:获取成员变量的作用是进行赋值和取值
// 通过反射暴力获取成员变量的值
Field school = c.getDeclaredField("school");
Student s = new Student("张三", 20, "清华大学");
school.setAccessible(true);//临时将成员变量设置为公开
// 通过反射进行赋值---field(school)对应的是该对象的成员变量
school.set(s,"北京大学");//通过这句话对于该对象的这个成员变量进行赋值
System.out.println(s);
// 通过反射进行取值
System.out.println(school.get(s));
}
@Test
public void testGetMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class c = Student.class;
// 获取成员方法(getMethods()获取所有成员方法,其中返回的是该对象的公开成员方法的数组)
System.out.println(Arrays.toString(c.getMethods()));
// 获取单个成员方法,通过方法名
System.out.println(c.getMethod("getAge"));
// TODO:通过反射获取成员方法的作用是进行方法调用
Student s = new Student("张三", 20, "清华大学");
// s.study();为私有的方法不能直接调用
Method study = c.getDeclaredMethod("study");
study.setAccessible(true);
study.invoke(s);//相当于是s.study();
}
反射的应用(通过反射绕过泛型约束)
@Test
public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// TODO:通过反射绕过相关的泛型约束
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
// TODO:由于泛型约束,不能添加其他类型的数据
// list.add(2.9);
// list.add(1);
// 获取类对象
Class c = list.getClass();
// 获取对应的add成员方法
Method add = c.getDeclaredMethod("add", Object.class);
// 通过反射原理去跳过泛型约束
add.invoke(list, 2.9);
add.invoke(list, 1);
System.out.println(list);
}
Java的框架一般都是通过反射设计一些相关通用功能
对于私有的构造器,方法,成员变量的话要进行,通过类名调用getDeclaredXxx获取到的成员变量,方法,构造器,并将其在要使用的时候设置为公开的
// TODO:通过反射获取成员方法的作用是进行方法调用
Student s = new Student("张三", 20, "清华大学");
// s.study();为私有的方法不能直接调用
Method study = c.getDeclaredMethod("study");
study.setAccessible(true);
study.invoke(s);//相当于是s.study();
// TODO:获取构造器的作用是创建对象
// 如果构造器是私有的,那么我们就需要通过反射机制来创建对象
dc1.setAccessible(true);//临时将构造器的权限设置为公开的
Student s = (Student) dc1.newInstance();
// Student s= new Student();
System.out.println(s);
// TODO:获取成员变量的作用是进行赋值和取值
// 通过反射暴力获取成员变量的值
Field school = c.getDeclaredField("school");
Student s = new Student("张三", 20, "清华大学");
school.setAccessible(true);//临时将成员变量设置为公开
// 通过反射进行赋值---field(school)对应的是该对象的成员变量
school.set(s,"北京大学");//通过这句话对于该对象的这个成员变量进行赋值
System.out.println(s);
// 通过反射进行取值
System.out.println(school.get(s));
注解的使用:
自定义注解–》相当于是一个接口继承了Annotation接口
语法格式:
public @interface 注解名{
数据类型 参数名();
}
使用注解的方法
@注解名(…)参数为定义参数名,以及为相关的用法进行赋值
如果说是只有一个value没有定义默认值的话
@注解名(“delete”)—>相当于就是@注解名(value=“delete”)
public @interface A {
//value为一个特殊的注解属性,如果在只有一个属性时,value可以省略
String value();
String name() default "Java";
}
元注解(注解-》注解的注解)
// 表示该注解只能用于类和成员变量上
@Target({ElementType.TYPE,ElementType.FIELD})
// 表示该注解在运行时生效--》一直都有效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
JUnit注解模拟@MyTest
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AnnotationDemo {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
// TODO:搞清楚注解的应用场景,模拟junit框架
// 有MyTest的注解就执行
// TODO:步骤流程
// 1、获取类对象
Class c = AnnotationDemo.class;
// 2、获取这个类中所有方法
Method[] methods = c.getDeclaredMethods();
// 3、遍历所有的方法,判断是否有MyTest注解
for(Method m:methods){
if(m.isAnnotationPresent(MyTest.class)){
// 获取这个注解
MyTest myTest = m.getDeclaredAnnotation(MyTest.class);
// 获取注解中的count值
int count = myTest.count();
for(int i=0;i<count;i++){
m.invoke(new AnnotationDemo());
}
// // 有就执行
// m.invoke(new AnnotationDemo());
}
}
}
// JUnit的测试方法都是public void
@MyTest
public void Test(){
System.out.println("test");
}
public void Test2(){
System.out.println("test2");
}
@MyTest
public void Test3(){
System.out.println("test3");
}
@MyTest(count = 3)
public void Test4(){
System.out.println("test4");
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 表示该注解只能用于方法上
@Target({ElementType.METHOD})
// 表示该注解在运行时生效--》一直都有效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
int count() default 1;//表示执行的次数
}