前面提到的都是与类的泛型化相关的话题,不过方法也可以从泛型中受益,尤其是Helper类的工具方法这种"无状态"的方法更加合适。还是有几个话题可以进一步讨论下的。
1. 类型推导
所谓类型推导,就是编译器可以通过判断参数的类型来推导类型参数(泛型)的类型。这句话初看会发现非常绕口,举个例子就能很好的理解了。
public class GenericHelper {
public static <E> Set<E> merge(Set<E> set1, Set<E> set2){
Set<E> retSet = new HashSet<E>(set1);
retSet.addAll(set2);
return retSet;
}
}
这个方法的目的是将set1和set2的元素进行合并。在使用这个方法的时候,如果传入的参数是Set<Integer>类型的,那么编译器就会自动推导出E的类型是Integer了。
这个特性可以使用在一种叫做"泛型静态工厂方法"的的编写上,比如下面的几个方法。
public static <E> Set<E> createSet() {
return new HashSet<E>();
}
public static <K, V> Map<K, Set<V>> createMap() {
return new HashMap<K, Set<V>>();
}
public static void main(String[] args) {
Map<String, Set<Integer>> str = createMap();
Set<Integer> set = createSet();
str.put("key", set);
}
这里的一系列方法就是运用了类型推导的来使Map和Set的创建语句缩短,程序员都应该是懒人吗!呵呵。
这里,对于类型推导,还有一个比较重要的用法,就是"泛型单例工厂"。举个例子如下:
假设有一个如下的接口:
public interface NumberWrapper<T extends Number> {
public double square(T num);
}
这个接口可以对Number的子类进行封装,它提供了一个方法可以输出值的平方。对于这样的Wrapper,我并不想对于每一个T都实例化一个相应的对象,那样有一些浪费,这时,就可以使用这个泛型单例工厂来生成支持不同T的单例。另外,因为NumberWrapper的泛型信息在运行时是会被擦除的,所以也没有必要对每一个T生成一个实例。泛型单例工厂的代码如下:
public class GenericFactory {
private static NumberWrapper<Number> numWrapper = new NumberWrapper<Number>() {
@Override
public double square(Number num) {
return num.doubleValue() * num.doubleValue();
}
};
@SuppressWarnings("unchecked")
public static <T extends Number> NumberWrapper<T> getWrapperInstance() {
return (NumberWrapper<T>) numWrapper;
}
public static void main(String[] args) {
NumberWrapper<Integer> integerWrapper = GenericFactory.getWrapperInstance();
System.out.println(integerWrapper.square(2));
NumberWrapper<Double> doubleWrapper = GenericFactory.getWrapperInstance();
System.out.println(doubleWrapper.square(0.05));
}
}
这里,有一个点要注意下,就是getWrapperInstance()方法的的类型转换,这里是一个NumberWrapper<Number>向NumberWrapper<T>的转换,这里,由于square()方法返回的仅仅是平方,这里是不会导致类型错误的,所以可以放心的禁止这条警告了。
程序的运行结果如下所示:
4.0
0.0025000000000000005
说明程序还是运行良好的。
2. 递归类型限制
所谓递归类型限制,是使用包含某个参数类型本身的表达式去限制参数的类型。比如java.util.Collections的max()方法,定义如下:
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
这里面的具体实现先不用去关注。这里,类型参数的定义是T extends Object & Comparable<? super T>。T是要扩展自Comparable<? super T>的,这里就是一个递归类型限制。其实也好理解,比如String类就是Comparable<String>的子类,Integer是Comparable<Integer>的子类,只有类型是"可以比较的"才能去计算的最大值吗。
这个的用法不多,就不去仔细研究了,到真正会使用的时候再去研究也不晚,这就是所谓的"延迟加载"吧,呵呵。
分享到:
相关推荐
java泛型深入.pdf
java,学习java泛型,java培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptx
深入理解java泛型,包括类名泛型的定义,方法泛型定义,泛型的返回
java 泛型的使用 详细讲解
java泛型详细学习,深入学习java的不二之选
泛型编程 [翻译]Java泛型编程指南(上).htm
详细介绍JAVA的泛型,泛型的类型参数只能是类类型(包括自定义类)
一个可以让你对Java泛型更加深入了解的下例子。
深入浅出的解释了Java泛型编程方面的相关技术,适合初学者学习阅读。
主要介绍了Java中的泛型详解,什么是泛型,作用以及基础实例等,喜欢的朋友可以参考
一.什么是Generics?...在我们深入了解Generics之前,我们先来看一看当前的java 集合框架(Collection)。在j2SE1.4中所有集合的Root Interface是Collection Collections example without genericity: Example 1
主要介绍了JAVA泛型的相关知识,文中代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
java泛型深入[参考].pdf
java泛型深入[参照].pdf
实际上泛型可以用得很复杂,复杂到编写代码的人员自己也难以看懂。这往往是对泛型的滥用或者类或接口本身设计不合理导致的。 看来用好泛型还真不容易,为此必须从根源说起
深入理解java泛型详解!Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化。
java泛型机制,深入理解java编程的思想.
二 泛型类、泛型接口、泛型方法、泛型通配符 2.1 泛型类: 2.2 泛型接口: 2.3 泛型方法: 2.4 泛型通配符: 三 限定类型变量 四 泛型中的约束和局限性 4.1 不能用基本类型实例化类型参数 4.2 运行时类型查询只适用...
主要介绍了JAVA 反射和泛型的的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下