9.1 枚举

9.1.1 枚举介绍

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

9.1.2 枚举的两种实现方式

  1. 自定义类实现枚举
  2. 使用eunm关键字实现枚举

9.1.3 自定义类实现枚举

9.1.3.1 实现步骤
  1. 构造器私有化(防止外部创建对象实例)
  2. 本类内部创建一组对象
  3. 对外暴露对象(为对象添加 public final static修饰符)
  4. 可以提供get方法,但不要提供set方法
9.1.3.2 示例
public class Enum01 {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.WINTER);
    }
}

class Season {
    private String name;
    private String desc;//描述

    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("冬天","寒冷");

    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 + '\'' +
                '}';
    }
}
9.1.3.3 使用细节
  1. 不需要set方法,因为枚举的对象值通常为只读
  2. 对枚举对象/属性使用final+static共同修饰,实现底层优化
  3. 枚举对象名通常使用大写,常量的命名规范
  4. 枚举对象根据需要,可以有多个属性

9.1.4 enum关键字实现枚举

9.1.4.1 实现步骤
  1. 使用关键字enum替代class
  2. 通过常量名(实参列表)定义常量
  3. 多个常量(对象)使用,隔开
  4. 定义的常量要写在最前边
  5. 如果使用无参构造器,创建常量对象可以省略()
  6. 构造器私有化
  7. 可以有get方法和toString方法
9.1.4.2 示例
public class Enum02 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        System.out.println(Season2.SUMMER);
    }
}
enum Season2 {
    SPRING("春天","温暖"),
    SUMMER("夏天","炎热"),
    AUTUMN("秋天","凉爽"),
    WINTER("冬天","寒冷");

    private String name;
    private String desc;//描述

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

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }
}
9.1.4.3 注意事项
  1. 使用enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类
  2. java 在注解中使用枚举值 java枚举注释_System

  3. 传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”),调用的是两个形参为字符串的构造器
  4. 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
  5. 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
  6. 枚举对象必须放在枚举类的行首
9.1.4.4 练习
enum Gender {
    BOY,GIRL;
}

Gender boy = Gender.BOY;	//OK
Gender boy2 = Gender.BOY;	//OK
System.out.println(boy);	//输出BOY,调用了Gender父类Enum的toString方法,输出了name属性的值
System.out.println(boy == boy2);	//true,同一静态对象,地址赋给了两个引用
9.1.4.5 enum常用方法

java 在注解中使用枚举值 java枚举注释_java 在注解中使用枚举值_02

  1. toString:Enum 类已经重写过了,返回的是当前对象 名,子类可以重写该方法,用于返回对象的属性信息
  2. name:返回当前对象名(常量名),子类中不能重写
  3. ordinal:返回当前对象的位置号,默认从 0 开始
  4. values:返回当前枚举类中所有的常量
  5. valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常!
  6. compareTo:比较两个枚举常量,比较的就是编号!
public class Enum02 {
    public static void main(String[] args) {
        Season2 autumn = Season2.AUTUMN;

        //name()输出枚举对象的名字
        System.out.println(autumn.name());  //AUTUMN
        System.out.println("===============");

        //ordinal()输出的是该枚举对象的次序/编号,从 0 开始编号
        System.out.println(autumn.ordinal());   //2
        System.out.println("===============");

        //values()返回含有 已定义的所有枚举对象 的数组
        Season2[] seasons = Season2.values();
        for (Season2 season : seasons) {
            System.out.print(season + " ");
        }   //SPRING SUMMER AUTUMN WINTER
        System.out.println("\n===============");

        //valueOf():将字符串转换成枚举对象,要求字符串必须
        //为已有的常量名,否则报异常
        Season2 autumn1 = Season2.valueOf("AUTUMN");
        System.out.println("autumn1= " + autumn1);  //autumn1= AUTUMN
        System.out.println(autumn == autumn);   //true
        System.out.println("===============");

        //compareTo():比较两个枚举常量,比较的就是编号,返回前者编号-后者编号的值
        System.out.println(Season2.AUTUMN.compareTo(Season2.SPRING));
    }
}
enum Season2 {
    SPRING("春天","温暖"),
    SUMMER("夏天","炎热"),
    AUTUMN("秋天","凉爽"),
    WINTER("冬天","寒冷");

    private String name;
    private String desc;//描述

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

    public String getName() {
        return name;
    }

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

示例:

public class EnumInterface {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing();	//播放好听的音乐...
    }
}

interface IPlaying {
    public void playing();
}

enum Music implements IPlaying {
    CLASSICMUSIC;

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

9.2 注解(Annotation)

9.2.1 理解

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

9.2.2 介绍

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

三个基本的 Annotation:

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

9.2.3 @Override

  1. @Override表示指定重写父类的方法,如果父类没有该方法,则会报错
  2. 如果不写@Override注解,而子类仍然可以重写父类方法
  3. 如果你写了@Override 注解,编译器就会去检查该方法是否真的重写了父类的方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
  4. @Override只能修饰方法,不能修饰其他(类、包、属性等)
//@Override源码为:
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.SOURCE) 
public @interface Override { }
  1. 查看@Override注解源码为@Target(ElementType.METHOD),说明只能修饰方法
  2. @Target是修饰注解的注解,称为元注解
  3. @interface不是interface,表示一个注解类,jdk5.0后加入的

9.2.4 @Deprecated

  1. 用于表示某个程序元素(类、方法等)已过时
  1. 过时不代表不能用,而是不推荐使用
  1. 可以修饰方法、类、字段、包、参数等等
//源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
  1. @Deprecated的作用可以做到新旧版本的兼容和过渡

示例:

public class Deprecated_ {
    public static void main(String[] args) {
        A a = new A();
        a.hi();
        System.out.println(a.n1);
    }
}
@Deprecated
class A {
    @Deprecated
    public int n1 = 10;
    @Deprecated
    public void hi(){
    }
}

9.2.5 @SuppressWarnings

9.2.5.1 介绍

当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息 ,在{""}中,可以写入你希望抑制(不显示)警告信息,多个类型通过,隔开

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

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

9.2.5.4 源码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}
  1. 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
  2. 该注解类有数组 String[] values() 设置一个数组比如 {“rawtypes”, “unchecked”,“unused”}
9.2.5.5 示例
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
public class SuppressWarnings_ {
    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));
    }
}

9.2.6 jdk的元注解

JDK 的元 Annotation 用于修饰其他 Annotation

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

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

//源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

@Retention 的三种值

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

示例:

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.SOURCE) 
public @interface Override { }
//Override的作用域在SOURCE,当编译器编译时生效,不会写入到.class文件,也不会在runtime(运行时)生效
9.2.6.3 @Target

用于修饰 Annotation 定义,用于指定被修饰的Annotation能用于哪些程序元素,@Target也包含一个名为value的成员变量

//源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

ElementType可取的值有:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

示例:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})//作用范围为:构造器、field、局部变量、方法、包、parameter、type
public @interface Deprecated {
}
9.2.6.4 @Documentd

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

//源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
9.2.6.5 @Inherited

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

9.3 练习

java 在注解中使用枚举值 java枚举注释_开发语言_03

public class Exer9_01 {
    public static void main(String[] args) {
        Color green = Color.GREEN;
        green.show();
        switch (green) {
            case RED:
                System.out.println("匹配到红色");
                break;
            case BLUE:
                System.out.println("匹配到蓝色");
                break;
            case BLACK:
                System.out.println("匹配到黑色");
                break;
            case GREEN:
                System.out.println("匹配到绿色");
                break;
            case YELLOW:
                System.out.println("匹配到黄色");
                break;
            default:
                System.out.println("没有匹配到");
        }
    }
}
enum Color implements ShowColor{
    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(name()+"的属性值为("+redValue+","+greenValue+","+blueValue+")");
    }
}

interface ShowColor {
    public void show();
}