effective java(27) 之优先考虑泛型方法

来源:互联网 发布:seo网络推广教程 编辑:程序博客网 时间:2024/05/19 10:42
effective java 之优先考虑泛型方法


1、就如类可以从泛型中受益一般,方法也可以。静态工具方法尤其适合与泛型化。
JDK中的Collections泛型中的所有“算法”方法都泛型化了。


2、编写泛型方法与编写泛型类型类似。如:下面这个方法返回两个集合的联合。

public class testSet {public static Set union(Set s1, Set s2) {Set result = new HashSet(s1);result.addAll(s2);return result;}}

虽然这个方法可以编译,但是编译这段代码会产生警告,为了方法变成类型安全的,要将方法声明修改为声明一个类型参数。
表示这三个集合的元素类型(两个参数和一个返回值),并在方法中使用类型参数。声明类型参数的类型参数列表,处在方法的修饰符及其返回类型之间。
在这个示例中,类型参数列表为<E>,返回类型为Set<E>。类型参数的命名习惯与泛型方法以及泛型的相同,一般是E或者T。
改写为泛型方法如下:
public class testArray {/*public static Set union(Set s1, Set s2) {Set result = new HashSet(s1);result.addAll(s2);return result;}*/public static <E> Set<E> union(Set<E> s1, Set<E> s2) {Set<E> result = new HashSet<E>(s1);result.addAll(s2);return result;}public static void main(String[] args) {Set<String> firstSet = new HashSet<String>(Arrays.asList("Bady", "Tim","Alice"));Set<String> secondSet = new HashSet<String>(Arrays.asList("Come", "On","Go", "With", "Me"));Set<String> set = union(firstSet, secondSet);System.out.println(set);}}

[Me, Alice, On, Come, Go, Tim, With, Bady]
上面这个union方法的局限性在于,三个集合的类型(两个输入参数和一个返回值)必须全部相同。利用有限制的通配符类型,可以使这个方法更加灵活。


3、泛型方法还有一个比较重要的概念叫做类型推导。
我们在创建一个泛型集合实例时,这样写 Map<String , Integer>   map  =  new  HashMap<String , Integer>();
我们在调用泛型HashMap的构造器时,在new HashMap之后使用<String , Integer>指明了类型参数。那么我们在使用泛型方法的时候是否也需要这样做呢?
写出这样的代码 :Set.union<String>(s1,s2);   也就是说是否在需要调用方法的时候像调用构造器的那样在方法名后面指明类型参数。不需要
泛型方法会根据你具体传入的s1,s2的类型,来推断出类型参数E。如果你传入的s1,s2是HashSet<String>,那么类型参数E就是String;
如果你传入的s1,s2是HashSet<Integer>,那么类型参数E就是Integer。  
一句话就是:泛型方法的类型参数根据传入的实际参数的类型而定,不需要再调用时显示指明。


4、有的时候,我们发现使用泛型的时候,在调用构造器的时候要明确泛型的类型,这样书写很麻烦这里可以使用一个泛型静态方法,利用泛型的类型推导

import java.util.HashMap;import java.util.List;import java.util.Map;public class GenericStaticFactory{public static <K, V> HashMap<K, V> newHashMap(){return new HashMap<K, V>();}public static void main(String[] args){//这里创建对象的时候,就会根据前面map中的String和List<String>自动转换Map<String, List<String>> anagrams = newHashMap();}}


5、关于泛型单例工厂的实现


一个接口,描述一个方法,该方法接受和返回某个类型T的值
public interface UnaryFunction<T> {T apply(T arg);}public class GenericSingletonFactory {// 先创建object对象,暂时替代T对象private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {public Object apply(Object arg) {return arg;}};// 根据T,把IDENTITY_FUNCTION转换为相应的类型,由于IDENTITY_FUNCTION返回未被修改的object类型参数,所以下面类型转换时安全的@SuppressWarnings("unchecked")public static <T> UnaryFunction<T> identityFunction() {return (UnaryFunction<T>) IDENTITY_FUNCTION;}public static void main(String[] args) {String[] strings = { "jute", "hemp", "nylon" };UnaryFunction<String> sameString = identityFunction();for (String s : strings)System.out.println(sameString.apply(s));Number[] numbers = { 1, 2.0, 3L };UnaryFunction<Number> sameNumber = identityFunction();// 这里用来判断是否真的实现了单例Object t1 = sameString;Object t2 = sameNumber;if (t1 == t2) {System.out.println("相同引用,是单例");}else {System.out.println("引用不相同");}String s1 = "123456";String s2 = new String("123456");if (s1.equals(s2))System.out.println("相同内容");for (Number n : numbers)System.out.println(sameNumber.apply(n));}}

jute
hemp
nylon
相同引用,是单例
相同内容
1
2.0
3


6、有限制的类型参数的特殊形式(递归的类型限制)
形式:<E extends Comparable<E>>
表述:可以与自身比较的E类
使用情形:一般用于Comparable类
例:求List容器中的最大值
public class testComparable {public <T extends Comparable<T>> T calculateMax(List<T> list) {Iterator<T> iterator = list.iterator();T result = iterator.next();while (iterator.hasNext()) {T t = iterator.next();// 需要判断大小if (result.compareTo(t) < 0) {result = t;}}return result;}}




7、总之,泛型方法就像泛型一样,使用起来比要求客户端转换输入参数并返回值的方法来的更加安全,也更加容易。
就像类型一样,你应该确保新的方法可以不用转换就能使用,这通常意味着要将它们泛型化。
并且就像类型一样,还应该将现有的方法泛型化,使新用户使用起来更加轻松,且不会破坏现有的客户端。


每天努力一点,每天都在进步。

阅读全文
0 0