JAVA-基础加强

第一节 Junit单元测试

测试分类:
1、黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望值
2、白盒测试:需要写代码,关注程序具体的执行流程

Junit使用:白盒测试
使用步骤:
1、定义一个测试类
建议:测试类名:被测试的类名Test
包名:XXX.XX.XX.test
2、定义测试方法:可以独立运行
建议:方法名:test测试的方法名
返回值:void
参数列表:空参
3、给方法加注解@Test
4、导入junit依赖环境
判断结果:
红色:代表失败
绿色:代表成果
一般会使用断言操作来处理结果
Assert.assertEquals(期望的结果, 运算的结果);

//计算器类
public class Calculator {
    public int add(int a, int b){
        return a + b;
    };
    public int sub(int a, int b){
        return a - b;
    }
}
import Demo01.Junit.Calculator;
import org.junit.Assert;
import org.junit.Test;

public class CalculatorTest {
    //测试add方法
    @Test
    public void testAdd(){
        //System.out.println("我被执行了");
        Calculator c = new Calculator();
        int result = c.add(1, 2);
        //System.out.println(result);
        //断言 我断言这个结果是3
        Assert.assertEquals(3, result);
    }
    //测试sub方法
    @Test
    public void testSub(){
        Calculator c = new Calculator();
        int result = c.sub(3, 2);
        Assert.assertEquals(1,result);
    }
}

初始化方法:
用于资源申请,所有测试方法在执行之前都会先执行该方法
释放资源方法:
在所有测试方法执行完毕后,都会自动执行该方法

@Before
    public void init(){
        System.out.println("init...");
    }
@After
    public void close(){
        System.out.println("close...");
    }

第二节 反射

反射:框架设计的灵魂
框架:半成品软件,可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制

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

2.1 获取Class类对象的方式

1、Class.forName(“全类名”):将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2、类名.class:通过类名的属性class获取
多用于参数的传递
3、对象.getClass():getClass()方法在Object类中定义
多用于对象的获取字节码的方式

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个

public class ReflectDemo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //Class.forName("全类名")
        Class cls = Class.forName("Demo01.domain.Person");
        System.out.println(cls);
        //类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //对象.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);
        //比较三个对象 ==
        System.out.println(cls == cls2);//true
        System.out.println(cls == cls3);//true
    }
}

2.2 使用Class类对象

Class对象功能:
1、获取功能

获取成员变量们
获取构造方法们
获取成员方法们
获取类名

//获取成员变量们
public class ReflectDemo02 {
    public static void main(String[] args) throws Exception {
        Class personClass = Person.class;
        //getFields()获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //getField(String name)
        Field a = personClass.getField("a");
        //获取成员变量a的值
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value);//null
        //设置a的值
        a.set(p,"小松狮");
        System.out.println(p);
        System.out.println("==========");
        //getDeclaredFields()获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        //getDeclaredField(String name)
        Field d = personClass.getDeclaredField("d");
        //忽略访问权限修饰符的安全检查
        d.setAccessible(true);//暴力反射
        Object value2 = d.get(p);
        System.out.println(value2);//null
    }
}
//获取构造方法们
public class ReflectDemo03 {
    public static void main(String[] args) throws Exception {
        Class personClass = Person.class;
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        //创建对象newInstance方法
        Object person = constructor.newInstance("小松狮", 19);
        System.out.println(person);
        System.out.println("=======");
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        //创建对象newInstance方法
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
        //如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
        Object o = personClass.newInstance();
        System.out.println(o);
    }
}
//获取成员方法们
public class ReflectDemo04 {
    public static void main(String[] args) throws Exception {
        Class personClass = Person.class;
        //获取指定名称的方法getMethod
        Method eat_method = personClass.getMethod("eat");
        Person p = new Person();
        eat_method.invoke(p);
        Method eat_method1 = personClass.getMethod("eat", String.class);
        eat_method1.invoke(p,"饭饭");
        //获取所有public修饰的方法getMethods()
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //获取方法名getName()
            String name = method.getName();
            System.out.println(name);
        }
        //获取全类名
        String name = personClass.getName();
        System.out.println(name);
    }
}

2.3 案例

需求:写一个“框架”,不能改变该类的任何代码前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

实现:
1、配置文件
2、反射
步骤:
1、将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2、在程序中加载读取配置文件
3、使用反射技术来加载类文件进内存
4、创建对象
5、执行方法

配置文件
className=Demo01.domain.Student
methodName=sleep
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

//框架类
public class ReflectTest {
    public static void main(String[] args) throws Exception{
        /*
            前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
         */
        /*Person p = new Person();
        p.eat();*/
        /*Student s = new Student();
        s.sleep();*/
        //1、加载配置文件
        //1.1 创建Properties对象
        Properties prop = new Properties();
        //1.2 加载配置文件,转换为一个集合
        //1.2.1 获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        prop.load(is);
        //2、获取配置文件中定义的数据
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");
        //3、加载该类进内存
        Class cls = Class.forName(className);
        //4、创建对象
        Object obj = cls.newInstance();
        //5、获取方法对象
        Method method = cls.getMethod(methodName);
        //6、执行方法
        method.invoke(obj);
    }
}

第三节 注解

注释:用文字描述程序的,给程序员看的
注解:说明程序的,给计算机看的
概念描述:JDK1.5之后的新特性,说明程序的,使用注解:@注解名称

JDK中预定义的一些注解
@Override:检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告,一般传递参数all,@SuppressWarnings(“all”)

@SuppressWarnings("all")
public class AnnoDemo01 {
    @Override
    public String toString(){
        return super.toString();
    }
    @Deprecated
    public void show1(){
        //有缺陷
    }
    public void show2(){
        //替代show1方法
    }
    public void demo(){
        show1();
        show2();
    }
}

3.1 自定义注解

/*
自定义注解
格式:
    元注解
    public @interface 注解名称{
        属性列表
    }
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
    public interface MyAnno extends java.lang.annotation.Annotation{}
属性:接口中可以定义的抽象成员方法
    要求:
     1、属性的返回值类型:基本数据类型、String、枚举、注解、以上类型的数组
     2、定义了属性,在使用时要给属性赋值
        (1)如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行属性的赋值
        (2)如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可
        (3)数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略
元注解:用于描述注解的注解
    @Target:描述注解能够作用的位置
        ElementType取值:
            TYPE:可以作用于类上
            METHOD:可以作用于方法上
            FIELD:可以作用于成员变量上
    @Retention:描述注解被保留的阶段
        @Retention(RetentionPolicy.RUNTIME):当前被描述的注解会保留到class字节码文件中,并被JVM读取到
    @Documented:描述注解是否被抽取到api文档中
    @Inherited:描述注解是否被子类继承
 */
public @interface MyAnno {
    int value();
    String name() default "小松狮";//默认取值
}
@MyAnno(18)
public class Person {
}
import java.lang.annotation.*;

@Target(value = {ElementType.TYPE})//表示该MyAnno3注解只能作用于类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnno3 {

}

3.2 解析注解

/*
在程序中使用(解析)注解:获取注解中定义的属性值
1、获取注解定义的位置的对象(Class,Method,Field)
2、获取指定的注解
    getAnnotation(Class)
3、调用注解中的抽象方法获取注解的配置属性值
 */
public class Demo1 {
    public void show(){
        System.out.println("demo1...show...");
    }
}
/*
描述需要执行的类名和方法名
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}
import java.lang.reflect.Method;

@Pro(className = "Day20.Demo01.Demo1",methodName = "show")
public class ReflectTest {
    public static void main(String[] args) throws Exception{
        /*
            前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
         */
        //解析注解,获取该类的字节码文件对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //获取注解对象
        Pro annotation = reflectTestClass.getAnnotation(Pro.class);
        String className = annotation.className();
        String methodName = annotation.methodName();
        System.out.println(className);
        System.out.println(methodName);
        //3、加载该类进内存
        Class cls = Class.forName(className);
        //4、创建对象
        Object obj = cls.newInstance();
        //5、获取方法对象
        Method method = cls.getMethod(methodName);
        //6、执行方法
        method.invoke(obj);
    }
}

3.3 异常测试案例

//定义的计算器类
public class Calculator {
    @Check
    public void add(){
        System.out.println("1 + 0 = " + (1 + 0) );
    }
    @Check
    public void sub(){
        System.out.println("1 - 0 = " + (1 - 0) );
    }
    @Check
    public void mul(){
        System.out.println("1 * 0 = " + (1 * 0) );
    }
    @Check
    public void div(){
        System.out.println("1 / 0 = " + (1 / 0) );
    }
    public void show(){
        System.out.println("无Bug!");
    }
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestCheck {
    public static void main(String[] args) throws IOException {
        //创建计算器类对象
        Calculator calculator = new Calculator();
        //获取字节码文件对象
        Class aClass = calculator.getClass();
        //获取所有方法
        Method[] methods = aClass.getMethods();
        int number = 0;//出现异常的次数
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
        for (Method method : methods) {
            if (method.isAnnotationPresent(Check.class)){
                try {
                    method.invoke(calculator);
                } catch (Exception e) {
                    number++;
                    bw.write(method.getName() + "方法出异常了");
                    bw.newLine();
                    bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("异常的原因:" + e.getCause().getMessage());
                    bw.newLine();
                    bw.write("---------------");
                    bw.newLine();
                }
            }
        }
        bw.write("本次测试出现了" + number + "次异常");
        bw.flush();
        bw.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值