java 泛型 extends 多個
1.泛型邊界:
Java泛型程式設計時,編譯器忽略泛型引數的具體型別,認為使用泛型的類、方法對Object都適用,這在泛型程式設計中稱為型別資訊檫除。
例如:
[java] view plaincopyprint?- class GenericType{
- publicstaticvoid 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());
}
}
輸出結果為:
java.util.ArrayList
java.util.ArrayList
泛型忽略了集合容器中具體的型別,這就是型別檫除。
但是如果某些泛型的類/方法只想針對某種特定型別獲取相關子類應用,這時就必須使用泛型邊界來為泛型引數指定限制條件。
例如:
[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(){
- //呼叫HasColor介面實現類的getColor()方法
- return item.getColor();
- }
- }
- class Dimension{
- public
- }
- 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{
- returnnull;
- }
- publicint weight(){
- return0;
- }
- }
- publicclass BasicBounds{
- publicstaticvoid 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(){
//呼叫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?- class Fruit{
- }
- class Apple extends Fruit{
- }
- class Jonathan extends Apple{
- }
- class Orange extends Fruit{
- }
- 如果使用陣列:
- publicclass 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{
}
如果使用陣列:
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?- publicclass NonConvariantGenerics{
- List<Fruit> flist = new ArrayList<Apple>();
- }
public class NonConvariantGenerics{
List<Fruit> flist = new ArrayList<Apple>();
}
很不幸的是,這段程式碼會報編譯錯誤:incompatible types,不相容的引數型別,集合認為雖然Apple繼承自Fruit,但是List的Fruit和List的Apple是不相同的,因為泛型引數在宣告時給定之後就被限制了,無法隨著具體的初始化例項而動態改變,為解決這個問題,泛型引入了萬用字元”?”。
對於這個問題的解決,使用萬用字元如下:
[java] view plaincopyprint?- publicclass NonConvariantGenerics{
- List<? extends Fruit> flist = new ArrayList<Apple>();
- }
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?- class Fruit{
- }
- class Apple extends Fruit{
- }
- class Jonathan extends Apple{
- }
- class Orange extends Fruit{
- }
- public superTypeWildcards{
- publicstaticvoid 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());
}
}
通過? Super限制了List元素只能是Apple的父類。
泛型下邊界還可以使用<?super T>,但是注意不能使用<Tsuper A>,即super之前的只能是泛型萬用字元,如:
[java] view plaincopyprint?- publicclass 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);
- }
- staticvoid f1(){
- writeExact(apples, new Apple());
- }
- staticvoid f2(){
- writeWithWildcards(apples, new Apple());
- writeWithWildcards(fruits, new Apple());
- }
- publicstaticvoid 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.無邊界的萬用字元:
泛型的萬用字元也可以不指定邊界,沒有邊界的萬用字元意思是不確定引數的型別,編譯時泛型檫除型別資訊,認為是Object型別。如:
[java] view plaincopyprint?- publicclass UnboundedWildcard{
- static List list1;
- static List<?> list2;
- static List<? extends Object> list3;
- staticvoid assign1(List list){
- list1 = list;
- list2 = list;
- //list3 = list; //有未檢查轉換警告
- }
- staticvoid assign2(List<?> list){
- list1 = list;
- list2 = list;
- list3 = list;
- }
- staticvoid assign3(List<? extends Object> list){
- list1 = list;
- list2 = list;
- list3 = list;
- }
- publicstaticvoid 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);
- }
- }
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?- 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無法編譯,因為由於泛型型別檫除,Payable<Employee>和Payable<Hourly>在編譯時是同一個型別Payable,因此無法同時實現一個介面兩次。
6.泛型方法過載注意事項:
由於泛型在編譯時將引數型別檫除,因此以引數型別來進行方法過載在泛型中要特別注意,如:
[java] view plaincopyprint?- publicclass 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){
}
}
無法通過編譯,因為泛型檫除型別資訊,上面兩個方法的引數都被看作為Object型別,使用引數型別已經無法區別上面兩個方法,因此無法過載。
7.泛型中的自繫結:
通常情況下,一個類無法直接繼承一個泛型引數,但是你可以通過繼承一個宣告泛型引數的類,這就是java泛型程式設計中的自繫結,如:
[java] view plaincopyprint?- class SelfBounded<T extends SelfBounded<T>>{
- T element;
- SelfBounded<T> set(T arg){
- Element = arg;
- returnthis;
- }
- 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();
- }
- }
- publicclass SelfBounding{
- publicstaticvoid 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());
}
}
泛型的自繫結約束目的是用於強制繼承關係,即使用泛型引數的類的基類是相同的,強制所有人使用相同的方式使用引數基類。
===========
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>{...}