9.1 枚举
9.1.1 枚举介绍
- 枚举对应英文(enumeration,简写enum)
- 枚举是一组常量的集合
- 可以理解为:枚举属于一种特殊的类,里边只包含一组有限的特定的对象
9.1.2 枚举的两种实现方式
- 自定义类实现枚举
- 使用eunm关键字实现枚举
9.1.3 自定义类实现枚举
9.1.3.1 实现步骤
- 构造器私有化(防止外部创建对象实例)
- 本类内部创建一组对象
- 对外暴露对象(为对象添加 public final static修饰符)
- 可以提供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 使用细节
- 不需要set方法,因为枚举的对象值通常为只读
- 对枚举对象/属性使用final+static共同修饰,实现底层优化
- 枚举对象名通常使用大写,常量的命名规范
- 枚举对象根据需要,可以有多个属性
9.1.4 enum关键字实现枚举
9.1.4.1 实现步骤
- 使用关键字enum替代class
- 通过
常量名(实参列表)
定义常量 - 多个常量(对象)使用
,
隔开 - 定义的常量要写在最前边
- 如果使用无参构造器,创建常量对象可以省略
()
- 构造器私有化
- 可以有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 注意事项
- 使用enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类
- 传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”),调用的是两个形参为字符串的构造器
- 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
- 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
- 枚举对象必须放在枚举类的行首
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常用方法
- toString:Enum 类已经重写过了,返回的是当前对象 名,子类可以重写该方法,用于返回对象的属性信息
- name:返回当前对象名(常量名),子类中不能重写
- ordinal:返回当前对象的位置号,默认从 0 开始
- values:返回当前枚举类中所有的常量
- valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常!
- 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实现接口
- 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制。
- 枚举类和普通类一样,可以实现接口,如下形式
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 理解
- 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
- 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
- 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角 色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等
9.2.2 介绍
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素
三个基本的 Annotation:
- @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
- @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
- @SuppressWarnings: 抑制编译器警告
9.2.3 @Override
- @Override表示指定重写父类的方法,如果父类没有该方法,则会报错
- 如果不写@Override注解,而子类仍然可以重写父类方法
- 如果你写了@Override 注解,编译器就会去检查该方法是否真的重写了父类的方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
- @Override只能修饰方法,不能修饰其他(类、包、属性等)
//@Override源码为:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override { }
- 查看@Override注解源码为
@Target(ElementType.METHOD)
,说明只能修饰方法 - @Target是修饰注解的注解,称为元注解
- @interface不是interface,表示一个注解类,jdk5.0后加入的
9.2.4 @Deprecated
- 用于表示某个程序元素(类、方法等)已过时
- 过时不代表不能用,而是不推荐使用
- 可以修饰方法、类、字段、包、参数等等
//源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
- @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 可以指定的警告类型
- 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,抑制与未用的程式码及停用的程式码相关的警告
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();
}
- 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
- 该注解类有数组 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 元注解的种类
- Retention:指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
- Targe:指定注解可以在哪些地方使用
- Documented:指定该注解是否会在 javadoc 体现
- 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 的三种值
- RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释
- RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认值
- 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 练习
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();
}