JavaWeb学习(Day1)

Day1学习进度

1.Juit单元测试

2.反射

3.注解

一、Junit单元测试

测试分类:黑盒测试(不需要写代码)、白盒测试(需要写代码,关注具体流程)

Junit是白盒测试中的一种

1.Junit使用:

  • 1.定义一个测试类(测试用例)

规范:

包名:xx.xx.test

类名:xxTest(CalculatorTest)

  • 2.定义测试方法(可以独立运行)

规范:

方法名:testxx(testAdd)

参数:空参(不被调用)

返回值:void(不被调用)

  • 3.给方法加@Test注解(导入junit的包)

2.判定结果

  • 红色:失败
  • 绿色:成功

一般会用断言操作来处理结果

Assert.assertEquals(期望的结果,运行的结果);

3.补充注解

  • @Before 修饰的方法在测试之前被执行

  • @After 修饰的方法在测试之后被执行

注:无论测试方法是否有异常,均会执行

4.例子

//Calculator类
public class Calculator {
    public int add(int a, int b) {
//        int s = 3/0;
        return a+b;
    }

    public int div(int a, int b) {
        return a-b;
    }
}

//Calculator的测试方法
public class CalculatorTest {

    /*
     * 初始化方法:
     * 用于资源申请,所有测试方法在执行之前都会执行该方法
     */
    @Before
    public void init() {
        System.out.println("申请了资源");
    }

    /*
     * 释放资源方法:
     * 所有测试方法在执行完成后都会执行该方法,不论test测试中是否出现异常
     */
    @After
    public void close() {
        System.out.println("释放了资源");
    }

    @Test
    public void testAdd() {
//        System.out.println("...");
        Calculator c = new Calculator();
        int result = c.add(1,1);
        //断言
        Assert.assertEquals(2,result);
        System.out.println("add" + result);
    }

    @Test
    public void testDiv() {
        Calculator c = new Calculator();
        int result = c.div(1,1);
        Assert.assertEquals(0,result);
        System.out.println("div" + result);
    }

}

二、反射(框架设计的灵魂)

反射:将类的各个组成部分封装为其他对象,称为反射机制

框架:半成品的软件(后续基于框架进行软件开发,简化编码)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LTwecjBp-1635858115030)(D:\学习资源\笔记\JavaWeb\Java代码三个阶段.png)]

类加载器

1.反射机制的好处:

  • 1.可以在程序运行过程中,操作这些对象
  • 2.可以解耦,提高程序的可扩展性

2.获取Class对象的方式:

  • Class cls1 = Class.forName("com.company.domain.Person");
    //将字节码文件加载进内存,并返回Class对象
    //多用于配置文件,将类名定义在配置文件中,读取文件,加载类
    
  • Class cls2 = Person.class;
    //多用于参数传递
    
  • Class cls3 = person.getClass();
    //多用于对象获取字节码方式
    

例子:

public class ReflectDemo1 {
    /*
    * 获取Class的三种方式
    */
    public static void main(String[] args) throws Exception {
        //第一种方式:Class.forName("全包名")
        //ClassNotFoundException:包名写错了
        Class cls1 = Class.forName("com.company.domain.Person");
        //第二种方式:类名.class
        Class cls2 = Person.class;
        //第三种方式:对象.getClass()
        Person person = new Person();
        Class cls3 = person.getClass();
        System.out.println(cls1 + " " + cls2 + " " + cls3);
        
        //==比较三个对象的内存地址
        System.out.println(cls1 == cls2); //true
        System.out.println(cls1 == cls3); //true
        //结论:同一个字节码文件(*.class)在一次程序运行过程中只会被加载一次
    }
}

3.Class对象功能

获取功能:获取类名、成员变量们、构造方法们、成员方法们

①获取成员变量

  • 获取成员变量的方法

    • Field[] getFields():获取public修饰的成员变量
    • Field getField(“成员变量名”):获取指定public修饰的成员变量
    • Field[] gettDeclaredFields():获取所有成员变量
    • Field getDeclaredField(“成员变量名”)
  • Field:成员变量的操作

    • 设置值 void set(Object obj, Object value)
    • 获取值 Object get(Object obj)
    • 暴力反射 void setAccessible(boolean flag)
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        Class cls = Person.class;

        //一、获取变量名
        //1.Field[] getFields():获取public修饰的成员变量
        Field[] fields = cls.getFields();
        for (Field field:fields) {
            System.out.println(field);
        }
        System.out.println("---------------------------");

        //2.Field getField("成员变量名"):获取指定public修饰的成员变量
        Field field = cls.getField("a");
        System.out.println(field);

        Person p1 = new Person();
        Object value1 = field.get(p1);//获取了值
        System.out.println(value1);
        field.set(p1,10);//设置了值
        System.out.println(p1);
        System.out.println("============================");

        //3.Field[] gettDeclaredFields():获取所有成员变量
        Field[] fields1 = cls.getDeclaredFields();
        for (Field field1:fields1) {
            System.out.println(field1);
        }

        System.out.println("----------------------------");

        //4.Field getDeclaredField("成员变量名")
        Field field1 = cls.getDeclaredField("d");
        System.out.println(field1);
        Person p2 = new Person();
        //忽略访问权限修饰符的安全检查
        field1.setAccessible(true); //暴力反射
        Object value2 = field1.get(p2); //IllegalAccessException
        System.out.println(value2);
    }
}

②获取构造方法

  • Constructor:构造方法的操作
    • 创建对象 newInstance()

③获取成员方法

  • Method:方法对象
    • Object invoke(Object obj,Object… args)

④获取类名

personClass.getName();//返回全包名

4.案例

用反射机制实现:创建任意类的对象,并执行其中任意的方法

//pro.properties文件

className=com.company.domain.Student
methodName=study

//ReflectTest.java

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        
        //1.加载配置文件
        Properties pro = new Properties();
        //获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        pro.load(resourceAsStream);

        //2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //3.加载该类进内存
        Class aClass = Class.forName(className);

        //4.创建对象
        Object obj = aClass.newInstance();

        //5.获取方法对象
        Method method = aClass.getMethod(methodName);

        //6.执行该方法
        method.invoke(obj);
    }
}

//Student.java

public class Student {
    public void study() {
        System.out.println("卷啊卷啊卷啊卷!");
    }
}

只要修改配置文件,就可以创建任意对象,执行其中的任意方法。

三、注解

注解:

  • 用来说明程序的
  • JDK1.5后的新特性
  • 作用分类:编写文档(生成doc文档)、编译检查、代码分析(使用反射)
  • 使用注解:@注解名称

1.JDK中预定义的一些注解

  • @Override:检测被该注释标注的方法是否是继承自父类(接口)的
  • @Deprecated:标识的内容,表示已过时
  • @SuppressWarnings:压制警告(一般传递“all”)

2.自定义注解

格式:

元注解

public @interface 注解名称{}

①本质

//自定义注解
public @interface MyAnno {
    属性列表;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R1eMm0Fc-1635858115032)(D:\学习资源\笔记\JavaWeb\注解反编译.png)]

反编译后结果(本质:接口,该接口默认继承Annotation接口)

public interface MyAnno extends java.lang.annotation.Annotation {
}

②属性(接口中的抽象方法)

要求:

  • 1.属性的返回值类型:基本数据类型、String、枚举、注解、以上类型的数组
  • 2.定义了属性使用时需要赋值(可以使用default默认;只有一个属性需要赋值,且叫value,可以省略)

③元注解(用于描述注解的注解)

  • @Target:描述注解能够作用的位置(类、方法、成员变量……)
  • @Retention:描述注释被保留的阶段(source、class、runtime)
  • @Documented:描述注解是否被抽取到api文档中
  • @Inherited:描述注解是否被子类自动继承

3.在程序使用(解析)注解

获取注解中定义的属性值

注解一般用来替换配置文件,简化配置文件的工作

  • 1.获取注解定义位置的对象(class,method,field)
  • 2.获取注解(getAnnotation(xx.class))
  • 3.获取注解定义的属性值

例子:创建任意类的对象,并执行其中任意的方法

//Pro.java:注解类

//描述需要执行的类名和方法名
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}

//ReflectTest.java

@Pro(className = "com.company.domain.Student",methodName = "study")
public class ReflectTest {
    public static void main(String[] args) throws Exception {

        //1.解析注解
        //获取该类的字节码文件对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //获取注解
        /**
         * 其实就是在内存中生成了一个该注解接口的子类的实现对象
         * public class ProImpl implements Pro {
         *      public String className() {
         *          return "com.company.domain.Student";
         *      }
         *      public String methodName() {
         *          return "study";
         *      }
         * }
         * */
        Pro annotation = reflectTestClass.getAnnotation(Pro.class);
        //调用注解对象中定义的抽象方法,获取返回值
        String className = annotation.className();
        String methodName = annotation.methodName();

        //2.执行注解中要执行的方法
        Class aClass = Class.forName(className);
        Method method = aClass.getMethod(methodName);
        Object obj = aClass.newInstance();
        method.invoke(obj);
    }
}

//Student.java 同上

4.例子

//Check.java注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}

//Calculator.java

public class Calculator {

    @Check
    public int add() {
        return 1 + 2;
    }

    @Check
    public int div() {
        return 1 - 2;
    }

    @Check
    public int mul() {
        return 1 * 2;
    }

    @Check
    public int dif() {
        return 3 / 0;
    }
}

//TestCheck.java

public class TestCheck {
    public static void main(String[] args) throws IOException {
        //1.创建计算器对象
        Calculator c = new Calculator();
        //2.获取字节码文件对象
        Class aClass = c.getClass();
        //3.获取所有方法
        Method[] methods = aClass.getMethods();

        int num = 0;
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
        //4.判断方法上是否有@Check
        for(Method method:methods) {
            if(method.isAnnotationPresent(Check.class)) {
                try {
                    method.invoke(c);
                } catch (Exception e) {
                    //5.捕获异常,记录到文件中
                    num++;
                    bw.write(method.getName() + "出现异常");
                    bw.newLine();
                    bw.write("异常名称:" + e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("异常原因:" + e.getCause().getMessage());
                    bw.newLine();
                }
            }
        }
        bw.write("共出现了" + num + "次异常");
        bw.flush();
        bw.close();
    }
}

结果

请添加图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值