chapter15 Junit&注解&枚举&反射

Junit单元测试

在这里插入图片描述
在这里插入图片描述

没有Junit情况下如何测试

在这里插入图片描述

Junit的使用

在这里插入图片描述

public class CalculatorTest {
    //测试add方法
    @Test//这是注解
    public void testAdd(){
        System.out.println("测试add方法:");
        Calculator cal=new Calculator();
        int add = cal.add(10, 30);
        System.out.println(add);
    }
    //测试minus方法
    @Test
    public void testMinus(){
        System.out.println("测试minus方法:");
        Calculator cal=new Calculator();
        int result = cal.minus(10, 30);
        System.out.println(result);
    }
}

在这里插入图片描述
在这里插入图片描述

//测试add方法
@Test//这是注解
public void testAdd(){
    System.out.println("测试add方法:");
    Calculator cal=new Calculator();
    int result = cal.add(10, 30);
    //System.out.println(result);------>程序的运行结果可以不关注
    //加入断言:预测一些结果,判断一下我预测的结果与实际结果是否一致
    Assert.assertEquals(40,result);//第一个参数是:预测结果,第二个参数是:实际结果
}

long类型可以接int类型的数

@Before;@After

在这里插入图片描述

package com.msb.test;

import nojunit.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @Auther:sky
 * @Date:2022/3/16-03-16-16:06
 * @Description:test
 * @Version:1.0
 */
public class CalculatorTest {
    @Before
    public void init(){
        System.out.println("方法测试开始了");
    }
    @After
    public void close(){
        System.out.println("方法测试结束了");
    }
    //测试add方法
    @Test
    public void testAdd(){

        System.out.println("测试add方法:");
        Calculator cal=new Calculator();
        int result = cal.add(10, 30);
        //System.out.println(result);------>程序的运行结果可以不关注
        //加入断言:预测一些结果,判断一下我预测的结果与实际结果是否一致
        Assert.assertEquals(40,result);

    }
    //测试minus方法
    @Test
    public void testMinus(){
        System.out.println("测试minus方法:");
        Calculator cal=new Calculator();
        int result = cal.minus(10, 30);
        System.out.println(result);
    }
}

注解 Annotation

在这里插入图片描述

注解的实例:文档注解

/**
文档注释
@version 1.0//这个就叫文档注解
@author sky
*/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package anno;

/**
 * @author : sky
 * @version : 1.0
 */
public class Person {
    /**
     * 下面是eat方法,实现了XXX功能
     * @param num1 int 就餐人数
     * @param num2 int 点了几个菜
     */
    public void eat(int num1,int num2){

    }

    /**
     *
     * @param age int 年龄
     * @return int
     * @exception RuntimeException 当年龄过大时
     * @exception IndexOutOfBoundsException 当年龄过小时
     * @see Student
     */
    public int sleep(int age){
        new Student();
        if(age>100){
            throw new RuntimeException();
        }
        if(age<0){
            throw new IndexOutOfBoundsException();
        }
        return age;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JDK内置的3个注解

在这里插入图片描述

public class Student extends Person{
   /*@Override的作用:限定重写的方法,只要重写的方法有问题,就有错误提示*/
    @Override
    public void eat(int num1, int num2) {
        super.eat(num1, num2);
    }
    /*在方法前加入@Deprecated,这个方法就会变成一个废弃方法/过期方法/过时方法*/
    @Deprecated
    public void study(){
        System.out.println("study");
    }
    @SuppressWarnings("unused")//压制未使用警告
    int age=10;

    int num=10;
    @SuppressWarnings({"unused","rwatypes"})//压制警告泛型
    ArrayList al=new ArrayList();
}

在这里插入图片描述

在这里插入图片描述

实现替代配置文件功能的注解

学高级课程再看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义注解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

元注解

在这里插入图片描述

Retention:声明注解生命周期

在这里插入图片描述

RetentionPolicy.SOURCE
在这里插入图片描述

RetentionPolicy.CLASS:如果没有加Retention注解,那么默认为.CLASS状态
在这里插入图片描述

RetentionPolicy.RUNTIME

反射再学

Target:声明可以修饰什么

在这里插入图片描述

Documented(了解即可):提取到API

在这里插入图片描述

Inherited(极少):继承

在这里插入图片描述

枚举

在这里插入图片描述

自定义枚举类:JDK1.5之前

public class Season {
    //属性:
    private final String seasonName;//季节名字
    private final String seasonDesc;//季节描述
    //利用构造器对属性进行赋值
    //构造器私有化,外界不能调用,只能在season内部调用
    private Season(String seasonName,String seasonDesc) {
        this.seasonName=seasonName;
        this.seasonDesc=seasonDesc;
    }

    //提供枚举类的有限的,确定的对象
    public static final Season SPRING =new Season("春天","春暖花开");
    public static final Season SUMMER =new Season("夏天","烈日炎炎");
    public static final Season AUTUMN =new Season("秋天","硕果累累");
    public static final Season WINTER =new Season("冬天","冰天雪地");

    //额外因素:

    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}
public class TestSeason {
    public static void main(String[] args) {
        Season autumn = Season.AUTUMN;
        System.out.println(autumn);
        System.out.println(autumn.getSeasonDesc());
        System.out.println(autumn.getSeasonName());
    }
}

JDK1.5之后使用enum关键字来创建枚举类

在这里插入图片描述

变为下面的枚举类

public enum Season {
    //enum枚举类要求对象(常量)必须放在最开始的位置
    //提供枚举类的有限的,确定的对象
    //多个对象之间用逗号进行链接,最后一个用分号完结
    SPRING ("春天","春暖花开"),
    SUMMER ("夏天","烈日炎炎"),
    AUTUMN ("秋天","硕果累累"),
    WINTER("冬天","冰天雪地");
    //属性:
    private final String seasonName;//季节名字
    private final String seasonDesc;//季节描述
    //利用构造器对属性进行赋值
    //构造器私有化,外界不能调用,只能在season内部调用
    private Season(String seasonName, String seasonDesc) {
        this.seasonName=seasonName;
        this.seasonDesc=seasonDesc;
    }

    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}
public class TestSeason {
    public static void main(String[] args) {
        Season winter = Season.WINTER;
        System.out.println(winter);//WINTER
        //enum关键字对应的枚举类的上层父类是:java.lang.Enum
        //我们自定义的枚举类的父类是Object
        System.out.println(Season.class.getSuperclass().getName());//java.lang.Enum
    }
}

在源码中经常看到别人定义的枚举类的形态:

public enum Season {
    
    SPRING,
    SUMMER,
    AUTUMN, 
    WINTER;
    
}

在这里插入图片描述

Enum类的常用方法

public class TestSeason {
    public static void main(String[] args) {
        //用enum关键字创建的seaseon枚举类的父类是:java.lang.Enum,
        //常用方法子类season可以直接拿来使用:
        //1.toSting:----->获取对象名字
        Season autumn = Season.AUTUMN;
        System.out.println(autumn);

        //2.values:----》返回枚举类对象的数组
        Season[] values = Season.values();
        for(Season s:values){
            System.out.println(s);
        }

        //3.valueOf---->通过对象名字获取枚举对象
        //注意:对象的名字必须传正确,否则抛出异常
        Season autumn1 = Season.valueOf("AUTUMN");
        System.out.println(autumn1);
    }
}

枚举类实现接口

接口:

public interface MeiJu {
    void show();
}

枚举类:

public enum Season implements MeiJu {

    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;


    @Override
    public void show() {
        System.out.println("season");
    }
}

测试:

public class Deno {
    public static void main(String[] args) {
        Season autumn = Season.AUTUMN;
        autumn.show();
        Season summer= Season.SUMMER;
        summer.show();
    }
}

在这里插入图片描述

修改枚举类:

public enum Season implements MeiJu {

    SPRING{
        @Override
        public void show() {
            System.out.println("spring");
        }
    },
    SUMMER{
        @Override
        public void show() {
            System.out.println("summer");
        }
    },
    AUTUMN{
        @Override
        public void show() {
            System.out.println("autumn");
        }
    },
    WINTER{
        @Override
        public void show() {
            System.out.println("winter");
        }
    }
}

运行结果:
在这里插入图片描述

实际应用

public enum Gender {,;
}
public class Person {
    private int age;
    private String name;
    private Gender sex;


    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Gender getSex() {
        return sex;
    }

    public void setSex(Gender sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Person p=new Person();
        p.setAge(19);
        p.setName("sky");
        p.setSex(Gender.);//传入枚举类gender的对象;----》在入口处对参数进行了限制
        System.out.println(p);
    }
}

枚举还可以通过结合switch来处理

public class Test01 {
    public static void main(String[] args) {
        Gender sex=Gender.;
        //switch后面的()可以传入枚举类型
        //switch后面的()可以传入int,short,byte,char,string,枚举;
        // float double,long,boolean都不可以
        switch(sex){
            case:
                System.out.println("girl");
                break;
            case:
                System.out.println("boy");
                break;
        }
    }
}

反射

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

案例

美团外卖—》付款—》要么使用微信要么使用支付宝支付

//接口的制定方:美团外卖
public interface MeiTuan {
    //在线支付功能:
    public abstract void payOnline();
}

微信

public class WeChat implements MeiTuan{
    @Override
    public void payOnline() {
        //具体实现微信支付的功能
        System.out.println("我已经点了外卖,正在使用微信支付");
    }
}

支付宝

public class AliPay implements MeiTuan{
    @Override
    public void payOnline() {
        //具体的支付宝的支付
        System.out.println("我已经点了外卖,正在使用支付宝支付");
    }
}

银行卡

public class BankCard implements MeiTuan{
    @Override
    public void payOnline() {
        System.out.println("点外卖,银行卡支付");
    }
}

实现

public class Test {
    public static void main(String[] args) {
        //定义一个字符串,用来模拟前台的支付方式:
        String str="银行卡";
        if("微信".equals(str)){//不用str.equals("微信")这个,是为了避免空指针异常
            //微信支付:
            //WeChat weChat = new WeChat();
            // weChat.payOnline();
            pay(new WeChat());
        }
        if("支付宝".equals(str)){
            //支付宝支付
            //AliPay aliPay = new AliPay();
            //aliPay.payOnline();
            pay(new AliPay());
        }
        if("银行卡".equals(str)){
            //new BankCard().payOnline();
            pay(new BankCard());
        }
    }
    public static void pay(WeChat wc){
        wc.payOnline();
    }
    //重载
    public static void pay(AliPay ap){
        ap.payOnline();
    }
    public static void pay(BankCard bc){
        bc.payOnline();
    }
}

为了提高代码的扩展性------》面向对象的特性–》多态

public class Test {
    public static void main(String[] args) {
        //定义一个字符串,用来模拟前台的支付方式:
        String str="微信";
        if("微信".equals(str)){//不用str.equals("微信")这个,是为了避免空指针异常
            //微信支付:
            pay(new WeChat());
        }
        if("支付宝".equals(str)){
            //支付宝支付
            pay(new AliPay());
        }
        if("银行卡".equals(str)){
            pay(new BankCard());
        }
    }
    //方法形参是接口,具体传入的是接口的实现类的对象-----》多态的一种形式
    public static void pay(MeiTuan mt){
        mt.payOnline();
    }
}

多态确实可以提高代码的扩展性,但是,扩展性并没有达到最好。

怎么没有达到最好?上面的分支还是需要手动的删除和添加

解决办法:反射机制

利用反射实现上述功能:

public class Demo {
    public static void main(String[] args) throws Exception {
        //利用反射实现上述功能
        //定义一个字符串,用来模拟前台的支付方式:
        String str="fanshe.BankCard";//字符串:实际上就是微信类的全限定路径

        //下面的代码就是利用反射
        Class cls = Class.forName(str);//cls---》Class类的具体的对象---》Alipay字节码信息
        Object o = cls.newInstance();
        Method method = cls.getMethod("payOnline");
        method.invoke(o);
    }
}

其他代码和没用反射前一样

Class类

具体实例向上抽取形成对象--------》类本身就是对象
在这里插入图片描述

获取字节码信息的四种方式

public class Test {
    public static void main(String[] args) throws Exception {
        //案例:以person的字节码信息为案例

        //方式1.通过getClass()方法获取
        Person p=new Person();
        Class c1=p.getClass();
        System.out.println(c1);

        //方式2.通过内置class属性获取
        Class<Person> c2 = Person.class;
        System.out.println(c2);

        System.out.println(c1==c2);//true;获取的是一个字节码信息
        //注意:方式1与方式2不常用

        //方式3.最常用;通过调用Class类提供的静态方法forName()获取
        Class c3=Class.forName("fanbao.Person");//里面传一个person类的全限定路径
        
        //方式4.了解即可;利用类的加载器
        ClassLoader loader = Test.class.getClassLoader();//系统类加载器
        Class<?> c4 = loader.loadClass("fanbao.Person");
    }
}

Class类的具体实例

在这里插入图片描述

public class Demo {
    public static void main(String[] args) {
        //1.类
        Class personClass = Person.class;
        //2.接口
        Class comparableClass = Comparable.class;
        //3.注解
        Class overrideClass = Override.class;
        //4.数组
        int[] arry1={1,2,3};
        Class aClass = arry1.getClass();
        int[] arry2={4,5,6};
        Class aClass1 = arry2.getClass();
        System.out.println(aClass==aClass1);//true;同一个维度,同一个元素类型,得到的字节码就是同一个
        //5.基本数据类型
        Class integerClass = int.class;
        //6.void
        Class voidClass = void.class;
    }
}

获取运行时类的完整结构

//作为一个父类
public class Person implements Serializable {
    //属性
    private int age;
    public String name;

    //方法
    private void eat(){
        System.out.println("eat---------");
    }
    public void sleep(){
        System.out.println("sleep------------");
    }
}
//作为一个子类
@MyAnno("hello")
public class Student extends Person implements MyInterface{
    //属性
    private int sno;
    double hight;
    protected double weight;
    public double score;
    //方法
    @MyAnno("method")
    public String showInfo(){
        return "我是好学生";
    }
    public String showInfo(int a,int b){
        return "重载方法======我是好学生";
    }
    private void work(){
        System.out.println("我是程序媛");
    }
    void happy(){
        System.out.println("做人最重要的就是开心啦!");
    }
    protected int getSno(){
        return sno;
    }
    //构造器
    public Student() {
        System.out.println("空参构造器");
    }
    private Student(int sno){
        this.sno=sno;
    }
    Student(int sno,double weight){
        this.sno=sno;
        this.weight=weight;
    }
    protected  Student(int sno,double hight,double weight){
        this.sno=sno;
    }

    @Override
    @MyAnno("hello my")
    public void myMethod() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", hight=" + hight +
                ", weight=" + weight +
                ", score=" + score +
                '}';
    }
}
public interface MyInterface {
    public abstract void myMethod();
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
    String value();//属性
}

获取构造器和创建对象

public class Test01 {
    public static void main(String[] args) throws Exception {
        //获取字节码信息
        Class  cls= Class.forName("fanbao.Student");
        //通过字节码信息获取构造器
        //getConstructors()方法只能获取被public修饰的构造器
        Constructor[] con1 = cls.getConstructors();
        for(Constructor c:con1){
            System.out.println(c);//只能获取被public修饰的构造器
        }
        System.out.println("-----------------------");
        //getDeclaredConstructors()获取运行时类的全部修饰符的构造器
        Constructor[] con2 = cls.getDeclaredConstructors();
        for(Constructor c:con2){
            System.out.println(c);//所有构造器都可以获取
        }
        System.out.println("-----------------------");
        //获取指定构造器
        //getConstructor()只能得到public修饰的
        //getConstructor()什么都不传得到空构造器
        Constructor con3 = cls.getConstructor();
        System.out.println(con3);
        System.out.println("-----------------------");
        //传可变参数可以得到指定的构造器
        Constructor con4= cls.getConstructor(double.class,double.class);
        System.out.println(con4);
        System.out.println("-----------------------");

        //getDeclaredConstructor可以得到任意修饰的构造器,传参就行
        Constructor con5 = cls.getDeclaredConstructor(int.class);
        System.out.println(con5);
        System.out.println("-----------------------");
        //有了构造器之后就可以创建对象了
        Object o1 = con3.newInstance();
        System.out.println(o1);
        Object o2 = con4.newInstance(170.2, 135.6);
        System.out.println(o2);
    }
}

获取属性和对属性进行赋值

在这里插入图片描述

public class Test02 {
    public static void main(String[] args) throws Exception {
        //获取运行时类的字节码信息
        Class cls=Student.class;
        //获取属性
        //getFields()获取当前运行时类student和父类person中被public修饰的属性
        Field[] fields = cls.getFields();
        for(Field f:fields){
            System.out.println(f);
        }
        System.out.println("------------------------------");
        //getDeclaredFields()获取当前运行时类student的所有属性
        Field[] declaredFields = cls.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println(f);
        }
        System.out.println("------------------------------");
        //获取指定的属性
        Field score = cls.getField("score");
        System.out.println(score);
        System.out.println("------------------------------");
        Field sno = cls.getDeclaredField("sno");
        System.out.println(sno);
        System.out.println("------------------------------");
        //属性的具体结构
        //获取属性名字
        String name = sno.getName();
        System.out.println(name);
        System.out.println("------------------------------");
        //获取属性数据类型
        Class type = sno.getType();
        System.out.println(type.getName());
        System.out.println("------------------------------");
        //获取属性修饰符
        int modifiers = sno.getModifiers();//返回的是修饰符对应的数
        System.out.println(modifiers);
        System.out.println(Modifier.toString(modifiers));//private
        System.out.println("------------------------------");

        //给属性赋值:给属性赋值必须要有对象
        Field sco = cls.getField("score");
        Object obj = cls.newInstance();
        sco.set(obj,98);//给obj对象的score属性设置具体的值
        System.out.println(obj);
    }
}

获取方法和调用方法

public class Test03 {
    public static void main(String[] args) throws Exception {
        //获取字节码信息
        Class<Student> cls= Student.class;
        //获取方法
        //获取被public修饰的运行时类的方法和所有父类的方法
        Method[] methods = cls.getMethods();
        for(Method m:methods){
            System.out.println(m);
        }
        System.out.println("--------------------------");
        //获取运行时类中所有方法,父类不可以
        Method[] methods1 = cls.getDeclaredMethods();
        for(Method m:methods1){
            System.out.println(m);
        }
        System.out.println("--------------------------");
        //获取指定方法
        Method showInfo = cls.getMethod("showInfo");
        System.out.println(showInfo);
        Method showInfo1 = cls.getMethod("showInfo", int.class, int.class);
        System.out.println(showInfo1);
        //private修饰
        Method work = cls.getDeclaredMethod("work",int.class);//注意可能会错
        System.out.println(work);
        //获取方法的具体结构
        //@注解
        //修饰符 返回值类型 方法名(参数列表) throws xxxxx{}
        //名字
        System.out.println(work.getName());
        //修饰符
        System.out.println(Modifier.toString(work.getModifiers()));
        //返回值
        System.out.println(work.getReturnType());
        //参数列表
        Class[] parameterTypes = work.getParameterTypes();
        for(Class c:parameterTypes){
            System.out.println(c);
        }
        //注解
        Method myMethod = cls.getMethod("myMethod");
        Annotation[] annotations = myMethod.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);//只能获取到生命周期是runtime的注解
        }
        //异常
        Class[] exceptionTypes = myMethod.getExceptionTypes();
        for(Class c1:exceptionTypes){
            System.out.println(c1);
        }

        //调用方法
        Student s = cls.newInstance();
        myMethod.invoke(s);//调用s对象的myMethod
        System.out.println(showInfo1.invoke(s, 12, 45));
    }
}

###获取类的 接口,所在包,注解

public class Test04 {
    public static void main(String[] args) {
        //获取字节码信息
        Class<Student> cls= Student.class;
        //获取运行时类的接口
        Class<?>[] interfaces = cls.getInterfaces();
        for(Class c:interfaces){
            System.out.println(c);
        }
        System.out.println("-----------------------");
        //获取父类接口
        //先得到父类的字节码信息在得到接口
        Class superclass = cls.getSuperclass();
        Class[] interfaces1 = superclass.getInterfaces();
        for(Class c:interfaces1){
            System.out.println(c);
        }
        System.out.println("-----------------------");

        //获取运行时类所在的包
        Package aPackage = cls.getPackage();
        System.out.println(aPackage);
        System.out.println(aPackage.getName());

        //获取运行类的注解
        Annotation[] annotations = cls.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);
        }
    }
}

关于反射的面试题

在这里插入图片描述

1=什么时候用反射?

需要体现程序的扩展性和动态性时;

2、没有;(操作private时,确实破坏了)

封装是为了提高代码的安全性

反射提出最重要的目的是为了动态性,封装只是不建议使用private修饰的东西

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值