国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Java中的泛型

1          參考

2         簡單泛型

2.1   泛型類

public class Holder3<T> {

    private T a;

   

    public Holder3(T a ){

        this.a=a;

    }

   

    public void set(T a){this.a=a;}

   

    public T get(){return a;}

   

    public static void main(String[] args){

        Holder3<Animal> h3=new Holder3<Animal>(new AnimalWrapper());

    } 

}

就象main方法,

當(dāng)創(chuàng)建Holder3對象時,必須指明向持有什么類型的對象,將其置于尖括號內(nèi)。

2.2   泛型方法

定義泛型方法,只需要將泛型參數(shù)列表置于返回值之前,就像下面:

public class GenericMethods {

 

    public <T> void f(T x){

        System.out.println(x.getClass().getName());

    }

   

    public static void main(String[] agrs){

        GenericMethods gm=new GenericMethods();

        gm.f("");

        gm.f(1);

        gm.f(1.0);

        gm.f(1.0F);

       

        gm.f(gm); 

    }  

}

結(jié)果:

java.lang.String

java.lang.Integer

java.lang.Double

java.lang.Float

proxy.generic.GenericMethods

 

如果是泛型類,必須在創(chuàng)建對象的時候指定類型參數(shù)的值,而是用泛型方法的時候,通常不必指明參數(shù)類型,因為編譯器會為我們找出具體的類型,這稱為類型參數(shù)推斷。因此,可以想調(diào)用普通方法一樣調(diào)用f(),而且,就好像是f()被無限次重載過。

 3         擦除

 

3.1   初步擦除

Class c1=new ArrayList<String>().getClass();

Class c2=new ArrayList<Integer>().getClass();

   

System.out.println(c1==c2);

 

從代碼上看,我們很容易認為是不同的類型。不同的類型在行為上不同,例如嘗試將一個Integer放入ArrayList<String>,所得到的行為(失?。┡cInteger放入ArrayList<Integer>,所得到的行為完全不同,但是程序會打印出來相同。下面是另外一個奇怪的程序:

public class LostInformation {

 

    public static void main(String[] args){

        List<Frob> list=new ArrayList<Frob>();

        Map<Frob,Fnorkie> map=new HashMap<Frob, Fnorkie>();

       

        Quark<Fnorkie> quark=new Quark<Fnorkie>();

        Particle<Long,Double> p=new Particle<Long, Double>();

            System.out.println(Arrays.toString(list.getClass().getTypeParameters()));

        System.out.println(Arrays.toString(map.getClass().getTypeParameters()));

        System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));

        System.out.println(Arrays.toString(p.getClass().getTypeParameters()));

   

    }

}

class Frob{}

class Fnorkie{}

class Quark<Q>{}

class Particle<POSITION,MOMENTUN>{}

 

[E]

[K, V]

[Q]

[POSITION, MOMENTUN]

Class.getTypeParameters()的說明看起來是返回一個TypeVarible對象數(shù)組,表示有泛型聲明所聲明的類型參數(shù),這好像是暗示你可能發(fā)現(xiàn)參數(shù)類型的信息,但是,正如結(jié)果看到的,你能夠發(fā)現(xiàn)的只是用作參數(shù)占位符的標(biāo)識符,殘酷的現(xiàn)實是:

在泛型代碼內(nèi)部,無法獲得任何有關(guān)泛型參數(shù)類型的信息

 

3.2   C++的泛型與Java泛型邊界

 

Template<class T> class Manipulator{

T obj;

public:

Void manipulator(T x){obj.f();}

}

C++的實現(xiàn)中,obj上可以調(diào)用f()方法,為什么?當(dāng)實例化這個模板時,C++編譯器將進行檢查,因此在Manipulator<HasF>被實例化的這一刻,看到HasF擁有一個方法f(),如果不是這樣,將會得到一個編譯期錯誤,這樣類型安全就得到了保障。

 

Java中不能這么做,除非借助泛型類的邊界,以此告訴編譯器,只能接受遵循這個邊界的類型,這里重用了extends關(guān)鍵字:

Class Mainpulator<T extends Hasf>{

Private T obj;

Public void mainpulate{obj.f();}

}

 

3.3   擦除原因

擦除并不是語言的一個特性,是Java實現(xiàn)泛型的一種折中,因為泛型不是Java語言出現(xiàn)時就有的組成部分,所以這種折中是必須的。

 

如果泛型在Java1.0中就已經(jīng)是其一部分,那么這個特性就不會使用搽除來實現(xiàn),它將具體化,使類型參數(shù)保持為第一類試題,因此你就能夠在泛型參數(shù)上執(zhí)行基于類型的語言操作和反射操作。主要是為了向后兼容性,即現(xiàn)有的代碼和類文件仍舊合法,并且繼續(xù)保持其之前的含義,而且還要支持遷移兼容性,使得類庫按照它們自己的步調(diào)變?yōu)榉盒偷?/b>。

 

在基于擦除的實現(xiàn)中,泛型類型被當(dāng)作第二類類型處理,即不能再某些重要的上下文環(huán)境中使用的類型,泛型類型只有在靜態(tài)類型檢查期間出現(xiàn),在此之后,程序中所有泛型類型都將被擦除,替換為它們的非泛型上界,例如,諸如List<T>被擦除為List,而普通的類型變量在未指定邊界的情況下,被擦除為Object。

 

3.4   擦除的問題

public class ArrayMaker<T> {

 

    private Class<T> kind;

    public ArrayMaker(Class<T> kind){this.kind=kind;}

   

   

    T[] create(int size){

//這里必須轉(zhuǎn)型成有意義的類型,因為T并沒有包含具體的意思,它被擦除了,會 //有警告

        return (T[])Array.newInstance(kind, size);

    }

   

    public static void main(String[] grs){

        ArrayMaker<String> stringMarker=

new ArrayMaker<String>(String.class);

        String[] stringArray=stringMarker.create(9);

        System.out.println(Arrays.toString(stringArray));

    }

   

}

結(jié)果:

[null, null, null, null, null, null, null, null, null]

 

即使kind被存儲為Class<T>,擦除也意味著它實際被存儲為Class,沒有任何參數(shù)。因此,當(dāng)你在使用它時,例如創(chuàng)建數(shù)組時,Array.newInstance()實際上并未擁有kind所蘊含的類型信息,因此不會產(chǎn)生具體的結(jié)果。在Java中推薦使用工廠(直接使用class.newInstance()或者顯示的工程方法)方法或者模板方法來解決這類創(chuàng)建問題

 

3.5      擦除的邊界

 

雖然在運行的時候,擦除在方法體重移除了類型信息,但是在邊界(看了下面的例子再解釋邊界)的時候,還是會進行類型轉(zhuǎn)換(檢查)。

public class FilledListMaker<T> {

    List<T> create(T t,int n){

        List<T> result=new ArrayList<T>();

        for(int i=0;i<n;i++){

            result.add(t);

        }

result.add((T)new b());

        return result;

    }

   

    public static void main(String[] agrs){

        FilledListMaker<demo> stringMarker=

new FilledListMaker<demo>();

       

        List<demo> list=stringMarker.create(demo.init("44"), 4);

        System.out.println(list.get(4));

        //這里發(fā)生了異常

System.out.println(list.get(4).getaa());

        System.out.println(list);  

    }

}

上面的泛型接受demo類型,但是我們悄悄放入了一個b類型。

 

javap -c FilledListMaker反編譯類,會得到下面的內(nèi)容:

 
可以看到,
main方法在get(4)的時候,會需要調(diào)用它的toString方法,它是Object的方法,并不需要轉(zhuǎn)型,沒有任何類型檢查,所以沒有發(fā)生異常,但是下次調(diào)用get(4).getaa()的時候,這需要類型轉(zhuǎn)換,所以這里進行類型檢查,拋出了異常。

 

所以可以記住,邊界就是發(fā)生在需要轉(zhuǎn)型的地方

 

3.6   New泛型

創(chuàng)建一個new T()的嘗試將無法實現(xiàn),部分原因是因為擦除,另一部分原因是因為編譯器不能驗證具有默認的無參構(gòu)造函數(shù),但是在C++中,這種操作很自然,很直觀,并且很安全。

 

Java中的解決方案是傳遞一個工廠對象,并使用它來創(chuàng)建新的實例,最便利的工廠就是Class對象,因此,如果使用類型標(biāo)簽,就可以使用newInstance來創(chuàng)建這個類型的新對象:

public class ClassAsFactory<T> {

    T x;

    public ClassAsFactory(Class<T> kind){

        try {

            x=kind.newInstance();

        } catch (Exception e){

            throw new RuntimeException(e);

        }

    }

   

    public static void main(String[] args){

        ClassAsFactory<Employee> fe=new

            ClassAsFactory<Employee>(Employee.class);

       

        //這里會拋出異常,因為Integer沒有默認的構(gòu)造函數(shù)

        ClassAsFactory<Integer> f1=new

            ClassAsFactory<Integer>(Integer.class);

    }

}

 

class Employee{}

 

可以看到,這種方式,在某些情況下會有異常,因為Integer沒有任何默認的構(gòu)造函數(shù),所以sun并不是很推薦使用這種方式,建議使用顯示的工廠,并將限制其類型,使得智能接受實現(xiàn)了這個工廠的類:

 

3.7   Extends,Super?

 

1.上面提到了邊界,因此擦除移除了類型信息,所以,可以用無界泛型參數(shù)調(diào)用的方法只是那些可以用Object調(diào)用的方法,但是,如果能夠?qū)⑦@個參數(shù)限制為某個類型子集,那么就可以用這些類型子集來調(diào)用方法。為了執(zhí)行這種限制,Java泛型重用了extends關(guān)鍵字,

 

interface face1 {}

interface face2 {}

class class1 {}

class Bound<T extends class1 & face1 & face2> {}

 

在子類還能加入更多的限定

interface face3 {}

class BoundDerived<T extends class1 & face1 & face2 & face3> extends Bound<T> {}

 

2.Super關(guān)鍵字限定了下界,但是沒有限定上界,所以

ArrayList<? super Derived1> alsb = new ArrayList<Base1>();

alsb.add(new Derived1()); //success

// alsb.add(new Base1()); // error: The method add(capture#4-of ? super Derived1) in the type ArrayList<capture#4-of ? super Derived1> is not applicable for the arguments (Base1)

Object d = alsb.get(0); // return an Object

 

可以看到在接受參數(shù)時限制放寬了,因為編譯器知道范型的下界,只要是Derived類或它的子類都是合法的。但是在返回時,它只能返回Object類型,因為它不能確定它的上界。

 

 

3.無界通配符,即<?>,與原生類型(非范型類)大體相似

 

 

個人感覺這部分是在太繞了,看java編程思想里面那么多的解釋,還是大概知道咋用就好了,貼一個我之前系統(tǒng)的設(shè)計圖吧

 

4    關(guān)于取得泛型的類型

 

4.1   Type體系

 

java5之后,java加入了type體系,這部分太麻煩了,以后有機會用到再寫吧,shit

 

4.2   獲得泛型類型

參看Java獲得泛型類型

Java泛型有這么一種規(guī)律:

位于聲明一側(cè)的,源碼里寫了什么到運行時就能看到什么;

位于使用一側(cè)的,源碼里寫什么到運行時都沒了。

聲明一側(cè),即在Class類內(nèi)的信息;使用一側(cè),即在一些方法體內(nèi)部

 

public class GenericClassTest<A,B extends Number> {

 

   private List<String> list;   

   public static void main(String[] args) throws NoSuchFieldException, SecurityException{

        GenericClassTest<String,Integer> gc=new GenericClassTest<String,Integer>();

        for(TypeVariable ty:gc.getClass().getTypeParameters()){

            System.out.println(ty.getName());

        }

        out(((ParameterizedType)gc.getClass().getDeclaredField("list")

                        .getGenericType()).getOwnerType());

        out(((ParameterizedType)gc.getClass().getDeclaredField("list")

                        .getGenericType()).getRawType());

        out(((ParameterizedType)gc.getClass().getDeclaredField("list").

                        getGenericType()).getActualTypeArguments()[0]);

    }}

輸出:

A

B

null

interface java.util.List

class java.lang.String

可以看到,聲明的list可以取到String,但是方法內(nèi)的對象缺只能取到A,B

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服