一、枚举介绍

1.1 问题引出

要求创建季节(Season)对象,请设计并完成
class Season {
private String name;
private String desc;
//构造器
//getXXX
//setXXX
}

  1. package com.hspedu.enum_;
  2. public class Enumeration01 {
  3. public static void main(String[] args) {
  4. Season spring = new Season("春","春暖花开");
  5. Season summer = new Season("夏","夏日炎炎");
  6. Season autumn = new Season("秋","秋高气爽");
  7. Season winter = new Season("冬","寒冬凛冽");
  8. //因为对于季节而言,它的对象(具体值),是固定的四个,不会有更多
  9. //按传统的写法, 不能体现季节是固定的四个对象
  10. //优化方案 ===> 枚举类
  11. Season other = new Season("它天","~~~~~")
  12. }
  13. }

创建Season对象有如下特点

  1. 季节的值是有限的几个值(Spring,Summer,Autumn,Winter)
  2. 只读,不要修改

1.2 枚举简述

  1. 枚举对应英文(enumeration,简写enum)
  2. 枚举是一组常量的集合
  3. 可以这样理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象

1.3 枚举的两种实现方式

  1. 自定义类实现枚举
    1. 不需要提供 setXXX方法,因为枚举对象值通常为只读
    2. 对枚举对象/属性使用 final + static 共同修饰,实现底层优化
    3. 枚举对象名通常使用全部大写,同常量的命名规范
    4. 枚举对象根据需要,也可以有多个属性 ```java package com.hspedu.enum_;

public class Season { private String name; private String desc; //自定义类实现枚举 //1. 将构造器设为私有,防止创建对象 //2. 去掉setXXX方法 //3. 在本类内部创建一组对象 //4. 优化, 可以加入 static final 修饰符,这样就不会每次调用都加载类 private Season(String name, String desc) { this.name = name; this.desc = desc; }

  1. public String getName() {
  2. return name;
  3. }
  4. public String getDesc() {
  5. return desc;
  6. }
  7. public static final Season SPRING = new Season("春","春暖花开");
  8. public static final Season SUMMER = new Season("夏","夏日炎炎");
  9. public static final Season AUTUMN = new Season("秋","秋高气爽");
  10. public static final Season WINTER = new Season("冬","寒冬凛冽");
  11. public String toString() {
  12. return "Season{" +
  13. "name='" + name + '\'' +
  14. ", desc='" + desc + '\'' +
  15. '}';
  16. }

}

  1. ```java
  2. package com.hspedu.enum_;
  3. public class Enumeration02 {
  4. public static void main(String[] args) {
  5. System.out.println(Season.SPRING);
  6. System.out.println(Season.SUMMER);
  7. System.out.println(Season.AUTUMN);
  8. System.out.println(Season.WINTER);
  9. }
  10. }
  1. 使用enum 关键字实现枚举

当我们使用enum 关键字来开发枚举类时,默认会继承 Enum类,而且是一个final类【可以用 javap 反编译验证】

  1. 传统的 public static final Season2 SPRING = new Season2(“春天”,”温暖”); 简化成 SPRING(“春天”,”温暖”),这里必须知道,它调用的是哪个构造器
  2. 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
  3. 当有多个枚举对象时,使用,逗号间隔,最后有一个分号结尾
  4. 枚举对象必须放在枚举类的行首

    1. enum Season2 {
    2. //使用enum 实现枚举类
    3. //1. 使用关键字 enum 代替 class
    4. //2. 直接使用 SPRING("春","春暖花开")创建对象,
    5. // SPRING("春","春暖花开") 解读:常量名(实参列表)
    6. //3. 多个对象使用逗号分隔,最后一个对象用分号结束
    7. //4. 要求把定义常量写在最前面
    8. SPRING("春","春暖花开"),
    9. SUMMER("夏","夏日炎炎"),
    10. AUTUMN("秋","秋高气爽"),
    11. WINTER("冬","寒冬凛冽"),
    12. What; //调用无参构造器可省略()
    13. private String name;
    14. private String desc;
    15. private Season2(String name, String desc) {
    16. this.name = name;
    17. this.desc = desc;
    18. }
    19. private Season2() {
    20. //无参构造器
    21. }
    22. public String getName() {
    23. return name;
    24. }
    25. public String getDesc() {
    26. return desc;
    27. }
    28. public String toString() {
    29. return "Season2{" +
    30. "name='" + name + '\'' +
    31. ", desc='" + desc + '\'' +
    32. '}';
    33. }
    34. }

    1.4 小练习

  1. 下面代码是否正确,并说明表示的含义。
    enum Gender {
    BOY,GIRL;
    }
    答案:

    1. 上面语法是正确的
    2. 有一个枚举类Gender,没有属性
    3. 有两个枚举对象 BOY,GIRL,使用的无参构造器创建
  2. 下面代码输出什么?
    enum Gender2 {
    BOY,GIRL;
    }
    Gender2 boy = Gender2.BOY;
    Gender2 boy2 = Geder2.BOY;
    System.out.println(boy); //输出BOY 本质就是调用 Gender的父类 Enum的 toString()
    System.out.println(boy == boy2); //输出 true

二、Enum类成员方法

说明:使用关键字 enum 时,会隐式继承 Enum类,这样我们就可以使用 Enum类的相关方法

2.1 Enum 常用方法一览表

image.png

  1. toString() : Enum重写了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息
  2. name() : 返回当前对象名(常量名),子类中不能重写
  3. ordinal() : 返回当前对象的位置号,从0开始
  4. values() : 返回当前枚举类中所有常量,保存在数组中
  5. valueOf() : 将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
  6. compareTo() : 比较两个枚举常量,比较的就是编号

2.2 案例演示

  1. package com.hspedu.enum_;
  2. /**
  3. * @author HarborGao
  4. * @version 1.0
  5. * 演示 Enum 类的各种方法的使用
  6. */
  7. public class EnumMethod {
  8. public static void main(String[] args) {
  9. Season2 autumn = Season2.AUTUMN;
  10. //输出枚举对象的名字
  11. System.out.println(autumn.name());
  12. //ordinal() 输出的是该枚举对象的次序/编号,从0开始编号
  13. //AUTUMN 枚举对象是第三个,因此输出2
  14. System.out.println(autumn.ordinal());
  15. //从反编译可以看出,value方法,返回Season2数组
  16. //含有定义的所有枚举对象
  17. Season2[] values = Season2.values();
  18. for (Season2 season : values) {
  19. System.out.println(season);
  20. }
  21. //valueOf:将字符串转换成枚举对象,要求字符串必须为已有常量名,否则报异常
  22. //执行流程
  23. //1.根据输入的 "AUTUMN" 到 Season2 的枚举对象去找
  24. //2.如果找到了,就返回,如果没有找到,就报错
  25. Season2 autumn1 = Season2.valueOf("AUTUMN");
  26. System.out.println("autumn1=" + autumn1);
  27. System.out.println(autumn == autumn1);
  28. //compareTo:比较两个枚举常量,比较的就是编号
  29. //1. 就是把 Season2.SPRING枚举对象的编号 与 Season2.SUMMER枚举对象的编号 进行比较
  30. /*
  31. public final int compareTo(E o) { //底层源码
  32. return self.ordinal - other.ordinal;
  33. }
  34. */
  35. //2. 返回的是Season2.SPRING的编号[0] - Season2.SUMMER的编号[1] = -1
  36. System.out.println(Season2.SPRING.compareTo(Season2.SUMMER));
  37. int[] nums = {1, 5, 10, 3};
  38. //普通的 for 循环
  39. for (int i = 0; i < nums.length; i++) {
  40. System.out.println(nums[i]);
  41. }
  42. //增强 for循环
  43. for (int i : nums) { //每次从 nums数组中取1个数据,赋给变量i,全部取出,退出循环
  44. System.out.println("i = " + i);
  45. }
  46. }
  47. }

2.3 enum 注意事项和使用细节

  1. 使用 enum 关键字后,就不能再继承其他类了,因为enum 会隐式继承 Enum,而Java是单继承机制
  2. 枚举类和普通类一样,可以实现接口,形式如下:
    enum 类名 implements 接口1,接口2 { }

2.4 小练习

  1. 声明 Week 枚举类,其中包含星期一至星期日的定义
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY,FRIDAY, SATURDAY, SUNDAY;

  2. 使用 values 返回所有的枚举数组,并遍历,输出下图效果
    image.png

三、注解

3.1 注解的理解

  1. 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌套在代码中的补充信息。
  3. 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替了Java EE 旧版中所遗留的繁冗代码和XML配置等。

3.2 Annotation 基本介绍

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

三个基本的 Annotation:

  1. @Override:限定某个方法,是重写父类方法,该注解只能用于方法
  2. @Deprecated:用于表示某个程序元素(类、方法等)已过时
  3. @SuppressWarnings:抑制编译器警告

3.3 @Override 注解

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

  1. class Father {
  2. public void fly(){
  3. System.out.println("Father fly...");
  4. }
  5. }
  6. class Son extends Father {
  7. //解读:
  8. //1. @Override 注解放在fly方法上,表示子类的fly方法是重写了父类的fly方法
  9. //2. 如果这里没有写 @Override ,依然会重写父类的 fly
  10. //3. 它的作用是,加了@Override 注解,编译器就会去检查该方法是否重写了父类的方法,
  11. // 如果的确重写了,则编译通过,如果没有构成重写,则编译报错
  12. @Oerride
  13. public void fly() {
  14. System.out.println("Son fly...");
  15. }
  16. }

补充说明:@interface的说明
@interface 不是 interface,是一个类(注解类) ,jdk 1.5 之后加入的

@Override 使用说明

  1. @Override 表示指定重写父类的方法(从编译层面验证),如果父类没有 fly方法,则会报错
  2. 如果不写@Override注解,而父类仍有public void fly(){},仍然构成重写
  3. @Override 只能修饰方法,不能修饰其他类,包,属性等等
  4. 查看@Override注解源码为 @Target(ElementType.METHOD),说明只能修饰方法
  5. @Target 是修饰注解的注解,称为元注解

3.4 @Deprecated 注解

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

  1. public class Deprecated_ {
  2. public static void main(String[] args) {
  3. A a = new A();
  4. System.out.println(a.n1);
  5. a.hi();
  6. }
  7. }
  8. //解读:
  9. //1. @Deprecated 修饰某个元素,表示该元素已经过时
  10. //2. 即不再推荐使用,但仍然可以使用
  11. @Deprecated
  12. class A {
  13. @Deprecated
  14. public int n1 = 10;
  15. @Deprecated
  16. public void hi() {
  17. }
  18. }

@Deprecated 使用说明

  1. 用于表示某个程序元素(类、方法等)已过时
  2. 可以修饰方法、类、字段、包、参数 等等
  3. @Target(value = {CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
  4. @Deprecated 的作用可以做到新旧版本的兼容和过渡

3.5 @SuppressWarnings 注解

抑制编译器警告

  1. package com.hspedu.annotation_;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class SuppressWarnings_ {
  5. //解读
  6. //1. 当我们不希望看到这些警告的时候,可以使用 @SuppressWarnings注解 抑制警告信息
  7. //2. 在{""}中,可以写入希望抑制(不显示)警告的信息
  8. //3. 可以指定的抑制警告(见下方)
  9. //4. @SuppressWarnings 的作用范围和放置的位置有关
  10. // 比如 放在 main方法,那么抑制警告的范围就是 main
  11. // 通常放置在具体的语句、方法、类
  12. //5. 看看 @SuppressWarnings 的源码
  13. /*
  14. @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
  15. @Retention(RetentionPolicy.SOURCE)
  16. public @interface SuppressWarnings {
  17. String[] value();
  18. }
  19. */
  20. @SuppressWarnings({"all"})
  21. public static void main(String[] args) {
  22. List list = new ArrayList();
  23. list.add("jack");
  24. list.add("tom");
  25. list.add("merry");
  26. int i = 1;
  27. System.out.println(list.get(1));
  28. }
  29. }

@SuppressWarning 中的属性介绍以及属性说明
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,抑制与未用的程式码及停用的程式码相关的警告

四、JDK 的元 Annotation(元注解,了解)

4.1 元注解的基本介绍

JDK 的元 Annotation 用于修饰其他 Annotation

4.2 元注解的种类

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

4.3 @Retention 注解

说明:
只能用于修饰一个 Annotation 定义,用于指定该Annotation 可以保留多长时间,@Retention 包含一个 RetentionPolicy 类型的成员变量,使用 @Retention 时,必须为该 value 成员变量指定值:

@Retention的三种值

  1. RetentionPolicy.SOURCE:编译器使用后,直接丢弃这种策略的注解
  2. RetentionPolicy.CLASS:编译器将把注解记录在 class 文件中,当运行 Java 程序时, JVM 不会保留这些注解。这是默认值
  3. RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中,当运行Java程序时,JVM 会保留注解,程序可以通过反射获取该注解

4.4 @Target 注解

说明:
用于修饰 Annotation 定义,用于指定被修饰的 Annotation 能用于修饰哪些程序元素。@Target 也包含一个名为 value 的成员变量。
作用范围(限定值):

  1. public enum ElementType {
  2. /** Class, interface (including annotation type), or enum declaration */
  3. TYPE,
  4. /** Field declaration (includes enum constants) */
  5. FIELD,
  6. /** Method declaration */
  7. METHOD,
  8. /** Formal parameter declaration */
  9. PARAMETER,
  10. /** Constructor declaration */
  11. CONSTRUCTOR,
  12. /** Local variable declaration */
  13. LOCAL_VARIABLE,
  14. /** Annotation type declaration */
  15. ANNOTATION_TYPE,
  16. /** Package declaration */
  17. PACKAGE,
  18. /**
  19. * Type parameter declaration
  20. *
  21. * @since 1.8
  22. */
  23. TYPE_PARAMETER,
  24. /**
  25. * Use of a type
  26. *
  27. * @since 1.8
  28. */
  29. TYPE_USE
  30. }

4.5 @Documented 注解

基本说明
用于 指定被该元 Annotation 修饰的 Annotation 类将被 Javadoc 工具提取成文档,即在生成文档时,可以看到该注解。

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

4.6 @Inherited 注解

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

五、章节练习