類似于Item 26里優(yōu)先考慮泛型礁蔗,Item 27告訴我們要優(yōu)先考慮泛型方法骆膝。
編寫泛型方法和編寫泛型類相似惶傻。泛型方法的特性是,無需明確指定類型參數(shù)的值,編譯器通過檢查方法參數(shù)的類型來計算類型參數(shù)的值鲫剿。類型推導(dǎo)鳄逾。
下面我們來詳細(xì)說明。
泛型方法的使用
我們先來看下面一個例子灵莲,這個method目的在于返回在傳入的兩個set里任意出現(xiàn)的元素:
// uses raw types - unacceptable! (Item 28)
public static Set union(Set s1, Set s2) {
Set result = new HashSet(s1);
result.addAll(s2);
return result;
}
上面這段代碼雕凹,我們能夠編譯成功,但是會有兩個warning:
Union.java:5: warning: [unchecked] unchecked call to HashSet(Collection<? extends E>) as member of raw type HashSet
Set result = new HashSet(s1);
Union.java:6: warning: [unchecked] unchecked call to HashSet(Collection<? extends E>) as member of raw type HashSet
result.addAll(s2);
要解決這些warning政冻,我們需要定義三個set(兩個傳入值枚抵,一個返回值)的類型。我們可以使用泛型明场。
// generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<E>(s1);
result.addAll(s2);
return result;
}
使用泛型后汽摹,warning都沒有了。我們可以用類似下面的代碼使用這個union method榕堰。
// simple program to exercise generic method
public static void main(String[] args) {
Set<String> set1 = new HashSet<>(Arrays.asList("A"));
Set<String> set2 = new HashSet<>(Arrays.asList("B"));
Set<String> res = union(set1, set2);
}
Type Interface
在上面的代碼中竖慧,當(dāng)我們調(diào)用union,我們不需要直接指定參數(shù)類型逆屡,compiler會自動處理圾旨。比如compiler看到上面union里面?zhèn)魅氲氖莾蓚€Set<String>,就知道E這個泛型在這里實際指的是String魏蔗,那么返回值自然就是Set<String>砍的。這個過程就是Type Interface。
把三個set都定義為泛型有一個缺點莺治,就是三個set的實際類型必須一致廓鞠。比如傳入的兩個set都必須存String,返回的set也必須存String谣旁。
因為有type interface床佳,在使用constructor定義一個parameter的時候,我們能減少很多不必要的參數(shù)定義榄审。比如:
// parameterized type instance creation with constructor
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
上面的代碼里面右邊HashMap里的類型定義其實是冗余的砌们。
而在Java里,Map里有一個method:
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}
這個method使用了generic static factory method搁进。generic static factory method里面使用到了type interface浪感。因為這個method,anagrams的定義可以簡化成:
// parameterized type instance creation with static factory
Map<String, List<String>> anagrams = new HashMap<>();
Generic Singleton Factory
由此我們引出一個相關(guān)的概念饼问,叫g(shù)eneric singleton factory(泛型單例工廠)影兽。
有時候我們希望能創(chuàng)造出一個適用于很多不同類型的,immutable的object莱革。因為泛型是有擦除來實現(xiàn)峻堰,我們可以寫一個static factory method來實現(xiàn)讹开。這種方法常用在function object里面,比如Collections.reverseOrder茧妒。
我們來看下面的例子:
// generic singleton factory pattern
private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
public Object apply(Object arg) {
return arg;
}
}
// in Java 8, can be written as
private static UnaryFunction<Object> IDENTITY_FUNCTION = (t) -> t;
// IDENTITY_FUNCTION is stateless and its type parameter is unbounded so it's safe to share one instance across all types
// use @SuppressWarnings because we have warning due to converting Object to T
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY_FUNCTION;
}
實際在Java中萧吠,F(xiàn)unction已經(jīng)實現(xiàn)了identity()左冬。
它的源碼是:
/**
* Returns a function that always returns its input argument.
*
* @param <T> the type of the input and output objects to the function
* @return a function that always returns its input argument
*/
static <T> Function<T, T> identity() {
return t -> t;
}
使用identityFunction的代碼:
String[] strings = { "jute", "hemp", "nylon" };
UnaryOperator<String> sameString = identityFunction();
for (String s : strings) {
System.out.println(sameString.apply(s));
}
Number[] numbers = { 1, 2.0, 3L };
UnaryOperator<Number> sameNumber = identityFunction();
for (Number n : numbers) {
System.out.println(sameNumber.apply(n));
}
Recursive Type Bound
如果一個參數(shù)類型被含自身的表達(dá)式限制(a type parameter to be bounded by some expression involving that type parameter itself)桐筏,那么這個參數(shù)類型就是recursive type bound。
最常見和recursive type bound一起使用的是Comparator
這個interface拇砰。比如:
// using a recursive type bound to express mutual comparability
public static <T extends Comparable<T>> T max(List<T> list) {...}
其中<T extends Comparable<T>>梅忌,可以讀成 for every type T that can be compared to itself。
我們來看看它的使用:
// returns the max value in a list - uses recursive type bound
public static <T extends Comparable<T>> T max(List<T> list) {
Iterator<T> i = list.iterator();
T result = i.next();
while (i.hasNext()) {
T t = i.next();
if (t.compareTo(result) > 0) {
result = t;
}
}
return result;
}
雖然recursive type bound比較復(fù)雜除破,但好在并不常用牧氮。我們只需要簡單了解一下就好。
Reference