標籤:www. xtend cas creat 有一個 參數 win select cpp
1. Java範型時編譯時間技術,在運行時不包含範型資訊,僅僅Class的執行個體中包含了型別參數的定義資訊。
泛型是通過java編譯器的稱為擦除(erasure)的前端處理來實現的。你可以(基本上就是)把它認為是一個從源碼到源碼的轉換,它把泛型版本轉換成非泛型版本。 基本上,擦除去掉了所有的泛型型別資訊。所有在角括弧之間的類型資訊都被扔掉了,因此,比如說一個List<String>類型被轉換為List。所有對類型變數的引用被替換成類型變數的上限(通常是Object)。而且,無論何時結果代碼類型不正確,會插入一個到合適類型的轉換。
<T> T badCast(T t, Object o) { return (T) o; // unchecked warning }
型別參數在運行時並不存在。這意味著它們不會添加任何的時間或者空間上的負擔,這很好。不幸的是,這也意味
著你不能依靠他們進行類型轉換。
2.一個泛型類被其所有調用共用
下面的代碼列印的結果是什嗎?
List<String> l1 = new ArrayList<String>(); List<Integer> l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass());
或許你會說false,但是你想錯了。它列印出true。因為一個泛型類的所有執行個體在運行時具有相同的運行時類(class),
而不管他們的實際型別參數。
事實上,泛型之所以叫泛型,就是因為它對所有其可能的型別參數,有同樣的行為;同樣的類可以被當作許多不同
的類型。作為一個結果,類的靜態變數和方法也在所有的執行個體間共用。這就是為什麼在靜態方法或靜態初始化代碼
中或者在靜態變數的聲明和初始化時使用型別參數(型別參數是屬於具體執行個體的)是不合法的原因。
3. 轉型和instanceof
泛型類被所有其執行個體(instances)共用的另一個暗示是檢查一個執行個體是不是一個特定類型的泛型類是沒有意義的。
Collection cs = new ArrayList<String>(); if (cs instanceof Collection<String>) { ...} // 非法
類似的,如下的類型轉換
Collection<String> cstr = (Collection<String>) cs;
得到一個unchecked warning,因為運行時環境不會為你作這樣的檢查。
4. 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中被廣泛使用的習慣用法。
5. 為了保證代碼的相容性,下面的代碼編譯器(javac)允許,型別安全有你自己保證
List l = new ArrayList<String>();
List<String> l = new ArrayList();
6. 在將你的類庫升級為範型版本時,慎用協變式傳回值。
例如,將代碼
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(); }
}
要小心你類庫的用戶端。
上海尚學堂java培訓原作,請多關注。陸續java相關技術文章奉上!
JAVA泛型實現原理