久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java中的泛型

 碧海山城 2012-08-19

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對象時(shí),必須指明向持有什么類型的對象,,將其置于尖括號內(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í)候,,通常不必指明參數(shù)類型,,因?yàn)榫幾g器會為我們找出具體的類型,這稱為類型參數(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);

 

從代碼上看,我們很容易認(rèn)為是不同的類型,。不同的類型在行為上不同,,例如嘗試將一個Integer放入ArrayList<String>,所得到的行為(失敗)與Integer放入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)實(shí)是:

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

 

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

 

Template<class T> class Manipulator{

T obj;

public:

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

}

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

 

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

Class Mainpulator<T extends Hasf>{

Private T obj;

Public void mainpulate{obj.f();}

}

 

3.3   擦除原因

擦除并不是語言的一個特性,,是Java實(shí)現(xiàn)泛型的一種折中,,因?yàn)榉盒筒皇?/SPAN>Java語言出現(xiàn)時(shí)就有的組成部分,所以這種折中是必須的,。

 

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

 

在基于擦除的實(shí)現(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)型成有意義的類型,,因?yàn)門并沒有包含具體的意思,它被擦除了,,會 //有警告

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

 

3.5      擦除的邊界

 

雖然在運(yùn)行的時(shí)候,擦除在方法體重移除了類型信息,,但是在邊界(看了下面的例子再解釋邊界)的時(shí)候,,還是會進(jìn)行類型轉(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)的時(shí)候,,會需要調(diào)用它的toString方法,它是Object的方法,,并不需要轉(zhuǎn)型,,沒有任何類型檢查,所以沒有發(fā)生異常,,但是下次調(diào)用get(4).getaa()的時(shí)候,,這需要類型轉(zhuǎn)換,所以這里進(jìn)行類型檢查,,拋出了異常,。

 

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

 

3.6   New泛型

創(chuàng)建一個new T()的嘗試將無法實(shí)現(xiàn),,部分原因是因?yàn)椴脸硪徊糠衷蚴且驗(yàn)榫幾g器不能驗(yàn)證具有默認(rèn)的無參構(gòu)造函數(shù),,但是在C++中,,這種操作很自然,很直觀,,并且很安全,。

 

Java中的解決方案是傳遞一個工廠對象,并使用它來創(chuàng)建新的實(shí)例,,最便利的工廠就是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);

       

        //這里會拋出異常,,因?yàn)镮nteger沒有默認(rèn)的構(gòu)造函數(shù)

        ClassAsFactory<Integer> f1=new

            ClassAsFactory<Integer>(Integer.class);

    }

}

 

class Employee{}

 

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

 

3.7   ExtendsSuper?

 

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ù)時(shí)限制放寬了,,因?yàn)榫幾g器知道范型的下界,,只要是Derived類或它的子類都是合法的。但是在返回時(shí),,它只能返回Object類型,,因?yàn)樗荒艽_定它的上界。

 

 

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

 

 

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

 

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

 

4.1   Type體系

 

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

 

4.2   獲得泛型類型

參看Java獲得泛型類型

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

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

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

聲明一側(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ǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多