Skip to content

0424 0442 第十一章 枚举和注解

11.1 先看一个需求

要求创建季节 (Season) 对象,请设计并完成。

class Season{//类
    private String name; 
    private String desc;
    //描述
    //构造器
    //getXX 
    //setXX
}

11.2 分析问题

11.2.1 创建 Season 对象有如下特点

1) 季节的值是有限的几个值 (spring, summer, autumn, winter)

2) 只读,不需要修改。


11.3 解决方案-枚举

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

  2. 枚举是一组常量的集合。

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


11.4 枚举的二种实现方式

  1. 自定义类实现枚举

  2. 使用 enum 关键字实现枚举


11.5 自定义类实现枚举-应用案例

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

  2. 对枚举对象 / 属性使用 final + static 共同修饰,实现底层优化.

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

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

  5. 构造器私有化,防止被 new

  6. 本类内部创建一组对象

  7. 对外暴露对象(通过为对象添加 public final static 修饰符)

public class Enumeration {
    public static void main(String[] args) {

    }
}

class Season {
    private String Name;
    private String desc;

    //定义了四个对象, 固定.
    public static final Season SPRING = new Season("春天", "温暖");
    public static final Season WINTER = new Season("冬天", "寒冷");
    public static final Season AUTUMN = new Season("秋天", "凉爽");
    public static final Season SUMMER = new Season("夏天", "炎热");

    private Season(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 = " 
    }

}

11.7 enum 关键字实现枚举-快速入门

如果使用了 enum 来实现枚举类

  1. 使用关键字 enum 替代 class

  2. public static final Season SPRING = new Season("春天", "温暖") 直接使用 SPRING("春天", "温暖")

    常量名(实参列表)

  3. 如果有多个常量 (对象),使用 ,号间隔即可可

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

  5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()

    • SPRING,SUMMER

import java.util.Enumeration;  

public class Main {  
    public static void main(String[] args) {  

    }  
}  

enum Season {  
    SPRING("春天", "春暖花开"),  
    SUMMER("夏天", "烈日炎炎"),  
    AUTUMN("秋天", "秋高气爽"),  
    WINTER("冬天", "冰天雪地");  


    private final String Name;  
    private final String Desc;  

    private Season(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 +  
                '}';  
    }  

}

11.7.2 enum 关键字实现枚举注意事项

  1. 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类

  2. 传统的 public static final Season2 SPRING = new Season2("春天", "温暖"); 简化成 SPRING("春天", "温暖"),这里必须知道,它调用的是哪个构造器

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

  4. 当有多个枚举对象时,使用 , 间隔,最后有一个分号结尾

  5. 枚举对象必须放在枚举类的行首


11.9 enum 常用方法说明

使用关键字 enum 时,会隐式继承 Enum 类, 这样我们就可以使用 Enum 类相关的方法。 public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { }


11.10 enum 常用方法应用实例

方法名 描述
valueOf(Class<T> enumType, String name) 传递枚举类型的 Class 对象和枚举常量名称给静态方法 valueOf,会得到与参数匹配的枚举常量。
toString() 返回当前枚举常量的名称。可以通过重写此方法使返回结果更易读。
equals(Object other) 在枚举类型中可以直接使用 == 比较两个枚举常量是否相等。Enum 提供的 equals 方法内部也是使用 == 实现,存在是为了在 SetListMap 中使用。注意,equals 返回的结果是不可变的。
hashCode() Enum 实现了 hashCode,与 equals 保持一致,返回值是不可变的。
getDeclaringClass() 返回枚举常量所属枚举类型的 Class 对象,可用于判断两个枚举常量是否属于同一枚举类型。
name() 返回当前枚举常量的名称。建议优先使用 toString 方法。
ordinal() 返回当前枚举常量的次序(即在枚举声明中的位置,从 0 开始)。
compareTo(E o) 枚举类型实现了 Comparable 接口,可比较两个枚举常量的大小(按声明顺序排列)。
clone() 枚举类型不可克隆。Enum 实现的 clone 方法仅抛出 CloneNotSupportedException 异常,防止子类实现克隆。

11.11 enum 实现接口

  1. 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制。

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

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


11.12 注解的理解

  1. 注解 (Annotation) 也被称为元数据 (Metadata),用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息。

  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息

  3. 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。

    • 在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。

11.13 基本的 Annotation 介绍

使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素

三个基本的 Annotation:

  1. @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法

  2. @Deprecated: 用于表示某个程序元素 (类, 方法等) 已过时

  3. @SuppressWarnings: 抑制编译器警告


11.14 基本的 Annotation 应用案例

11.14.1 @Override 注解

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

class Father {
    public void fly() {
        System.out.println("Father fly...");
    }
}
class Son extends Father {
    @Override 说明
    public void fly() {
        System.out.println("Son fly....");
    }
}

Override 源码:

@Target(ElementType.MERHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}

@interface 不是 interface, 是注解类是 jdk 5.0 之后加入

@Target 是修饰注解的注解,称为元注解, 记住这个概念.

@Override 使用说明

  1. @Override 表示指定重写父类的方法 (从编译层面验证),如果父类没有 fly 方法,则会报错

  2. 如果不写 @Override 注解, 而父类仍有 public void fly(){}, 仍然构成重写

  3. @Override 只能修饰方法,不能修饰其它类,包,属性等等

  4. 查看 @Override 注解源码为 @Target(ElementType.METHOD), 说明只能修饰方法

  5. @Target 是修饰注解的注解,称为元注解, 记住这个概念.


11.14.2 @Deprecated 注解

@Deprecated: 用于表示某个程序元素 (类, 方法等) 已过时代码

@Deorecated 源码

@Target(value={CONSTRUCTOR, FIELD, LOCAL VARIABLE, METHOD,
PACKAGE, PARAMETER, TYPE})

@Deprecated 使用说明

  1. 用于表示某个程序元素 (类, 方法等) 已过时

  2. 可以修饰方法,类,字段, 包, 参数等等

  3. @Deprecated 的作用可以做到新旧版本的兼容和过渡


11.14.3 @SuppressWarnings 注解

@SuppressWarnings: 抑制编译器警告

@Suppress@Warnings 的使用

//1. 当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息

//2. 在{""} 中,可以写入你希望抑制(不显示)警告信息

//3. 可以指定的警告类型有

// all,抑制所有警告boxing,抑制与封装/拆装作业相关的警告
//cast,抑制与强制转型作业相关的警告
//dep-ann,抑制与淘汰注释相关的警告
//deprecation,抑制与淘汰的相关警告
//fallthrough,抑制与 switch 陈述式中遗漏 break 相关的警告
//finally,抑制与未传回 finally 区块相关的警告
//hiding,抑制与隐藏变数的区域变数相关的警告
//incomplete-switch,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
//javadoc,抑制与 javadoc 相关的警告|
//nls,抑制与非 nls 字串文字相关的警告
//null,抑制与空值分析相关的警告
//rawtypes,抑制与使用 raw 类型相关的警告
//resource,抑制与使用 Closeable 类型的资源相关的警告
//restriction,抑制与使用不建议或禁止参照相关的警告
//serial,抑制与可序列化的类别遗漏 serialVersionUID 栏位相关的警告
//static-access,抑制与静态存取不正确相关的警告
//static-method,抑制与可能宣告为 static 的方法相关的警告
//super,抑制与置换方法相关但不含 super 呼叫的警告
//synthetic-access,抑制与内部类别的存取未最佳化相关的警告
//sync-override,抑制因为置换同步方法而遗漏同步化的警告
//unchecked,抑制与未检查的作业相关的警告
//unqualified-field-access,抑制与栏位存取不合格相关的警告
//unused,抑制与未用的程式码及停用的程式码相关的警告

// 4. 关于 SuppressWarnings 作用范围是和你放置的位置相关
// 比如 @SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main通常我们可以放置具体的语句, 方法, 类.

// 5. 看看 @SuppressWarnings 源码

//(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE 
//(2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}


public static void main(String[] args) {
    List list = new ArrayList(); list.add("jack"); list.add("tom"); list.add("mary");

    int i; System.out.println(list.get(1));

}

public void f1() { // @SuppressWarnings({"rawtypes"})

    List list = new ArrayList();

    list.add("jack"); list.add("tom"); list.add("mary");

// @SuppressWarnings({"unused"}) int i; System.out.println(list.get(1));

}
参数名 描述
all 抑制所有类型的警告(不推荐使用,过于宽泛)。
unchecked 抑制与未检查的类型转换相关的警告,例如使用泛型时未指定类型。
deprecation 抑制使用已废弃(过时)的方法、类或字段的警告。
rawtypes 抑制使用原始类型(未指定泛型的类型)时的警告。
unused 抑制未使用的变量、方法或类的警告。
null 抑制与空指针分析相关的警告。
serial 抑制缺少 serialVersionUID 的警告(适用于实现 Serializable 的类)。
cast 抑制不安全的类型转换警告。
fallthrough 抑制 switch 语句中 case 缺少 break 导致的穿透警告。
finally 抑制 finally 块中可能导致资源泄漏的警告。
resource 抑制未正确关闭资源(如 try-with-resources)的警告。
boxing 抑制基本类型与包装类型之间自动装箱/拆箱的警告。
varargs 抑制可变参数方法中可能导致的类型安全警告。
static-access 抑制通过实例访问静态成员的警告。
synthetic-access 抑制访问编译器生成的合成构造(如内部类访问外部类成员)的警告。
nls 抑制非国际化字符串(非本地化字符串)的警告。
restriction 抑制使用受限 API(如某些 Sun 内部 API)的警告。

说明 - @SuppressWarnings 注解用于抑制编译器生成的特定警告,需谨慎使用,避免隐藏真正的代码问题。 - 参数可以组合使用,例如 @SuppressWarnings({"unchecked", "deprecation"})。 - 建议将注解作用范围尽量缩小(如方法或变量级别),避免在整个类上使用。

SuppressWarnings 源码

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

@SuppressWarnings 的说明

  1. unchecked 是忽略没有检查的警告

  2. rawtypes 是忽略没有指定泛型的警告(传参时没有指定泛型的警告错误)

  3. unused 是是忽略没有使用某个变量的警告错误.

  4. @SuppressWarnings 可以可以修饰的程序元素为, 查看 Target 生成生成 upperssWarnings 时,不用背,直接点击左侧的黄色提示,就可以选择(注意可以指定生成的位置)


11.15 JDK 的元 Annotation (元注解,了解)

11.15.1 元注解的基本介绍

JDK 的元 Annotation 用于修饰其他 Annotation


11.15.2 元注解的种类

  1. Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
  2. Target // 指定注解可以在哪些地方使用
  3. Documented //指定该注解是否会在 javadoc 体现
  4. Inherited //子类会继承父类注解

11.15.3 @Retention

只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy 类型的成员变量,

  • 使用 @Rentention 时必须为该 value 成员变量指定值:

@Retention 的三种值

  1. RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释

  2. RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。这是默认值

  3. RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注解


11.15.4 @Target

用于修饰 Annotation 定义,用于指定被修饰的 Annotation 能用于修饰哪些程序元素 .

@Target 也包含一个名为 value 的成员变量

@Target 源码

@Documented
@Retention(RetentionPolicy.RUNTIME) // 作用范围是 RUNTIME
@Target(ElementType.ANNOTATIOP// ANNOTATION_TYPE 说明 @Target 只能修饰注解
public ©interface Target { // 说明它是注解
    /**
    * Returns an array of the kinds of elements an annotation type
    * can be applied to.
    * @return an array of the kinds of elements an annotation type
    * can be applied to
    */
    ElementType[] value; 

}

11.15.5 @Documented

@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取成文档, 即在生成文档时,可以看到该注解。

说明: 定义为Documented的注解必须设置Retention值为RUNTIME


11.15.5 @Inherited

被它修饰的Annotation 将具有继承性.

如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解