Java泛型與注解全面分析講解
1.什么是泛型
其實(shí)我們在使用集合時就用過泛型List<T> 創(chuàng)建一個List對象List<Student> list=new ArrayList();<T>它就是泛型。
所謂的泛型就是在類定義時,不為類中屬性和方法指定數(shù)據(jù)類型,而是在類對象創(chuàng)建時為其指定相應(yīng)的數(shù)據(jù)類型。
2.為何使用泛型
例子: 要求定義一個Point點(diǎn)類,該類中屬性有x坐標(biāo)和y坐標(biāo)。
要求: x和y的值可以都是整數(shù)類型。
? x和y的值可以都是小數(shù)類型。
? x和y的值可以都是字符串類型。
如何定義該類呢? 如何確定屬性的類型。----可以想到使用Object類型
如果我們?yōu)樽鴺?biāo)一個賦值整數(shù),一個賦值為字符串,這時不會報錯 ,
但是它違背了我們設(shè)計的要求,這就是我們提到的數(shù)據(jù)類型安全問題。如何解決數(shù)據(jù)類型安全問題?可以使用泛型來解決,使用泛型就保證了數(shù)據(jù)類型安全問題 。
2.1.如何定義泛型
泛型可以定義在類上,接口上,方法上。 泛型類,泛型接口以及泛型方法。
泛型可以解決數(shù)據(jù)類型的安全性問題,其主要原理是在類聲明時通過一個標(biāo)識表示類中某個屬性的數(shù)據(jù)類型或者是某個方法的返回值及參數(shù)類型。這樣在類聲明或者實(shí)例化時只要指定好需要的類型即可。
格式:
public class 類名<泛型標(biāo)志,泛型標(biāo)志....>{
//類成員
}
代碼展示:
//T標(biāo)志可以任意起名-----若此處有多個標(biāo)志時,使用時必須為每個泛型指定數(shù)據(jù)類型 public class Student<T> { private T name; private T age; public void show(){ System.out.println("name:"+name+"age:"+age); } public Student() { } public Student(T name, T age) { this.name = name; this.age = age; } public T getName() { return name; } public void setName(T name) { this.name = name; } public T getAge() { return age; } public void setAge(T age) { this.age = age; } }
測試類:
public class StudentTest { public static void main(String[] args) { Student<Integer> stu=new Student<Integer>(33,44); stu.show(); //若指定泛型類型默認(rèn)為Object Student<String> stu1=new Student<>("張三","22"); stu1.show(); Student stu2=new Student("李四","55"); String age = (String) stu2.getAge();//若想使用真正的類型接受,那么必須進(jìn)行強(qiáng)轉(zhuǎn) System.out.println(age); } }
2.2.通配符
在開發(fā)中對象的引用傳遞是最常見的,但是如果在泛型類的操作中,在進(jìn)行引用傳遞時泛型類型必須匹配才可以傳遞,否則是無法傳遞的。如果想傳遞,可以定義泛型為?通配符。
代碼展示:
public class Test04 { public static void main(String[] args) { Info<Integer> i=new Info<>(); i.setVar(25); fun(i); Info<String> i2=new Info<>(); i2.setVar("張三"); fun(i2); //如果下面不是使用通配符?則會報錯 原因是如果為泛型類型:不但要求數(shù)據(jù)類型相同之外還要求泛型類型也匹配。 Info<Double> i3=new Info<>(); i3.setVar(25.5); fun(i3); //能不能設(shè)置泛型類型可以接受任意的類型呢? 我們可以使用同配置? } public static void fun(Info<?> info){ info.show(); } } //T標(biāo)志可以任意起名.----> 那么在創(chuàng)建對象時,必須為每個泛型指定數(shù)據(jù)類型。 class Info<T>{ private T var; public void show(){ System.out.println("var========"+var); } public T getVar() { return var; } public void setVar(T var) { this.var = var; } }
2.3.受限泛型
在引用傳遞中,在泛型操作中也可以設(shè)置一個泛型對象的范圍上限和范圍下限。范圍上限使用extends關(guān)鍵字聲明,表示參數(shù)化的類型可能是所指定的類型或者是此類型的子類,而范圍下限使用super進(jìn)行聲明,表示參數(shù)化的類型可能是所指定的類型或者此類型的父類型。
語法:
[設(shè)置上限]
聲明對象: 類名稱<? extends 類> 對象名稱;
定義類: [訪問權(quán)限] 類名稱<泛型標(biāo)識 extends 類>{}
[設(shè)置下限]
聲明對象: 類名稱<? super 類> 對象名稱;
定義類: [訪問權(quán)限] 類名稱<泛型標(biāo)識 super 類>{}
代碼展示:
public class ShangXiaXianTest { public static void main(String[] args) { Info<Number> i=new Info<>(); fun2(i); Info<Object> i3=new Info<>(); fun2(i3); Info<Integer> i4=new Info<>(); fun2(i4); } //傳遞的參數(shù)泛型類型必須為Number的父類或者Number類型 下限 public static void fun2(Info<? super Number> info){ info.show(); } //傳遞的參數(shù)泛型類型必須為Number的子類(注意String不是Number的子類)或者Number類型 上限 public static void fun3(Info<? extends Number> info){ info.show(); } public static void fun(Info<?> info){ info.show(); } } class Info<T>{ private T var; public void show(){ System.out.println("var==============="+var); } public Info(T var) { this.var = var; } public Info() { } public T getVar() { return var; } public void setVar(T var) { this.var = var; } }
2.4.泛型接口
上面那些例子都是使用泛型類。而在jdk1.5以后,泛型也可以定義在接口上了,定義接口的泛型和定義泛型類語法相似。
語法:
public interface 接口名<泛型標(biāo)志,泛型標(biāo)志....>{
//靜態(tài)常量
//抽象方法
}
類如何實(shí)現(xiàn)泛型接口 代碼展示:
public class JieKouTest { public static void main(String[] args) { Upan u=new Upan(); u.name="小可愛"; Mouse<String> mouse=new Mouse<>(); mouse.t="5555"; System.out.println(mouse.fun()); System.out.println(u.fun()); } } interface USB<T>{ public static final String NAME="";//常量的命名必須全部大寫 public T fun(); //JDK1.8后新特性 default void fun2(){ } static void fun3(){ } } //子類也實(shí)現(xiàn)泛型和父類名相同的泛型 class Mouse<T> implements USB<T>{ T t; @Override public T fun() { return t; } } //子類在實(shí)現(xiàn)接口時,確定泛型類型 class Upan implements USB<String>{ public String name; @Override public String fun() { return name; } }
2.5.泛型方法
前面學(xué)習(xí)的所有泛型操作都是將整個類進(jìn)行泛型化,但同樣也可以在類中定義泛型化的方法。泛型方法的定義與其所在的類是否是泛型類是沒有任何關(guān)系的,所在的類可以是泛型類,也可以不是泛型類。
【泛型方法的簡單定義】
[訪問權(quán)限] <泛型標(biāo)識> 泛型標(biāo)識 方法名稱(泛型標(biāo)識 參數(shù)名稱)
代碼展示:
public class factorTest { String hello = Student.fun("hello"); Integer fun = Student.fun(25); Double fun1 = Student.fun(25.0); System.out.println(hello+"--"+fun+"--"+fun1); } class Student{ //泛型方法: static靜態(tài)成員,隨著類的加載而被加載到JVM內(nèi)存中 常量池 public static <T> T fun(T t){ return t; } //泛型方法: static靜態(tài)成員,隨著類的加載而被加載到JVM內(nèi)存中 常量池 public static <T> Info<?> fun1(Info<? extends T> t){ return t; } } class Info<T>{ }
3.java高級--注解
注釋: java不會編譯注釋的內(nèi)容,注釋給程序員看的。
注解: 它是程序看,當(dāng)程序看到這個注解時,就應(yīng)該解析它。
譬如: @Controller @Override
注解的分類:
1. 預(yù)定義注解
2. 自定義注解
3. 元注解
3.1.預(yù)定義注解
預(yù)定義注解就是JDK自帶的一些注解,該注解被JVM而解析。
1. @Override: 重寫得注解。符合重寫得規(guī)則。
2. @Deprecated: 表示已過時。
3. @SuppressWarnings: 表示壓制警告。
4. @FunctionInterface: 表示函數(shù)式接口。表示該接口中有且僅有一個抽象方法。
3.2.自定義注解(初級)
語法:
public可以省略
public @interface 注解名{
//注解屬性
}
代碼展示:
public class Test { public static void main(String[] args) { Info i=new Info(); i.name="張三"; i.show(); } } //定義好注解了 @interface My{ //注解屬性 } //使用注解 @My class Info{ @My public String name; @My public void show(){ System.out.println("show================="+name); } }
注意: 使用注解和不使用注解沒有區(qū)別
注解本身沒有任何意義,它只有被解析了,才會賦予真正的意義。
我們后會使用反射來對象注解進(jìn)行解析。
像:@Override 它被JVM解析,從而使其具有相應(yīng)的意義。
? @Controller @RequestMapping 它被Spring框架解析,所以具有相應(yīng)的意義。
3.3.元注解
定義在注解上的注解稱為元注解。
@Controller它只能加在類上 @Override它只能加在方法上。
原因它使用了元注解可以設(shè)置注解使用的位置
1. @Target(value=可以取下面這些內(nèi)容): 作用限制注解使用得位置。
/** 表示可以作用在類,接口,枚舉 */ TYPE,
/** 屬性 */
FIELD,
/** 普通方法上 */
METHOD,
/** 方法參數(shù) */
PARAMETER,
/** 構(gòu)造方法上 */
CONSTRUCTOR,
/** 局部變量 */
LOCAL_VARIABLE
2. @Retention: 注解什么時候生效。默認(rèn)時源碼 java經(jīng)歷了那些階段。
源碼階段-->字節(jié)碼階段--->運(yùn)行階段 /** * 源碼時生效 */ SOURCE,
/**
* 字節(jié)碼時生效 */ CLASS,
/**
* 運(yùn)行時生效。 * 在JVM內(nèi)存中還有該注解。 都會被設(shè)置為運(yùn)行時有效 */ RUNTIME
3. @Documented 當(dāng)生產(chǎn)API文檔時該注解還存在。
4. @Inherited 是否運(yùn)行被子類繼承。
3.4.自定義注解(高級)
@RequestMapping("/hello") 因?yàn)樗x@RequestMaping注解中有屬性。
@interface 注解名{
數(shù)據(jù)類型 屬性名() default 默認(rèn)值;
}
數(shù)據(jù)類型: 基本類型,字符串類型,枚舉類型【常量】,注解類型,數(shù)組類型【必須是上面這些類型的數(shù)組】
代碼展示:
public class Test { public static void main(String[] args) { Info i=new Info(); i.name="張三"; i.show(); } } //定義好注解 //表示該注解可以使用的位置 @Target(value = {ElementType.TYPE,ElementType.METHOD}) //表示注解什么時候生效--source--class[默認(rèn)字節(jié)碼有效]---runtime[反射時驗(yàn)證] @Retention(value = RetentionPolicy.RUNTIME) //是否在生成api文檔時存在該注解 @Documented //子類是否能繼承該注解,如果注解在定義時使用了下面這個元注解則能被子類繼承。 @Inherited @interface My{ String value(); //如果設(shè)置default默認(rèn)值,那么在使用該注解時可以不為該屬性賦值。 int age() default 15; String[] hobby() default {};// } //使用注解 如果使用注解時有且僅有一個屬性沒有賦值,而且該屬性的名字value那么在給該屬性賦值值,可以省略value,當(dāng)寫其他內(nèi)容時,不能省略value @My(value = "hello",hobby = "游泳") class Info{ public String name; public void show(){ System.out.println("show================="+name); } } class Student extends Info{ }
到此這篇關(guān)于Java泛型與注解全面分析講解的文章就介紹到這了,更多相關(guān)Java泛型與注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot?@RestControllerAdvice注解對返回值統(tǒng)一封裝的處理方法
這篇文章主要介紹了SpringBoot?@RestControllerAdvice注解對返回值統(tǒng)一封裝,使用@RestControllerAdvice對響應(yīng)進(jìn)行增強(qiáng),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09java Swing基礎(chǔ)教程之圖形化實(shí)例代碼
這篇文章主要介紹了java Swing基礎(chǔ)教程之圖形化實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02Spring的FactoryBean<Object>接口示例代碼
FactoryBean是Spring框架中的一個接口,用于創(chuàng)建和管理Bean對象,它的作用是將Bean的創(chuàng)建過程交給FactoryBean實(shí)現(xiàn)類來完成,而不是直接由Spring容器來創(chuàng)建,本文給大家介紹Spring的FactoryBean<Object>接口,感興趣的朋友一起看看吧2023-11-11application.yml的格式寫法和pom.xml讀取配置插件方式
這篇文章主要介紹了application.yml的格式寫法和pom.xml讀取配置插件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07mybatis錯誤之in查詢?<foreach>循環(huán)問題
這篇文章主要介紹了mybatis錯誤之in查詢?<foreach>循環(huán)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01springboot整合websocket后啟動報錯(javax.websocket.server.ServerCont
這篇文章主要介紹了springboot整合websocket后啟動報錯(javax.websocket.server.ServerContainer not available),通過分析錯誤信息、排查代碼和配置,找出問題的根源,并給出相應(yīng)的解決方案,感興趣的可以了解一下2024-01-01SpringBoot使用Aspect切面攔截打印請求參數(shù)的示例代碼
這篇文章主要介紹了SpringBoot使用Aspect切面攔截打印請求參數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07