Java泛型大全( 四 )

这也就是为什么上面会报错的原因了 , setData((Integer) data);的时候String无法转换成Integer 。所以上面第2行编译器提示unchecked warning的时候 , 我们不能选择忽略 , 不然要等到运行期间才能发现异常 。如果我们一开始加上Node n = mn就好了 , 这样编译器就可以提前帮我们发现错误 。
问题三
正如我们上面提到的 , Java泛型很大程度上只能提供静态类型检查 , 然后类型的信息就会被擦除 , 所以像下面这样利用类型参数创建实例的做法编译器不会通过:
public static <E> void append(List<E> list) { E elem = new E(); list.add(elem);}但是如果某些场景我们想要需要利用类型参数创建实例 , 我们应该怎么做呢?可以利用反射解决这个问题:
public static <E> void append(List<E> list, Class<E> cls) throws Exception { E elem = cls.newInstance(); list.add(elem);}我们可以像下面这样调用:
List<String> ls = new ArrayList<>();append(ls, String.class);实际上对于上面这个问题 , 还可以采用Factory和Template两种设计模式解决 , 感兴趣的朋友不妨去看一下Thinking in Java中第15章中关于Creating instance of types(英文版第664页)的讲解 , 这里我们就不深入了 。
问题四
我们无法对泛型代码直接使用instanceof关键字 , 因为Java编译器在生成代码的时候会擦除所有相关泛型的类型信息 , 正如我们上面验证过的JVM在运行时期无法识别出ArrayList和ArrayList的之间的区别:
public static <E> void rtti(List<E> list) { if (list instanceof ArrayList<Integer>) { }}=> { ArrayList<Integer>, ArrayList<String>, LinkedList<Character>, ... }和上面一样 , 我们可以使用通配符重新设置bounds来解决这个问题:
public static void rtti(List<?> list) { if (list instanceof ArrayList<?>) { }}工厂模式
接下来我们利用泛型来简单的实现一下工厂模式 , 首先我们先声明一个接口Factory:
package typeinfo.factory;public interface Factory<T> { T create();}接下来我们来创建几个实体类FuelFilter和AirFilter以及FanBelt和GeneratorBelt 。
class Filter extends Part {}class FuelFilter extends Filter { public static class Factory implements typeinfo.factory.Factory<FuelFilter> { public FuelFilter create() { return new FuelFilter(); } }}class AirFilter extends Filter { public static class Factory implements typeinfo.factory.Factory<AirFilter> { public AirFilter create() { return new AirFilter(); } }}class Belt extends Part {}class FanBelt extends Belt { public static class Factory implements typeinfo.factory.Factory<FanBelt> { public FanBelt create() { return new FanBelt(); } }}class GeneratorBelt extends Belt { public static class Factory implements typeinfo.factory.Factory<GeneratorBelt> { public GeneratorBelt create() { return new GeneratorBelt(); } }}Part类的实现如下 , 注意我们上面的实体类都是Part类的间接子类 。在Part类我们注册了我们上面的声明的实体类 。所以以后我们如果要创建相关的实体类的话 , 只需要在调用Part类的相关方法了 。这么做的一个好处就是如果的业务中出现了CabinAirFilter或者PowerSteeringBelt的话 , 我们不需要修改太多的代码 , 只需要在Part类中将它们注册即可 。老大难的空指针 , 如何优雅处理?
class Part { static List<Factory<?extends Part>> partFactories = new ArrayList<Factory<?extends Part>>(); static { partFactories.add(new FuelFilter.Factory()); partFactories.add(new AirFilter.Factory()); partFactories.add(new FanBelt.Factory()); partFactories.add(new PowerSteeringBelt.Factory()); } private static Random rand = new Random(47); public static Part createRandom() { int n = rand.nextInt(partFactories.size()); return partFactories.get(n).create(); } public String toString() { return getClass().getSimpleName(); }}最后我们来测试一下:
public class RegisteredFactories { public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.println(Part.createRandom()); } }} References

  • ORACLE-DOCUMENTATION
  • THINKING IN JAVA
  • EFFECTIVE JAVA

【Java泛型大全】


推荐阅读