Posted on 2008-08-05 10:12
夢與橋 閱讀(1184)
評論(0) 編輯 收藏 所屬分類:
java基礎
1、描述:泛型是類和接口的一種擴展機制,利用這種機制程序員可定義類或接口的集合。由泛型定義實際的類或接口時,只需為泛型的每個類型參數提供類型實參。
2、簡單的泛型類聲明,形如:pubic class ClassName<K,V>(){類體}
例子:
import java.util.Vector;
public class Test


{
public static void main(String args[])

{
Stack<String> strStack;
strStack=new Stack<String>(10);
strStack.push(" Generics Class.");
strStack.push("am");
strStack.push("I ");
System.out.println(strStack.pop()+strStack.pop()+strStack.pop());
}
}
class Stack<T>


{
private int stackSize=100;//設置棧的大小
Vector<T> stack=new Vector<T>();
public Stack(int size)

{
stack.setSize(size);
}
//入棧
public boolean push(T o)

{
if(stack.size()>=stackSize)

{
System.out.println("棧溢出");
return false;
}
else

{
return stack.add(o);
}
}
//出棧
public T pop()

{
if(!isEmpty())

{
T o=stack.lastElement();
stack.remove(o);
return o;
}
else

{
System.out.println("棧空");
return null;
}
}
//判定棧是否為空
public boolean isEmpty()

{
return stack.isEmpty();
}
}
3、受限泛型類聲明:所謂受限是指類型參數受限,其類型參數列表一般格式如:
<T [extends] 類t1或接口t1[& 接口t2 [& 接口 t3]……]],
E [extends] 類e1或接口e1[& 接口e2 [& 接口 e3]……]],
……
>
這樣使其實參類型限制于某個類的派生類或接口實現類,或一組接口的實現類。
例子:
import java.util.Vector;
public class Test


{
public static void main(String args[])

{
//String不是有界參數的有效替代項
//Stack<String> strStack;
Stack<Academician> acaStack=new Stack<Academician>(10);
acaStack.push(new Academician("張三",20,"西方文學"));
acaStack.push(new Academician("李四",21,"工商管理"));
acaStack.push(new Academician("王五",19,"計算機科學與技術"));
System.out.println(acaStack.pop());
System.out.println(acaStack.pop());
System.out.println(acaStack.pop());
}
}
//這里的Student稱為類型參數的最左限制
//Stack<T>的最左限制為Object,因為任何類都是Object派生的
class Stack<T extends Student>


{
private int stackSize=100;//設置棧的大小
Vector<T> stack=new Vector<T>();
public Stack(int size)

{
stack.setSize(size);
}
//入棧
public boolean push(T o)

{
if(stack.size()>=stackSize)

{
System.out.println("棧溢出");
return false;
}
else

{
return stack.add(o);
}
}
//出棧
public T pop()

{
if(!isEmpty())

{
T o=stack.lastElement();
stack.remove(o);
return o;
}
else

{
System.out.println("棧空");
return null;
}
}
//判定棧是否為空
public boolean isEmpty()

{
return stack.isEmpty();
}
}
class Student


{
private String name;
private int age;
Student(String name,int age)

{
this.name=name;
this.age=age;
}
public String toString()

{
return "name:"+name+"\tage:"+age;
}
}
class Academician extends Student


{
private String specialty;
Academician(String name,int age,String specialty)

{
super(name,age);
this.specialty=specialty;
}
public String toString()

{
return super.toString()+"\tspecialty:"+specialty+"\n";
}
}
泛型類只是類的一種的擴展,其實體的類體與普通類基本一樣,只是泛型類的實例變量的類型和實例方法的參數類型及返回值可以參數化而已。如例中:void push(T o)、T pop()。但由于泛型的類型參數在創建泛型類對象時才傳入,是一個實例化參數,所以不能使用在泛型類的靜態成員域中,也不能用在靜態初始化塊中。
泛型類可以看做類的模板,程序員可以通過將具體的類名作為泛型類型參數的實參,傳入泛型中定義新的類。如例中:Stack<Academician> acaStack=new Stack<Academician>(10);編譯器將用所提供的類名Academician替換類型參數T,生成一個想像類Stack<Academician>,此類實際上并不存在,只是java編譯器編譯時當其存在。泛型的實參也可以使用泛型定義的類型,如:Stack<Stack<String>> strStack=new Stack<Stack<String>>;
作為泛型類型參數的實參,必須是引用數據類型,不能是基本數據類型。如果希望基本數據類型的值存儲在堆棧中,可以使用其裝類:Integer、Short等。
用具體的類型名稱作為泛型類型參數的實參,創建新類型的過程稱為類型擦除。在這個過程中,所有的T將用最左限制類型替換掉,像Stack(T)擦除后,用其最左限制替換它。省略了泛型類型參數的類型被稱為泛型的原生類型。
假如使用泛型Stack創建了如下兩個不同的類型:
Stack<Integer> I=new Stack<Integer>(10);
Stack<Integer> D=new Stack<Integer>(10);
顯然,編譯器會將其作為不同的類型(因此I和D之間不能進行類型轉換),但在運行時共享相同的類名——可以使用instanceof進行測試。也就是說泛型生成的類具有相同的運行時類名稱,也正因為如此,泛型生成類型的實例無法用instanceof關鍵字確定其類型。
4、通配符
為了表示泛型定義的類型集合中的某個具體類型,需要為泛型的每個類型參數提供類型實參,否則編譯器將會提示警告信息。為此要判斷泛型Stack<T>產生的新類型:Stack<Integer>、Stack<Double>、Stack<String>是否為空,需要定義一組生載方法,很麻煩。為此,java提供了泛型參數通配符<?>,通配符可以代表任何類或接口(基本類型不包括在內)。看一個例子:
import java.util.Vector;
public class Test


{
public static boolean isEmpty(Stack<?> s)

{
return s.isEmpty();
}
public static void main(String args[])

{
Stack<Integer> intStack=new Stack<Integer>(10);
Stack<Double> dblStack=new Stack<Double>(10);
Stack<String> strStack=new Stack<String>(10);
if(!isEmpty(intStack))

{
System.out.println("intStack是空棧!");
}
if(!isEmpty(dblStack)&&!isEmpty(strStack))

{
System.out.println("dblStack和strStack都是空棧!");
}
}
}
class Stack<T>


{
private int stackSize=100;//設置棧的大小
Vector<T> stack=new Vector<T>();
public Stack(int size)

{
stack.setSize(size);
}
//入棧
public boolean push(T o)

{
if(stack.size()>=stackSize)

{
System.out.println("棧溢出");
return false;
}
else

{
return stack.add(o);
}
}
//出棧
public T pop()

{
if(!isEmpty())

{
T o=stack.lastElement();
stack.remove(o);
return o;
}
else

{
System.out.println("棧空");
return null;
}
}
//判定棧是否為空
public boolean isEmpty()

{
return stack.isEmpty();
}
}
java提供了兩種方法,將通配符限制在某一個范圍內:
(1)通配符的上界(<? extends 類或接口>):將通配符限制為指定的類及其派生類或接口的實現類。
(2)通配符的下界(<? super 類或接口>);將通配符限制為指定的類或其父類。
5、泛型類的繼承問題:
方式一:
public class IntStack extends Stack<Integer>


{
public IntStack(int size)

{
super(size);
}
public static void main(String args[])

{
IntStack intStack=new IntStack(10);
intStack.push(3);
System.out.println(intStack.pop());
}
}
方式二:SubStack(T)的T和Stack(T)的T相對應,保持一致。
public class SubStack<T> extends Stack<T>


{
public SubStack(int size)

{
super(size);
}
public static void main(String args[])

{
SubStack<Integer> intStack=new SubStack(10);
intStack.push(3);
System.out.println(intStack.pop());
SubStack<String> strStack=new SubStack(10);
strStack.push("Hello");
System.out.println(strStack.pop());
}
}
6、泛型接口
(1)定義:
public interface Stackable<T>


{
boolean push(T o);
T pop();
boolean isEmpty();
}
(2)實現:
public class ImpStack implements Stackable<String>


{
public boolean push(String s)

{省略具體實現}
public String pop()

{省略具體實現}
public boolean isEmpty()

{省略具體實現}

}
或者
public class ImpStack<T> implements Stackable<T>


{
public boolean push(T o)

{省略具體實現}
public T pop()

{省略具體實現}
public boolean isEmpty()

{省略具體實現}
}
7、泛型數組:java編譯器不允許創建泛型生成類的數組,但允許用無界限通配符作為實參得到的類型定義數組,如:List<?> ls=new List<?> [2];這種類型的數組,簡稱為通配符數組。雖然通配符數組存在著類型安全問題,如果使用恰當還是非常靈活好用的。通配符數組的元素可以是任何泛型生成的具體類型的對象或其派生類的對象。例子:
import java.util.*;
class ArrayGeneric<T>


{
public static void listAll(List<?>[] ls)

{
for(List<?> obj:ls)

{
listAll(obj);
}
}
public static void listAll(List<?> ls)

{
for(Object obj:ls)

{
System.out.println(obj);
}
}
}
public class Test


{
public static void main(String args[])

{
ArrayList al=new ArrayList();
LinkedList lls=new LinkedList();
al.add("123");
al.add("156");
lls.add("abc");
lls.add("def");
List<?>[] ls=new List<?>[2];
ls[0]=al;
ls[1]=lls;
ArrayGeneric.listAll(ls);
}
}
注意:
List<?>[] words =new List<?> [20];
Object[] objs=words;
objs[0]=3;
這三行能通過編譯,但在運行時會發生錯誤
8、泛化方法:可對所有的方法進行泛化,包括實例方法、靜態方法、構造方法。
例子:
import java.util.*;
public class Test


{
public <T> Test(T t)

{
System.out.println(t);
}
public static <T> void print1(T t)

{
System.out.println(t);
}
public <T> void print2(T t)

{
System.out.println(t);
}
public static void main(String args[])

{
print1(2008);
print1("北京歡迎你!");
Test test1=new Test(2008);
Test test2=new Test("北京歡迎你!");
test1.print2(2008);
test1.print2("北京歡迎你!");
}
}