❶ 關於c#中的泛型介面
泛型:通過參數化類型來實現在同一份代碼上操作多種數據類型。利用「參數化類型」將類型抽象化,從而實現靈活的復用。在.NET類庫中處處都可以看到泛型的身影,尤其是數組和集合中,泛型的存在也大大提高了程序員的開發效率。更重要的是,C#的泛型比C++的模板使用更加安全,並且通過避免裝箱和拆箱操作來達到性能提升的目的。因此,我們很有必要掌握並善用這個強大的語言特性。
C#泛型特點:
1、如果實例化泛型類型的參數相同,那麼JIT編輯器會重復使用該類型,因此C#的動態泛型能力避免了C++靜態模板可能導致的代碼膨脹的問題。
2、C#泛型類型攜帶有豐富的元數據,因此C#的泛型類型可以應用於強大的反射技術。
3、C#的泛型採用「基類、介面、構造器,值類型/引用類型」的約束方式來實現對類型參數的「顯示約束」,提高了類型安全的同時,也喪失了C++模板基於「簽名」的隱式約束所具有的高靈活性
C#泛型繼承:
C#除了可以單獨聲明泛型類型(包括類與結構)外,也可以在基類中包含泛型類型的聲明。但基類如果是泛型類,它的類型要麼以實例化,要麼來源於子類(同樣是泛型類型)聲明的類型參數,看如下類型
class C<U,V>
class D:C<string,int>
class E<U,V>:C<U,V>
class F<U,V>:C<string,int>
class G:C<U,V> //非法
E類型為C類型提供了U、V,也就是上面說的來源於子類
F類型繼承於C<string,int>,個人認為可以看成F繼承一個非泛型的類
G類型為非法的,因為G類型不是泛型,C是泛型,G無法給C提供泛型的實例化
泛型類型的成員:
泛型類型的成員可以使用泛型類型聲明中的類型參數。但類型參數如果沒有任何約束,則只能在該類型上使用從System.Object繼承的公有成員。如下圖:
泛型介面:
泛型介面的類型參數要麼已實例化,要麼來源於實現類聲明的類型參數
泛型委託:
泛型委託支持在委託返回值和參數上應用參數類型,這些參數類型同樣可以附帶合法的約束
delegate bool MyDelegate<T>(T value);
class MyClass
{
static bool F(int i){...}
static bool G(string s){...}
static void Main()
{
MyDelegate<string> p2 = G;
MyDelegate<int> p1 = new MyDelegate<int>(F);
}
}
泛型方法:
1、C#泛型機制只支持「在方法聲明上包含類型參數」——即泛型方法。
2、C#泛型機制不支持在除方法外的其他成員(包括屬性、事件、索引器、構造器、析構器)的聲明上包含類型參數,但這些成員本身可以包含在泛型類型中,並使用泛型類型的類型參數。
3、泛型方法既可以包含在泛型類型中,也可以包含在非泛型類型中。
泛型方法聲明:如下
public static int FunctionName<T>(T value){...}
泛型方法的重載:
public void Function1<T>(T a);
public void Function1<U>(U a);
這樣是不能構成泛型方法的重載。因為編譯器無法確定泛型類型T和U是否不同,也就無法確定這兩個方法是否不同
public void Function1<T>(int x);
public void Function1(int x);
這樣可以構成重載
public void Function1<T>(T t) where T:A;
public void Function1<T>(T t) where T:B;
這樣不能構成泛型方法的重載。因為編譯器無法確定約束條件中的A和B是否不同,也就無法確定這兩個方法是否不同
泛型方法重寫:
在重寫的過程中,抽象類中的抽象方法的約束是被默認繼承的。如下:
abstract class Base
{
public abstract T F<T,U>(T t,U u) where U:T;
public abstract T G<T>(T t) where T:IComparable;
}
class MyClass:Base
{
public override X F<X,Y>(X x,Y y){...}
public override T G<T>(T t) where T:IComparable{}
}
對於MyClass中兩個重寫的方法來說
F方法是合法的,約束被默認繼承
G方法是非法的,指定任何約束都是多餘的
泛型約束:
1、C#泛型要求對「所有泛型類型或泛型方法的類型參數」的任何假定,都要基於「顯式的約束」,以維護C#所要求的類型安全。
2、「顯式約束」由where子句表達,可以指定「基類約束」,「介面約束」,「構造器約束」,「值類型/引用類型約束」共四種約束。
3、「顯式約束」並非必須,如果沒有指定「顯式約束」,范型類型參數將只能訪問System.Object類型中的公有方法。例如:在開始的例子中,定義的那個obj成員變數。比如我們在開始的那個例子中加入一個Test1類,在它當中定義兩個公共方法Func1、Func2,如下圖:
泛型的概念,用通俗的語言來講,泛型其實就是類的一個參數,但是要求參數必須是一個類,而不能是一個對象。很多人可能對泛型中T的作用不太理解,其中T在泛型中扮演的角色就相當於一個佔位符,確切的說,是類型佔位符。凡是出現T的地方都會替換成你所傳遞的類型。
❷ java中泛型是什麼意思,作用是什麼
java 泛型是java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、介面和方法的創建中,分別稱為泛型類、泛型介面、泛型方法。
泛型(Generic type 或者 generics)是對 Java 語言的類型系統的一種擴展,以支持創建可以按類型進行參數化的類。可以把類型參數看作是使用參數化類型時指定的類型的一個佔位符,就像方法的形式參數是運行時傳遞的值的佔位符一樣。
可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 添加任意類的對象,即使最常見的情況是在給定映射(map)中保存某個特定類型(比如 String)的對象。
因為 Map.get() 被定義為返回 Object,所以一般必須將 Map.get() 的結果強制類型轉換為期望的類型,如下面的代碼所示:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
要讓程序通過編譯,必須將 get() 的結果強制類型轉換為 String,並且希望結果真的是一個 String。但是有可能某人已經在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。
理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵映射到 String 值。這可以讓您消除代碼中的強制類型轉換,同時獲得一個附加的類型檢查層,該檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所做的工作。
泛型的好處
Java 語言中引入泛型是一個較大的功能增強。不僅語言、類型系統和編譯器有了較大的變化,以支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經成為泛型化的了。
這帶來了很多好處:
1,類型安全。 泛型的主要目標是提高 Java 程序的類型安全。通過知道使用泛型定義的變數的類型限制,編譯器可以在一個高得多的程度上驗證類型假設。沒有泛型,這些假設就只存在於程序員的頭腦中(或者如果幸運的話,還存在於代碼注釋中)。
2,消除強制類型轉換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉換。這使得代碼更加可讀,並且減少了出錯機會。
3,潛在的性能收益。 泛型為較大的優化帶來可能。在泛型的初始實現中,編譯器將強制類型轉換(沒有泛型的話,程序員會指定這些強制類型轉換)插入生成的位元組碼中。但是更多類型信息可用於編譯器這一事實,為未來版本的 JVM 的優化帶來可能。由於泛型的實現方式,支持泛型(幾乎)不需要 JVM 或類文件更改。所有工作都在編譯器中完成,編譯器生成類似於沒有泛型(和強制類型轉換)時所寫的代碼,只是更能確保類型安全而已。
Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。
泛型在使用中還有一些規則和限制:
1、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
2、同一種泛型可以對應多個版本(因為參數類型是不確定的),不同版本的泛型類實例是不兼容的。
3、泛型的類型參數可以有多個。
4、泛型的參數類型可以使用extends語句,例如<T extends superclass>。習慣上成為「有界類型」。
5、泛型的參數類型還可以是通配符類型。例如Class<?> classType = Class.forName(Java.lang.String);
泛 型還有介面、方法等等,內容很多,需要花費一番功夫才能理解掌握並熟練應用。在此給出我曾經了解泛型時候寫出的兩個例子(根據看的印象寫的),實現同樣的 功能,一個使用了泛型,一個沒有使用,通過對比,可以很快學會泛型的應用,學會這個基本上學會了泛型70%的內容。
❸ 什麼是泛型
泛型。即通過參數化類型來實現在同一份代碼上操作多種數據類型。泛型是在C#2.0引入的。泛型(Genericity)的字面意思是指具有在多種數據類型上皆可操作的含意,與模板有些相似。
泛型是程序設計語言的一種特性。允許程序員在強類型程序設計語言中編寫代碼時定義一些可變部分,那些部分在使用前必須作出指明。各種程序設計語言和其編譯器、運行環境對泛型的支持均不一樣。
優點:
泛型方法可以出現在泛型或非泛型類型上。需要注意的是,並不是只要方法屬於泛型類型,或者甚至是方法的形參的類型是封閉類型的泛型參數,就可以說方法是泛型方法。只有當方法具有它自己的類型參數列表時,才能稱其為泛型方法。在下面的代碼中,只有方法 G 是泛型方法。
❹ 怎麼去很好理解Java的泛型!
理解Java泛型最簡單的方法是把它看成一種便捷語法,能節省你某些Java類型轉換(casting)上的操作:
1 List<Apple> box = ...;
2 Apple apple = box.get(0);
上面的代碼自身已表達的很清楚:box是一個裝有Apple對象的List。get方法返回一個Apple對象實例,這個過程不需要進行類型轉換。沒有泛型,上面的代碼需要寫成這樣:
1 List box = ...;
2 Apple apple = (Apple) box.get(0);
很明顯,泛型的主要好處就是讓編譯器保留參數的類型信息,執行類型檢查,執行類型轉換操作:編譯器保證了這些類型轉換的絕對無誤。
相對於依賴程序員來記住對象類型、執行類型轉換——這會導致程序運行時的失敗,很難調試和解決,而編譯器能夠幫助程序員在編譯時強制進行大量的類型檢查,發現其中的錯誤。
泛型的構成
由泛型的構成引出了一個類型變數的概念。根據Java語言規范,類型變數是一種沒有限制的標志符,產生於以下幾種情況:
泛型類聲明
泛型介面聲明
泛型方法聲明
泛型構造器(constructor)聲明
泛型類和介面
如果一個類或介面上有一個或多個類型變數,那它就是泛型。類型變數由尖括弧界定,放在類或介面名的後面:
1 public interface List<T> extends Collection<T> {
2 ...
3 }
簡單的說,類型變數扮演的角色就如同一個參數,它提供給編譯器用來類型檢查的信息。
Java類庫里的很多類,例如整個Collection框架都做了泛型化的修改。例如,我們在上面的第一段代碼里用到的List介面就是一個泛型類。在那段代碼里,box是一個List<Apple>對象,它是一個帶有一個Apple類型變數的List介面的類實現的實例。編譯器使用這個類型變數參數在get方法被調用、返回一個Apple對象時自動對其進行類型轉換。
實際上,這新出現的泛型標記,或者說這個List介面里的get方法是這樣的:
1 T get(int index);
get方法實際返回的是一個類型為T的對象,T是在List<T>聲明中的類型變數。
泛型方法和構造器(Constructor)
非常的相似,如果方法和構造器上聲明了一個或多個類型變數,它們也可以泛型化。
1 public static <t> T getFirst(List<T> list)
這個方法將會接受一個List<T>類型的參數,返回一個T類型的對象。
例子
你既可以使用Java類庫里提供的泛型類,也可以使用自己的泛型類。
類型安全的寫入數據…
下面的這段代碼是個例子,我們創建了一個List<String>實例,然後裝入一些數據:
1 List<String> str = new ArrayList<String>();
2 str.add("Hello ");
3 str.add("World.");
如果我們試圖在List<String>裝入另外一種對象,編譯器就會提示錯誤:
1 str.add(1); // 不能編譯
類型安全的讀取數據…
當我們在使用List<String>對象時,它總能保證我們得到的是一個String對象:
1 String myString = str.get(0);
遍歷
類庫中的很多類,諸如Iterator<T>,功能都有所增強,被泛型化。List<T>介面里的iterator()方法現在返回的是Iterator<T>,由它的T next()方法返回的對象不需要再進行類型轉換,你直接得到正確的類型。
1 for (Iterator<String> iter = str.iterator(); iter.hasNext();) {
2 String s = iter.next();
3 System.out.print(s);
4 }
使用foreach
「for each」語法同樣受益於泛型。前面的代碼可以寫出這樣:
1 for (String s: str) {
2 System.out.print(s);
3 }
這樣既容易閱讀也容易維護。
自動封裝(Autoboxing)和自動拆封(Autounboxing)
在使用Java泛型時,autoboxing/autounboxing這兩個特徵會被自動的用到,就像下面的這段代碼:
1 List<Integer> ints = new ArrayList<Integer>();
2 ints.add(0);
3 ints.add(1);
4
5 int sum = 0;
6 for (int i : ints) {
7 sum += i;
8 }
然而,你要明白的一點是,封裝和解封會帶來性能上的損失,所有,通用要謹慎的使用。
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、介面和方法的創建中,分別稱為泛型類、泛型介面、泛型方法。
Java語言引入泛型的好處是安全簡單。
在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的「任意化」,「任意化」帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對於強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。
泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。
泛型在使用中還有一些規則和限制:
1、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
2、同一種泛型可以對應多個版本(因為參數類型是不確定的),不同版本的泛型類實例是不兼容的。
3、泛型的類型參數可以有多個。
4、泛型的參數類型可以使用extends語句,例如。習慣上成為「有界類型」。
5、泛型的參數類型還可以是通配符類型。例如Class classType = Class.forName(java.lang.String);
泛型還有介面、方法等等,內容很多,需要花費一番功夫才能理解掌握並熟練應用。在此給出我曾經了解泛型時候寫出的兩個例子(根據看的印象寫的),實現同樣的功能,一個使用了泛型,一個沒有使用,通過對比,可以很快學會泛型的應用,學會這個基本上學會了泛型70%的內容。
例子一:使用了泛型
public class Gen﹤T﹥ {
private T ob; //定義泛型成員變數
public Gen(T ob) {
this.ob = ob;
}
public T getOb() {
return ob;
}
public void setOb(T ob) {
this.ob = ob;
}
public void showTyep() {
System.out.println("T的實際類型是: " + ob.getClass().getName());
}
}
public class GenDemo {
public static void main(String[] args){
//定義泛型類Gen的一個Integer版本
Gen﹤Integer﹥ intOb=new Gen﹤Integer﹥(88);
intOb.showTyep();
int i= intOb.getOb();
System.out.println("value= " + i);
System.out.println("----------------------------------");
//定義泛型類Gen的一個String版本
Gen﹤String﹥ strOb=new Gen﹤String﹥("Hello Gen!");
strOb.showTyep();
String s=strOb.getOb();
System.out.println("value= " + s);
}
例子二:沒有使用泛型
public class Gen2 {
private Object ob; //定義一個通用類型成員
public Gen2(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void setOb(Object ob) {
this.ob = ob;
}
public void showTyep() {
System.out.println("T的實際類型是: " + ob.getClass().getName());
}
}
public class GenDemo2 {
public static void main(String[] args) {
//定義類Gen2的一個Integer版本
Gen2 intOb = new Gen2(new Integer(88));
intOb.showTyep();
int i = (Integer) intOb.getOb();
System.out.println("value= " + i);
System.out.println("----------------------------------");
//定義類Gen2的一個String版本
Gen2 strOb = new Gen2("Hello Gen!");
strOb.showTyep();
String s = (String) strOb.getOb();
System.out.println("value= " + s);
}
}
運行結果:
兩個例子運行Demo結果是相同的,控制台輸出結果如下:
T的實際類型是:
java.lang.Integer
value= 88
----------------------------------
T的實際類型是: java.lang.String
value= Hello Gen!
Process finished with exit code 0
看明白這個,以後基本的泛型應用和代碼閱讀就不成問題了。
❺ Java 泛型使用 < super T> < extends T>
泛型中<? extends T>和<? super T> 差別
<? extends T>和<? super T>含有JAVA5.0的新的概念。由於它們的外表導致了很多人誤解了它們的用途:
1.<?
extends T>首先你很容易誤解它為繼承於T的所有類的集合,這是大錯特錯的,相信能看下去你一定見過或用過List<?
extends T>吧?為什麼我說理解成一個集合是錯呢?如果理解成一個集合那為什麼不用List<T>來表示?所以<?
extends
T>不是一個集合,而是T的某一種子類的意思,記住是一種,單一的一種,問題來了,由於連哪一種都不確定,帶來了不確定性,所以是不可能通過
add()來加入元素。你或許還覺得為什麼add(T)不行?因為<? extends
T>是T的某種子類,能放入子類的容器不一定放入超類,也就是沒可能放入T。
2.<? super T>這里比較容易使用,沒<? extends T>這么多限制,這里的意思是,以T類為下限的某種類,簡單地說就是T類的超類。但為什麼add(T)可以呢?因為能放入某一類的容器一定可以放入其子類,多態的概念。
擦除
也
許泛型最具挑戰性的方面是擦除(erasure),這是 Java
語言中泛型實現的底層技術。擦除意味著編譯器在生成類文件時基本上會拋開參數化類的大量類型信息。編譯器用它的強制類型轉換生成代碼,就像程序員在泛型出
現之前手工所做的一樣。區別在於,編譯器開始已經驗證了大量如果沒有泛型就不會驗證的類型安全約束。
通過擦除實現泛型的含意是很重要的,並
且初看也是混亂的。盡管不能將List<Integer> 賦給List<Number>,因為它們是不同的類型,但是
List<Integer> 和 List<Number> 類型的變數是相同的類!要明白這一點,請評價下面的代碼:
new List<Number>().getClass() == new List<Integer>().getClass()
編譯器只為 List 生成一個類。當生成了 List 的位元組碼時,將很少剩下其類型參數的的跟蹤。
當
生成泛型類的位元組碼時,編譯器用類型參數的擦除替換類型參數。對於無限制類型參數(<V>),它的擦除是
Object。對於上限類型參數(<K extends Comparable<K>>),它的擦除是其上限(在本例中是
Comparable)的擦除。對於具有多個限制的類型參數,使用其最左限制的擦除。
如果檢查生成的位元組碼,您無法說出 List<Integer> 和 List<String> 的代碼之間的區別。類型限制 T 在位元組碼中被 T 的上限所取代,該上限一般是 Object。
多重限制
一個類型參數可以具有多個限制。當您想要約束一個類型參數比如說同時為 Comparable 和 Serializable 時,這將很有用。多重限制的語法是用「與」符號分隔限制:
class C<T extends Comparable<? super T>&Serializable>
通配符類型可以具有單個限制 —— 上限或者下限。一個指定的類型參數可以具有一個或多個上限。具有多重限制的類型參數可以用於訪問它的每個限制的方法和域。
類型形參和類型實參
在
參數化類的定義中,佔位符名稱(比如 Collection<V> 中的 V)叫做類型形參(type
parameter),它們類似於方法定義中的形式參數。在參數化類的變數的聲明中,聲明中指定的類型值叫做類型實參(type
argument),它們類似於方法調用中的實際參數。但是實際中二者一般都通稱為「類型參數」。所以給出定義:
interface Collection<V> { ... }
和聲明:
Collection<String> cs = new HashSet<String>();
那麼,名稱 V(它可用於整個 Collection 介面體內)叫做一個類型形參。在 cs 的聲明中,String 的兩次使用都是類型實參(一次用於 Collection<V>,另一次用於 HashSet<V>)。
關
於何時可以使用類型形參,存在一些限制。大多數時候,可以在能夠使用實際類型定義的任何地方使用類型形參。但是有例外情況。不能使用它們創建對象或數組,
並且不能將它們用於靜態上下文中或者處理異常的上下文中。還不能將它們用作父類型(class Foo<T> extends
T),不能用於 instanceof 表達式中,不能用作類常量。
類似地,關於可以使用哪些類型作為類型實參,也存在一些限制。類型實參
必須是引用類型(不是基本類型)、通配符、類型參數,或者其他參數化類型的實例化。所以您可以定義
List<String>(引用類型)、List<?>(通配符)或者
List<List<?>>(其他參數化類型的實例化)。在帶有類型形參 T 的參數化類型的定義中,您也可以聲明
List<T>(類型形參)。
❻ Java泛型集合的應用和方法
泛型(Generic type 或者 generics)是對 Java 語言的類型系統的一種擴展,以支持創建可以按類型進行參數化的類。可以把類型參數看作是使用參數化類型時指定的類型的一個佔位符,就像方法的形式參數是運行時傳遞的值的佔位符一樣。
可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 添加任意類的對象,即使最常見的情況是在給定映射(map)中保存某個特定類型(比如 String)的對象。
因為 Map.get() 被定義為返回 Object,所以一般必須將 Map.get() 的結果強制類型轉換為期望的類型,如下面的代碼所示:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
要讓程序通過編譯,必須將 get() 的結果強制類型轉換為 String,並且希望結果真的是一個 String。但是有可能某人已經在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。
理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵映射到 String 值。這可以讓您消除代碼中的強制類型轉換,同時獲得一個附加的類型檢查層,該檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所做的工作。
泛型的好處
Java 語言中引入泛型是一個較大的功能增強。不僅語言、類型系統和編譯器有了較大的變化,以支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經成為泛型化的了。這帶來了很多好處:
類型安全。 泛型的主要目標是提高 Java 程序的類型安全。通過知道使用泛型定義的變數的類型限制,編譯器可以在一個高得多的程度上驗證類型假設。沒有泛型,這些假設就只存在於程序員的頭腦中(或者如果幸運的話,還存在於代碼注釋中)。
Java 程序中的一種流行技術是定義這樣的集合,即它的元素或鍵是公共類型的,比如「String 列表」或者「String 到 String 的映射」。通過在變數聲明中捕獲這一附加的類型信息,泛型允許編譯器實施這些附加的類型約束。類型錯誤現在就可以在編譯時被捕獲了,而不是在運行時當作 ClassCastException 展示出來。將類型檢查從運行時挪到編譯時有助於您更容易找到錯誤,並可提高程序的可靠性。
消除強制類型轉換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉換。這使得代碼更加可讀,並且減少了出錯機會。
盡管減少強制類型轉換可以降低使用泛型類的代碼的羅嗦程度,但是聲明泛型變數會帶來相應的羅嗦。比較下面兩個代碼例子。
該代碼不使用泛型:
List li = new ArrayList();
li.put(new Integer(3));
Integer i = (Integer) li.get(0);
該代碼使用泛型:
List<Integer> li = new ArrayList<Integer>();
li.put(new Integer(3));
Integer i = li.get(0);
在簡單的程序中使用一次泛型變數不會降低羅嗦程度。但是對於多次使用泛型變數的大型程序來說,則可以累積起來降低羅嗦程度。
潛在的性能收益。 泛型為較大的優化帶來可能。在泛型的初始實現中,編譯器將強制類型轉換(沒有泛型的話,程序員會指定這些強制類型轉換)插入生成的位元組碼中。但是更多類型信息可用於編譯器這一事實,為未來版本的 JVM 的優化帶來可能。
由於泛型的實現方式,支持泛型(幾乎)不需要 JVM 或類文件更改。所有工作都在編譯器中完成,編譯器生成類似於沒有泛型(和強制類型轉換)時所寫的代碼,只是更能確保類型安全而已。
泛型用法的例子
泛型的許多最佳例子都來自集合框架,因為泛型讓您在保存在集合中的元素上指定類型約束。考慮這個使用 Map 類的例子,其中涉及一定程度的優化,即 Map.get() 返回的結果將確實是一個 String:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
如果有人已經在映射中放置了不是 String 的其他東西,上面的代碼將會拋出 ClassCastException。泛型允許您表達這樣的類型約束,即 m 是一個將 String 鍵映射到 String 值的 Map。這可以消除代碼中的強制類型轉換,同時獲得一個附加的類型檢查層,這個檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。
下面的代碼示例展示了 JDK 5.0 中集合框架中的 Map 介面的定義的一部分:
public interface Map<K, V> {
public void put(K key, V value);
public V get(K key);
}
注意該介面的兩個附加物:
類型參數 K 和 V 在類級別的規格說明,表示在聲明一個 Map 類型的變數時指定的類型的佔位符。
在 get()、put() 和其他方法的方法簽名中使用的 K 和 V。
為了贏得使用泛型的好處,必須在定義或實例化 Map 類型的變數時為 K 和 V 提供具體的值。以一種相對直觀的方式做這件事:
Map<String, String> m = new HashMap<String, String>();
m.put("key", "blarg");
String s = m.get("key");
當使用 Map 的泛型化版本時,您不再需要將 Map.get() 的結果強制類型轉換為 String,因為編譯器知道 get() 將返回一個 String。
在使用泛型的版本中並沒有減少鍵盤錄入;實際上,比使用強制類型轉換的版本需要做更多鍵入。使用泛型只是帶來了附加的類型安全。因為編譯器知道關於您將放進 Map 中的鍵和值的類型的更多信息,所以類型檢查從執行時挪到了編譯時,這會提高可靠性並加快開發速度。
向後兼容
在 Java 語言中引入泛型的一個重要目標就是維護向後兼容。盡管 JDK 5.0 的標准類庫中的許多類,比如集合框架,都已經泛型化了,但是使用集合類(比如 HashMap 和 ArrayList)的現有代碼將繼續不加修改地在 JDK 5.0 中工作。當然,沒有利用泛型的現有代碼將不會贏得泛型的類型安全好處。
二 泛型基礎
類型參數
在定義泛型類或聲明泛型類的變數時,使用尖括弧來指定形式類型參數。形式類型參數與實際類型參數之間的關系類似於形式方法參數與實際方法參數之間的關系,只是類型參數表示類型,而不是表示值。
泛型類中的類型參數幾乎可以用於任何可以使用類名的地方。例如,下面是 java.util.Map 介面的定義的摘錄:
public interface Map<K, V> {
public void put(K key, V value);
public V get(K key);
}
Map 介面是由兩個類型參數化的,這兩個類型是鍵類型 K 和值類型 V。(不使用泛型)將會接受或返回 Object 的方法現在在它們的方法簽名中使用 K 或 V,指示附加的類型約束位於 Map 的規格說明之下。
當聲明或者實例化一個泛型的對象時,必須指定類型參數的值:
Map<String, String> map = new HashMap<String, String>();
注意,在本例中,必須指定兩次類型參數。一次是在聲明變數 map 的類型時,另一次是在選擇 HashMap 類的參數化以便可以實例化正確類型的一個實例時。
編譯器在遇到一個 Map<String, String> 類型的變數時,知道 K 和 V 現在被綁定為 String,因此它知道在這樣的變數上調用 Map.get() 將會得到 String 類型。
除了異常類型、枚舉或匿名內部類以外,任何類都可以具有類型參數。
命名類型參數
推薦的命名約定是使用大寫的單個字母名稱作為類型參數。這與 C++ 約定有所不同(參閱 附錄 A:與 C++ 模板的比較),並反映了大多數泛型類將具有少量類型參數的假定。對於常見的泛型模式,推薦的名稱是:
K —— 鍵,比如映射的鍵。
V —— 值,比如 List 和 Set 的內容,或者 Map 中的值。
E —— 異常類。
T —— 泛型。
泛型不是協變的
關於泛型的混淆,一個常見的來源就是假設它們像數組一樣是協變的。其實它們不是協變的。List<Object> 不是 List<String> 的父類型。
如果 A 擴展 B,那麼 A 的數組也是 B 的數組,並且完全可以在需要 B[] 的地方使用 A[]:
Integer[] intArray = new Integer[10];
Number[] numberArray = intArray;
上面的代碼是有效的,因為一個 Integer 是 一個 Number,因而一個 In。
❼ java中的泛型 求詳細解釋
1、Java泛型
其實Java的泛型就是創建一個用類型作為參數的類。就象我們寫類的方法一樣,方法是這樣的method(String str1,String str2 ),方法中參數str1、str2的值是可變的。而泛型也是一樣的,這樣寫class Java_Generics<K,V>,這里邊的K和V就象方法中的參數str1和str2,也是可變。下面看看例子:
//code list 1
import Java.util.Hashtable;
class TestGen0<K,V>{
public Hashtable<K,V> h=new Hashtable<K,V>();
public void put(K k, V v) {
h.put(k,v);
}
public V get(K k) {
return h.get(k);
}
public static void main(String args[]){
TestGen0<String,String> t=new TestGen0<String,String>();
t.put("key", "value");
String s=t.get("key");
System.out.println(s);
}
}
正確輸出:value
這只是個例子(Java中集合框架都泛型化了,這里費了2遍事.),不過看看是不是創建一個用類型作為參數的類,參數是K,V,傳入的「值」是String類型。這個類他沒有特定的待處理型別,以前我們定義好了一個類,在輸入輸入參數有所固定,是什麼型別的有要求,但是現在編寫程序,完全可以不制定參數的類型,具體用的時候來確定,增加了程序的通用性,像是一個模板。
呵呵,類似C++的模板(類似)。
1.1. 泛型通配符
下面我們先看看這些程序:
//Code list 2
void TestGen0Medthod1(List l) {
for (Object o : l)
System.out.println(o);
}
看看這個方法有沒有異議,這個方法會通過編譯的,假如你傳入String,就是這樣List<String>。
接著我們調用它,問題就出現了,我們將一個List<String>當作List傳給了方法,JVM會給我們一個警告,說這個破壞了類型安全,因為從List中返回的都是Object類型的,而讓我們再看看下面的方法。
//Code list 3
void TestGen0Medthod1(List<String> l) {
for (Object o : l)
System.out.println(o);
}
因為這里的List<String>不是List<Object>的子類,不是String與Object的關系,就是說List<String>不隸屬於list<Object>,他們不是繼承關系,所以是不行的,這里的extends是表示限制的。
類型通配符是很神奇的,List<?>這個你能為他做什麼呢?怎麼都是「?」,它似乎不確定,他總不能返回一個?作為類型的數據吧,是啊他是不會返回一個「?」來問程序員的?JVM會做簡單的思考的,看看代碼吧,更直觀些。
//code list 4
List<String> l1 = new ArrayList<String>();
li.add(「String」);
List<?> l2 = l1;
System.out.println(l1.get(0));
這段代碼沒問題的,l1.get(0)將返回一個Object。
1.2. 編寫泛型類要注意:
1) 在定義一個泛型類的時候,在 「<>」之間定義形式類型參數,例如:「class TestGen<K,V>」,其中「K」 , 「V」不代表值,而是表示類型。
2) 實例化泛型對象的時候,一定要在類名後面指定類型參數的值(類型),一共要有兩次書寫。例如:
TestGen<String,String> t=new TestGen<String,String>();
3) 泛型中<K extends Object>,extends並不代表繼承,它是類型範圍限制。
2、泛型與數據類型轉換
2.1. 消除類型轉換
上面的例子大家看到什麼了,數據類型轉換的代碼不見了。在以前我們經常要書寫以下代碼,如:
//code list 5
import Java.util.Hashtable;
class Test {
public static void main(String[] args) {
Hashtable h = new Hashtable();
h.put("key", "value");
String s = (String)h.get("key");
System.out.println(s);
}
}
這個我們做了類型轉換,是不是感覺很煩的,並且強制類型轉換會帶來潛在的危險,系統可能會拋一個ClassCastException異常信息。在JDK5.0中我們完全可以這么做,如:
//code list 6
import Java.util.Hashtable;
class Test {
public static void main(String[] args) {
Hashtable<String,Integer> h = new Hashtable<String,Integer> ();
h.put("key", new Integer(123));
int s = h.get("key").intValue();
System.out.println(s);
}
}
這里我們使用泛化版本的HashMap,這樣就不用我們來編寫類型轉換的代碼了,類型轉換的過程交給編譯器來處理,是不是很方便,而且很安全。上面是String映射到String,也可以將Integer映射為String,只要寫成HashTable<Integer,String> h=new HashTable<Integer,String>();h.get(new Integer(0))返回value。果然很方便。
❽ 如何在Java程序中使用泛型
在使用泛型前,存入集合中的元素可以是任何類型的,當從集合中取出時,所有的元素都是Object類型,需要進行向下的強制類型轉換,轉換到特定的類型。
比如:
List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3
第三行的這個強制類型轉換可能會引起運行時的錯誤。
泛型的思想就是由程序員指定類型,這樣集合就只能容納該類型的元素。
使用泛型:
List<Integer> myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'
將第三行的強制類型轉換變為了第一行的List類型說明,編譯器會為我們檢查類型的正確性。這樣,代碼的可讀性和健壯性也會增強。
泛型使用基礎
例如:
public interface List <E>
{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>
{
E next();
boolean hasNext();
}
尖括弧中包含的是形式類型參數(formal type parameters),它們就如同一般的類型一樣,可以在整個類的聲明中被使用。
當類被使用時,會使用具體的實際類型參數(actual type argument)代替。
比如前面的例子中的List<Integer>,那麼所有的E將會被Integer類型所代替。
泛型類型參數只能被類或介面類型賦值,不能被原生數據類型賦值,原生數據類型需要使用對應的包裝類。
形式類型參數的命名:盡量使用單個的大寫字母(有時候多個泛型類型時會加上數字,比如T1,T2),比如許多容器集合使用E,代表element(元素),Map中用K代表鍵keys,V代表值。
❾ ArrayList<E> 泛型使用
你好,泛型現在用的很廣泛,省去了強制類型轉換
JDK5中類型,從而的泛形允許程序員在編寫集合代碼時,就限制集合的處理把原來程序運行時可能發生問題,轉變為編譯時的問題,以此提高程序的可讀性和穩定性(尤其在大型程序中更為突出)。
ArrayList<E>中的E稱為類型參數變數
• ArrayList<Integer>中的Integer稱為實際類型參數
• 整個稱為ArrayList<E>泛型類型
• 整個ArrayList<Integer>稱為參數化的類型ParameterizedType
七里河團隊答疑助人,希望我的回答對你有所幫助
七里河團隊期待你的加入,我們一起幫助別人
❿ 求java泛型的詳細講解,最基礎的,我去網上博客里的什麼都比較高深,看不懂
泛型:JDK1.5版本以後出現的新特性,用於解決安全問題,是一個安全機制。
好處
1.將運行時期出現的問題ClassCastException,轉移到了編譯時期
方便於程序員解決問題,讓運行時期問題減少,安全
2.避免了強制轉換麻煩
泛型格式:通過<>來定義要操作的引用數據類型。
在使用java提供的對象時,什麼時候寫泛型呢?
通常在集合框架中很常見,只要見到<>就要定義泛型
其實<>就是用來接收類型的
當使用集合時,將集合中要存儲的數據類型作為參數傳遞到<>中即可
什麼時候定義泛型類?
當類中要操作的引用數據類型不確定的時候,早期定義object來完成擴展,現在定義泛型來完成擴展
泛型類定義的泛型,在整個類中有效,如果被方法使用,那麼泛型類的對象明確要操作的具體類型後,所有要操作的類型就已經固定了
那麼為了讓不同方法可以操作不同類型,而且類型還不確定,那麼可以將泛型定義在方法上
特殊之處:靜態方法不可以訪問類上定義的泛型,如果靜態方法操作的應用數據類型不確定,可以將泛型定義在方法上
通配符。也可以理解為佔位符。
泛型的限定:
? extends E:可以接收E類型或者E的子類型。上限
一般存儲對象的時候用。比如 添加元素 addAll.
? super E:可以接收E類型或者E的父類型。下限
一般取出對象的時候用。比如比較器。