導航:首頁 > 編程語言 > java泛型方法靜態

java泛型方法靜態

發布時間:2023-11-27 19:29:36

A. 還是關於java泛型的問題:在靜態方法中為什麼不能引用類級別的類型參數

靜態變數和靜態方法是屬於使用泛型參數的基類的,跟泛型無關。
Java目前的泛型還是偽泛型,需要在編譯的時候進行強轉。

B. java 泛型 的意義

java是所謂的靜態類型語言,意思是在運行前,或者叫編譯期間,就能夠確定一個對象的類型,這樣做的好處是減少了運行時由於類型不對引發的錯誤。但是強制類型轉換是鑽了一個空子,在編譯期間不會有問題,而在運行期間,就有可能由於錯誤的強制類型轉換,導致錯誤,這個編譯器無法檢查到。
有了泛型,就可以用不著強制類型轉換,在編譯期間,編譯器就能對類型進行檢查,杜絕了運行時由於強制類型轉換導致的錯誤。

C. Java基礎知識總結:什麼時候用泛型類

當類中的操作的引用數據類型不確定的時候,以前用的Object來進行擴展的,現在可以用泛型來表示。這樣可以避免強轉的麻煩,而且將運行問題轉移到的編譯時期。
----------------------------------------------------------
泛型在程序定義上的體現:
//泛型類:將泛型定義在類上。
class Tool {
private Q obj;
public void setObject(Q obj) {
this.obj = obj;
}
public Q getObject() {
return obj;
}
}
//當方法操作的引用數據類型不確定的時候,可以將泛型定義在方法上。
publicvoid method(W w) {
System.out.println("method:"+w);
}
//靜態方法上的泛型:靜態方法無法訪問類上定義的泛型。如果靜態方法操作的引用數據類型不確定的時候,必須要將泛型定義在方法上。
public static void function(Q t) {
System.out.println("function:"+t);
}
//泛型介面.
interface Inter{
void show(T t);
}
class InterImplimplements Inter{
public void show(R r) {
System.out.println("show:"+r);
}
}

D. 學習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,因而一個Integer數組是一個Number數組。但是對於泛型來說則不然。下面的代碼是無效的:

List<Integer> intList = new ArrayList<Integer>();

List<Number> numberList = intList; // invalid

最初,大多數 Java 程序員覺得這缺少協變很煩人,或者甚至是「壞的(broken)」,但是之所以這樣有一個很好的原因。如果可以將List<Integer>賦給List<Number>,下面的代碼就會違背泛型應該提供的類型安全:

List<Integer> intList = new ArrayList<Integer>();

List<Number> numberList = intList; // invalid

numberList.add(new Float(3.1415));

因為intList和numberList都是有別名的,如果允許的話,上面的代碼就會讓您將不是Integers的東西放進intList中。但是,正如下一屏將會看到的,您有一個更加靈活的方式來定義泛型。
package com.ibm.course.generics;
import java.util.ArrayList;
import java.util.List;
public class GenericsExample {
public static void main(String[] args) {
Integer[] integer = new Integer[5];
Number[] number = integer;
System.out.println(number[0]);// null
number[0] = new Float(7.65);
System.out.println(number[0]);
System.out.println(integer[0]);
List<Integer> list = new ArrayList<Integer>();
// Type mismatch: cannot convert from List<Integer> to List<Number>
// List<Number> listObj = list;
}
}
List<Number> listObj = list;導致編譯錯誤:Type mismatch: cannot convert from List<Integer> to List<Number>
而System.out.println(number[0]);和System.out.println(integer[0]);導致運行時異常:
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Float
at com.ibm.course.generics.GenericsExample.main(GenericsExample.java:15)

類型通配符
假設您具有該方法:

void printList(List l) {

for (Object o : l)

System.out.println(o);

}

上面的代碼在 JDK 5.0 上編譯通過,但是如果試圖用List<Integer>調用它,則會得到警告。出現警告是因為,您將泛型(List<Integer>)傳遞給一個只承諾將它當作List(所謂的原始類型)的方法,這將破壞使用泛型的類型安全。
如果試圖編寫像下面這樣的方法,那麼將會怎麼樣?

void printList(List<Object> l) {

for (Object o : l)

System.out.println(o);

}

它仍然不會通過編譯,因為一個List<Integer>不是一個List<Object>(正如前一屏泛型不是協變的 中所學的)。這才真正煩人——現在您的泛型版本還沒有普通的非泛型版本有用!
解決方案是使用類型通配符:

void printList(List<?> l) {

for (Object o : l)

System.out.println(o);

}

上面代碼中的問號是一個類型通配符。它讀作「問號」。List<?>是任何泛型List的父類型,所以您完全可以將List<Object>、List<Integer>或List<List<List<Flutzpah>>>傳遞給printList()。
package com.ibm.course.generics;
import java.util.ArrayList;
import java.util.List;
public class GenericExample {
public static void main(String[] args) {
List<Integer> integer = new ArrayList<Integer>();
integer.add(new Integer(0));
integer.add(new Integer(1));
List<String> str = new ArrayList<String>();
str.add(new String("Hello"));
str.add(new String("World"));
List<?> li=integer;
li=str;
printList(integer);
printList(str);
}
public static void printList(List<?> l) {
for (Object o : l) {
System.out.println(o);
}
}
}
上面的例子程序沒有警告也沒有編譯錯誤。
類型通配符的作用
前一屏類型通配符 中引入了類型通配符,這讓您可以聲明List<?>類型的變數。您可以對這樣的List做什麼呢?非常方便,可以從中檢索元素,但是不能添加元素(可以添加null)。原因不是編譯器知道哪些方法修改列表哪些方法不修改列表,而是(大多數)變化的方法比不變化的方法需要更多的類型信息。下面的代碼則工作得很好:

List<Integer> li = new ArrayList<Integer>();

li.add(new Integer(42));

List<?> lu = li;

System.out.println(lu.get(0));

為什麼該代碼能工作呢?對於lu,編譯器一點都不知道List的類型參數的值。但是編譯器比較聰明,它可以做一些類型推理。在本例中,它推斷未知的類型參數必須擴展Object。(這個特定的推理沒有太大的跳躍,但是編譯器可以作出一些非常令人佩服的類型推理,後面就會看到(在底層細節 一節中)。所以它讓您調用List.get()並推斷返回類型為Object。
另一方面,下面的代碼不能工作:

List<Integer> li = new ArrayList<Integer>();

li.add(new Integer(42));

List<?> lu = li;

lu.add(new Integer(43)); // error

在本例中,對於lu,編譯器不能對List的類型參數作出足夠嚴密的推理,以確定將Integer傳遞給List.add()是類型安全的。所以編譯器將不允許您這么做。
以免您仍然認為編譯器知道哪些方法更改列表的內容哪些不更改列表內容,請注意下面的代碼將能工作,因為它不依賴於編譯器必須知道關於lu的類型參數的任何信息:

List<Integer> li = new ArrayList<Integer>();

li.add(new Integer(42));

List<?> lu = li;

lu.clear();

泛型方法
(在類型參數 一節中)您已經看到,通過在類的定義中添加一個形式類型參數列表,可以將類泛型化。方法也可以被泛型化,不管它們定義在其中的類是不是泛型化的。
泛型類在多個方法簽名間實施類型約束。在List<V>中,類型參數V出現在get()、add()、contains()等方法的簽名中。當創建一個Map<K, V>類型的變數時,您就在方法之間宣稱一個類型約束。您傳遞給add()的值將與get()返回的值的類型相同。
類似地,之所以聲明泛型方法,一般是因為您想要在該方法的多個參數之間宣稱一個類型約束。例如,下面代碼中的ifThenElse()方法,根據它的第一個參數的布爾值,它將返回第二個或第三個參數:

public <T> T ifThenElse(boolean b, T first, T second) {

return b ? first : second;

}

注意,您可以調用ifThenElse(),而不用顯式地告訴編譯器,您想要T的什麼值。編譯器不必顯式地被告知 T 將具有什麼值;它只知道這些值都必須相同。編譯器允許您調用下面的代碼,因為編譯器可以使用類型推理來推斷出,替代T的String滿足所有的類型約束:

String s = ifThenElse(b, "a", "b");

類似地,您可以調用:

Integer i = ifThenElse(b, new Integer(1), new Integer(2));

但是,編譯器不允許下面的代碼,因為沒有類型會滿足所需的類型約束:

String s = ifThenElse(b, "pi", new Float(3.14));

為什麼您選擇使用泛型方法,而不是將類型T添加到類定義呢?(至少)有兩種情況應該這樣做:

* 當泛型方法是靜態的時,這種情況下不能使用類類型參數。
* 當 T 上的類型約束對於方法真正是局部的時,這意味著沒有在相同類的另一個 方法簽名中使用相同 類型 T 的約束。通過使得泛型方法的類型參數對於方法是局部的,可以簡化封閉類型的簽名。

有限制類型
在前一屏泛型方法 的例子中,類型參數V是無約束的或無限制的類型。有時在還沒有完全指定類型參數時,需要對類型參數指定附加的約束。
考慮例子Matrix類,它使用類型參數V,該參數由Number類來限制:

public class Matrix<V extends Number> { ... }

編譯器允許您創建Matrix<Integer>或Matrix<Float>類型的變數,但是如果您試圖定義Matrix<String>類型的變數,則會出現錯誤。類型參數V被判斷為由Number限制。在沒有類型限制時,假設類型參數由Object限制。這就是為什麼前一屏泛型方法 中的例子,允許List.get()在List<?>上調用時返回Object,即使編譯器不知道類型參數V的類型。

E. java 泛型的幾種用法

1. public class DAO<T> {
/**
* 泛型類
* 聲明類的同時聲明泛型類型
* 1.方法的返回值可以是使用聲明的泛型類型
* 2.方法的參數也可以是聲明類的泛型類型
* 3.方法體內可以使用泛型類型
*/
public T get(Integer id){
return null;
}

public void save(T entity){
}
}
2.
/**
* 泛型方法: 在方法聲明時, 同時聲明泛型. 在方法的返回值, 參數列表以及方法體中都可以使用泛型類型.
* public static <T> T get(Integer id){
* T result = null;
* return result;
* }
* 把指定類型的數組中的元素放入到指定類型的集合中
*/

F. 請教關於java的泛型方法

Java泛型詳解

  1. 概述
    在引入范型之前,Java類型分為原始類型、復雜類型,其中復雜類型分為數組和類。引入范型後臘陸仔,一個復雜類型
    就可以在細分成更多的類型。
    例如原先的類型List,現在在細分成List<Object>, List<String>等更多的類型。
    注意,現在List<Object>, List<String>是兩種不同的類型,
    他們之間沒有繼承關系,即使String繼承了Object。下面的代碼是非法的
    List<String> ls = new ArrayList<String>();
    List<Object> lo = ls;
    這樣設計的原因在於,根據lo的聲明,編譯器允許你向lo中添加任意對象(例如Integer),但是此對象是
    List<String>,破壞了數據類型的完整性。
    在引入范型之前,要在類中的方法支持多個數據類型,就需要對方法進行重載,在引入范型後,可以解決此問題
    (多態),更進一步可以定義多個參數以及返回值之間的關系。
    例如
    public void write(Integer i, Integer[] ia);
    public void write(Double d, Double[] da);
    的范型版本為
    public <T> void write(T t, T[] ta);

    2. 定義&使用
    類型參數的命名風格為:
    推薦你用簡練的名字作為形式類型參數的名字(如果可能,單個字元)。最好避免小寫字母,這使它和其他的普通
    的形式悉頃參數很容易被區分開來。
    使用T代表類型,無論何時都沒有比這更具體的類型來區分它。這經常見於泛型方法。如果有多個類型參數,我們
    可能使用字母表中T的臨近的字母,比如S。
    如果一個泛型函數在一個泛型類裡面出現,最好避免在方法的類型參數和類的類型參數中使用同樣的名字來避免混
    淆。對內部類也是同樣。

    2.1 定義帶類型參數的類
    在定義帶類型參數的類時,在緊跟類命之後的<>內,指定一個或多個類型參數的名字,同時也可以對類型參數的取
    值范圍進行限定,多個類型參數之間用,號分隔。
    定義完類型參數後,可以在定義位置之後的類的幾乎任意地方(靜態塊,靜態屬性,靜態方法除外)使用類型參數,
    就像使用普通的類型一樣。
    注意,父類定義的類型參數不能被子類繼承。
    public class TestClassDefine<T, S extends T> {
    ....
    }

    2.2 定義待類型參數方法
    在定義帶類型參數的方法時,在緊跟可見范圍修飾(例如public)之後的<>內,指定一個或多個類型參數的名字,同時也可以對類型參數的取值范圍進行限定,多個類型參數之間用,號分隔。
    定義完類型參數後,可以在定義位置之後的方法的任意地方使用類型參數,就像使用普通的類型一樣。
    例如:
    public <T, S extends T> T testGenericMethodDefine(T t, S s){
    ...
    }
    注意:定義帶類型參數的方法,騎主要目的是為了表達多個參數以及返回值之間的關系。例如本例子中T和S的繼承關系, 返回值的類型和第一個類型參數的值相同。
    如輪汪果僅僅是想實現多態,請優先使用通配符解決。通配符的內容見下面章節。
    public <T> void testGenericMethodDefine2(List<T> s){
    ...
    }
    應改為
    public void testGenericMethodDefine2(List<?> s){
    ...
    }

    3. 類型參數賦值
    當對類或方法的類型參數進行賦值時,要求對所有的類型參數進行賦值。否則,將得到一個編譯錯誤。

    3.1 對帶類型參數的類進行類型參數賦值
    對帶類型參數的類進行類型參數賦值有兩種方式
    第一聲明類變數或者實例化時。例如
    List<String> list;
    list = new ArrayList<String>;
    第二繼承類或者實現介面時。例如
    public class MyList<E> extends ArrayList<E> implements List<E> {...}

    3.2 對帶類型參數方法進行賦值
    當調用范型方法時,編譯器自動對類型參數進行賦值,當不能成功賦值時報編譯錯誤。例如
    public <T> T testGenericMethodDefine3(T t, List<T> list){
    ...
    }
    public <T> T testGenericMethodDefine4(List<T> list1, List<T> list2){
    ...
    }

    Number n = null;
    Integer i = null;
    Object o = null;
    testGenericMethodDefine(n, i);//此時T為Number, S為Integer
    testGenericMethodDefine(o, i);//T為Object, S為Integer

    List<Number> list1 = null;
    testGenericMethodDefine3(i, list1)//此時T為Number

    List<Integer> list2 = null;
    testGenericMethodDefine4(list1, list2)//編譯報錯

    3.3 通配符
    在上面兩小節中,對是類型參數賦予具體的值,除此,還可以對類型參數賦予不確定值。例如
    List<?> unknownList;
    List<? extends Number> unknownNumberList;
    List<? super Integer> unknownBaseLineIntgerList;
    注意: 在Java集合框架中,對於參數值是未知類型的容器類,只能讀取其中元素,不能像其中添加元素,因為,其類型是未知,所以編譯器無法識別添加元素的類型和容器的類型是否兼容,唯一的例外是NULL

    List<String> listString;
    List<?> unknownList2 = listString;
    unknownList = unknownList2;
    listString = unknownList;//編譯錯誤

    4. 數組范型
    可以使用帶范型參數值的類聲明數組,卻不可有創建數組
    List<Integer>[] iListArray;
    new ArrayList<Integer>[10];//編譯時錯誤

    5. 實現原理

    5.1. Java范型時編譯時技術,在運行時不包含范型信息,僅僅Class的實例中包含了類型參數的定義信息。
    泛型是通過java編譯器的稱為擦除(erasure)的前端處理來實現的。你可以(基本上就是)把它認為是一個從源碼到源碼的轉換,它把泛型版本轉換成非泛型版本。
    基本上,擦除去掉了所有的泛型類型信息。所有在尖括弧之間的類型信息都被扔掉了,因此,比如說一個List<String>類型被轉換為List。所有對類型變數的引用被替換成類型變數的上限(通常是Object)。而且,無論何時結果代碼類型不正確,會插入一個到合適類型的轉換。
    <T> T badCast(T t, Object o) {
    return (T) o; // unchecked warning
    }
    類型參數在運行時並不存在。這意味著它們不會添加任何的時間或者空間上的負擔,這很好。不幸的是,這也意味著你不能依靠他們進行類型轉換。

    5.2.一個泛型類被其所有調用共享
    下面的代碼列印的結果是什麼?
    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();
    System.out.println(l1.getClass() == l2.getClass());
    或許你會說false,但是你想錯了。它列印出true。因為一個泛型類的所有實例在運行時具有相同的運行時類(class),
    而不管他們的實際類型參數。
    事實上,泛型之所以叫泛型,就是因為它對所有其可能的類型參數,有同樣的行為;同樣的類可以被當作許多不同的類型。作為一個結果,類的靜態變數和方法也在所有的實例間共享。這就是為什麼在靜態方法或靜態初始化代碼中或者在靜態變數的聲明和初始化時使用類型參數(類型參數是屬於具體實例的)是不合法的原因。

    5.3. 轉型和instanceof
    泛型類被所有其實例(instances)共享的另一個暗示是檢查一個實例是不是一個特定類型的泛型類是沒有意義的。
    Collection cs = new ArrayList<String>();
    if (cs instanceof Collection<String>) { ...} // 非法
    類似的,如下的類型轉換
    Collection<String> cstr = (Collection<String>) cs;
    得到一個unchecked warning,因為運行時環境不會為你作這樣的檢查。

    6. Class的范型處理
    Java 5之後,Class變成范型化了。
    JDK1.5中一個變化是類 java.lang.Class是泛型化的。這是把泛型擴展到容器類之外的一個很有意思的例子。
    現在,Class有一個類型參數T, 你很可能會問,T 代表什麼?它代表Class對象代表的類型。比如說,
    String.class類型代表 Class<String>,Serializable.class代表 Class<Serializable>。
    這可以被用來提高你的反射代碼的類型安全。
    特別的,因為 Class的 newInstance() 方法現在返回一個T, 你可以在使用反射創建對象時得到更精確的類型。
    比如說,假定你要寫一個工具方法來進行一個資料庫查詢,給定一個SQL語句,並返回一個資料庫中符合查詢條件
    的對象集合(collection)。
    一個方法是顯式的傳遞一個工廠對象,像下面的代碼:
    interface Factory<T> {
    public T[] make();
    }
    public <T> Collection<T> select(Factory<T> factory, String statement) {
    Collection<T> result = new ArrayList<T>();
    /* run sql query using jdbc */
    for ( int i=0; i<10; i++ ) { /* iterate over jdbc results */
    T item = factory.make();
    /* use reflection and set all of item』s fields from sql results */
    result.add( item );
    }
    return result;
    }
    你可以這樣調用:
    select(new Factory<EmpInfo>(){
    public EmpInfo make() {
    return new EmpInfo();
    }
    } , 」selection string」);
    也可以聲明一個類 EmpInfoFactory 來支持介面 Factory:
    class EmpInfoFactory implements Factory<EmpInfo> { ...
    public EmpInfo make() { return new EmpInfo();}
    }
    然後調用:
    select(getMyEmpInfoFactory(), "selection string");
    這個解決方案的缺點是它需要下面的二者之一:
    調用處那冗長的匿名工廠類,或為每個要使用的類型聲明一個工廠類並傳遞其對象給調用的地方,這很不自然。
    使用class類型參數值是非常自然的,它可以被反射使用。沒有泛型的代碼可能是:
    Collection emps = sqlUtility.select(EmpInfo.class, 」select * from emps」); ...
    public static Collection select(Class c, String sqlStatement) {
    Collection result = new ArrayList();
    /* run sql query using jdbc */
    for ( /* iterate over jdbc results */ ) {
    Object item = c.newInstance();
    /* use reflection and set all of item』s fields from sql results */
    result.add(item);
    }
    return result;
    }
    但是這不能給我們返回一個我們要的精確類型的集合。現在Class是泛型的,我們可以寫:
    Collection<EmpInfo> emps=sqlUtility.select(EmpInfo.class, 」select * from emps」); ...
    public static <T> Collection<T> select(Class<T>c, String sqlStatement) {
    Collection<T> result = new ArrayList<T>();
    /* run sql query using jdbc */
    for ( /* iterate over jdbc results */ ) {
    T item = c.newInstance();
    /* use reflection and set all of item』s fields from sql results */
    result.add(item);
    }
    return result;
    }
    來通過一種類型安全的方式得到我們要的集合。
    這項技術是一個非常有用的技巧,它已成為一個在處理注釋(annotations)的新API中被廣泛使用的習慣用法。

    7. 新老代碼兼容

    7.1. 為了保證代碼的兼容性,下面的代碼編譯器(javac)允許,類型安全有你自己保證
    List l = new ArrayList<String>();
    List<String> l = new ArrayList();

    7.2. 在將你的類庫升級為范型版本時,慎用協變式返回值。
    例如,將代碼
    public class Foo {
    public Foo create(){
    return new Foo();
    }
    }

    public class Bar extends Foo {
    public Foo create(){
    return new Bar();
    }
    }
    採用協變式返回值風格,將Bar修改為
    public class Bar extends Foo {
    public Bar create(){
    return new Bar();
    }
    }
    要小心你類庫的客戶端。

G. 【Java基礎語法】如何在使用靜態方法的時候指定其泛型萬分感謝!

舉個例子:
public void f(int i, char ch, String s){}
這個方法中有三個參數,分別為int類型的i,char類型的ch,String類型的s。這三個參數的類型都已經指定了,如果實際參數類型和對應參數類型不一致,編譯器會出現錯誤。
如何才能做到可以任意指定參數的類型呢?這個時候可以使用泛型方法。舉個例子:
public <A, B, C> void f(A a, B b, C c){}
這個就是所謂的泛型方法,當向方法中傳遞參數後,編譯器會自動推斷出參數的類型,如:
f(1, "hello", 123.123);
第一個參數類型為Integer,第二個為String,第三個為Double(自動包裝機制讓基本類型自動包裝成對應的包裝類)。
泛型方法的特徵就是方法前面有對尖括弧<>,尖括弧裡面的就是類型參數,也就是說類型是個變數,要由實際的參數推斷得來。
Java中的方法就是這樣獲取泛型能力的,還有其他方式。但是static方法比較特殊,如果要使得static方法具有反省能力就必須要使用到上面的方法。
希望能解決你的問題。

閱讀全文

與java泛型方法靜態相關的資料

熱點內容
arm查詢法的局限性和編譯流程 瀏覽:78
醒圖的文件夾叫什麼 瀏覽:998
php程序員北京 瀏覽:175
gcc編譯進程數據 瀏覽:653
手機上的文件夾是怎樣的 瀏覽:166
微雲群共享文件夾改變 瀏覽:534
程序員三年後能做什麼 瀏覽:449
分解運演算法則 瀏覽:876
python腳本執行sudo 瀏覽:721
安徽科海壓縮機 瀏覽:372
怎麼下載app里的講義 瀏覽:158
命令重啟伺服器 瀏覽:210
android電視root許可權獲取 瀏覽:249
解放戰爭pdf王樹增 瀏覽:685
python壓測app介面 瀏覽:953
抖音app怎麼推薦 瀏覽:100
歌庫伺服器能做其他什麼用途 瀏覽:95
安卓44虛擬機怎麼root 瀏覽:38
程序員瘦身c盤空間 瀏覽:243
dell伺服器溫度怎麼看 瀏覽:303