首頁 > 軟體

Java泛型與註解全面分析講解

2022-08-25 22:01:36

1.什麼是泛型

其實我們在使用集合時就用過泛型List<T> 建立一個List物件List<Student> list=new ArrayList();<T>它就是泛型。

所謂的泛型就是在類定義時,不為類中屬性和方法指定資料型別,而是在類物件建立時為其指定相應的資料型別。

2.為何使用泛型

例子: 要求定義一個Point點類,該類中屬性有x座標和y座標。

要求: x和y的值可以都是整數型別。

​ x和y的值可以都是小數型別。

​ x和y的值可以都是字串型別。

如何定義該類呢? 如何確定屬性的型別。----可以想到使用Object型別

如果我們為座標一個賦值整數,一個賦值為字串,這時不會報錯 ,

但是它違背了我們設計的要求,這就是我們提到的資料型別安全問題。如何解決資料型別安全問題?可以使用泛型來解決,使用泛型就保證了資料型別安全問題 。

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.萬用字元

在開發中物件的參照傳遞是最常見的,但是如果在泛型類的操作中,在進行參照傳遞時泛型型別必須匹配才可以傳遞,否則是無法傳遞的。如果想傳遞,可以定義泛型為?萬用字元。

程式碼展示:

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標誌可以任意起名.----> 那麼在建立物件時,必須為每個泛型指定資料型別。
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 介面名<泛型標誌,泛型標誌....>{

//靜態常數

//抽象方法

}

類如何實現泛型介面 程式碼展示:

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靜態成員,隨著類的載入而被載入到JVM記憶體中 常數池
    public static <T> T fun(T t){
        return t;
    }
    //泛型方法: static靜態成員,隨著類的載入而被載入到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: 重寫得註解。符合重寫得規則。

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);
    }
}

注意: 使用註解和不使用註解沒有區別

註解本身沒有任何意義,它只有被解析了,才會賦予真正的意義。

我們後會使用反射來物件註解進行解析。

像:@Override 它被JVM解析,從而使其具有相應的意義。

​ @Controller @RequestMapping 它被Spring框架解析,所以具有相應的意義。

3.3.元註解

定義在註解上的註解稱為元註解。

@Controller它只能加在類上 @Override它只能加在方法上。

原因它使用了元註解可以設定註解使用的位置

1. @Target(value=可以取下面這些內容): 作用限制註解使用得位置。

/** 表示可以作用在類,介面,列舉 */ TYPE,

/** 屬性 */

FIELD,

/** 普通方法上 */

METHOD,

/** 方法引數 */

PARAMETER,

/** 構造方法上 */

CONSTRUCTOR,

/** 區域性變數 */

LOCAL_VARIABLE

2. @Retention: 註解什麼時候生效。預設時原始碼 java經歷了那些階段。

原始碼階段-->位元組碼階段--->執行階段 /** * 原始碼時生效 */ SOURCE,

/**

* 位元組碼時生效 */ 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[預設位元組碼有效]---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泛型與註解內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com