java 泛型特性

泛型

  1. oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
    在Java中,泛型的引入是為了在編譯時(shí)提供強(qiáng)類型檢查和支持泛型編程。為了實(shí)現(xiàn)泛型,Java編譯器應(yīng)用類型擦除實(shí)現(xiàn):
    1、 用類型參數(shù)(type parameters)的限定(如果沒(méi)有就用Object)替換泛型類型中的所有類型參數(shù)。
    2、 需要保持類型安全的時(shí)候插入類型轉(zhuǎn)換(隱含插入)
    3、 在extened 泛型類型中生成橋方法來(lái)保證多態(tài)性
    類型擦除確保不會(huì)為已參數(shù)化了的類型(paramterized types)產(chǎn)生新類,這樣泛型能保證沒(méi)有運(yùn)行時(shí)的負(fù)載。

  2. 泛型的好處是在編譯的時(shí)候檢查類型安全,減少運(yùn)行時(shí)的問(wèn)題;避免強(qiáng)制轉(zhuǎn)換的麻煩;

特性

只在編譯階段有效。在編譯過(guò)程中,正確檢驗(yàn)泛型結(jié)果后,會(huì)將泛型的相關(guān)信息擦除
如:

public class MyClass {

    private static List<String> list1 = new ArrayList<>();
    private static List<Integer> list2 = new ArrayList<>();


    public static void main(String args[]){
        list1.add("aaaa");
        list2.add(11);
        System.out.println("----list1------>" + list1.getClass());
        System.out.println("----list2------>" + list2.getClass());
        System.out.println("泛型類型是否相同-->" + list2.getClass().equals(list1.getClass()));
    }
}

輸出結(jié)果:

----list1------>class java.util.ArrayList
----list2------>class java.util.ArrayList
泛型類型是否相同-->true

在編譯之后程序會(huì)采取去泛型化的措施。也就是說(shuō)Java中的泛型,只在編譯階段有效。在編譯過(guò)程中,正確檢驗(yàn)泛型結(jié)果后,會(huì)將泛型的相關(guān)信息擦出,并且在對(duì)象進(jìn)入和離開(kāi)方法的邊界處添加類型檢查和類型轉(zhuǎn)換的方法。也就是說(shuō),泛型信息不會(huì)進(jìn)入到運(yùn)行時(shí)階段。

對(duì)此總結(jié)成一句話:泛型類型在邏輯上看以看成是多個(gè)不同的類型,實(shí)際上都是相同的基本類型。

擦除規(guī)則

JVM并不知道泛型的存在,因?yàn)榉盒驮诰幾g階段就已經(jīng)被處理成普通的類和方法;
處理機(jī)制是通過(guò)類型擦除,擦除規(guī)則:

若泛型類型沒(méi)有指定具體類型,用Object作為原始類型;
若有限定類型< T exnteds XClass >,使用XClass作為原始類型;
若有多個(gè)限定< T exnteds XClass1 & XClass2 >,使用第一個(gè)邊界類型XClass1 XClass2作為原始類型
如下例:
測(cè)試目錄結(jié)構(gòu)
├── MyClass.java //測(cè)試類
├── parent
│ ├── IOne.java //接口1
│ ├── ITwo.java //接口2
│ └── ParentOne.java //父類
├── sun
│ ├── Sun.java
│ └── SunOne.java
├── Test.java
├── TestOne.java
└── TestTwo.java

定義測(cè)試類

package com.example.test;

import com.example.test.sun.Sun;
import com.example.test.sun.SunOne;

public class MyClass {
    public static void main(String args[]){
        //無(wú)限定
        Test test = new Test();
        test.setT("test");
        //< T exnteds XClass > 限定
        TestOne testOne = new TestOne();
        testOne.setT(new SunOne());
        //多個(gè)限定< T exnteds XClass1 & XClass2 >
        TestTwo testTwo = new TestTwo();
        testTwo.setT(new Sun());
        System.out.println("----test------>" + test.getClass());
        System.out.println("----testOne------>" + testOne.getClass());
        System.out.println("----testTwo------>" + testTwo.getClass());
    }

}

無(wú)限定

package com.example.test;

/**
 * T 無(wú)限定
 * @param <T>
 */
public class Test<T> {
    /**
     * T 最終等同于
     *   private Object t;
     */
    private T t;

    public void setT(T t) {
        this.t = t;
    }
}

單個(gè)限定

package com.example.test;

import com.example.test.parent.ParentOne;

/**
 * T 傳入的類型必須繼承于ParentOne
 * @param <T>
 */
public class TestOne<T extends ParentOne> {

    private T t;

    public void setT(T t) {
        this.t = t;
    }
}


package com.example.test.sun;

import com.example.test.parent.ParentOne;

public class SunOne extends ParentOne {
}

package com.example.test.parent;

public class ParentOne {
}

多個(gè)限定 類實(shí)現(xiàn)兩個(gè)接口

package com.example.test;

import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;

/**
 * T 類型 必須繼承IOne ITwo 接口
 * @param <T>
 */
public class TestTwo<T extends IOne & ITwo> {
    private T t;

    public void setT(T t) {
        this.t = t;
    }
}

package com.example.test.sun;

import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;

public class Sun implements IOne,ITwo {
}

package com.example.test.parent;

public interface ITwo {
}

package com.example.test.parent;

public interface IOne {
}

泛型中占位符T和?區(qū)別

“<T>"和"<?>",首先要區(qū)分開(kāi)兩種不同的場(chǎng)景:

  1. 第一,聲明一個(gè)泛型類或泛型方法。
  2. 第二,使用泛型類或泛型方法。
  3. 類型參數(shù)“<T>”主要用于第一種,聲明泛型類或泛型方法。
  4. 無(wú)界通配符“<?>”主要用于第二種,使用泛型類或泛型方法
    泛型的限定:
    ? extends E:接收E類型或者E的子類型。
    ?super E:接收E類型或者E的父類型。
    簡(jiǎn)單例子
package com.example.test;

import java.util.ArrayList;
import java.util.List;

public class MyClass {
    private static List list1 = new ArrayList();
    private static List<String> list2 = new ArrayList();
    public static void main(String args[]){
        list1.add("aaa");
        list1.add(33);
        list2.add("bbbb");
        list2.add("cccc");
        for (int i =0 ;i<list1.size();i++){
            System.out.println("---------->" + list1.get(i));
        }
        System.out.println("-----#############-----");
        for (int i =0 ;i<list2.size();i++){
            System.out.println("---------->" + list2.get(i));
        }
    }
}

輸出

---------->aaa
---------->33
-----#############-----
---------->bbbb
---------->cccc

一個(gè)限定類型,只能add String
另一個(gè),可添加多種類型的數(shù)據(jù)

//使用通配符?
SuperClass<?> sup = new SuperClass<String>("例子");
sup = new SuperClass<Student>(new Student());
sup = new SuperClass<Teacher>(new Teacher());
//不使用通配符
SuperClass<String> sup1 = new SuperClass<String>("lisi");
SuperClass<Student> sup2 = new SuperClass<Student>(new Student());
SuperClass<Teacher> sup3 = new SuperClass<Teacher>(new Teacher());
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容