Java面向对象之枚举和注解

1、枚举

1.1、需求引出

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

package Enumeration01;

public class Enumeration01 {
    public static void main(String[] args) {
        // 要求创建季节(Season) 对象, 请设计并完成
        Season spring = new Season("春天", "温暖");
        Season winter = new Season("冬天", "寒冷");
        Season summer = new Season("夏天", "炎热");
        Season autumn = new Season("秋天", "凉爽");

        // 以下都是不合理的
        autumn.setName("XXX");
        autumn.setDesc("非常的热...");
        // 因为对于季节而已, 他的对象(具体值), 是固定的四个, 不会有更多
        // 按照这个设计类的思路, 不能体现季节是固定的四个对象
        // 因此, 这样的设计不好 ===> 枚举类[枚: 一个一个 举: 例举, 即把具体的对象一个一个例举出来的类, 就称为枚举类]
        Season other = new Season("红天", "~~~");
    }
}

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

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }
}
1.2、分析问题

创建 Season 对象的特点

  1. 季节的值是有限的几个值(spring,summer,autumn,winter)
  2. 只读,不需要修改
1.3、解决方案 ==> 枚举
  1. 枚举对应英文(enumeration, 简写 enum)
  2. 枚举是一组常量的集合
  3. 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象
1.4、枚举的二种实现方式
  1. 自定义类实现枚举
  2. 使用 enum 关键字实现枚
1.4.1、自定义类实现枚举
  1. 不需要提供 setXxx方法,因为枚举对象值通常为只读
  2. 对枚举对象/属性使用 final + static 共同修饰,实现底层优化
  3. 枚举对象名通常使用全部大写,常量的命名规范
  4. 枚举对象根据需要,也可以有多个属性
package Enumeration01;

public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.SUMMER);
        System.out.println(Season.AUTUMN);
        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("冬天", "寒冷");

    // 1. 将构造器私有化, 目的防止直接 new
    // 2. 去掉 setXxx 方法, 防止属性被修改
    // 3. 在 Season 内部, 直接创建固定的对象
    // 4. 优化, 可以加入 final 修饰符
    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 + '\'' +
                '}';
    }
}

自定义类实现枚举的特点

  1. 构造器私有化
  2. 本类内部创建一组对象[四个 春夏秋冬]
  3. 对外暴露对象(通过为对象添加 public final static 修饰符)
  4. 可以提供 get 方法,但是不要提供 set
1.4.2、enum 关键字实现枚举
package Enumeration01;

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

enum Season {
    // 1. 使用关键字 enum 替代 class
    // 2. public static final Season SPRING = new Season("春天", "温暖") 直接使用 SPRING("春天", "温暖")  常量名(实参列表)
    // 3. 如果有多个常量(对象),  使用逗号间隔即可
    // 4. 如果使用 enum 来实现枚举, 要求将定义常量对象写在前面
    // 5. 如果使用的是无参构造器, 创建常量对象, 则可以省略 ()  // What()
    SPRING("春天", "温暖"), SUMMER("夏天", "炎热"),
    AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷");

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

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

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

    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

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

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

  1. 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类,而且是一个 final 类,可以使用 javap 工具来演示
  2. 传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”), 这里必须知道,它调用的是哪个构造器.
  3. 如果使用无参构造器 创建枚举对象,则实参列表和小括号都可以省略
  4. 当有多个枚举对象时,使用逗号间隔,最后有一个分号结尾
  5. 枚举对象必须放在枚举类的行首

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

1.5、案例演示
下面代码是否正确, 并说明表示的含义
enum Gender{
	BOY , GIRL;  // 这里其实就是调用 Gender 类的无参构造器
}
  1. 上面语法是 ok
  2. 有一个枚举类 Gender, 没有属性
  3. 有两个枚举对象 BOY,GIRL,使用的无参构造器创建

在这里插入图片描述

1.6、enum 常用方法说明
1.6.1、定义

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

在这里插入图片描述

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

public class EnumMethod {
    public static void main(String[] args) {
        // 使用 Season 枚举类, 来演示各种方法
        Season autumn = Season.AUTUMN;

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

        // 输出的是该枚举对象的次序/编号, 从0开始编号【 ordinal() 】
        // AUTUMN 枚举对象是第三个, 因此输出 2
        System.out.println(autumn.ordinal());  // 2

        // 从反编译可以看出 values 方法, 返回 Season[] 【 values() 】
        // 含有定义的所有枚举对象
        System.out.println("===遍历取出枚举对象(增强 for)===");
        Season[] values = Season.values();
        for (Season season1 : values) {
            System.out.println(season1);  // Season{name='春天', desc='温暖'}
                                          // Season{name='夏天', desc='炎热'}
                                          // Season{name='秋天', desc='凉爽'}
                                          // Season{name='冬天', desc='寒冷'}
        }

        // 将字符串转换成枚举对象, 要求字符串必须为已有的常量名, 否则报异常【 valueOf 】
        // 执行流程
        // 1. 根据你输入的 "AUTUMN" 到 Season 的枚举对象去查找
        // 2. 如果找到了就返回, 如果没有找到就报错
        Season autumn1 = Season.valueOf("AUTUMN");
        System.out.println("autumn1=" + autumn1);  // autumn1=Season{name='秋天', desc='凉爽'}
        System.out.println(autumn == autumn1);  // true
        // Season autumn2 = Season.valueOf("AUTUMN1");  // 报错

        // 比较两个枚举常量, 比较的就是编号【 compareTo() 】
        // 就是把 Season.AUTUMN 枚举对象的编号 和 Season.SUMMER 枚举对象的编号
        // 通过源码可以到看到 compareTo 的含义: return self.ordinal - other.ordinal;
        System.out.println(Season.AUTUMN.compareTo(Season.SUMMER));  // 1

        // 增强 for 循环的使用
        int[] nums = {1, 2, 3, 4};
        System.out.println("普通 for 循环");
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + "\t");
        }
        System.out.println("\n增强 for 循环");
        // 执行流程是 依次从 nums 数组中取出数据, 赋给 i, 如果取出完毕, 则退出 for
        for (int i: nums) {
            System.out.print(i + "\t");
        }
    }
}
1.6.3、案例演示

声明 Week 枚举类, 其中包含星期一至星期日的定义, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
使用 values 返回所有的枚举数组, 并遍历

package Enumeration01;

// 声明 Week 枚举类, 其中包含星期一至星期日的定义, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
// 使用 values 返回所有的枚举数组, 并遍历
public class EnumExercise02 {
    public static void main(String[] args) {
        // 获取到所有的枚举对象, 即数组
        Week[] weeks = Week.values();
        System.out.println("===所有星期的信息如下===");
        for (Week week : weeks) {
            System.out.println(week);
        }
    }
}

enum Week {

    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"),
    FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期天");
    private String name;

    Week(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Week{" +
                "name='" + name + '\'' +
                '}';
    }
}
1.6.4、enum 实现接口
  1. 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制
  2. 枚举类和普通类一样,可以实现接口,如下形式:
    enum 类名 implements 接口1,接口2 {}
package Enumeration01;

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

class A {
}

// 1.使用 enum 关键字后, 就不能再继承其它类了, 因为 enum 会隐式继承 Enum,而Java 是单继承机制
// enum Season2 extends A {}  // 报错

// 2.enum 实现的枚举类, 仍然是一个类, 所以还是可以实现接口的
interface IPlaying {
    public void playing();
}

enum Music implements IPlaying {
    CLASSICMUSIC;

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

2、注解

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

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

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

在这里插入图片描述

package annotation_;

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

class Father {  // 父类

    public void fly() {
        System.out.println("Father fly...");
    }

    public void say() {
    }
}

class Son extends Father {  // 子类
    // 1. @Override 注解放在 fly 方法上, 表示子类的 fly 方法时重写了父类的 fly
    // 2. 这里如果没有写 @Override 还是重写了父类 fly
    // 3. 如果你写了@Override 注解, 编译器就会去检查该方法是否真的重写了父类的方法, 如果的确重写了则编译通过, 如果没有构成重写则编译错误
    // 4. @Override 的定义
    // 解读: 如果发现 @interface 表示一个 注解类
    /*
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    */
    @Override //说明
    public void fly() {
        System.out.println("Son fly....");
    }

    @Override
    public void say() {
    }
}

在这里插入图片描述

2.2.2.2、@Deprecated 注解
package annotation_;

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

// 1. @Deprecated 修饰某个元素, 表示该元素已经过时
// 2. 即不在推荐使用, 但是仍然可以使用
// 3. 查看 @Deprecated 注解类的源码
// 4. 可以修饰方法, 类, 字段, 包, 参数等
// 5. @Deprecated 可以做版本升级过渡使用

/*
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
*/
@Deprecated
class A {
    @Deprecated
    public int n1 = 10;

    @Deprecated
    public void hi() {

    }
}

在这里插入图片描述

2.2.2.3、@SuppressWarnings 注解

@SuppressWarnings:抑制编译器警告

package annotation_;


import java.util.ArrayList;
import java.util.List;

public class SuppressWarnings_ {
    // 1. 当我们不希望看到这些警告的时候, 可以使用 SuppressWarnings 注解来抑制警告信息
    // 2. 在{""} 中, 可以写入你希望抑制(不显示)警告信息
    // 3. 可以指定的警告类型有
    // (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, 抑制与未用的程式码及停用的程式码相关的警告
    // 4. 关于 SuppressWarnings 作用范围是和你放置的位置相关
    // 比如 @SuppressWarnings 放置在 main 方法, 那么抑制警告的范围就是 main
    // 通常我们可以放置具体的语句, 方法, 类
    // 5. 看看 @SuppressWarnings 源码
    // (1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
    // (2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}
    /*
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
    String[] value()

    }
    */
    // @SuppressWarnings("all")
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        @SuppressWarnings({"unused"})
        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));
    }
}

在这里插入图片描述

2.3、JDK 的元 Annotation(元注解)
2.3.1、元注解的基本介绍

JDK 的元 Annotation 用于修饰其他 Annotation
元注解: 本身作用不大,只是为了看源码时能读懂即可

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

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

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

在这里插入图片描述

2.3.2.2、@Target 注解

在这里插入图片描述

2.3.2.3、@Documented 注解

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

2.3.2.4、@Inherited 注解

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值