JAVA笔记(十五):枚举类、注解、异常

枚举类Enumeration

1)枚举对应英文(enumeration,简写enum)

2)枚举是一组常量的集合

3)可以理解为:枚举属于一种特殊的类,里面只包含一组 有限的 特定的 对象

1、自定义类实现枚举

  1. 不需要提供setXxx方法,因为枚举对象值通常为只读

  2. 对枚举对象/属性使用final+static修饰,实现底层优化(类不用加载)

  3. 枚举对象名通常使用全部大写,常量的命名规范

  4. 枚举对象根据需要,也可以有多个属性

public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season.AUTUMN);
        System.out.println(Season.SPRING);
    }
}

//演示自定义枚举实现
class Season {
    private String name;
    private String desc; //描述

    //定义了四个对象
    //public final static:类不用被加载,在外部其他类可以直接调用自定义枚举
    public final static Season SPRING = new Season("春天","温暖");//多个属性(2个)
    public final static Season SUMMER = new Season("夏天","炎热");
    public final static Season AUTUMN = new Season("秋天","凉爽");
    public final static Season WINTER = new Season("冬天","寒冷");

    //1. 构造器私有化-》防止直接new
    //2. 去掉set相关方法-》防止属性被修改(只读不能写)
    //3. 在Season内部,直接创建固定的对象
    private Season(String name, String desc){
        this.name = name;
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

2、enum关键字实现枚举

1)使用注意事项

  1. 使用关键字enum替代class

  2. SPRING(“春天”,“温暖”); ==> 常量名(实参列表) =》根据实参列表判断调用的是哪个构造器

  3. 如果有多个常量(对象),使用,号间隔。最后一个用;号结束

  4. 如果使用enum来实现枚举,要求将定义常量对象写在类体的最前面

  5. 当使用enum关键字开发一个枚举类时,默认会继承Enum类(用javap反编译证明),并且是一个final类

  6. enum后不能再继承其他类(不能有extends关键字),因为底层隐式继承了Enum类
    在这里插入图片描述

  7. 如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略

public class Enumeration03 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        System.out.println(Season2.SPRING);
    }
}

//使用enum关键字来实现枚举类
enum Season2 {
    //使用enum来实现枚举类
    //1. 使用关键字enum替代class
    //2. SPRING("春天","温暖"); ==> 常量名(实参列表)
    //3. 如果有多个常量(对象),使用,号间隔。最后一个用;号结束
    //4. 如果使用enum来实现枚举,要求将定义常量对象写在类体的最前面
    SPRING("春天","温暖"),
    SUMMER("夏天","炎热"),
    AUTUMN("秋天","凉爽"),
    WINTER("冬天","寒冷"),
    OTHER(); //调用的无参构造器,还可以直接简化成OTHER
    private String name;
    private String desc; //描述

    private Season2(){ //无参构造器

    }
    private Season2(String name, String desc){
        this.name = name;
        this.desc = desc;
    }
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

2)enum常用方法说明

说明:使用enum时,会隐式继承Enum类,这样我们可以使用Enum类的相关方法
在这里插入图片描述

public class EnumMethod {
    public static void main(String[] args) {
        //使用Season2 枚举类来演示(只有春夏秋冬四个枚举)
        Season2 autumn = Season2.AUTUMN;
        //【对象调用】name:输出枚举对象的名称
        System.out.println(autumn.name() + "\n"); //AUTUMN

        //【对象调用】ordinal: 输出该美剧对象的次序/编号(从0开始编号)
        System.out.println(autumn.ordinal()+ "\n"); //2

        //【类调用】values: 返回枚举数组,包含定义的所有枚举对象
        Season2[] values = Season2.values();
        for (Season2 season : values) {
            System.out.println(season);
        }
        System.out.println();

        //【类调用】valueOf: 将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
        //功能:根据枚举名找到枚举,获得完整的枚举(包括枚举类属性)
        Season2 autumn1 = Season2.valueOf("AUTUMN");
        System.out.println("autumn1 = " + autumn1);
        System.out.println(autumn == autumn1); //true

        //compareTo:比较两个枚举常量,比较的是编号,①当==0,编号相等 ②当<0,前面的编号比后面的编号小
        //底层:return self.ordinal - other.ordinal;
        //Season2.AUTUMN - Season2.SUMMER编号
        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER)); //1

        //toString:Enum类已经重写过,返回的是当前对象的名字(枚举名),如果自己再在枚举类中重写,则调用自己写的toString方法
        System.out.println(autumn);
    }
}

3)课堂练习

第一题
在这里插入图片描述
Enum的toString方法返回name,就是枚举的名字
在这里插入图片描述

输出:
BOY
true


第二题
在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        Week[] weeks = Week.values();
        for(Week week : weeks){
            System.out.println(week);
        }
    }
}

enum Week {
    MONDAY("星期一"),
    TUESDAY("星期二"),
    WEDNSDAY("星期三"),
    THURSDAY("星期四"),
    FRIDAY("星期五"),
    SATURDAY("星期六"),
    SUNDAY("星期日");

    private String desc;
    private Week(String desc){
        this.desc = desc;
    }

    @Override
    public String toString() {
        return desc;
    }
}

4)enum实现接口

枚举和普通类一样,可以实现接口,如下形式:

enum 类名 implements 接口1,接口2{}

使用实现接口的方法:枚举类名.枚举名.方法名()

public class Test {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing(); //使用实现接口的方法,枚举类名.枚举名.方法名()
    }
}

interface IAA {
    public void playing();
}
enum Music implements IAA{
    CLASSICMUSIC;

    @Override
    public void playing() {
        System.out.println("播放音乐...");
    }
}

注解Annotation

1、JDK内置的基本注解类型

1)@Override

限定某个方法,是重写父类方法。该注解只能用于方法

功能:语法校验


如果写了@Override,编译器就会去检查该方法是否真的重写了父类的方法。

如果的确重写了,则编译通过

如果没有构成重写,则编译错误


@Override定义

在这里插入图片描述

@interface:表示一个注解类

@Target:可以修饰的类型,这里只能修饰METHOD方法

@Target是修饰注解的注解 ==》元注解

2)@Deprecated

用于表示某个程序元素已过时

功能:做一个过渡,版本升级时的兼容过渡
在这里插入图片描述

3)@SuppressWarnings

抑制编译器警告

功能:当我们不希望看到警告信息时,可以使用SuppressWarnings抑制警告信息

用法:

@SuppressWarnings({""})

{""}中,可以写入希望抑制的警告信息

一般方便就是@SuppressWarnings({"all"})

在这里插入图片描述


注意:

SuppressWarnings作用范围和你放置的位置相关

比如:放在main方法头上,作用域就只有main方法,对其他类成员无效

2、元注解(了解):对注解进行注解

在这里插入图片描述
Retention注解
在这里插入图片描述
在这里插入图片描述
Target注解
在这里插入图片描述
Documented注解
在这里插入图片描述
Inherited注解
在这里插入图片描述

内部类、枚举、注解练习题

第一题
在这里插入图片描述
考点:static变量,对不同的对象是共享的
输出:
9.0 red
100 red


第二题
在这里插入图片描述
考点:匿名内部类,调用

第一种方法:匿名内部类作为对象,直接调用方法

public class Test {
    public static void main(String[] args) {
        CellPhone cellPhone = new CellPhone();
        cellPhone.testWork();
    }
}

interface Computer {
    void work();
}
class CellPhone {
    public void testWork(){
        new Computer(){
            @Override
            public void work() {
                System.out.println("手机在工作");
            }
        }.work();
    }
}

第二种方法:匿名内部类作为参数传递

public class Test {
    public static void main(String[] args) {
        CellPhone cellPhone = new CellPhone();
        cellPhone.testWork(new Computer() {
            @Override
            public void work() {
                System.out.println("手机在工作");
            }
        });
    }
}

interface Computer {
    void work();
}
class CellPhone {
    public void testWork(Computer computer){
        computer.work();
    }
}

第三题
在这里插入图片描述
考点:局部内部类,重名属性

public class Test {
    public static void main(String[] args) {
        A a = new A();
        a.m1();
    }
}

class A {
    private final String NAME = "李三";

    public void m1(){
        class B {
            private final String NAME = "张三";
            public void show(){
                System.out.println(NAME);
                System.out.println(A.this.NAME);
            }
        }

        //下面这段代码不能放在class B{}前面,因为classB也是一个局部变量
        //局部变量还没有创建的时候,不能使用它
        B b = new B();
        b.show();
    }
}

第四题

在这里插入图片描述
版本一:通过设置isRiver来判断是否过河,输出只有一句

public class Test {
    public static void main(String[] args) {
        Boolean isRiver = false;
        Person person = new Person("唐僧", null);
        person.work(isRiver);
    }
}

interface Vehicles {
    void work();
}
class Horse implements Vehicles {
    @Override
    public void work() {
        System.out.println("骑马走...");
    }
}

class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println("坐船过...");
    }
}

class Factory {
    //这里,将方法做成static比较方便(不用创建对象)
    public static Horse getHorse(){
        return new Horse();
    }

    public static Boat getBoat(){
        return new Boat();
    }
}

class Person {
    private String name;
    private Vehicles vehicles;

    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }
    //这里涉及到一个编程思路,就是可以把具体的要求,封装成方法 -> 这里就是编程思想
    //如何不浪费属性Vehicle
    public void work(Boolean isRiver){
        //向上转型
        if(isRiver){
            vehicles = Factory.getBoat();
        } else {
            vehicles = Factory.getHorse();
        }
        vehicles.work(); //动态绑定
    }
    public String getName(){
        return name;
    }
}

题目增加条件:唐僧过火焰山,用飞机
版本二:分别调用过河和一般情况,参数额外判断

public class Test {
    public static void main(String[] args) {
        Boolean isRiver = false;
        Person person = new Person("唐僧", null);
        person.Common();
        person.passRiver();
        person.passMountain();
        person.passRiver();
        person.Common();
    }
}

interface Vehicles {
    void work();
}
class Horse implements Vehicles {
    @Override
    public void work() {
        System.out.println("Common:一般情况,骑马走...");
    }
}

class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println("PassRiver:遇到河流,坐船过...");
    }
}
class Plane implements Vehicles {
    @Override
    public void work() {
        System.out.println("PassMountain: 遇到火山,用飞机...");
    }
}

class Factory {
    //存储马:static是公共共享空间
    //饿汉式
    private static Horse horse = new Horse();

    private Factory(){};
    //这里,将方法做成static比较方便(不用创建对象)
    public static Horse getHorse(){
        //返回的马应该是只有一匹马,第一次取到马之后就固定了
        return horse;
    }

    public static Boat getBoat(){
        return new Boat();
    }

    public static Plane getPlane() {
        return new Plane();
    }
}

class Person {
    private String name;
    private Vehicles vehicles;

    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }
    //这里涉及到一个编程思路,就是可以把具体的要求,封装成方法 -> 这里就是编程思想
    //如何不浪费属性Vehicle
    //传入的参数vehicles有三种情况:null、Boat、Horse
    public void passRiver() { //当传入null和Horse时,需要将vehicles改为Boat
        if(!(vehicles instanceof Boat)){
            vehicles = Factory.getBoat();
        }vehicles.work();
    }
    //过火焰山用飞机
    public void passMountain() {
        if(!(vehicles instanceof Plane)){
            vehicles = Factory.getPlane();
        }vehicles.work();
    }
    public void Common() {
        if(!(vehicles instanceof Horse)){
            vehicles = Factory.getHorse();
        }vehicles.work();
    }
    public String getName(){
        return name;
    }
}

第五题
在这里插入图片描述
考点:成员内部类的调用

public class Test {
    public static void main(String[] args) {
        Car car1 = new Car(40.6);
        Car car2 = new Car(41.6);
        Car car3 = new Car(25.6);
        Car car4 = new Car(-3.6);
        car1.m(); //或者car1.getAir().flow();
        car2.m();
        car3.m();
        car4.m();
    }
}

class Car {
    private double temperature;

    public Car(double temperature) {
        this.temperature = temperature;
    }

    class Air {
        public void flow(){
            if(temperature > 40) {
                System.out.println("吹冷气");
            } else if(temperature < 0){
                System.out.println("吹暖气");
            } else {
                System.out.println("关空调");
            }
        }
    }

    public Air getAir(){
        return new Air();
    }
    public void m(){
        Air air = new Air();
        air.flow();
    }
}

第六题
在这里插入图片描述
考点:枚举、枚举再switch中的使用

switch(枚举对象){
	case 枚举名1:
		...
		break;
	case 枚举名2:
		...
		break;
}
public class Test {
    public static void main(String[] args) {
        Color[] colors = Color.values();
        for(Color color : colors){
            switch (color){
                case RED:
                    System.out.println("匹配到红色");
                    break;
                case BLUE:
                    System.out.println("匹配到蓝色");
                    break;
                case BLACK:
                    System.out.println("匹配到黑色");
                    break;
                case YELLOW:
                    System.out.println("匹配到黄色");
                    break;
                case GREEN:
                    System.out.println("匹配到绿色");
                    break;
                default:
                    System.out.println("没有匹配到");
                    break;
            }
        }
    }
}

enum Color implements IA{
    RED(255,0,0),
    BLUE(0,0,255),
    BLACK(0,0,0),
    YELLOW(255,255,0),
    GREEN(0,255,0);
    private int redValue;
    private int greenValue;
    private int blueValue;

    Color(int redValue, int greenValue, int blueValue) {
        this.redValue = redValue;
        this.greenValue = greenValue;
        this.blueValue = blueValue;
    }

    @Override
    public void show() {
        System.out.println("redValue=" + redValue + "  greenValue=" + greenValue + "  blueValue=" + blueValue);
    }
}

interface IA {
    void show();
}

异常Exception

1、异常的概念

  • 异常的出现:

    程序中出现了一个不算致命的问题,就导致整个程序抛出异常后退出(崩溃),这不合理。
    所以在发现异常后,程序仍然能够继续执行,这就是java异常处理机制

  • 异常基本概念:

    java中,将程序执行过程发生的不正常情况称为“异常”(语法错误和逻辑错误和不是异常)

  • 异常分为两类

    • Error(错误):Java虚拟机无法解决的严重错误。如StackOverflowError栈溢出,OOM(out of memory)程序会崩溃。
    • Exception :其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码处理。例如空指针访问,网络连接中断等等。
      • Exception分为两大类:
      • 运行时异常【程序运行时发生的异常】
      • 编译时异常【编程时,编译器检查出的异常】

2、异常体系图⭐⭐⭐

类的异常体系图,体现了继承和实现关系
在这里插入图片描述

小结

在这里插入图片描述

3、常见的异常

① 常见的运行时异常

1)NullPointerException空指针异常
当应用程序试图在需要对象的地方使用null时,抛出该异常

public class Test {
    public static void main(String[] args) {
        String name = null;
        System.out.println(name.length());
    }
}

2)ArithmeticException数学运算异常
当出现异常的运算条件时,抛出此异常,比如除以0

3)ArrayIndexOutOfBoundsException数组下标越界异常
用非法所哟i你访问数组时抛出的异常,如果索引为负或者大于等于数组大小,则该索引为非法索引

4)ClassCastException类型转换异常
当试图将对象强制转换为不是实例运行类型或者其子类时,抛出该异常。(向下向上转型错误)

class A{}
class B extends A{}
class C extends A{}
A a = new B(); //向上转型
B b = (B)a; //向下转型
C c = (C)a; //转型错误,因为a的运行类型是B,和C无关

5)NumberFormatException数字格式不正确异常
当应用程序试图将字符串转换成一种数值类型,但该字符串不能抓换位适当格式时,抛出该异常 =》 使用异常我们可以确保输入的是 满足条件的 数字

String name = "你好";
int num = Integer.parseInt(name);

② 常见的编译异常

1)SQLException //操作数据库时,查询表可能发生异常

2)IOException //操作文件时,发生的异常

3)FILENotFoundException //当操作一个不存在的文件时,发生异常

4)ClassNotFoundException //加载类时,该类不存在,发生异常

5)EOFException //操作文件,到文件末尾,发生异常

6)IllegalArgumentException //参数异常

4、异常处理概念和处理机制图

  1. 基本介绍

异常处理就是当异常发生时,对异常处理的方式

  1. 异常处理的方式

    1)try-catch-finally
    程序员在代码中捕获发生的异常,自行处理

在这里插入图片描述
2)throws
将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM
不用try-catch时,默认用throws(隐式的)
在这里插入图片描述

5、异常处理分类

1)try-catch

  1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块

  2. 如果异常没有发生,则顺序执行try代码块,不会进入到catch

  3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用fianlly{}

public class TryCatchDetail {
    public static void main(String[] args) {
        try {
            String str = "你好";
            int a = Integer.parseInt(str);
            System.out.println("数字:" + a); //1. 一旦发生异常,这句代码不会执行,而是直接进入到catch块
        } catch (NumberFormatException e) {
            System.out.println("异常信息:" + e.getMessage());
        } finally {
            System.out.println("finally代码块被执行...");
        }
        System.out.println("程序继续...");
    }
}
  1. 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch
public class TryCatchDetail {
    public static void main(String[] args) {
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getName()); //NullPointerException
            int n1 = 10;
            int n2 = 0;
            int res = n1 / n2; //ArithmeticException
            //↓下面捕获三种异常,子类在前,父类在后(否则父类异常包含子类异常,子类异常永远用不到)
        } catch (NullPointerException e) {
            System.out.println("空指针异常=" + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("算术异常=" + e.getMessage());
        } catch (Exception e) {
            System.out.println("父类异常=" + e.getMessage());
        } finally {

        }
    }
}

class Person {
    private String name = "jack";
    public String getName() {
        return name;
    }
}
  1. 可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。【应用场景:执行一段代码,不管是否发生异常,都必须执行某个业务逻辑(检测到异常时并不马上崩掉,而是执行完这段finally代码后再崩)】
public class TryCatchDetail {
    public static void main(String[] args) {
        try {
            int n1 = 10;
            int n2 = 0;
            System.out.println(n1 / n2);
        } finally {
            System.out.println("执行了finally..");
        }
        System.out.println("程序继续执行..");
    }
}

输出:
在这里插入图片描述

2)throws

在这里插入图片描述
在这里插入图片描述
注意事项
在这里插入图片描述

3)如下图,NullPointerException是RuntimeException的子类
在这里插入图片描述
4)抛出的(编译)异常有两种处理方式:调用者也抛出异常,或者调用者内部使用try-catch处理异常
在这里插入图片描述
抛出运行异常可以不做处理
在这里插入图片描述

6、自定义异常

基本概念
在这里插入图片描述
自定义异常的步骤
在这里插入图片描述

public class CustomException {
    public static void main(String[] args) /* throws AgeException */{
        int age = 80;

        if(!(age >= 18 && age <= 120)){
            //这里通过构造器,设置信息
            throw new AgeException("年龄需要在18 ~ 120之间");
            //throw和throws的区别看后文
        }
    }
}

//一般继承运行时异常
//如果是继承编译异常Exception,调用者需要throws AgeException
class AgeException extends RuntimeException {
     public AgeException(String message) { //构造器
         super(message);
     }
}

7、throw和throws的对比

在这里插入图片描述

8、异常练习

【第一题】
在这里插入图片描述

输出:
i=4
3


【第二题】
如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        int n = 0;
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.print("请输入一个整数:");
            try {
                n = Integer.parseInt(scanner.next()); //容易有NumberFormatException
                System.out.println("你输入的整数为:" + n);
                break;
            } catch (NumberFormatException e) {
                System.out.println("你输入的不是一个整数,请重新输入!");
            }
        }
    }
}

在这里插入图片描述


【第三题】

下面的测试输出什么
在这里插入图片描述
当try中存在return或者throw时,finally优先于return和throw运行
当存在catch时,catch优先于finally运行
在这里插入图片描述

输出:

在这里插入图片描述


【第四题】
在这里插入图片描述

public class EcmDef {
    public static void main(String[] args) {
        try {
            //ArrayIndexOutOfBoundsException
            if(args.length != 2) {
                throw new ArrayIndexOutOfBoundsException("缺少命令行参数或参数个数不对");
            }
            //NumberFormatException
            int n1 = Integer.parseInt(args[0]);
            int n2 = Integer.parseInt(args[1]);
            //ArithmeticException
            double res = cal(n1, n2);

            //三个异常都通过,则执行下面代码(输出结果)
            System.out.println("n1/n2 => " + n1 + "/" + n2 + "=" + cal(n1, n2));
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("缺少命令行参数");//注意,空指针异常是有数组元素,只不过没有初始化,而不是缺少元素(命令行参数)
        } catch(NumberFormatException e) {
            System.out.println("数据格式不正确");
        } catch(ArithmeticException e) {
            System.out.println("不能除0");
        }
    }

    public static double cal(int n1, int n2) {
        return n1 / n2;
    }
}

【第五题】

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


【第六题】
写出运行结果
在这里插入图片描述

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值