http://blog.csdn.net/chjttony/article/details/6801406
1.泛型邊界:
Java泛型編程時(shí),編譯器忽略泛型參數(shù)的具體類型,認(rèn)為使用泛型的類、方法對(duì)Object都適用,這在泛型編程中稱為類型信息檫除。
例如:
[java] view plaincopyprint?
class ?GenericType{??????public ?static ?void ?main(String[]?args){?? ????????System.out.println(new ?ArrayList<String>().getClass());?? ????????System.out.println(new ?ArrayList<Integer>().getClass());?? }?? }??
class GenericType{public static void main(String[] args){System.out.println(new ArrayList<String>().getClass());System.out.println(new ArrayList<Integer>().getClass());
}
}
?
輸出結(jié)果為:
java.util.ArrayList
java.util.ArrayList
泛型忽略了集合容器中具體的類型,這就是類型檫除。
但是如果某些泛型的類/方法只想針對(duì)某種特定類型獲取相關(guān)子類應(yīng)用,這時(shí)就必須使用泛型邊界來(lái)為泛型參數(shù)指定限制條件。
例如:
[java] view plaincopyprint?
interface ?HasColor{??????java.awt.Color?getColor();?? }?? class ?Colored<T?extends ?HasColor>{??????T?item;?? ????Colored(T?item){?? ????????this .item?=?item;?? }?? java.awt.Color?color(){?? ???? ?? ????return ?item.getColor();?? }?? }?? class ?Dimension{??????public ?int ?x,?y,?z;?? }?? Class?ColoredDimension<T?extends ?Dimension?&?HasColor>{?? ????T?item;?? ????ColoredDimension(T?item){?? ????????this .item?=?item;?? }?? T?getItem(){?? ????return ?item;?? }?? java.awt.Color?color(){?? ?????? ????return ?item.getColor();?? }?? ?? int ?getX(){??????return ?item.x;?? }?? int ?getY(){??????return ?item.y;?? }?? int ?getZ(){??????return ?item.z;?? }?? }?? interface ?Weight{??????int ?weight();?? }?? class ?Solid<T?extends ?Dimension?&?HasColor?&?Weight>{??????T?item;?? ????Solide(T?item){?? ????????this .item?=?item;?? }?? T?getItem(){?? ????return ?item;?? }?? java.awt.Color?color(){?? ?????? ????return ?item.getColor();?? }?? ?? int ?getX(){??????return ?item.x;?? }?? int ?getY(){??????return ?item.y;?? }?? int ?getZ(){??????return ?item.z;?? }?? int ?weight(){???????? ????return ?item.weight();?? }?? }?? class ?Bounded?extends ?Dimension?implements ?HasColor,?Weight{??????public ?java.awt.Color?getColor{?? ????????return ?null ;?? }?? public ?int ?weight(){??????return ?0 ;?? }?? }?? public ?class ?BasicBounds{??????public ?static ?void ?main(String[]?args){?? ????????Solid<Bounded>?solid?=?new ?Solid<Bounded>(new ?Bounded());?? ????????solid.color();?? ????????solid.getX();?? ????????solid.getY();?? ????????solid.getZ();?? ????????solid.weight();?? }?? }??
interface HasColor{java.awt.Color getColor();
}
class Colored<T extends HasColor>{T item;Colored(T item){this.item = item;
}
java.awt.Color color(){//調(diào)用HasColor接口實(shí)現(xiàn)類的getColor()方法return item.getColor();
}
}
class Dimension{public int x, y, z;
}
Class ColoredDimension<T extends Dimension & HasColor>{T item;ColoredDimension(T item){this.item = item;
}
T getItem(){return item;
}
java.awt.Color color(){//調(diào)用HasColor實(shí)現(xiàn)類中的getColor()方法return item.getColor();
}
//獲取Dimension類中定義的x,y,z成員變量
int getX(){return item.x;
}
int getY(){return item.y;
}
int getZ(){return item.z;
}
}
interface Weight{int weight();
}
class Solid<T extends Dimension & HasColor & Weight>{T item;Solide(T item){this.item = item;
}
T getItem(){return item;
}
java.awt.Color color(){//調(diào)用HasColor實(shí)現(xiàn)類中的getColor()方法return item.getColor();
}
//獲取Dimension類中定義的x,y,z成員變量
int getX(){return item.x;
}
int getY(){return item.y;
}
int getZ(){return item.z;
}
int weight(){//調(diào)用Weight接口實(shí)現(xiàn)類的weight()方法return item.weight();
}
}
class Bounded extends Dimension implements HasColor, Weight{public java.awt.Color getColor{return null;
}
public int weight(){return 0;
}
}
public class BasicBounds{public static void main(String[] args){Solid<Bounded> solid = new Solid<Bounded>(new Bounded());solid.color();solid.getX();solid.getY();solid.getZ();solid.weight();
}
}
?
Java泛型編程中使用extends關(guān)鍵字指定泛型參數(shù)類型的上邊界(后面還會(huì)講到使用super關(guān)鍵字指定泛型的下邊界),即泛型只能適用于extends關(guān)鍵字后面類或接口的子類。
Java泛型編程的邊界可以是多個(gè),使用如<T extends A & B & C>語(yǔ)法來(lái)聲明,其中只能有一個(gè)是類,并且只能是extends后面的第一個(gè)為類,其他的均只能為接口(和類/接口中的extends意義不同)。
使用了泛型邊界之后,泛型對(duì)象就可以使用邊界對(duì)象中公共的成員變量和方法。
2.泛型通配符:
泛型初始化過(guò)程中,一旦給定了參數(shù)類型之后,參數(shù)類型就會(huì)被限制,無(wú)法隨著復(fù)制的類型而動(dòng)態(tài)改變,如:
[java] view plaincopyprint?
class ?Fruit{??}?? class ?Apple?extends ?Fruit{??}?? class ?Jonathan?extends ?Apple{??}?? class ?Orange?extends ?Fruit{??}?? 如果使用數(shù)組:?? public ?class ?ConvariantArrays{??????Fruit?fruit?=?new ?Apple[10 ];?? ????Fruit[0 ]?=?new ?Apple();?? ????Fruit[1 ]?=?new ?Jonathan();?? ????try {?? ????????fruit[0 ]?=?new ?Fruit();?? }catch (Exception?e){?? ????System.out.println(e);?? }?? try {??????????fruit[0 ]?=?new ?Orange();?? }catch (Exception?e){?? ????System.out.println(e);?? }?? }??
class Fruit{
}
class Apple extends Fruit{
}
class Jonathan extends Apple{
}
class Orange extends Fruit{
}
如果使用數(shù)組:
public class ConvariantArrays{Fruit fruit = new Apple[10];Fruit[0] = new Apple();Fruit[1] = new Jonathan();try{fruit[0] = new Fruit();
}catch(Exception e){System.out.println(e);
}
try{fruit[0] = new Orange();
}catch(Exception e){System.out.println(e);
}
}
?
編譯時(shí)沒(méi)有任何錯(cuò)誤,運(yùn)行時(shí)會(huì)報(bào)如下異常:
java.lang.ArrayStoreException:Fruit
java.lang.ArrayStoreException:Orange
為了使得泛型在編譯時(shí)就可以進(jìn)行參數(shù)類型檢查,我們推薦使用java的集合容器類,如下:
[java] view plaincopyprint?
public ?class ?NonConvariantGenerics{??????List<Fruit>?flist?=?new ?ArrayList<Apple>();?? }??
public class NonConvariantGenerics{List<Fruit> flist = new ArrayList<Apple>();
}
?
很不幸的是,這段代碼會(huì)報(bào)編譯錯(cuò)誤:incompatible types,不兼容的參數(shù)類型,集合認(rèn)為雖然Apple繼承自Fruit,但是List的Fruit和List的Apple是不相同的,因?yàn)榉盒蛥?shù)在聲明時(shí)給定之后就被限制了,無(wú)法隨著具體的初始化實(shí)例而動(dòng)態(tài)改變,為解決這個(gè)問(wèn)題,泛型引入了通配符”?”。
對(duì)于這個(gè)問(wèn)題的解決,使用通配符如下:
[java] view plaincopyprint?
public ?class ?NonConvariantGenerics{??????List<??extends ?Fruit>?flist?=?new ?ArrayList<Apple>();?? }??
public class NonConvariantGenerics{List<? extends Fruit> flist = new ArrayList<Apple>();
}
?
泛型通配符”?”的意思是任何特定繼承Fruit的類,java編譯器在編譯時(shí)會(huì)根據(jù)具體的類型實(shí)例化。
另外,一個(gè)比較經(jīng)典泛型通配符的例子如下:
public class SampleClass < T extendsS> {…}
假如A,B,C,…Z這26個(gè)class都實(shí)現(xiàn)了S接口。我們使用時(shí)需要使用到這26個(gè)class類型的泛型參數(shù)。那實(shí)例化的時(shí)候怎么辦呢?依次寫(xiě)下
SampleClass<A> a = new SampleClass();
SampleClass<B> a = new SampleClass();
…
SampleClass<Z> a = new SampleClass();
這顯然很冗余,還不如使用Object而不使用泛型,使用通配符非常方便:
SampleClass<? Extends S> sc = newSampleClass();
3.泛型下邊界:
在1中大概了解了泛型上邊界,使用extends關(guān)鍵字指定泛型實(shí)例化參數(shù)只能是指定類的子類,在泛型中還可以指定參數(shù)的下邊界,是一super關(guān)鍵字可以指定泛型實(shí)例化時(shí)的參數(shù)只能是指定類的父類。
例如:
[java] view plaincopyprint?
class ?Fruit{??}?? class ?Apple?extends ?Fruit{??}?? class ?Jonathan?extends ?Apple{??}?? class ?Orange?extends ?Fruit{??}?? public ?superTypeWildcards{??????public ?static ?void ?writeTo(List<??super ?Apple>?apples){?? ????????apples.add(new ?Apple());?? ????????apples.add(new ?Jonathan());?? }?? }??
class Fruit{
}
class Apple extends Fruit{
}
class Jonathan extends Apple{
}
class Orange extends Fruit{
}
public superTypeWildcards{public static void writeTo(List<? super Apple> apples){apples.add(new Apple());apples.add(new Jonathan());
}
}
?
通過(guò)? Super限制了List元素只能是Apple的父類。
泛型下邊界還可以使用<?super T>,但是注意不能使用<Tsuper A>,即super之前的只能是泛型通配符,如:
[java] view plaincopyprint?
public ?class ?GenericWriting{??????static ?List<Apple>?apples?=?new ?ArrayList<Apple>();?? ????static ?List<Fruit>?fruits?=?new ?ArrayList<Fruit>();?? ????static ?<T>?void ?writeExact(List<T>?list,?T?item){?? ????????list.add(item);?? }?? static ?<T>?void ?writeWithWildcards(List<??super ?T>?list,?T?item){??????list.add(item);?? }?? static ?void ?f1(){??????writeExact(apples,?new ?Apple());?? }?? static ?void ?f2(){??writeWithWildcards(apples,?new ?Apple());?? ????writeWithWildcards(fruits,?new ?Apple());?? }?? public ?static ?void ?main(String[]?args){??????f1();?? ????f2();?? }?? }??
public class GenericWriting{static List<Apple> apples = new ArrayList<Apple>();static List<Fruit> fruits = new ArrayList<Fruit>();static <T> void writeExact(List<T> list, T item){list.add(item);
}
static <T> void writeWithWildcards(List<? super T> list, T item){list.add(item);
}
static void f1(){writeExact(apples, new Apple());
}
static void f2(){
writeWithWildcards(apples, new Apple());writeWithWildcards(fruits, new Apple());
}
public static void main(String[] args){f1();f2();
}
}
?
4.無(wú)邊界的通配符:
泛型的通配符也可以不指定邊界,沒(méi)有邊界的通配符意思是不確定參數(shù)的類型,編譯時(shí)泛型檫除類型信息,認(rèn)為是Object類型。如:
[java] view plaincopyprint?
public ?class ?UnboundedWildcard{??????static ?List?list1;?? ????static ?List<?>?list2;?? ????static ?List<??extends ?Object>?list3;?? ????static ?void ?assign1(List?list){?? ????????list1?=?list;?? ????????list2?=?list;?? ???????? ?? }??? static ?void ?assign2(List<?>?list){??????????list1?=?list;?? ????????list2?=?list;?? ????list3?=?list;?? }?? static ?void ?assign3(List<??extends ?Object>?list){??????????list1?=?list;?? ????????list2?=?list;?? ????list3?=?list;?? }?? public ?static ?void ?main(String[]?args){??????assign1(new ?ArrayList());?? assign2(new ?ArrayList());?? ?? assign1(new ?ArrayList<String>());?? assign2(new ?ArrayList<String>());?? assign3(new ?ArrayList<String>());??? List<?>?wildList?=?new ?ArrayList();?? assign1(wildList);?? assign2(wildList);?? assign3(wildList);??? }?? }??
public class UnboundedWildcard{static List list1;static List<?> list2;static List<? extends Object> list3;static void assign1(List list){list1 = list;list2 = list;//list3 = list; //有未檢查轉(zhuǎn)換警告
}
static void assign2(List<?> list){list1 = list;list2 = list;list3 = list;
}
static void assign3(List<? extends Object> list){list1 = list;list2 = list;list3 = list;
}
public static void main(String[] args){assign1(new ArrayList());
assign2(new ArrayList());
//assign3(new ArrayList()); //有未檢查轉(zhuǎn)換警告
assign1(new ArrayList<String>());
assign2(new ArrayList<String>());
assign3(new ArrayList<String>());
List<?> wildList = new ArrayList();
assign1(wildList);
assign2(wildList);
assign3(wildList);
}
}
?
List和List<?>的區(qū)別是:List是一個(gè)原始類型的List,它可以存放任何Object類型的對(duì)象,不需要編譯時(shí)類型檢查。List<?>等價(jià)于List<Object>,它不是一個(gè)原始類型的List,它存放一些特定類型,只是暫時(shí)還不確定是什么類型,需要編譯時(shí)類型檢查。因此List的效率要比List<?>高。
5.實(shí)現(xiàn)泛型接口注意事項(xiàng):
由于泛型在編譯過(guò)程中檫除了參數(shù)類型信息,所以一個(gè)類不能實(shí)現(xiàn)以泛型參數(shù)區(qū)別的多個(gè)接口,如:
[java] view plaincopyprint?
interface ?Payable<T>{??}?? class ?Employee?implements ?Payable<Employee>{??}?? class ?Hourly?extends ?Employee?implements ?Payable<Hourly>{??}??
interface Payable<T>{
}
class Employee implements Payable<Employee>{
}
class Hourly extends Employee implements Payable<Hourly>{
}
?
類Hourly無(wú)法編譯,因?yàn)橛捎诜盒皖愋烷叱?#xff0c;Payable<Employee>和Payable<Hourly>在編譯時(shí)是同一個(gè)類型Payable,因此無(wú)法同時(shí)實(shí)現(xiàn)一個(gè)接口兩次。
6.泛型方法重載注意事項(xiàng):
由于泛型在編譯時(shí)將參數(shù)類型檫除,因此以參數(shù)類型來(lái)進(jìn)行方法重載在泛型中要特別注意,如:
[java] view plaincopyprint?
public ?class ?GenericMethod<W,T>{??????void ?f(List<T>?v)?{?? }?? void ?f(List<W>?v){??}?? }??
public class GenericMethod<W,T>{void f(List<T> v) {
}
void f(List<W> v){
}
}
?
無(wú)法通過(guò)編譯,因?yàn)榉盒烷叱愋托畔?#xff0c;上面兩個(gè)方法的參數(shù)都被看作為Object類型,使用參數(shù)類型已經(jīng)無(wú)法區(qū)別上面兩個(gè)方法,因此無(wú)法重載。
7.泛型中的自綁定:
通常情況下,一個(gè)類無(wú)法直接繼承一個(gè)泛型參數(shù),但是你可以通過(guò)繼承一個(gè)聲明泛型參數(shù)的類,這就是java泛型編程中的自綁定,如:
[java] view plaincopyprint?
class ?SelfBounded<T?extends ?SelfBounded<T>>{??????T?element;?? ????SelfBounded<T>?set(T?arg){?? ????????Element?=?arg;?? ????????return ?this ;?? }??? T?get(){?? ????return ?element;?? }?? }?? class ?A?extends ?SelfBounded<A>{??}?? class ?B?extends ?SelfBounded<A>{??}?? class ?C?extends ?SelfBounded<C>{??????C?setAndGet(C?arg){?? ????????set(arg);?? ????????return ?get();?? }?? }?? public ?class ?SelfBounding{??????public ?static ?void ?main(String[]?args){?? ????????A?a?=?new ?A();?? ????????a.set(new ?A());?? ????????a?=?a.set(new ?A()).get();?? ????????a?=?a.get();?? ????????C?c?=?new ?C();?? ????????C?=?c.setAndGet(new ?C());?? }?? }??
class SelfBounded<T extends SelfBounded<T>>{T element;SelfBounded<T> set(T arg){Element = arg;return this;
}
T get(){return element;
}
}
class A extends SelfBounded<A>{
}
class B extends SelfBounded<A>{
}
class C extends SelfBounded<C>{C setAndGet(C arg){set(arg);return get();
}
}
public class SelfBounding{public static void main(String[] args){A a = new A();a.set(new A());a = a.set(new A()).get();a = a.get();C c = new C();C = c.setAndGet(new C());
}
}
?
泛型的自綁定約束目的是用于強(qiáng)制繼承關(guān)系,即使用泛型參數(shù)的類的基類是相同的,強(qiáng)制所有人使用相同的方式使用參數(shù)基類。
===========
public class Generic <T,S,R extends S>{ public <E> E getR(E e) { return e; } public static void main(String[] args) { Generic<Integer, Object, Number> g = new Generic<Integer, Object, Number>(); BigDecimal bd = new BigDecimal(1); g.getR(0.1); Generic<?,?,?> g1= new Generic<Integer, Object, Number>(); List<Integer>[] iListArray = new ArrayList[10]; } } class MyGeneric<T extends Object & Serializable > { } class YourGeneric<E,T,S,R extends S> extends Generic<T,S,R> implements List<E>{...}
?
總結(jié)
以上是生活随笔 為你收集整理的java 泛型 extends 多个 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。