JDK5.0 泛型不泛
来源:互联网 发布:报名软件app 编辑:程序博客网 时间:2024/04/30 17:36
如果你追求新的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类型的对象。
在说说泛型的问题:
首先,由于擦除,泛型的类型信息都在编译后失去了。
例如:
你认为输出的是true还是false?
事实上,ArrayList<String>与ArrayList<Integer>是截然不同的ArrayList<Integer>中是不能放入String的。
这是为什么呢?
我们再来看看下面一个例子。
根据JKD文档描述,Class.getTypeParameters 将返回一个TypeVariable对象的数组,表示有泛型声明所声明的
参数类型。事实上呢,输出了什么?
你自己试试,并对比一下ArrayList的源代码和HashMap的源代码。实际上输出的只是占位符号。
来看看以下的C++代码,摘自《Think in java 4》,稍有改动。
如果你没有学过C++模板,你一定会惊奇,为什么Manipulator的obj可以调用f(),因为他根本不知道obj会有这个函数阿。原因是编译期间编译器能知道Manipulator的模板(泛型)为HasF类,于是在HasF中自动寻找f()这个函数,如果没有,则出错。
而java却不能这样。问题就出在当编译器去寻找Manipulator的具体类的时候,具体类的信息丢失了,于是不知道从何寻找f()这个函数。
幸好我们还可以使用协助泛型类,看下面的java实现代码:
HasF省略。
由此已可看到擦除的问题了,但是为什么要用擦除呢?
这个就得从兼容性说起了。为了兼容jdk1.4的版本,当我们使用那些用1.4编写的类库或者其他资源时,我们可以
不必再使用jdk5.0来重写,或许这就是牺牲泛型,使用擦除的原因吧。当然,也提供了擦除的补偿。大家可以实现自己的补偿,使用各种方法。这里提一个函数isInstance(obj), 由于擦除,instancof已经不起作用了,所以
我们用isInstance来补偿。看下面的java代码(来自《Think in java4》:
让我们来看看结果:
true
true
false
true
isInstance是一个动态信息,在执行的时候才检测。
还有一个问题,不知道大家发现没有,就是在定义一个泛型时如下:
public <K,V> Map<K,V> f(){
...
}
使用的时候,我们不得不在赋值语句两边都写类型参数,这样似乎很不合理。
Map<Integer,String> map = new HashMap<Integer, String>();
这样,Integer,String写了两次,显得编译器很笨。这也是擦除的原因。
大家自己看看有什么办法可以不用这样写呢?
java泛型的问题还很多,现在就到这里,我们下次在说。
先说说泛型的语法吧。
首先,一个类,接口都可泛型。语法是: 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 {
public static void main(String args[]){
Class c1 = new ArrayList<String>().getclass();
Class c2 = new ArrayList<Integer>().getclass();
System.out.println(c1 == c2);
}
}
public static void main(String args[]){
Class c1 = new ArrayList<String>().getclass();
Class c2 = new ArrayList<Integer>().getclass();
System.out.println(c1 == c2);
}
}
事实上,ArrayList<String>与ArrayList<Integer>是截然不同的ArrayList<Integer>中是不能放入String的。
这是为什么呢?
我们再来看看下面一个例子。
public class LostInformation{
public static void main(String[] args){
List<String> list = new ArrayList<String>();
Map<Integer, String> map = new HashMap<Integer, String>Map();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
}
}
public static void main(String[] args){
List<String> list = new ArrayList<String>();
Map<Integer, String> map = new HashMap<Integer, String>Map();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
}
}
参数类型。事实上呢,输出了什么?
你自己试试,并对比一下ArrayList的源代码和HashMap的源代码。实际上输出的只是占位符号。
来看看以下的C++代码,摘自《Think in java 4》,稍有改动。
#include<iostream>
using namespace std:
template<Class T> class Manipulator{
T obj;
public:
Manipulator(T x) {obj = x; }
Manipulator() {obj = new T();}
void manipulator() { obj.f(); }
};
class HasF {
public:
void f() { count << "HashF::f() " << endl;
};
int main(){
HasF hf;
Manipulator<HasF> manipulator(hf);
manipulator.mainpulate();
}
using namespace std:
template<Class T> class Manipulator{
T obj;
public:
Manipulator(T x) {obj = x; }
Manipulator() {obj = new T();}
void manipulator() { obj.f(); }
};
class HasF {
public:
void f() { count << "HashF::f() " << endl;
};
int main(){
HasF hf;
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> {
T obj;
public Manipulator(T obj){this.obj = obj; }
public void manipulate(){obj.f();}
public static void main(String[] args){
HasF hf = new HasF();
Manipulator<HasF> manipulator = new Manipulator<HasF>(hf);
manipulator.manipulate();
}
}
T obj;
public Manipulator(T obj){this.obj = obj; }
public void manipulate(){obj.f();}
public static void main(String[] args){
HasF hf = new HasF();
Manipulator<HasF> manipulator = new Manipulator<HasF>(hf);
manipulator.manipulate();
}
}
由此已可看到擦除的问题了,但是为什么要用擦除呢?
这个就得从兼容性说起了。为了兼容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;
public ClassTypeCapture(Class<T> kind){
this.kind = kind;
}
public boolean f(Object obj){
return kind.isInstance(obj);
}
public static void main(String[] args){
ClassTypeCapture<Building> cttb = new ClassTypeCapture<Building>();
System.out.println(cttb.f(new Building()));
System.out.println(cttb.f(new House()));
ClassTypeCapture<House> cttbh = new ClassTypeCapture<House>();
System.out.println(ctth.f(new Building()));
System.out.println(ctth.f(new Housse()));
}
}
public class House{}
public class ClassTypeCapture<T> {
Class<T> kind;
public ClassTypeCapture(Class<T> kind){
this.kind = kind;
}
public boolean f(Object obj){
return kind.isInstance(obj);
}
public static void main(String[] args){
ClassTypeCapture<Building> cttb = new ClassTypeCapture<Building>();
System.out.println(cttb.f(new Building()));
System.out.println(cttb.f(new House()));
ClassTypeCapture<House> cttbh = new ClassTypeCapture<House>();
System.out.println(ctth.f(new Building()));
System.out.println(ctth.f(new Housse()));
}
}
true
true
false
true
isInstance是一个动态信息,在执行的时候才检测。
还有一个问题,不知道大家发现没有,就是在定义一个泛型时如下:
public <K,V> Map<K,V> f(){
...
}
使用的时候,我们不得不在赋值语句两边都写类型参数,这样似乎很不合理。
Map<Integer,String> map = new HashMap<Integer, String>();
这样,Integer,String写了两次,显得编译器很笨。这也是擦除的原因。
大家自己看看有什么办法可以不用这样写呢?
java泛型的问题还很多,现在就到这里,我们下次在说。
- JDK5.0 泛型不泛
- JDK5.0 范型小测验
- JDK5.0的collection
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0新特性
- JDK5.0新特性:
- jdk5.0新特性
- JDK5.0 新特性
- JDK5.0 Annotation 介绍
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0 Annotation
- JDK5.0特性
- JDK5.0泛型
- JDK5.0新特性
- JDK5.0 新特性
- jdk5.0新特性
- 如何取得数据库对象的脚本信息
- javascript对下拉列表框(select)的操作
- 使用 ASP.NET Login 控件的高级功能
- 全面认识UML类图元素
- access 2007打开mdb文件时需要密码,打开每一个mdb文件都需要,这些文件并没有设置密码
- JDK5.0 泛型不泛
- 企业管理软件平台架构内幕揭秘
- 【摘选】嵌入式学习步骤
- Oracle中判断表是否存在
- GDI+绘图中的刷新闪屏问题
- HFC-S mini芯片通道复位和初始化
- symbian注释风格
- Flex与JavaScript的交互:调用JavaScipt或者被JavaScript调用
- 软件需求的方法论(2)