JDK5.0 泛型不泛

如果你追求新的JDK,那么当你习惯了JDK1.4 的编码后,使用JDK1.5一定出现很多问题。其中,使用泛型的警告一定是布满整个程序吧( 可用@SuppressWarnings("unchecked")消除警告),于是便打算看看泛型的知识。结果不看不知道,一看吓一跳。
先说说泛型的语法吧。
首先,一个类,接口都可泛型。语法是: public class classname<T> , public interface interfacename<T>
其次,泛型可用于函数(方法)。语法为: public <T> void f(T x) 或静态方法 public <A,B> Map<A,B> f()
最后,泛型可以定界。例如 public class ClassRoom<T extends Room<E>> 。 ClassRoom现在接受一个Room类型的对象。

在说说泛型的问题:
首先,由于擦除,泛型的类型信息都在编译后失去了。
例如:
public class EraserCheck ... {
publicstaticvoidmain(Stringargs[])...{
Classc1
=newArrayList<String>().getclass();
Classc2
=newArrayList<Integer>().getclass();
System.out.println(c1
==c2);
}

}
你认为输出的是true还是false?
事实上,ArrayList<String>与ArrayList<Integer>是截然不同的ArrayList<Integer>中是不能放入String的。
这是为什么呢?
我们再来看看下面一个例子。
public class LostInformation ... {
publicstaticvoidmain(String[]args)...{
List
<String>list=newArrayList<String>();
Map
<Integer,String>map=newHashMap<Integer,String>Map();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
}

}
根据JKD文档描述,Class.getTypeParameters 将返回一个TypeVariable对象的数组,表示有泛型声明所声明的
参数类型。事实上呢,输出了什么?
你自己试试,并对比一下ArrayList的源代码和HashMap的源代码。实际上输出的只是占位符号。

来看看以下的C++代码,摘自《Think in java 4》,稍有改动。
#include < iostream >
using namespace std:

template
< ClassT > class Manipulator ... {
Tobj;
public:
Manipulator(Tx)
...{obj=x;}
Manipulator()
...{obj=newT();}
voidmanipulator()...{obj.f();}
}
;

class HasF ... {
public:
voidf()...{count<<"HashF::f()"<<endl;
}
;

intmain()...{
HasFhf;
Manipulator
<HasF>manipulator(hf);
manipulator.mainpulate();
}


如果你没有学过C++模板,你一定会惊奇,为什么Manipulator的obj可以调用f(),因为他根本不知道obj会有这个函数阿。原因是编译期间编译器能知道Manipulator的模板(泛型)为HasF类,于是在HasF中自动寻找f()这个函数,如果没有,则出错。
而java却不能这样。问题就出在当编译器去寻找Manipulator的具体类的时候,具体类的信息丢失了,于是不知道从何寻找f()这个函数。
幸好我们还可以使用协助泛型类,看下面的java实现代码:
public class Manipulator < T extends HasF > ... {
Tobj;
publicManipulator(Tobj)...{this.obj=obj;}
publicvoidmanipulate()...{obj.f();}

publicstaticvoidmain(String[]args)...{
HasFhf
=newHasF();
Manipulator
<HasF>manipulator=newManipulator<HasF>(hf);
manipulator.manipulate();
}

}
HasF省略。
由此已可看到擦除的问题了,但是为什么要用擦除呢?
这个就得从兼容性说起了。为了兼容jdk1.4的版本,当我们使用那些用1.4编写的类库或者其他资源时,我们可以
不必再使用jdk5.0来重写,或许这就是牺牲泛型,使用擦除的原因吧。当然,也提供了擦除的补偿。大家可以实现自己的补偿,使用各种方法。这里提一个函数isInstance(obj), 由于擦除,instancof已经不起作用了,所以
我们用isInstance来补偿。看下面的java代码(来自《Think in java4》:
public class Building ... {}
public class House ... {}

public class ClassTypeCapture < T > ... {
Class
<T>kind;
publicClassTypeCapture(Class<T>kind)...{
this.kind=kind;
}

publicbooleanf(Objectobj)...{
returnkind.isInstance(obj);
}

publicstaticvoidmain(String[]args)...{
ClassTypeCapture
<Building>cttb=newClassTypeCapture<Building>();
System.out.println(cttb.f(
newBuilding()));
System.out.println(cttb.f(
newHouse()));
ClassTypeCapture
<House>cttbh=newClassTypeCapture<House>();
System.out.println(ctth.f(
newBuilding()));
System.out.println(ctth.f(
newHousse()));
}

}

让我们来看看结果:
true
true
false
true
isInstance是一个动态信息,在执行的时候才检测。

还有一个问题,不知道大家发现没有,就是在定义一个泛型时如下:
public <K,V> Map<K,V> f(){
...
}
使用的时候,我们不得不在赋值语句两边都写类型参数,这样似乎很不合理。
Map<Integer,String> map = new HashMap<Integer, String>();
这样,Integer,String写了两次,显得编译器很笨。这也是擦除的原因。
大家自己看看有什么办法可以不用这样写呢?
java泛型的问题还很多,现在就到这里,我们下次在说。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值