1. 程式人生 > >java 泛型 extends 多個

java 泛型 extends 多個

1.泛型邊界:

Java泛型程式設計時,編譯器忽略泛型引數的具體型別,認為使用泛型的類、方法對Object都適用,這在泛型程式設計中稱為型別資訊檫除。

例如:

[java] view plaincopyprint?
  1. class GenericType{  
  2. publicstaticvoid main(String[] args){  
  3.         System.out.println(new ArrayList<String>().getClass());  
  4.         System.out.println(new ArrayList<Integer>().getClass());  
  5. }  
  6. }  
class GenericType{
	public static void main(String[] args){
		System.out.println(new ArrayList<String>().getClass());
		System.out.println(new ArrayList<Integer>().getClass());
}
}

輸出結果為:

java.util.ArrayList

java.util.ArrayList

泛型忽略了集合容器中具體的型別,這就是型別檫除。

但是如果某些泛型的類/方法只想針對某種特定型別獲取相關子類應用,這時就必須使用泛型邊界來為泛型引數指定限制條件。

例如:

[java] view plaincopyprint?
  1. interface HasColor{  
  2.     java.awt.Color getColor();  
  3. }  
  4. class Colored<T extends HasColor>{  
  5.     T item;  
  6.     Colored(T item){  
  7. this.item = item;  
  8. }  
  9. java.awt.Color color(){  
  10. //呼叫HasColor介面實現類的getColor()方法
  11. return item.getColor();  
  12. }  
  13. }  
  14. class Dimension{  
  15. public
    int x, y, z;  
  16. }  
  17. Class ColoredDimension<T extends Dimension & HasColor>{  
  18.     T item;  
  19.     ColoredDimension(T item){  
  20. this.item = item;  
  21. }  
  22. T getItem(){  
  23. return item;  
  24. }  
  25. java.awt.Color color(){  
  26. //呼叫HasColor實現類中的getColor()方法
  27. return item.getColor();  
  28. }  
  29. //獲取Dimension類中定義的x,y,z成員變數
  30. int getX(){  
  31. return item.x;  
  32. }  
  33. int getY(){  
  34. return item.y;  
  35. }  
  36. int getZ(){  
  37. return item.z;  
  38. }  
  39. }  
  40. interface Weight{  
  41. int weight();  
  42. }  
  43. class Solid<T extends Dimension & HasColor & Weight>{  
  44.     T item;  
  45.     Solide(T item){  
  46. this.item = item;  
  47. }  
  48. T getItem(){  
  49. return item;  
  50. }  
  51. java.awt.Color color(){  
  52. //呼叫HasColor實現類中的getColor()方法
  53. return item.getColor();  
  54. }  
  55. //獲取Dimension類中定義的x,y,z成員變數
  56. int getX(){  
  57. return item.x;  
  58. }  
  59. int getY(){  
  60. return item.y;  
  61. }  
  62. int getZ(){  
  63. return item.z;  
  64. }  
  65. int weight(){  
  66. //呼叫Weight介面實現類的weight()方法
  67. return item.weight();  
  68. }  
  69. }  
  70. class Bounded extends Dimension implements HasColor, Weight{  
  71. public java.awt.Color getColor{  
  72. returnnull;  
  73. }  
  74. publicint weight(){  
  75. return0;  
  76. }  
  77. }  
  78. publicclass BasicBounds{  
  79. publicstaticvoid main(String[] args){  
  80.         Solid<Bounded> solid = new Solid<Bounded>(new Bounded());  
  81.         solid.color();  
  82.         solid.getX();  
  83.         solid.getY();  
  84.         solid.getZ();  
  85.         solid.weight();  
  86. }  
  87. }  
interface HasColor{
	java.awt.Color getColor();
}
class Colored<T extends HasColor>{
	T item;
	Colored(T item){
		this.item = item;
}
java.awt.Color color(){
	//呼叫HasColor介面實現類的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(){
	//呼叫HasColor實現類中的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(){
	//呼叫HasColor實現類中的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(){
	//呼叫Weight介面實現類的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關鍵字指定泛型引數型別的上邊界(後面還會講到使用super關鍵字指定泛型的下邊界),即泛型只能適用於extends關鍵字後面類或介面的子類。

Java泛型程式設計的邊界可以是多個,使用如<T extends A & B & C>語法來宣告,其中只能有一個是類,並且只能是extends後面的第一個為類,其他的均只能為介面(和類/介面中的extends意義不同)。

使用了泛型邊界之後,泛型物件就可以使用邊界物件中公共的成員變數和方法。

2.泛型萬用字元:

泛型初始化過程中,一旦給定了引數型別之後,引數型別就會被限制,無法隨著複製的型別而動態改變,如:

[java] view plaincopyprint?
  1. class Fruit{  
  2. }  
  3. class Apple extends Fruit{  
  4. }  
  5. class Jonathan extends Apple{  
  6. }  
  7. class Orange extends Fruit{  
  8. }  
  9. 如果使用陣列:  
  10. publicclass ConvariantArrays{  
  11.     Fruit fruit = new Apple[10];  
  12.     Fruit[0] = new Apple();  
  13.     Fruit[1] = new Jonathan();  
  14. try{  
  15.         fruit[0] = new Fruit();  
  16. }catch(Exception e){  
  17.     System.out.println(e);  
  18. }  
  19. try{  
  20.         fruit[0] = new Orange();  
  21. }catch(Exception e){  
  22.     System.out.println(e);  
  23. }  
  24. }  
class Fruit{
}
class Apple extends Fruit{
}
class Jonathan extends Apple{
}
class Orange extends Fruit{
}
如果使用陣列:
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);
}
}

編譯時沒有任何錯誤,執行時會報如下異常:

java.lang.ArrayStoreException:Fruit

java.lang.ArrayStoreException:Orange

為了使得泛型在編譯時就可以進行引數型別檢查,我們推薦使用java的集合容器類,如下:

[java] view plaincopyprint?
  1. publicclass NonConvariantGenerics{  
  2.     List<Fruit> flist = new ArrayList<Apple>();  
  3. }  
public class NonConvariantGenerics{
	List<Fruit> flist = new ArrayList<Apple>();
}

很不幸的是,這段程式碼會報編譯錯誤:incompatible types,不相容的引數型別,集合認為雖然Apple繼承自Fruit,但是List的Fruit和List的Apple是不相同的,因為泛型引數在宣告時給定之後就被限制了,無法隨著具體的初始化例項而動態改變,為解決這個問題,泛型引入了萬用字元”?”。

對於這個問題的解決,使用萬用字元如下:

[java] view plaincopyprint?
  1. publicclass NonConvariantGenerics{  
  2.     List<? extends Fruit> flist = new ArrayList<Apple>();  
  3. }  
public class NonConvariantGenerics{
	List<? extends Fruit> flist = new ArrayList<Apple>();
}

泛型萬用字元”?”的意思是任何特定繼承Fruit的類,java編譯器在編譯時會根據具體的型別例項化。

另外,一個比較經典泛型萬用字元的例子如下:

public class SampleClass < T extendsS> {…}

假如A,B,C,…Z這26個class都實現了S介面。我們使用時需要使用到這26個class型別的泛型引數。那例項化的時候怎麼辦呢?依次寫下

SampleClass<A> a = new SampleClass();

SampleClass<B> a = new SampleClass();

SampleClass<Z> a = new SampleClass();

這顯然很冗餘,還不如使用Object而不使用泛型,使用萬用字元非常方便:

SampleClass<? Extends S> sc = newSampleClass();

3.泛型下邊界:

在1中大概瞭解了泛型上邊界,使用extends關鍵字指定泛型例項化引數只能是指定類的子類,在泛型中還可以指定引數的下邊界,是一super關鍵字可以指定泛型例項化時的引數只能是指定類的父類。

例如:

[java] view plaincopyprint?
  1. class Fruit{  
  2. }  
  3. class Apple extends Fruit{  
  4. }  
  5. class Jonathan extends Apple{  
  6. }  
  7. class Orange extends Fruit{  
  8. }  
  9. public superTypeWildcards{  
  10. publicstaticvoid writeTo(List<? super Apple> apples){  
  11.         apples.add(new Apple());  
  12.         apples.add(new Jonathan());  
  13. }  
  14. }  
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());
}
}

通過? Super限制了List元素只能是Apple的父類。

泛型下邊界還可以使用<?super T>,但是注意不能使用<Tsuper A>,即super之前的只能是泛型萬用字元,如:

[java] view plaincopyprint?
  1. publicclass GenericWriting{  
  2. static List<Apple> apples = new ArrayList<Apple>();  
  3. static List<Fruit> fruits = new ArrayList<Fruit>();  
  4. static <T> void writeExact(List<T> list, T item){  
  5.         list.add(item);  
  6. }  
  7. static <T> void writeWithWildcards(List<? super T> list, T item){  
  8.     list.add(item);  
  9. }  
  10. staticvoid f1(){  
  11.     writeExact(apples, new Apple());  
  12. }  
  13. staticvoid f2(){  
  14. writeWithWildcards(apples, new Apple());  
  15.     writeWithWildcards(fruits, new Apple());  
  16. }  
  17. publicstaticvoid main(String[] args){  
  18.     f1();  
  19.     f2();  
  20. }  
  21. }  
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.無邊界的萬用字元:

泛型的萬用字元也可以不指定邊界,沒有邊界的萬用字元意思是不確定引數的型別,編譯時泛型檫除型別資訊,認為是Object型別。如:

[java] view plaincopyprint?
  1. publicclass UnboundedWildcard{  
  2. static List list1;  
  3. static List<?> list2;  
  4. static List<? extends Object> list3;  
  5. staticvoid assign1(List list){  
  6.         list1 = list;  
  7.         list2 = list;  
  8. //list3 = list; //有未檢查轉換警告
  9. }   
  10. staticvoid assign2(List<?> list){  
  11.         list1 = list;  
  12.         list2 = list;  
  13.     list3 = list;  
  14. }  
  15. staticvoid assign3(List<? extends Object> list){  
  16.         list1 = list;  
  17.         list2 = list;  
  18.     list3 = list;  
  19. }  
  20. publicstaticvoid main(String[] args){  
  21.     assign1(new ArrayList());  
  22. assign2(new ArrayList());  
  23. //assign3(new ArrayList()); //有未檢查轉換警告
  24. assign1(new ArrayList<String>());  
  25. assign2(new ArrayList<String>());  
  26. assign3(new ArrayList<String>());   
  27. List<?> wildList = new ArrayList();  
  28. assign1(wildList);  
  29. assign2(wildList);  
  30. assign3(wildList);   
  31. }  
  32. }  
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; //有未檢查轉換警告
} 
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()); //有未檢查轉換警告
assign1(new ArrayList<String>());
assign2(new ArrayList<String>());
assign3(new ArrayList<String>()); 
List<?> wildList = new ArrayList();
assign1(wildList);
assign2(wildList);
assign3(wildList); 
}
}

List和List<?>的區別是:List是一個原始型別的List,它可以存放任何Object型別的物件,不需要編譯時型別檢查。List<?>等價於List<Object>,它不是一個原始型別的List,它存放一些特定型別,只是暫時還不確定是什麼型別,需要編譯時型別檢查。因此List的效率要比List<?>高。

5.實現泛型介面注意事項:

由於泛型在編譯過程中檫除了引數型別資訊,所以一個類不能實現以泛型引數區別的多個介面,如:

[java] view plaincopyprint?
  1. interface Payable<T>{  
  2. }  
  3. class Employee implements Payable<Employee>{  
  4. }  
  5. class Hourly extends Employee implements Payable<Hourly>{  
  6. }  
interface Payable<T>{
}
class Employee implements Payable<Employee>{
}
class Hourly extends Employee implements Payable<Hourly>{
}

類Hourly無法編譯,因為由於泛型型別檫除,Payable<Employee>和Payable<Hourly>在編譯時是同一個型別Payable,因此無法同時實現一個介面兩次。

6.泛型方法過載注意事項:

由於泛型在編譯時將引數型別檫除,因此以引數型別來進行方法過載在泛型中要特別注意,如:

[java] view plaincopyprint?
  1. publicclass GenericMethod<W,T>{  
  2. void f(List<T> v) {  
  3. }  
  4. void f(List<W> v){  
  5. }  
  6. }  
public class GenericMethod<W,T>{
	void f(List<T> v) {
}
void f(List<W> v){
}
}

無法通過編譯,因為泛型檫除型別資訊,上面兩個方法的引數都被看作為Object型別,使用引數型別已經無法區別上面兩個方法,因此無法過載。

7.泛型中的自繫結:

通常情況下,一個類無法直接繼承一個泛型引數,但是你可以通過繼承一個宣告泛型引數的類,這就是java泛型程式設計中的自繫結,如:

[java] view plaincopyprint?
  1. class SelfBounded<T extends SelfBounded<T>>{  
  2.     T element;  
  3.     SelfBounded<T> set(T arg){  
  4.         Element = arg;  
  5. returnthis;  
  6. }   
  7. T get(){  
  8. return element;  
  9. }  
  10. }  
  11. class A extends SelfBounded<A>{  
  12. }  
  13. class B extends SelfBounded<A>{  
  14. }  
  15. class C extends SelfBounded<C>{  
  16.     C setAndGet(C arg){  
  17.         set(arg);  
  18. return get();  
  19. }  
  20. }  
  21. publicclass SelfBounding{  
  22. publicstaticvoid main(String[] args){  
  23.         A a = new A();  
  24.         a.set(new A());  
  25.         a = a.set(new A()).get();  
  26.         a = a.get();  
  27.         C c = new C();  
  28.         C = c.setAndGet(new C());  
  29. }  
  30. }  
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());
}
}

泛型的自繫結約束目的是用於強制繼承關係,即使用泛型引數的類的基類是相同的,強制所有人使用相同的方式使用引數基類。

===========

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>{...}