Java枚舉類型與泛型使用解讀
一、枚舉類型
1、使用枚舉類型設(shè)置常量
以往設(shè)置常量,通常將常量放置在接口中,這樣在程序中就可以直接使用,并且該常量不能被修改,因?yàn)樵诮涌谥卸x常量時(shí),該常量的修飾符為final與static。
常規(guī)定義常量的代碼如下所示。
例:在接口中定義常量的常規(guī)方式
public interface Constants{ public static final int Constants_A = 1; public static final int Constants_B = 12; }
枚舉類型出現(xiàn)后,逐漸取代了這種常量定義方式。
使用枚舉類型定義常量的語法如下:
public enum Constants{ Constants_A, Constants_B, Constants_C }
例:
interface Constants { // 將常量放置在接口中 public static final int Constants_A = 1; public static final int Constants_B = 12; } public class ConstantsTest { enum Constants2 { // 將常量放置在枚舉類型中 Constants_A, Constants_B } // 使用接口定義常量 public static void doit(int c) { // 定義一個(gè)方法,這里的參數(shù)為int型 switch (c) { // 根據(jù)常量的值做不同操作 case Constants.Constants_A: System.out.println("doit() Constants_A"); break; case Constants.Constants_B: System.out.println("doit() Constants_B"); break; } } // 定義一個(gè)方法,這里的參數(shù)為枚舉類型對象 public static void doit2(Constants2 c) { switch (c) { // 根據(jù)枚舉類型對象做不同操作 case Constants_A: System.out.println("doit2() Constants_A"); break; case Constants_B: System.out.println("doit2() Constants_B"); break; } } public static void main(String[] args) { ConstantsTest.doit(Constants.Constants_A); // 使用接口中定義的常量 ConstantsTest.doit2(Constants2.Constants_A); // 使用枚舉類型中的常量 ConstantsTest.doit2(Constants2.Constants_B); // 使用枚舉類型中的常量 ConstantsTest.doit(3); // ConstantsTest.doit2(3); // 必須為枚舉中定義的常量 } }
輸出:
注:在上述代碼中,當(dāng)用戶調(diào)用doit()方法時(shí),即使編譯器不接受在接口中定義的常量參數(shù),也不會報(bào)錯(cuò);但調(diào)用doit2()方法, 任意傳遞參數(shù),編譯器就會報(bào)錯(cuò),因?yàn)檫@個(gè)方法只接受枚舉類型的常量作為其參數(shù)。
枚舉類型也可在類的內(nèi)部進(jìn)行定義,如:
public class ConstantsTest { enum Constants2{ /將常放在枚舉類型中 Constants A, Constants_ B } }
這種形式類似于內(nèi)部類形式,當(dāng)編譯該類時(shí),除了ConstantsTest.class 外,還存在Constants-Test$1.class 與ConstantsTest$Constants2.class文件。
2、枚舉類型常用方法
用戶可以將一個(gè)枚舉類型看作是-一個(gè)類,它繼承于java.lang.Enum類,當(dāng)定義-一個(gè)枚舉類型時(shí),每一個(gè)枚舉類型成員都可以看作是枚舉類型的一個(gè)實(shí)例,這些枚舉類型成員都默認(rèn)被final、public.static修飾,所以當(dāng)使用枚舉類型成員時(shí)直接使用枚舉類型名稱調(diào)用枚舉類型成員即可。
枚舉類型的常用方法如下所示
注:調(diào)用compareTo()方法返回的結(jié)果,正值代表方法中參數(shù)在調(diào)用該方法的枚舉對象位置之前; 0代表兩個(gè)互相比較的枚舉成員的位置相同;負(fù)值代表方法中參數(shù)在調(diào)用該方法的枚舉對象位置之后。
例:
import static java.lang.System.*; public class EnumMethodTest { enum Constants2 { // 將常量放置在枚舉類型中 Constants_A, Constants_B } // 定義比較枚舉類型方法,參數(shù)類型為枚舉類型 public static void compare(Constants2 c) { // 根據(jù)values()方法返回的數(shù)組做循環(huán)操作 for (int i = 0; i < Constants2.values().length; i++) { // 將比較結(jié)果返回 out.println(c + "與" + Constants2.values()[i] + "的比較結(jié)果為:" + c.compareTo(Constants2.values()[i])); } } // 在主方法中調(diào)用compare()方法 public static void main(String[] args) { compare(Constants2.valueOf("Constants_B")); } }
輸出:
3、枚舉類型中的構(gòu)造方法
在枚舉類型中,可以添加構(gòu)造方法,但是規(guī)定這個(gè)構(gòu)造方法必須為private修飾符所修飾。
枚舉類型定義的構(gòu)造方法語法如下:
例:
import static java.lang.System.*; public class EnumIndexTest { enum Constants2 { // 將常量放置在枚舉類型中 Constants_A("我是枚舉成員A"), // 定義帶參數(shù)的枚舉類型成員 Constants_B("我是枚舉成員B"), Constants_C("我是枚舉成員C"), Constants_D(3); private String description; private int i = 4; private Constants2() { } // 定義參數(shù)為String型的構(gòu)造方法 private Constants2(String description) { this.description = description; } private Constants2(int i) { // 定義參數(shù)為整型的構(gòu)造方法 this.i = this.i + i; } public String getDescription() { // 獲取description的值 return description; } public int getI() { // 獲取i的值 return i; } } public static void main(String[] args) { for (int i = 0; i < Constants2.values().length; i++) { out.println(Constants2.values()[i] + "調(diào)用getDescription()方法為:" + Constants2.values()[i].getDescription()); } out.println(Constants2.valueOf("Constants_D") + "調(diào)用getI()方法為:" + Constants2.valueOf("Constants_D").getI()); } }
輸出:
注:在這里將枚舉類型的構(gòu)造方法設(shè)置為private修飾,以防止客戶代碼實(shí)例化一個(gè)枚舉類型。
除了可以使用上例中所示的方式定義getDescription()方法獲取枚舉類型成員定義時(shí)的描述之外,還可以將這個(gè)getDescription()方法放置在接口中,使枚舉類型實(shí)現(xiàn)該接口,然后使每個(gè)枚舉類型實(shí)現(xiàn)接口中的方法。
例:
interface d{ public String getDescriprion(); public int getI(); } public enum AnyEnum implements d{ Constants_A{ public String getDescriprion() { return("枚舉A"); } public int getI() { return i; } }, Constants_B{ public String getDescriprion() { return("枚舉B"); } public int getI() { return i; } }; static int i = 5; }
小結(jié):
- 類型安全。
- 緊湊有效的數(shù)據(jù)定義。
- 可以和程序其他部分完美交互。
- 運(yùn)行效率高。
二、泛型
在以往的類型轉(zhuǎn)換時(shí)通常有兩種類型,一種是向上轉(zhuǎn)型操作,如Boolen轉(zhuǎn)換為Object,另一種是向下轉(zhuǎn)型操作,如Object轉(zhuǎn)換為Float。
在這里向上轉(zhuǎn)型一般是安全的,而如果進(jìn)行向下轉(zhuǎn)型操作時(shí)用錯(cuò)了類型,或者并沒有執(zhí)行該操作,就會出現(xiàn)異常,而泛型機(jī)制有效地解決了這一問題。
泛型機(jī)制語法如下:
類名<T>
1、泛型的常規(guī)用法
(1)定義泛型時(shí)聲明多個(gè)類型
MutiOverClass<T1, T2> MutiOverClass:泛型類名稱
(2)定義泛型類型時(shí)聲明數(shù)組類型
定義泛型時(shí)也可聲明數(shù)組類型,但是要注意不可以使用泛型來建立數(shù)組的實(shí)例。
例:
public class ArrayClass<T> { private T[] array; // 定義泛型數(shù)組 public void SetT(T[] array) { // 設(shè)置SetXXX()方法為成員數(shù)組賦值 this.array = array; } public T[] getT() { // 獲取成員數(shù)組 return array; } public static void main(String[] args) { ArrayClass<String> a = new ArrayClass<String>(); String[] array = { "成員1", "成員2", "成員3", "成員4", "成員5" }; a.SetT(array); // 調(diào)用SetT()方法 for (int i = 0; i < a.getT().length; i++) { System.out.println(a.getT()[i]); // 調(diào)用getT()方法返回?cái)?shù)組中的值 } } }
輸出:
(3)集合類聲明容器的元素
可以使用K和V兩個(gè)字符代表容器中的鍵值和與鍵值相對應(yīng)的具體值。常用的被泛型化的集合類如下:
由于被泛型化的集合類已經(jīng)是屬于泛型,故不需要再定義泛型類,可直接使用如下所示語句實(shí)例化:
例:
public Map<K, V> m = new HashMap<K, V>();
例:
import java.util.*; public class AnyClass { public static void main(String[] args) { // 定義ArrayList容器,設(shè)置容器內(nèi)的值類型為Integer ArrayList<Integer> a = new ArrayList<Integer>(); a.add(1); // 為容器添加新值 for (int i = 0; i < a.size(); i++) { // 根據(jù)容器的長度循環(huán)顯示容器內(nèi)的值 System.out.println("獲取ArrayList容器的值:" + a.get(i)); } // 定義HashMap容器,設(shè)置容器的鍵名與鍵值類型分別為Integer與String型 Map<Integer, String> m = new HashMap<Integer, String>(); for (int i = 0; i < 5; i++) { m.put(i, "成員" + i); // 為容器填充鍵名與鍵值 } for (int i = 0; i < m.size(); i++) { // 根據(jù)鍵名獲取鍵值 System.out.println("獲取Map容器的值" + m.get(i)); } // 定義Vector容器,使容器中的內(nèi)容為String型 Vector<String> v = new Vector<String>(); for (int i = 0; i < 5; i++) { v.addElement("成員" + i); // 為Vector容器添加內(nèi)容 } for (int i = 0; i < v.size(); i++) { // 顯示容器中的內(nèi)容 System.out.println("獲取Vector容器的值" + v.get(i)); } } }
輸出:
2、泛型的高級用法
(1)限制泛型可用類型
默認(rèn)可以使用任何類型來實(shí)例化一個(gè)泛型類對象,但Java中也對泛型類實(shí)例的類型作了限制。語法如下:
class類名稱<T extends anyClass>
其中,anyClass 指某個(gè)接口或類。
使用泛型限制后,泛型類的類型必須實(shí)現(xiàn)或繼承了anyClass這個(gè)接口或類。無論anyClass是接口還是類,在進(jìn)行泛型限制時(shí)都必須使用extends 關(guān)鍵字。
例:
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class LimitClass<T extends List>{ public static void mian(String[] args) { // 可實(shí)例化已經(jīng)實(shí)現(xiàn)List接口的類 LimitClass<ArrayList> l1 = new LimitClass<ArrayList>(); LimitClass<LinkedList> l2 = new LimitClass<LinkedList>(); // 錯(cuò)誤,因?yàn)镠ashMap沒實(shí)現(xiàn)List()接口 // LimitClass<HashMap> l3 = new LimitClass<HashMap>(); } }
(2)使用類型通配符
在泛型機(jī)制中,提供了類型通配符,其主要作用是在創(chuàng)建一個(gè)泛型類對象時(shí)限制這個(gè)泛型類的類型實(shí)現(xiàn)或繼承某個(gè)接口或類的子類。要聲明這樣一個(gè)對象可以使用“?”通配符來表示,同時(shí)使用extends關(guān)鍵字來對泛型加以限制。
使用泛型類型通配符的語法如下:
泛型類名稱<? extends List> anll;
其中,<? extends List>表示類型未知,當(dāng)需要使用該泛型對象時(shí),可以單獨(dú)實(shí)例化。
例:
A<? extends List> a = null; a = new A<ArrayList>(); a = new A<LinkedList>();
除了可以實(shí)例化一個(gè)限制泛型類型的實(shí)例之外,還可以將該實(shí)例放置在方法的參數(shù)中。
例:
public void doSomething(A<? extends List> a){}
如果使用A<?>這種形式實(shí)例化泛型類對象,則默認(rèn)表示可以將A指定為實(shí)例化Object及以下的子類類型。
例:
List<String> 11=new ArrayList<String>(); //實(shí)例化一個(gè)ArrayList對象 I1.add("成員"): // 在集合中添加內(nèi)容 List<?> 12=11; // 使用通配符 List<?> l3=new Linkedl ist<Integer>(); System.out.rintn(2.g(0); // 獲取集合中第一個(gè)值
在上例中,List<?>類型的對象可以接受String類型的ArrayList集合,也可以接受Integer類型的LinkedList集合。
也許有的讀者會有疑問,List<?> 12=11語句與List 12=11存在何種本質(zhì)區(qū)別?
這里需要注意的是,使用通配符聲明的名稱實(shí)例化的對象不能對其加入新的信息,只能獲取或刪除。
例:
l1.set(0,“成員改變"); // 沒有使用通配符的對象調(diào)用set()方法 // 2.set(0,“成員改變"); // 使用通配符的對象調(diào)用set()方法,不能被調(diào)用 // 3.set(0, 1); l2.get(0); // 可以使用12的實(shí)例獲取集合中的值 12.remove(0); // 根據(jù)鍵名刪除集合中的值
注:泛型類型限制除了可以向下限制之外,還可以進(jìn)行向上限制,只要在定義時(shí)使用super 關(guān)鍵字即可。例如,“A<? super List> a=nll;"這樣定義后,對象a只接受List接口或上層父類類型,如”a=new A<Objec>;"
(3)繼承泛型類與實(shí)現(xiàn)泛型接口
定義為泛型的類和接口也可被繼承與實(shí)現(xiàn)。
例:
public class ExtendClass<T1>{ class SubClass<T1.T2,T3> extends ExtendClass<T1>{ }
如果在SubClass類繼承ExtendClass類時(shí)保留父類的泛型類型,需要在繼承時(shí)指明,如果沒有指明,直接使用extends ExtendsClass語句進(jìn)行繼承操作,則SubClass類中的T1、T2和T3都會自動變?yōu)镺bject,所以在一般情況下都將父類的泛型類型保留。
定義的泛型接口也可以被實(shí)現(xiàn)。
例:
Interface i<T1>{ } class SubClass2 <T1,T2,T3> implements i<T1>{ }
小結(jié):
- 泛型的類型參數(shù)只能是類類型,不可以是簡單類型,如A<int>這種泛型定義就是錯(cuò)誤的。
- 泛型的類型個(gè)數(shù)可以是多個(gè)。
- 可以使用extends 關(guān)鍵字限制泛型的類型。
- 可以使用通配符限制泛型的類型。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot @ConfigurationProperties使用詳解
這篇文章主要介紹了SpringBoot @ConfigurationProperties使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02java全角、半角字符的關(guān)系以及轉(zhuǎn)換詳解
這篇文章主要介紹了2013-11-11Java?MyBatis是如何執(zhí)行一條SQL語句的
這篇文章主要介紹了Java?MyBatis是如何執(zhí)行一條SQL語句的,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式
這篇文章主要給大家介紹了關(guān)于Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式,在一般操作中對于list集合取交集、差集、并集,比較簡單,需要的朋友可以參考下2023-08-08