国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - 扒一扒 Java 中的枚舉類型

扒一扒 Java 中的枚舉類型

2021-06-18 14:16阿進的寫字臺 Java教程

這篇文章主要給大家介紹了Java中枚舉類型的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

在 java 中, 枚舉, 也稱為枚舉類型, 其是一種特殊的數據類型, 它使得變量能夠稱為一組預定義的常量。 其目的是強制編譯時類型安全。

枚舉類更加直觀,類型安全。使用常量會有以下幾個缺陷:

1. 類型不安全。若一個方法中要求傳入季節這個參數,用常量的話,形參就是int類型,開發者傳入任意類型的int類型值就行,但是如果是枚舉類型的話,就只能傳入枚舉類中包含的對象。

2. 沒有命名空間。開發者要在命名的時候以season_開頭,這樣另外一個開發者再看這段代碼的時候,才知道這四個常量分別代表季節。

因此, 在 java 中, enum 是保留的關鍵字。

扒一扒 Java 中的枚舉類型

1. 枚舉的定義

在 java 是在 jdk 1.4 時決定引入的, 其在 jdk 1.5 發布時正式發布的。

舉一個簡單的例子:以日常生活中的方向來定義, 因為其名稱, 方位等都是確定, 一提到大家就都知道。

1.1 傳統的非枚舉方法

如果不使用枚舉, 我們可能會這樣子定義

?
1
2
3
4
5
6
7
8
9
10
public class direction {
 public static final int east = 0;
 
 public static final int west = 1;
 
 public static final int south = 2;
 
 public static final int north = 3;
 
}

以上的定義也是可以達到定義的, 我們在使用時

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@test
public void testdirection() {
system.out.println(getdirectionname(direction.east));
system.out.println(getdirectionname(5));// 也可以這樣調用
}
 
public string getdirectionname(int type) {
switch (type) {
 case direction.east:
 return "east";
 case direction.west:
 return "west";
 case direction.south:
 return "south";
 case direction.north:
 return "north";
 default:
 return "unknow";
}
}

運行起來也沒問題。 但是, 我們就如同上面第二種調用方式一樣, 其實我們的方向就在 4 種范圍之內,但在調用的時候傳入不是方向的一個 int 類型的數據, 編譯器是不會檢查出來的。

1.2 枚舉方法

我們使用枚舉來實現上面的功能

定義

?
1
2
3
public enum directionenum {
 east, west, north, south
}

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@test
public void testdirectionenum() {
system.out.println(getdirectionname(directionenum.east));
// system.out.println(getdirectionname(5));// 編譯錯誤
}
 
public string getdirectionname(directionenum direction) {
switch (direction) {
 case east:
 return "east";
 case west:
 return "west";
 case south:
 return "south";
 case north:
 return "north";
 default:
 return "unknow";
}
}

以上只是一個舉的例子, 其實, 枚舉中可以很方便的獲取自己的名稱。

通過使用枚舉, 我們可以很方便的限制了傳入的參數, 如果傳入的參數不是我們指定的類型, 則就發生錯誤。

1.3 定義總結

以剛剛的代碼為例

?
1
2
3
public enum directionenum {
 east, west, north, south
}
  • 枚舉類型的定義跟類一樣, 只是需要將 class 替換為 enum
  • 枚舉名稱與類的名稱遵循一樣的慣例來定義
  • 枚舉值由于是常量, 一般推薦全部是大寫字母
  • 多個枚舉值之間使用逗號分隔開
  • 最好是在編譯或設計時就知道值的所有類型, 比如上面的方向, 當然后面也可以增加

2 枚舉的本質

枚舉在編譯時, 編譯器會將其編譯為 java 中 java.lang.enum 的子類。

我們將上面的 directionenum 進行反編譯, 可以獲得如下的代碼:

?
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
31
32
33
34
35
36
37
38
// final:無法繼承
public final class directionenum extends enum
{
 // 在之前定義的實例
 public static final directionenum east;
 public static final directionenum west;
 public static final directionenum north;
 public static final directionenum south;
 private static final directionenum $values[];
 
 // 編譯器添加的 values() 方法
 public static directionenum[] values()
 {
 return (directionenum[])$values.clone();
 }
 // 編譯器添加的 valueof 方法, 調用父類的 valueof 方法
 public static directionenum valueof(string name)
 {
 return (directionenum)enum.valueof(cn/homejim/java/lang/directionenum, name);
 }
 // 私有化構造函數, 正常情況下無法從外部進行初始化
 private directionenum(string s, int i)
 {
 super(s, i);
 }
 
 // 靜態代碼塊初始化枚舉實例
 static
 {
 east = new directionenum("east", 0);
 west = new directionenum("west", 1);
 north = new directionenum("north", 2);
 south = new directionenum("south", 3);
 $values = (new directionenum[] {
  east, west, north, south
 });
 }
}

通過以上反編譯的代碼, 可以發現以下幾個特點

2.1 繼承 java.lang.enum

通過以上的反編譯, 我們知道了, java.lang.enum 是所有枚舉類型的基類。查看其定義

?
1
2
public abstract class enum<e extends enum<e>>
 implements comparable<e>, serializable {

可以看出來, java.lang.enum 有如下幾個特征

  • 抽象類, 無法實例化
  • 實現了 comparable 接口, 可以進行比較
  • 實現了 serializable 接口, 可進行序列化

因此, 相對應的, 枚舉類型也可以進行比較和序列化

2.2 final 類型

final 修飾, 說明枚舉類型是無法進行繼承的

2.3 枚舉常量本身就是該類的實例對象

可以看到, 我們定義的常量, 在類內部是以實例對象存在的, 并使用靜態代碼塊進行了實例化。

2.4 構造函數私有化
不能像正常的類一樣, 從外部 new 一個對象出來。

2.5 添加了 $values[] 變量及兩個方法

  • $values[]: 一個類型為枚舉類本身的數組, 存儲了所有的示例類型
  • values() : 獲取以上所有實例變量的克隆值
  • valueof(): 通過該方法可以通過名稱獲得對應的枚舉常量

3 枚舉的一般使用

枚舉默認是有幾個方法的

3.1 類本身的方法

從前面我的分析, 我們得出, 類本身有兩個方法, 是編譯時添加的

3.1.1 values()

先看其源碼

?
1
2
3
public static directionenum[] values() {
return (directionenum[])$values.clone();
}

返回的是枚舉常量的克隆數組。

使用示例

?
1
2
3
4
5
6
7
8
@test
public void testvalus() {
directionenum[] values = directionenum.values();
for (directionenum direction:
 values) {
 system.out.println(direction);
}
}

輸出

east
west
north
south

3.1.2 valueof(string)

該方法通過字符串獲取對應的枚舉常量

?
1
2
3
4
5
@test
public void testvalueof() {
directionenum east = directionenum.valueof("east");
system.out.println(east.ordinal());// 輸出0
}

3.2 繼承的方法

因為枚舉類型繼承于 java.lang.enum, 因此除了該類的私有方法, 其他方法都是可以使用的。

3.2.1 ordinal()

該方法返回的是枚舉實例的在定義時的順序, 類似于數組, 第一個實例該方法的返回值為 0。

在基于枚舉的復雜數據結構 enumset和enummap 中會用到該函數。

?
1
2
3
4
5
@test
public void testordinal() {
system.out.println(directionenum.east.ordinal());// 輸出 0
system.out.println(directionenum.north.ordinal()); // 輸出 2
}

3.2.2 compareto()

該方法時實現的 comparable 接口的, 其實現如下

?
1
2
3
4
5
6
7
8
public final int compareto(e o) {
enum<?> other = (enum<?>)o;
enum<e> self = this;
if (self.getclass() != other.getclass() && // optimization
 self.getdeclaringclass() != other.getdeclaringclass())
 throw new classcastexception();
return self.ordinal - other.ordinal;
}

首先, 需要枚舉類型是同一種類型, 然后比較他們的 ordinal 來得出大于、小于還是等于。

?
1
2
3
4
5
6
@test
public void testcompareto() {
system.out.println(directionenum.east.compareto(directionenum.east) == 0);// true
system.out.println(directionenum.west.compareto(directionenum.east) > 0); // true
system.out.println(directionenum.west.compareto(directionenum.south) < 0); // true
}

3.2.3 name() 和 tostring()

該兩個方法都是返回枚舉常量的名稱。 但是, name() 方法時 final 類型, 是不能被覆蓋的! 而 tostring 可以被覆蓋。

3.2.4 getdeclaringclass()

獲取對應枚舉類型的 class 對象

?
1
2
3
4
5
@test
public void testgetdeclaringclass() {
 system.out.println(directionenum.west.getdeclaringclass());
 // 輸出 class cn.homejim.java.lang.directionenum
}

2.3.5 equals

判斷指定對象與枚舉常量是否相同

?
1
2
3
4
5
@test
public void testequals() {
system.out.println(directionenum.west.equals(directionenum.east)); // false
system.out.println(directionenum.west.equals(directionenum.west)); // true
}

4 枚舉類型進階

枚舉類型通過反編譯我們知道, 其實也是一個類(只不過這個類比較特殊, 加了一些限制), 那么, 在類上能做的一些事情對其也是可以做的。 但是, 個別的可能會有限制(方向吧, 編譯器會提醒我們的)

4.1 自定義構造函數

首先, 定義的構造函數可以是 private, 或不加修飾符

扒一扒 Java 中的枚舉類型

自定義構造函數

我們給每個方向加上一個角度

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public enum directionenum {
 east(0), west(180), north(90), south(270);
 
 private int angle;
 
 directionenum(int angle) {
 this.angle = angle;
 }
 
 public int getangle() {
 return angle;
 }
}

測試

?
1
2
3
4
5
@test
public void testconstructor() {
system.out.println(directionenum.west.getangle()); // 180
system.out.println(directionenum.east.getangle()); // 0
}

4.2 添加自定義的方法

以上的 getangle 就是我們添加的自定義的方法

4.2.1 自定義具體方法

我們在枚舉類型內部加入如下具體方法

?
1
2
3
protected void move() {
system.out.println("you are moving to " + this + " direction");
}

測試

?
1
2
3
4
5
@test
public void testconcretemethod() {
 directionenum.west.move();
 directionenum.north.move();
}

輸出

you are moving to west direction
you are moving to north direction

4.2.2 在枚舉中定義抽象方法

在枚舉類型中, 也是可以定義 abstract 方法的

我們在directinenum中定義如下的抽象方法

?
1
abstract string ondirection();

定義完之后, 發現編譯器報錯了, 說我們需要實現這個方法

扒一扒 Java 中的枚舉類型

按要求實現

扒一扒 Java 中的枚舉類型

測試

?
1
2
3
4
5
@test
public void testabstractmethod() {
 system.out.println(directionenum.east.ondirection());
 system.out.println(directionenum.south.ondirection());
}

輸出

east direction 1
north direction 333

也就是說抽象方法會強制要求每一個枚舉常量自己實現該方法。 通過提供不同的實現來達到不同的目的。

4.3 覆蓋父類方法

在父類 java.lang.enum 中, 也就只有 tostring() 是沒有使用 final 修飾啦, 要覆蓋也只能覆蓋該方法。 該方法的覆蓋相信大家很熟悉, 在此就不做過多的講解啦

4.4 實現接口

因為java是單繼承的, 因此, java中的枚舉因為已經繼承了 java.lang.enum, 因此不能再繼承其他的類。

但java是可以實現多個接口的, 因此 java 中的枚舉也可以實現接口。

定義接口

?
1
2
3
public interface testinterface {
 void dosomething();
}

實現接口

?
1
2
3
4
5
6
7
public enum directionenum implements testinterface{
 // 其他代碼
 public void dosomething() {
  system.out.println("dosomething implement");
 }
 // 其他代碼
}

測試

?
1
2
3
4
@test
public void testimplement() {
 directionenum.west.dosomething(); // 輸出 dosomething implement
}

5 使用枚舉實現單例

該方法是在 《effective java》 提出的

?
1
2
3
4
5
6
7
public enum singlton {
 instance;
 
 public void dootherthing() {
  
 }
}

使用枚舉的方式, 保證了序列化機制, 絕對防止多次序列化問題, 保證了線程的安全, 保證了單例。 同時, 防止了反射的問題。

該方法無論是創建還是調用, 都是很簡單。 《effective java》 對此的評價:

單元素的枚舉類型已經成為實現singleton的最佳方法。

6 枚舉相關的集合類

java.util.enumset 和 java.util.enummap, 在此不進行過多的講述了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.cnblogs.com/homejim/p/10056701.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 91精品久久久久久久久久入口 | 亚洲激情在线 | 国产一级视频在线观看 | 美日韩精品| 欧美国产日韩在线观看 | 最新国产一区 | 亚洲人成网站999久久久综合 | 黄小视频 | 国产精品欧美久久久 | 亚洲国产精品99久久久久久久久 | 久久久国产一区二区三区 | 爱综合| 狠狠操网站 | 精品免费国产一区二区三区四区 | 久久国产精品久久久久久 | 国产一区二区免费 | 1000部精品久久久久久久久 | 亚洲一本| 激情五月婷婷基地 | 国产精品视频网 | 国产美女啪啪 | 精品久久久久久久久久久久久久久久久久 | 毛片大全 | 亚洲一区综合 | 另类综合在线 | 北条麻妃99精品青青久久 | 一区二区精品视频 | 亚洲电影在线观看 | 日韩一区二区在线观看 | 四季久久免费一区二区三区四区 | 伊人福利视频 | 在线成人亚洲 | 91精品久久 | 日韩中文字幕在线播放 | 中文字幕国产一区 | 天天干天天干天天干天天射 | 久久精品91久久久久久再现 | hh99me在线观看 | 久久久久久亚洲 | 91久久| 亚洲性在线|