日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java泛型,枚举,注解

發布時間:2024/7/5 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java泛型,枚举,注解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Java泛型,枚舉,注解

1 泛型

1.1 什么是泛型

泛型:即參數化類型。在不創建新的類型的情況下,通過泛型指定的不同類型來控制形參具體限制的類型。允許在定義類、接口時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。這個類型參數將在使用時確定。

集合類在聲明階段不能確定這個容器是存儲什么類的對象,在JDK1.5之前只能把元素的類型設計為Object,JDK1.5之后采用泛型類解決。這個時候除了元素的類型不確定其他部分是確定的,如元素如何保存,如何管理等,所以把元素的類型設計成一個參數,這個類型參數就是泛型。常見的List<E>,ArrayList<E>中的<E>就是泛型。

JDK1.5改寫了集合框架中的全部接口和類,為這些接口、類增加了泛型支持,從而可以在聲明集合變量、創建集合對象時傳入類型實參。

為什么要有泛型呢 ,解決集合中的兩個問題:(1)元素存儲的安全問題(添加元素時,檢查添加元素的類型),比如商品標簽不會搞混;(2)元素的類型轉換,問題泛型可以起到對類的限定作用,獲取數據元素時,就不需要類型強制轉換 。

1.2 泛型的特性

泛型只有在編譯階段有效(在編譯期正確檢驗泛型結果后,將泛型的相關信息擦除,并在對象進入和離開方法的邊界處添加類型檢查和類型裝換方法),不會進入到運行時階段

List<String> string1 = new ArrayList<String>(); List<Integer> integer1 = new ArrayList<Integer>();Class classString1 = string1.getClass(); Class classInteger1 = integer1.getClass();if(classString1.equals(classInteger1)){System.out.println("類型相同") } //輸出結果為:類型相同

1.3?泛型的使用

泛型類:用于類的定義中

//此處T為任意標識,常見的如T、E、K、V等形式的參數常用于表示泛型,在實例化泛型類時,必須指定T的具體類型 public class Dao<T> {//name這個成員變量的類型為T,T的類型由外部指定private T name;//泛型構造方法形參的類型也為T,T的類型由外部指定public Dao(T name) {this.name = name;}//添加,方法的形參值類型為T,T的類型由外部指定public void add(T u) {//添加數據 }//查詢多個public List<T> query() {//查詢數據庫return null;}//修改public boolean modificate(T u) {//修改操作return true;} }

在使用泛型的時候傳入泛型實參,根據傳入的實參做相應的限制;如果不傳入泛型的實參,在泛型類中使用泛型的方法或成員變量定義的類型可以為任意類型。

Dao d1 = new Dao("String"); Dao d2 = new Dao(9); Dao d3 = new Dao(6.6);

注意:泛型的類型參數只能是類類型,不能是簡單類型;不能對確切的泛型類型使用instanceof操作。

if(values instanceof List<T>) { //這是錯誤的,應該是(values instanceof List)List<T> list = (List<T>)values;return list; }

泛型接口:泛型接口與泛型類的定義及使用基本相同。泛型接口常被用在各種類的生產器中

public interface Genericity<T> {//添加void add(T u);//查詢多個List<T> getUser();//修改boolean updateUser(T u);}

泛型方法:調用方法,決定參數返回值或類型。格式:[訪問權限] <泛型> 返回值類型 方法名([泛型標識 參數名稱])

泛型類,是在實例化類的時候指明泛型的具體類型;泛型方法,是在調用方法的時候指明泛型的具體類型?。

public class Dao<T>{String T name;//定義泛型方法 //public 與 返回值中間<T>非常重要,可以理解為聲明此方法為泛型方法。//)<T>表明該方法將使用泛型類型T,此時才可以在方法中使用泛型類型T。public <T> E[] show(T[] e) {return e;}//在泛型類中聲明了一個泛型方法,使用泛型E,這種泛型E可以為任意類型。可以類型與T相同,也可以不同。由于泛型方法在聲明的時候會聲明泛型<E>,因此即使在泛型類中并未聲明泛型,編譯器也能夠正確識別泛型方法中識別的泛型。public <E> void show_3(E t){System.out.println(t.toString());}public <S,E> E show3(S s,E e) {return e;}/** * 這才是一個真正的泛型方法。* 首先在public與返回值之間的<T>必不可少,這表明這是一個泛型方法,并且聲明了一個泛型T* 這個T可以出現在這個泛型方法的任意位置.* 泛型的數量也可以為任意多個 * 如:public <T,K> K showKeyName(Generic<T> container){* ...* }*///雖然在方法中使用了泛型,但是這并不是一個泛型方法。這只是類中一個普通的成員方法,只不過他的 返回值是在聲明泛型類已經聲明過的泛型。所以在這個方法中才可以繼續使用 T 這個泛型。public T getName(){return Name;}//這個方法顯然是有問題的,在編譯器會給我們提示這樣的錯誤信息"cannot reslove symbol E"因為在類的聲明中并未聲明泛型E,所以在使用E做形參和返回值類型時,編譯器會無法識別。public E setName(E Name){this.Name= Name;}*/}//這也不是一個泛型方法,這就是一個普通的方法,只是使用了Dao<Number>這個泛型類做形參而已。public void showNameValue1(Dao<Number> obj){}//這也不是一個泛型方法,這也是一個普通的方法,只不過使用了泛型通配符?//同時這也印證了泛型通配符章節所描述的,?是一種類型實參,可以看做為Number等所有類的父類public void showKeyName2(Dao<?> obj){}/*** 這個方法是有問題的,編譯器會為我們提示錯誤信息:"UnKnown class 'E' "* 雖然我們聲明了<T>,也表明了這是一個可以處理泛型的類型的泛型方法。* 但是只聲明了泛型類型T,并未聲明泛型類型E,因此編譯器并不知道該如何處理E這個類型。public <T> T showKeyName(Dao<E> container){...} */}

泛型方法與可變參數

public <T> void printMsg( T... args){for(T t : args){System.out.println("t is " + t);} }

靜態方法與泛型。如果靜態方法要使用泛型的話,必須將靜態方法也定義成泛型方法?。

public class StaticGenerator<T> {/*** 如果在類中定義使用泛型的靜態方法,需要添加額外的泛型聲明(將這個方法定義成泛型方法)* 即使靜態方法要使用泛型類中已經聲明過的泛型也不可以。* 如:public static void show(T t){..},此時編譯器會提示錯誤信息:"StaticGenerator cannot be refrenced from static context"*/public static <T> void show(T t){} }

1.4 泛型通配符

Ingeter是Number的一個子類,但是List<Ingeter>和List<Number>是平行關系,List<Ingeter>不能看做是List<Number>的子類。因此通配符產生了。類型通配符一般是使用?代替具體的類型實參,而不是類型形參?。可以把?看成所有類型的父類。是一種真實的類型。

1.5?泛型繼承關系

(1)List<?> 是List<A>,List<B>等類型的父類,List<A>和List<B>是平行關系

(2)List<?> 可以遍歷,但不可以修改

(3)List<? extends Number> 可以小于或等于Number

(4)List<? super Number> 可以大于或等于Number

?

2 枚舉

枚舉的全稱為 enumeration,用于創建有限個對象。創建枚舉類型要使用 enum 關鍵字。枚舉類型符合通用模式?Class Enum<E extends Enum<E>>,而?E?表示枚舉類型的名稱。枚舉類型的每一個值都將映射到?protected Enum(String name, int ordinal)?構造函數中,在這里,每個值的名稱都被轉換成一個字符串,并且序數設置表示了此設置被創建的順序。

在什么情況下適合用枚舉:在一個類的對象有限且固定的時候,如星期:Monday(星期一)、......、Sunday(星期天) 。當需要定義一組常量時,強烈建議使用枚舉類

2.1 枚舉類

枚舉類的實現,JDK1.5之前需要自定義枚舉類。JDK 1.5 新增的 enum 關鍵字用于定義枚舉類 。

為什么不用靜態常量代替枚舉?(1)類型不安全,如定義一個季節的int類型的靜態常量,開發者可以傳入任何int類型的參數,如果是枚舉類型的話就只能傳入枚舉類型的類中包含的對象;(2)沒有命名空間,開發者要在命名的時候加個見名知意的前綴才知道這四個常量分別代表季節。

若枚舉只有一個對象, 則可以作為一種單例模式的實現方式。枚舉類對象的屬性不應允許被改動, 所以應該使用 private final 修飾。枚舉類的使用 private final 修飾的屬性應該在構造器中為其賦值。若枚舉類顯式的定義了帶參數的構造器, 則在列出枚舉值時也必須對應的傳入參數

(1)自定義枚舉類

/*** 步驟:* 1 私有化類的構造器,保證不能在類的外部創建其對象* 2 在類的內部創建枚舉類的實例。聲明為:public static final* 3 對象如果有實例變量,應該聲明為private final,并在構造器中初始化*/class TestEnum {private final String name;private TestEnum(String name) {this.name = name;}public static final TestEnum SPRING = new TestEnum("春天");public static final TestEnum SUMMER = new TestEnum("夏天");public static final TestEnum AUTUMN = new TestEnum("秋天");public static final TestEnum WINTER = new TestEnum("冬天"); }

?

(2)使用enum定義枚舉類

注意:①使用 enum 定義的枚舉類默認繼承了 java.lang.Enum類,因此不能再 繼承其他類;②枚舉類的構造器只能使用 private 權限修飾符 ;③枚舉類的所有實例必須在枚舉類中顯式列出(, 分隔 ; 結尾)。列出的 實例系統會自動添加 public static final 修飾;④必須在枚舉類的第一行聲明枚舉類對象。

枚舉類可以定義屬性和方法,可以是靜態的也可以是非靜態的。例子如下

public enum TestEnum {SPRING("春季"),SUMMER("夏季"),FALL("秋季"),WINTER("冬季");private final String name; private TestEnum(String name){this.name = name;}public String getName() {return name;} }

注意:(1)第一行寫枚舉類實例的時候,默認是調用了構造器的;(2)構造器需定義成私有的,就不能在在其他類中生成該對象;(3)枚舉類應該要設計成不可變類,所以字段用private final修飾。

2.2 枚舉實現接口

枚舉實現接口與普通類是一樣的,可以實現一個也可以實現多個,需要重寫接口中的方法,如果沒有完全實現,需要定義成抽象的,可以不需要顯示添加abstract修飾,系統會默認加上。

public enum TestEnum implements Paly {SPRING("春季"),SUMMER("夏季"),FALL("秋季"),WINTER("冬季");private final String name; private TestEnum(String name){this.name = name;}public String getName() {return name;}@Overridepublic void setPaly() {System.out.println("實現接口");} } interface Paly { public void setPaly(); }

上述代碼只是為了說明枚舉的功能,重點在下面的代碼。枚舉的常量值本質就是枚舉對象,那么我們可以采用匿名內部類。

public enum TestEnum implements Paly {SPRING(){@Overridepublic void setPaly() {System.out.println("春季踏青");} },SUMMER(){@Overridepublic void setPaly() {System.out.println("夏季游泳");} },FALL(){@Overridepublic void setPaly() {System.out.println("秋季收獲");} },WINTER(){@Overridepublic void setPaly() {System.out.println("冬季堆雪人");} }; } interface Paly { public void setPaly(); }

2.3 Switch語句中的枚舉

Java5新增了enum關鍵字,同時擴展了switch,case表達式中直接寫入枚舉值,不需加入枚舉類作為限定。

public class TestEnumSwitch {public void play(TestEnum t){switch(t){case SPRING:System.out.println("春");break;case SUMMER:System.out.println("夏");break;case FALL:System.out.println("秋");break;case WINTER:System.out.println("冬");break;}} }

?

3 注解

從 JDK 5.0 開始, Java 增加了對元數據(MetaData) 的支持, 也就是Annotation(注解) 。

什么是注解:Java 注解用于為 Java 代碼提供元數據。作為元數據,注解不直接影響你的代碼執行,但也有一些類型的注解實際上可以用于這一目的。簡單的理解為:代碼的一個特殊標記,可以在編譯,加載,運行時讀取,程序可以在不改變原有的代碼的基礎上可以在文件嵌入補充信息。

注解可以修飾:包,類,方法,構造器,參數,局部變量。這些信息被保存在 Annotation的“name=value” 對中。

3.1 注解的定義

注解通過?@interface關鍵字進行定義,和?classs 和 interface 一樣,注解也屬于一種類型。自定義注解自動繼承了java.lang.annotation.Annotation接口。

Annotation 的成員變量在 Annotation 定義中以無參數方法的形式來聲明。其方法名和返回值定義了該成員的名字和類型。我們稱為配置參數。類型只能是八種基本數據類型、String類型、Class類型、enum類型、Annotation類型、以上所有類型的數組。

public @interface MyAnnotation { }

注解的的使用方法是在類定義的地方的上面加上@MyAnnotation,如下

@MyAnnotation public class Test { }

注解的屬性也叫做成員變量。注解只有成員變量,沒有方法。注解的成員變量在注解的定義中以“無形參的方法”形式來聲明,其方法名定義了該成員變量的名字,其返回值定義了該成員變量的類型。注解中屬性可以有默認值,默認值需要用 default 關鍵值指定

@Target({TYPE, FIELD, METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {String name();int age() defalut 20; }

隨屬性賦值的方式是在注解的括號內以 value="" 形式,多個屬性之前用 ,隔開。如下

@MyAnnotation(name="aa",age=18) public class Test {}

注意:如果一個注解內僅僅只有一個名字為 value 的屬性時,應用這個注解時可以直接接屬性值填寫到括號內。要是沒有任何屬性的話可以把括號省略

public @interface MyAnnotation {String name(); }@MyAnnotation("cc") public class Test{ } ------------------------------------public @interface MyAnnotation { }@MyAnnotation public class Test{ }

3.2 常見注解使用案例

(1)生成文檔相關的注解

@author標明開發該類模塊的作者,多個作者之間使用,分割

@version?

標明該類模塊的版本
@see參考轉向,也就是相關主題
@since從哪個版本開始增加的
@param對方法中某參數的說明,如果沒有參數就不能寫
@return對方法返回值的說明,如果方法的返回值類型是void就不能寫
@exception對方法可能拋出的異常進行說明,如果方法沒有用throws顯式拋出的異常就不能寫其中

@param @return 和 @exception 這三個標記都是只用于方法的。@param的格式要求:@param 形參名形參類型 形參說明 @return 的格式要求:@return 返回值類型返回值說明@exception的格式要求:@exception 異常類型異常說明@param和@exception可以并列多個

/*** @author zs* @version 1.0* @see String*/ public class DocAnnotation {/*** @param args String[] 命令行參數*/public static void main(String[] args) {}/**** @param name 名稱* @return String*/public static String getName(String name){return "My name is "+name;} }

(2)在編譯時進行格式檢查(JDK內置的三個基本注解)

@Override限定重寫父類方法, 該注解只能用于方法
@Deprecated用于表示所修飾的元素(類, 方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇
@SuppressWarnings抑制編譯器警告
public class AnnotationTest {public static void main(String[] args) {@SuppressWarnings("unused")String str = "zs";}@Deprecatedpublic void deprecatedMethod(){System.out.println("已過時");}@Overridepublic String toString(){return "重寫";} }

(3)跟蹤代碼依賴性,實現替代配置文件功能

Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中進行Servlet的部署

@WebServlet("/login") public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);} }

代替

<servlet><servlet-name>LoginServlet</servlet-name><servlet-class>com.servlet.LoginServlet</servlet-class> </servlet><servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>LoginServlet</url-pattern> </servlet-mapping>

?

3.3?元注解

元注解就是可以注解到注解上的注解,也可以理解為元注解是一種基本注解,但是它可以運用到其他注解上。

元注解有:@Target,@Retention,@Documented,@Inherited,@Repeatable 5種

(1)@Target:target是目標的意思,@Target指定注解可以運用的地方。他的取值如下:

例:@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})

ElementType.TYPE給一個類型進行注解,比如類、接口、枚舉
ElementType.FIELD可以給屬性進行注解
ElementType.METHOD可以給方法進行注解
ElementType.PARAMETER?可以給一個方法內的參數進行注解
ElementType.CONSTRUCTOR可以給構造方法進行注解
ElementType.LOCAL_VARIABLE可以給局部變量進行注解

ElementType.ANNOTATION_TYPE

可以給一個注解進行注解
ElementType.PACKAGE可以給一個包進行注解

(2)@Retention:retention的意思為保留,@Retention指定注解的存活時間,他的取值如下

例:@Retention(RetentionPolicy.SOURCE)
RetentionPolicy.SOURCE注解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視。
RetentionPolicy.CLASS注解只被保留到編譯進行的時候,它并不會被加載到 JVM 中。
RetentionPolicy.RUNTIME注解可以保留到程序運行的時候,它會被加載進入到 JVM 中,所以在程序運行時可以獲取到它們。

(3)@Documented:他的作用是能夠將注解中的元素包含到 Javadoc 中去。

(4)@Inherited:Inherited的意思為繼承。他的作用是:如果一個超類被一個被@Inherited注解注解過的注解進行注解的話,如果子類沒有被任何注解應用,子類就繼承了超類的注解。

@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Inherit {}@Inherit public class A {} public class B extends A {}//注解Inherit被@Inherited 修飾,之后類A被Inherit注解,類B繼承A,類B也擁有Inherit這個注解。

(5)@Repeatable:repeatable是可重復的意思,jdk1.8才加進來的。在需要對同一種注解多次使用時,往往需要借助@Repeatable。比如人有多中身份把身份當成注解

//先聲明一個Persons類用來包含所有的身份 @interface Persons {Person[] value(); }//@Repeatable 注解了 Person。而 @Repeatable 后面括號中的類相當于一個用來保存該注解內容的容器。 @Repeatable(Persons.class) @interface Person{String role default ""; }//聲明一個People類,給該類加上一些身份。 @Person(role="son") @Person(role="father") @Person(role="CEO") public class People{}

3.3 java預置的注解

(1)@Deprecated:用來標記過時的元素。

(2)@Override:提示子類要復寫父類中被 @Override 修飾的方法;業可以做檢查,編譯器可以給你驗證@Override下面的方法名是否是你父類中所有的,如果沒有則報錯比如你如果沒寫@Override而你下面的方法名又寫錯了,這時你的編譯器是可以通過的。

(3)@SuppressWarnings:阻止警告

(4)@SafeVarargs:參數安全類型注解。它的目的是提醒開發者不要用參數做一些不安全的操作,它的存在會阻止編譯器產生 unchecked 這樣的警告。

(5)@FunctionalInterface:函數式接口注解,jdk1.8新特性

3.4 注解的提取

注解通過反射獲取。首先可以通過 Class 對象的 isAnnotationPresent() 方法判斷它是否應用了某個注解;然后通過 getAnnotation() 方法來獲取 Annotation 對象(返回指定類型的注解);或者是 getAnnotations() 方法(返回注解到這個元素上的所有注解);

3.5 自定義注解

public class TestPerson {public static void main(String[] args) {Test1.show(Test1.class);} } @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) @interface Person{String name() default "aa"; //default "aa" 默認值 int age() default 18; //default 18 默認值 } @Person(name="li",age=20) class Test1{public static void show(Class c) {System.out.println(c.getName()); //Test1類的全路徑Person p =(Person)c.getAnnotation(Person.class);System.out.println("name:"+p.name()+",age:"+p.age());} }

?

?

?

總結

以上是生活随笔為你收集整理的Java泛型,枚举,注解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。