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

