java学习笔记(十一)- 枚举和注解

一、自定义类实现枚举

1. 实现方法

  • 不需要提供setXxx方法,因为枚举对象值通常为只读
  • 对枚举对象/属性使用final + static共同修饰,实现底层优化
  • 枚举对象名通常使用全部大写,常量的命名规范
  • 枚举对象根据需要,也可以有多个属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Season{
private String name;//季节名称
private String description;//季节描述
public String getName() {
return name;
}
public String getDescription() {
return description;
}
private Season(String name,String description){
this.name= name;
this.description= description;
}
public final static Season SPRING = new Season("春天" ,"温暖");
public final static Season SUMMER = new Season("夏天","炎热");
public final static Season AUTUMN = new Season("秋天","凉爽");
public final static Season WINTER = new Season("冬天","寒冷");
}

2. 特点

  • 构造器私有化
  • 本类内部创建一组对象
  • 对外暴露对象(通过为对象添加public final static修饰符)
  • 可以提供get方法,但是不要提供set

二、enum关键字实现枚举

1. 实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enum Season2 {
//public final static Season2 SPRING = new Season2("春天", "温暖");
//因为使用了enum ,因此上面的代码可以简化成如下形式
SPRING("春天","温暖"),
SUMMER("夏天", "炎热"),
AUTUMN("秋天", "凉爽"),
WINTER("冬天", "寒冷");
private Season2(String name, String description) {
this.name = name;
this.description = description;
}
private String name;//季节名称
private String description;//季节描述
public String getName() {
return name;
}
public String getDescription() {
return description;
}}

2. 注意事项

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

3. 对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//定义了四个对象,固定.
// 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("夏天",” 炎热");
//如果使用了enum来实现枚举类
//1. 使用关键字enum替代cLass
//2. pubLic static final Season SPRING = new Season("春天", "温暖")直接使用
// SPRING("春天”,"温暖")解读常量名(实参列表)
//3. 如果有多个常量(对象), 使用,号间隔即可
//4. 如果使用enum来实现枚举,要求将定义常量对象,写在前面
SPRING("春天","温暖"),WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"), SUMMER("夏天","炎热");
private string name;
private string desc;

4. enum常用方法

方法名 详细描述
valueOf 传递枚举类型的Class对象和枚举常量名称给静态方法valueOf, 会得到与参数匹配的枚举常量
toString 得到当前枚举常量的名称。你可以通过重写这个方法来使得到的结果更易读
equals 在枚举类型中可以直接使用“==”来比较两个枚举常量是否相等。Enum提供的这个equals0方法, 也是直接使用“==”实现的。它的存在是为了在Set、 List和Map中使用。注意,equals()是不可变的。
hashCode Enum实现了hashCode0来和equals(保持一致。 它也是不可变的。
name 得到当前枚举常量的名称
ordinal 得到当前枚举常量的次序
compareTo 枚举类型实现了Comparable接口,这样可以比较两个枚举常量的大小(按照声明的顺序排列)
clone 枚举类型不能被Clone。 为了防止子类实现克隆方法,Enum实现了一个仅抛出CloneNotSupportedException异常的不变Clone()
getDeclaringClass 得到枚举常量所属枚举类型的Class对象。可以用它来判断两个枚举常量是否属于同-一个枚举类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Season2 autumn = Season2.AUTUMN;
//输出枚举对象的名字
System.out.println(autumn.name());
//ordinal()输出的是该枚举对象的次序/编号,从0开始编号
//AUTUMN枚举对象是第三个,因此输出2
System.out.println(autumn.ordinal());

//从反编译可以看出 values方法,返回Season2 []
//values为隐藏方法,需要反编译进行显示
//含有定义的所有枚举对象
Season2[ ] values = Season2. values() ;
System.out.println("===遍历取出枚举对象(增强for)====");
for (Season2 season: values) {//增强for循环
System.out.printLn(season);
}

//value0f:将字符串转换成枚举对象,要求字符串必须转换为已有的常量名,否则报异常
//执行流程
//1. 根据你输入的"AUTUMN" 到Season2的枚举对象去查找
//2. 如果找到了,就返回,如果没有找到,就报错
Season2 autumn1 = Season2.value0f("AUTUMN");
System.out.printLn("autumn1=" + autumn1);

/*
pubLic final int compareTo(E o) {
return seLf.ordinal - other.ordinal;
}
Season2.AUTUMN的编号[2] - Season2.SUMMER的编号[3]
*/
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));

5. 案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class EnumExercise02 {
public static void main(String[] args) {
Week[] values = Week.values();
System.out.println("===所有星期的信息如下===");
//增强for循环
for (Week week : values) {
System.out.println(week);
}
}
}

//枚举类
enum Week {
MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"),
FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");

private String week;

Week(String week) {//构造器 枚举类中 默认private 可以省略
this.week = week;
}

//重写toString方法
@Override
public String toString() {
return week;
}
}

6. 实现接口

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

  • 枚举类和普通类一样,可以实现接口

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

三、注解

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

1. Annotation

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

1.1 @Override(重写)

  • 限定某个方法,是重写父类方法,该注解只能用于方法
1
2
3
4
5
6
7
8
9
10
11
class Father{
public void fly({
System.out.println("Father fly..");
}
}
class Son extends Father {
@Override //说明
public void fly() {
System.out.println("Son fly...");
}
}
  • @Override表示指定重写父类的方法(从编译层面验证),如果父类没有fly方法,则会报错
  • 如果不写@Override注解,而父类仍有public void fly(){} ,仍然构成重写
  • @Override只能修饰方法,不能修饰其它类,包,属性等等
  • 查看@Override注解源码为@Target(ElementType.METHOD),说明只能修饰方法

1.2 @Deprecated

  • 用于表示某个程序元素(类、方法等)已过时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Deprecated
class Father{
@Deprecated
public String rame;
public void fly(){
System.out.println("Father fly... "); }
//@Deprecated的说明几点.
@Deprecated
public void sing(H{
System.out.println("Father sing... ");
}}
class Son extends Father {
//Override使用说明
@Override
public void fly() {
System.out.println("Son f.y... ");
}}
  • 可以修饰方法,类,宇段,包,参数等等
  • @Deprecated的作用可以做到新旧版本的兼容和过渡

1.3 @SuppressWarnings(抑制警告)

  • 抑制编译器警告
1
2
3
4
5
6
7
@SuppressWarnings({"all"})//抑制所有警告
public class Cellphone{
public void testWork(Calculator calculator, double n1, double n2) {
double res = calculator.work(n1, n2);
System.out.println("计算的结果为:" + res);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//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//忽略没有使用某个变量的警告

四、元注解

1. Retention

  • 指定注解的作用范围,三种值:SOURCE、CLASS、RUNTIME

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

1.1 SOURCE

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

1.2 CLASS

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

1.3 RUNTIME

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

2. Target

  • 指定注解可以用在那些地方

3. Documented

  • 指定该注解是否会在javadoc体现

4. Inherited

  • 子类会继承父类注解

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