維基百科中關(guān)于Java泛型的描述
Java 泛型的參數(shù)只可以代表類,不能代表個別對象槽棍。由于Java泛型的類型參數(shù)之實際類型在編譯時會被消除,所以無法在運行時得知其類型參數(shù)的類型,而且無法直接使用基本值類型作為泛型類型參數(shù)。Java編譯程序在編譯泛型時會自動加入類型轉(zhuǎn)換的編碼丧叽,故運行速度不會因為使用泛型而加快。
由于運行時會消除泛型的對象實例類型信息等缺陷經(jīng)常被人詬病公你,Java及JVM的開發(fā)方面也嘗試解決這個問題踊淳,例如Java通過在生成字節(jié)碼時添加類型推導(dǎo)輔助信息,從而可以通過反射接口獲得部分泛型信息陕靠。通過改進泛型在JVM的實現(xiàn)迂尝,使其支持基本值類型泛型和直接獲得泛型信息等。
Java允許對個別泛型的類型參數(shù)進行約束剪芥,包括以下兩種形式(假設(shè)
T
是泛型的類型參數(shù)垄开,C
是一般類、泛類税肪,或是泛型的類型參數(shù)):
T
實現(xiàn)接口I
溉躲。T
是C
榜田,或繼承自C
。
泛型Since jdk1.5
摘自《Java代碼與架構(gòu)完美優(yōu)化》
泛型的本質(zhì)是參數(shù)化類型锻梳,所操作的數(shù)據(jù)類型被指定為一個參數(shù)箭券。
Java中的泛型在編譯器中實現(xiàn),而不是在虛擬機中實現(xiàn)的疑枯,虛擬機對于泛型是一無所知的辩块。因此,編譯器一定要把泛型類修改為普通類荆永,才能夠在虛擬機中運行废亭。Java中把這種技術(shù)稱為擦除,泛型代碼經(jīng)過擦除后變成原生類型具钥。
源代碼>>>泛型>>>編譯器>>>字節(jié)碼(*.class文件)>>>JVM(類裝載器豆村,字節(jié)碼校驗器,解釋器)>>>操作系統(tǒng)平臺
使用泛型的優(yōu)勢
類型安全以及不需要進行類型轉(zhuǎn)換
類型安全性:我們只能在泛型中只保存一種類型的對象氓拼。 它不允許存儲其他對象你画。因此,也不再需要進行類型轉(zhuǎn)換桃漾。下面給出使用泛型和不使用泛型的區(qū)別坏匪。
List list = new ArrayList();
list.add("Hello Generics");
String s = (String) list.get(0); //需要類型轉(zhuǎn)換
List<String> list = new ArrayList<String>();
list.add("Hello Generics");
String s = list.get(0); //不需要類型轉(zhuǎn)換
類型檢查從運行時挪到編譯時
編譯時檢查:在編譯時檢查,所以運行時不會出現(xiàn)問題撬统。 良好的編程策略表明适滓,在編譯時處理這個問題要比運行時好得多。
使用泛型的注意事項
- 在static方法中不可以使用泛型恋追,泛型變量也不可以使用static關(guān)鍵字來修飾
- 泛型常用符號的含義-T(Type)凭迹、K(Key)、V(Value)苦囱、E(Element)嗅绸,N(Number)盡管其它形式也可以作為變量的符號,但是我們習(xí)慣使用這幾種符號撕彤。
- 泛型只適用于對象鱼鸠,基本類型不適用,但是可以使用基本類型的包裝類來實現(xiàn)羹铅,比如:
List<Integer> intList = new ArrayList<Integer>();
intList.add(1); //自動將1轉(zhuǎn)換成Integer
intList.add(2);
開發(fā)人員在使用泛型的時候蚀狰,很容易根據(jù)自己的直覺而犯一些錯誤。比如一個方法如果接收List<Object>作為形式參數(shù)职员,那么如果嘗試將一個List<String>的對象作為實際參數(shù)傳進去麻蹋,卻發(fā)現(xiàn)無法通過編譯。雖然從直覺上來說焊切,Object是String的父類扮授,這種類型轉(zhuǎn)換應(yīng)該是合理的芳室。但是實際上這會產(chǎn)生隱含的類型轉(zhuǎn)換問題,因此編譯器直接就禁止這樣的行為刹勃。http://www.infoq.com/cn/articles/cf-java-generics
泛型使用舉例
創(chuàng)建參數(shù)化類型-泛型類
//simple
class MyGen<T> {
T obj;
void add(T obj) {
this.obj = obj;
}
T get() {
return obj;
}
}
public class Generics {
public static void main(String args[]) {
MyGen<Integer> m = new MyGen<Integer>();
m.add(2);
//m.add("test"); //Compile time error
System.out.println(m.get());
}
}
//complex from agile java
import java.util.*;
public class MultiHashMap <K,V> {
private Map<K, List<V>> map = new HashMap<K, List<V>>();
public static <K extends Comparable<K>,V> List<K>
sortedKeys(MultiHashMap<K, V> map) {
List<K> keys = new ArrayList<K>();
keys.addAll(map.keys());
Collections.sort(keys);
return keys;
}
public Set<K> keys() {
return map.keySet();
}
public int size() {
return map.size();
}
public void put(K key, V value) {
List<V> values = map.get(key);
if (values == null) {
values = new ArrayList<V>();
map.put(key, values);
}
values.add(value);
}
public List<V> get(K key) {
return map.get(key);
}
protected Set<Map.Entry<K, List<V>>> entrySet() {
return map.entrySet();
}
public interface Filter<T> {
boolean apply(T item);
}
public static <K,V> void filter(final MultiHashMap<K, ? super V> target,
final MultiHashMap<K, V> source,
final Filter<? super V> filter) {
for (K key : source.keys()) {
final List<V> values = source.get(key);
for (V value : values)
if (filter.apply(value))
target.put(key, value);
}
}
}
泛型方法
public class Generics {
public static < E > void printArray(E[] elements) {
for ( E element : elements){
System.out.println(element );
}
System.out.println();
}
public static void main( String args[] ) {
Integer[] intArray = {6, 66, 666};
String[] stringArray = { "6","66","666" };
System.out.println( "Printing Integer Array" );
printArray( intArray );
System.out.println( "Printing String Array" );
printArray( stringArray );
}
}
上限
每個類型參數(shù)都有一個缺省為Object的上限渤愁,你可以將類型參數(shù)限制為不同的上限。這里需要使用extends關(guān)鍵字來指定某個類型參數(shù)的上限深夯。
//from agile java
import java.util.*;
public class EventMap<K extends Date,V>
extends MultiHashMap<K,V> {
public List<V> getPastEvents() {
List<V> events = new ArrayList<V>();
for (Map.Entry<K,List<V>> entry: entrySet()) {
K date = entry.getKey();
if (hasPassed(date))
events.addAll(entry.getValue());
}
return events;
}
private boolean hasPassed(K date) {
Calendar when = new GregorianCalendar();
when.setTime(date);
Calendar today = new GregorianCalendar();
if (when.get(Calendar.YEAR) != today.get(Calendar.YEAR))
return when.get(Calendar.YEAR) < today.get(Calendar.YEAR);
return when.get(Calendar.DAY_OF_YEAR) <
today.get(Calendar.DAY_OF_YEAR);
}
}
通配符wildcard
java允許使用一個通配符?來表示任意可能的類型,此外你可以使用extends子句限制通配符的上限诺苹。
import java.util.ArrayList;
import java.util.List;
abstract class Shape {
abstract void draw();
}
class Rectangle extends Shape {
void draw() {
System.out.println("drawing rectangle");
}
}
class Circle extends Shape {
void draw() {
System.out.println("drawing circle");
}
}
public class Generics {
// creating a method that accepts only child class of Shape
public static void drawShapes(List<? extends Shape> lists) {
for (Shape s : lists) {
s.draw(); // calling method of Shape class by child class instance
}
}
public static void main(String args[]) {
List<Rectangle> list1 = new ArrayList<Rectangle>();
list1.add(new Rectangle());
List<Circle> list2 = new ArrayList<Circle>();
list2.add(new Circle());
list2.add(new Circle());
drawShapes(list1);
drawShapes(list2);
}
}
demo來源
- https://www.javatpoint.com/generics-in-java
- agile java