• 沒有找到結果。

自訂泛型、列舉與標註

N/A
N/A
Protected

Academic year: 2021

Share "自訂泛型、列舉與標註"

Copied!
84
0
0

加載中.... (立即查看全文)

全文

(1)
(2)

自訂泛型、列舉與標註

學習目標

• 進階自訂泛型

• 進階自訂列舉

• 使用標準標註

• 自訂與讀取標註

(3)

使用 extends 與 ?

• 在定義泛型時,可以定義型態的邊界

(4)
(5)

使用 extends 與 ?

• 可以如下使用 quick() 方法:

(6)

使用 extends 與 ?

若 extends 之後指定了類別或介面後,想 再指定其它介面,可以使用 & 連接

(7)

使用 extends 與 ?

• 來看看在泛型中的型態通配字元 ?

(8)

使用 extends 與 ?

(9)

使用 extends 與 ?

• 如果有以下程式片段,則會發生編譯錯誤:

• Node<Apple> 是一種 Node<Fruit> 嗎?

(10)

使用 extends 與 ?

• 如果 B 是 A 的子類別,而 Node<B> 可視為 一種 Node<A> ,則稱 Node 具有共變性

( Covariance )或有彈性的( flexible )

• Java 的泛型並不具有共變性,不過可以使用 型態通配字元 ? 與 extends 來宣告變數,

使其達到類似共變性

(11)

使用 extends 與 ?

(12)

使用 extends 與 ?

• 若宣告 ? 不搭配 extends ,則預設為 ? extends Object

• 這與宣告為 Node<Object> 不同,如果

node 宣告為 Node<Object> ,那就真的只 能參考至 Node<Object> 實例了

(13)

使用 extends 與 ?

• 以下會編譯錯誤:

• 以下會編譯成功:

(14)

使用 extends 與 ?

• 使用通配字元 ? 與 extends 限制 T 的型態

,就只能透過 T 宣告的名稱取得物件指定給 Object ,或將 T 宣告的名稱指定為 null

,除此之外不能進行其它指定動作

(15)

使用 extends 與 ?

• Java 的泛型語法只用在編譯時期檢查,執行 時期的型態資訊都是未知

– 也就是執行時期實際上只會知道是 Object 型態

(又稱為型態抹除)

• 由於無法在執行時期獲得型態資訊,編譯器 只能就編譯時期看到的型態來作檢查

(16)

使用 super 與 ?

• 如果 B 是 A 的子類別,如果 Node<A> 視為 一種 Node<B> ,則稱 Node 具有逆變性

( Contravariance )

• Java 泛型並不支援逆變性

(17)

使用 super 與 ?

• 可以使用型態通配字元 ? 與 super 來宣告,

以達到類似逆變性的效果

(18)

使用 super 與 ?

• 你想設計了一個籃子,可以指定籃中置放的 物品,放置的物品會是同一種類(例如都是 一種 Fruit )

• 有一個排序方法,可指定

java.util.Comparator 針對籃中物品進 行排序

(19)

使用 super 與 ?

• 以下泛型未填寫部份該如何宣告?

(20)

使用 super 與 ?

• 宣告為 <? extends T> 嗎?

(21)

使用 super 與 ?

• 你希望可以有以下的操作:

(22)

使用 super 與 ?

• 應該宣告為 <? super T>

(23)

自訂列舉

在 7.2.3 中曾經簡介過列舉型態,請先瞭解該 節內容

(24)

瞭解 java.lang.Enum 類別

在 7.2.3 節中使用 enum 定義過以下的 Action 列舉型態:

(25)

瞭解 java.lang.Enum 類別

• enum 定義了特殊的類別,繼承自 java.lang.Enum

(26)

瞭解 java.lang.Enum 類別

(27)

瞭解 java.lang.Enum 類別

• 7.2.3 中 Action.class 反編譯後的內容 … .

(28)
(29)

瞭解 java.lang.Enum 類別

• 可以透過 Enum 定義的 name() 方法取得列 舉成員名稱字串,這適用於需要使用字串代 表列舉值的場合,相當於 toString() 的作 用,事實上 toString() 也只是傳回 name 成員的值

• 可透過 ordinal() 取得列舉 int 值,這適 用於需要使用 int 代表列舉值的場合

(30)

瞭解 java.lang.Enum 類別

• 例如 7.2.1 的 Game 類別,可以如下操作

(31)

瞭解 java.lang.Enum 類別

• Enum 的 valueOf() 方法,可以傳入字串與 Enum 實例,它會傳回對應的列舉實例

• 通常會透過 Enum 子類別的 valueOf() 方法

,其內部就使用了 Enum.valueOf() (可觀 察先前反編譯 Action 列舉的程式碼)

(32)

瞭解 java.lang.Enum 類別

• Enum 的 equals() 與 hashCode() 基本上 繼承了 Object 的行為,但被標示為 final

(33)

進階 enum 運用

• values() 方法會將內部維護 Action 列舉 實例的陣列複製後傳回

• 由於是複製品,因此改變傳回的陣列,並不 會影響 Action 內部所維護的陣列

(34)

進階 enum 運用

• 可以自行定義建構式,條件是不得為公開

( public )建構式,也不可以於建構式中 呼叫 super()

(35)

進階 enum 運用

• 例如原本有個 interface 定義的列舉常數

(36)

進階 enum 運用

(37)
(38)

進階 enum 運用

• 定義列舉時還可以實作介面,例如有個介面 定義如下:

(39)

進階 enum 運用

(40)

進階 enum 運用

• 可以如下執行程式:

(41)

進階 enum 運用

• 定義 enum 時有個特定值類別本體( Value- Specific Class Bodies )語法

(42)

進階 enum 運用

(43)

進階 enum 運用

• 實際上,編譯器會將 Action3 標示為抽象 類別:

• 並為每個列舉成員後的 {} 語法,產生匿名 內部類別,這個匿名內部類別繼承了

Action3 ,實作了 execute() 方法 …

(44)

進階 enum 運用

(45)

進階 enum 運用

• 以先前 Priority 為例,可改寫為以下:

(46)

進階 enum 運用

(47)

常用標準標註

(48)

常用標準標註

• 如果某個方法原先存在於 API 中,後來不建 議再使用,可於該方法上標註

@Deprecated

(49)

常用標準標註

• 若有使用者後續又想呼叫或重新定義這個方 法,編譯器會提出警訊 ..

(50)

常用標準標註

在 JDK5 之後加入泛型支援,對於支援泛型 的 API ,建議明確指定泛型真正型態,如果 沒有指定的話,編譯器會提出警訊

(51)

常用標準標註

• 如果不想看到這個警訊,可以使用

@SuppressWarnings 指定抑制 unckecked 的警訊產生:

(52)

常用標準標註

• @SuppressWarnings 的 value 可以指定 要抑制的警訊種類。例如你真的想呼叫

@Deprecated 標示過的方法,又不想看到 警訊,可以如下:

• 也可以一次指定抑制多項警訊:

(53)

常用標準標註

• 有沒有可能建立 List<String>[] 陣列實 例?答案是不行!

• 宣告 List<String>[] lists 是可以的,

只是實際上不會有人這麼做

• 可以宣告 List<String>[] lists 是為了 支援可變長度引數

(54)

常用標準標註

在 JDK6 中這個程式碼可以順利編譯,也不 會有任何警訊

• 如果你這麼使用:

(55)

常用標準標註

• Java 泛型語法是提供編譯器資訊,使其可在 編譯時期檢查型態錯誤

• 編譯器只能就 List<String> 的型態資訊

,在編譯時期幫你檢查呼叫 doSome() 時,

傳入的 list1 與 list2 是否為 List<String> 型態

(56)

常用標準標註

• 設計 doSome() 的人在實作流程時,是有可 能發生編譯器無法檢查出來的執行時期型態 錯誤

• 這類問題稱為 Heap pollution

(57)

常用標準標註

• 即使編譯器提醒身為 doSome() 的客戶端可 能會有這類問題發生又如何?

在 JDK7 中,同樣的 Util 類別編譯時,會 發生以下警訊:

(58)

常用標準標註

• 如果開發人員確定避免了這個問題,則可以 使用 @SafeVarargs 加以標註

(59)

常用標準標註

• 如下呼叫 Util.doSome() 不會再發生警訊

(60)

自訂標註型態

• 所有標註型態其實都是

java.lang.annotation.Annotation 子介面

– @Override 型態 java.lang.Override

– @Deprecated 型態 java.lang.Deprecated – …

(61)

自訂標註型態

• 要定義一個標註可以使用 @interface

(62)

自訂標註型態

• 設定單值標註( Single-value Annotation )

(63)

自訂標註型態

• 標註屬性也可以用陣列形式指定

(64)

自訂標註型態

• 在定義標註屬性時,如果屬性名稱為 value

,則可以省略屬性名稱,直接指定值

• 這個標註可以使用 @Ignore(value =

"message") 指定,也可以使用

@Ignore("message") 指定

(65)

自訂標註型態

• 以下這個標註:

• 可以使用 @TestClass(value =

{Some.class, Other.class}) 指定,

也可以使用 @TestClass({Some.class, Other.class}) 指定

(66)

自訂標註型態

• 使用 default 關鍵字可以對成員設定預設

(67)

自訂標註型態

• 如果是 Class 設定的屬性比較特別,必須自 訂一個類別作為預設值

(68)

自訂標註型態

• 如果要設定陣列預設值的話,可以在 default 之後加上 {}

(69)

自訂標註型態

• 可使用 java.lang.annotation.Target 限定標註使用位置,限定時可指定

java.lang.annotation.ElementType 的列舉值

(70)

自訂標註型態

• 想將 @Test8 限定只能用於方法:

(71)

自訂標註型態

• 想要將標註資料加入文件,可以使用

java.lang.annotation.Documented

(72)

自訂標註型態

• 在定義標註時設定

java.lang.annotation.Inherited 標 註,就可以讓標註被子類別繼承

(73)

JDK8 標註增強

在 JDK8 出現之前, ElementType 的列舉 成員,是用來限定哪個宣告位置可以進行標

• JDK8 的 ElementType 多了兩個列舉成員 TYPE_PARAMETER 、 TYPE_USE ,它們是 用來限定哪個型態可以進行標註

(74)

JDK8 標註增強

• 在定義 @Email 時,必須在 @Target 設定 ElementType.TYPE_PARAMETER ,表示 這個標註可用來標註型態參數

(75)

JDK8 標註增強

• 一個標註如果被設定為

ElementType.TYPE_USE ,只要是型態名 稱,都可以進行標註

(76)

JDK8 標註增強

• 以下幾個標註範例都是可以的:

• 以下的標註就不合法:

(77)

JDK8 標註增強

• 這可以讓你如下進行標註:

(78)

JDK8 標註增強

• JDK8 新增了個 @Repeatable

(79)

執行時期讀取標註資訊

• 如果希望於執行時期讀取標註資訊,可以於 自訂標註時使用

java.lang.annotation.Retention 搭

java.lang.annotation.RetentionPo licy 列舉指定…

(80)

執行時期讀取標註資訊

• 可使用 java.lang.reflect.AnnotatedElement 介面 實作物件取得標註資訊

(81)

執行時期讀取標註資訊

• Class 、 Constructor 、 Field 、 Meth od 、 Package 等類別,都實作了

AnnotatedElement 介面

• 如果標註在定義時的 RetentionPolicy 指定為 RUNTIME ,就可以用

Class 、 Constructor 、 Field 、 Meth od 、 Package 等類別的實例,取得設定的 標註資訊

(82)

執行時期讀取標註資訊

(83)
(84)

執行時期讀取標註資訊

• JDK8 新增了

getDeclaredAnnotation() 、 getDecl aredAnnotationsByType() 、 getAnno tationsByType()

參考文獻

相關文件

對於給定的一個 x 值,經過某一對應方式後得到「唯一」的 y 值,這種對應方式我們稱 為函數,其中 x 是自變數,y 是應變數。. 而在表

請舉出一個可以準確計算出根號值的數字。這類數字有什麼樣

自從 Engle(1982)提出 ARCH 模型以來,已經超過 20 年,實證上也有相當多的文獻 探討關於 ARCH 族模型的應用,Chou(2002)將 GARCH

此位址致能包括啟動代表列與行暫存器的 位址。兩階段的使用RAS與CAS設定可以

(三) 「愛,就是在別人的需要上,看到自己的責任」

微算機基本原理與應用 第15章

 真值表必須在關鍵字table table table table及endtable endtable endtable之 endtable 間。. 

理解並欣賞幾何的性質可以透過坐標而轉化成數與式的 關係,而數與式的代數操作也可以透過坐標產生對應的