1.junit单元测试
单元测试:是指对程序中的最小功能单位进行检查和验证,以确认自己编写的程序是否符合预期。
junit单元测试框架是第三方组织开发的一个测试工具。
- 测试代码与主程序是分离的,不影响主程序的业务逻辑
- 上一个测试单元出现问题,对下一个测试单元没有影响
- 可以生成的是报告,测试成功是绿色,测试失败是红色
使用步骤:
- 导jar包:将JUnit的jar包导入到项目中
- 编写测试类:在测试类中编写测试方法,测试方法上需要添加一个@Test注解
- 运行测试方法:查看是红色,还是绿色。
public class StringUtil{ public static void test1(String name){ System.out.println("名字长度:"+name.length()); } public static int test2(String name){ if(name==null){ return -1; } int length = name.length(); return length; } }
public class StringUtilTest { //1.写一个测试方法,测试StringUtil类中的test1方法是否正确 @Test public void test1(){ StringUtil.test1("穆斯林"); } //2.写一个测试方法,测试StringUtil类中的test2方法的返回值是否符合预期 @Test public void test2(){ int result = StringUtil.test2("穆斯林"); //断言:预期的值是3,验证result结果是否是3. Assert.assertEquals(3,result); } }
Junit常用注解:
public class MyTest { //1.测试方法 @Test public void test1(){ System.out.println("test1"); } @Test public void test2(){ System.out.println("test2"); } //2.用来修饰实例方法,在每一个测试方法前执行一次。 @Before public void before(){ System.out.println("===before==="); } //3.用来修饰实例方法,在每一个测试方法后执行一次。 @After public void after(){ System.out.println("===after==="); } //4.用来修饰静态方法,在所有测试方法前只执行一次。 @BeforeClass public static void BeforeClass(){ System.out.println("===BeforeClass==="); } //4.用来修饰静态方法,在所有测试方法后只执行一次。 @AfterClass public static void afterClass(){ System.out.println("===AfterClass==="); } }
2.反射
反射是Java语言的一个重要特性,它允许开发者编写程序去获取一个类的各个组成部分。
反射可以获取到字节码的各个组成部分,并对他们进行使用。
类的各个组成部分其实都是对象(Field,Method,Constructor)
反射获取类的字节码对象
- 任何一个类的字节码对象,它的类型都是Class类型。
- 获取类的字节码有三种方式。
- 1.Class aClass=Class.forName(包名.类名);
- 2.Class aClass=类名.class;
- 3,Class aClass=对象.getClass();
public class Student { public String name; private int age; //空参数的构造器 public Student(){ } //有参数的构造器 private Student(String name, int age){ this.name=name; this.age=age; } public void test1(){ System.out.println("test1"); } public void test2(String name){ System.out.println("test2..."+name); } private int test3(int a,int b){ return a+b; } public void study(){ System.out.println("学生在努力学习"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class Teacher { public void teach(){ System.out.println("老师正在激情的讲课"); } public void eat(){ System.out.println("老师一会要去食堂吃炒河粉"); } }
反射获取构造器对象
- 获取类的字节码(Class对象)
- 调用Class对象的getConstructor()获取构造器(Constructor对象)
- 调用Constructor对象的newInstance()方法,创建类的对象
/* 反射获取构造器对象,并使用构造器创建对象 */ public class Demo2 { public static void main(String[] args) throws Exception { //1.获取Student类的字节码 Class<Student> aClass = Student.class; //2.获取Student类所有公有的构造器对象 Constructor<?>[] arrs = aClass.getConstructors(); for (Constructor<?> arr : arrs) { System.out.println(arr); } //3.获取Student类中所有的构造器对象(包括私有) Constructor<?>[] arrss = aClass.getDeclaredConstructors(); for (Constructor<?> ar : arrss) { System.out.println(ar); } System.out.println("=============================="); //4.获取单个公有的构造器对象 Constructor<Student> con1 = aClass.getConstructor(); System.out.println(con1); //执行con1代表的空参构造方法 Student student1 = con1.newInstance(); System.out.println(student1); //5.获取单个私有的构造器对象 Constructor<Student> con2 = aClass.getDeclaredConstructor(String.class,int.class); System.out.println(con2); //取消权限检查(暴力反射) con2.setAccessible(true); //执行con2代表的有参构造方法 Student obj2 = con2.newInstance("小明", 20); System.out.println(obj2); } }
反射获取成员变量对象
- 先获取类的字节码(Class对象)。
- 调用Class对象的getField("变量名")方法获取Field对象
- 调用Field对象的set/get方法,给成员变量赋值/获取值
//成员变量的反射,并使用 public class Demo3 { public static void main(String[] args) throws Exception { //1.获取Student类的字节码 Class<?> aClass = Class.forName("com.itheima.d2_reflect.Student"); //2.获取Student类所有公有的成员变量对象 Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println(field); } //3.获取Student类中所有的成员变量对象(包括私有) Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("-------------------------------------------"); //创建学生对象 Constructor<?> constructor = aClass.getConstructor(); Object obj = constructor.newInstance(); //4.获取单个公有的成员变量对象 Field name = aClass.getField("name"); //给name这个成员变量设置值。 name.set(obj,"小明"); //获取name这个成员变量的值。 Object o1 = name.get(obj); System.out.println(o1); //5.获取单个私有的成员变量对象 Field age = aClass.getDeclaredField("age"); //因为age是私有的,不能直接使用,需要暴力反射后再使用 age.setAccessible(true); age.set(obj,23); Object o2 = age.get(obj); System.out.println(o2); } }
反射获取方法对象
- 先获取类的字节码(Class对象)
- 调用Class对象的方法获取Method对象
- 调用Method对象的inovke(对象.实际参数)方法,执行方法
/* 通过反射获取成员方法对象(Method对象) */ public class Demo4 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { //1.获取Student类的字节码 Student student=new Student(); Class<? extends Student> aClass = student.getClass(); //2.获取Student类所有公有的成员方法对象 Method[] methods1 = aClass.getMethods(); for (Method method : methods1) { System.out.println(method); } System.out.println("-------------------------------------"); //3.获取Student类中所有的成员方法对象(包括私有) Method[] methods2 = aClass.getDeclaredMethods(); for (Method method : methods2) { System.out.println(method); } System.out.println("-------------------------------------"); Constructor<? extends Student> constructor = aClass.getConstructor(); Student s = constructor.newInstance(); //4.获取单个公有的成员方法对象 Method m1 = aClass.getMethod("test1"); System.out.println(m1); m1.invoke(s); Method m2 = aClass.getMethod("test2", String.class); System.out.println(m2); m2.invoke(s,"hahah"); System.out.println("-------------------------------------"); //5.获取单个私有的成员方法对象 Method m3 = aClass.getDeclaredMethod("test3", int.class, int.class); System.out.println(m3); //暴力反射 m3.setAccessible(true); Object result = m3.invoke(s, 25, 36); System.out.println(result); } }
反射的引用:编写通用框架
- 定义配置文件,约定每一个配置表示的含义
- 使用Properties对象读取配置文件,获取类名和方法名
- 根据类名获取类的字节码对象(Class对象)
- 在根据方法名,获取要执行的方法对象(Method对象)
- 执行方法
public class Demo5 { public static void main(String[] args) throws Exception { //第一步:读取配置文件 //这是一个双列集合,键和值都是Stirng类型 Properties prop = new Properties(); //读取配置文件中的键和值,存储到Properties集合中 prop.load(new FileReader("reflect\\src\\com\\itheima\\d2_reflect\\config.properties")); //第二步:获取键对应的值 String methodName = prop.getProperty("methodName"); //获取方法名 String className = prop.getProperty("className"); //获取类名 //第三步:通过反射加载要执行的类、要执行的方法 //假设类名是com.itheima.Student Class<?> clazz = Class.forName(className); Method m = clazz.getDeclaredMethod(methodName); m.setAccessible(true); //第四步:执行目标方法 //执行目标方法,依赖于一个对象,可以通过字节码创建对象 Object obj = clazz.getConstructor().newInstance(); m.invoke(obj); } }
3.注解:
Java注解又称Java标注。通过Java注解可以给类,方法,变量添加一些标注数据。
程序可以读取代码上的标注数据,从而做出不同的处理。
自定义注解
public @interface 注解名{
public 属性类型 属性名() default 默认值;
}
元注解:(两个)
- @Target:约束自定义注解只能在哪些地方使用
- @Retention:声明注解的生命周期
注解解析:
就是通过反射读取代码上的注解信息,然后做出针对性的处理。
所有的类的成分Class,Method,Field,Constructor,都实现了AnnotatedElement接口,他们都拥有解析注解的方法。
任何一个注解都是Annotation的子类对象
注解+反射编写通用框架