一、疑问-我们真的了解java 泛型吗?
二、困惑-不菜的泛型菜问题
三、突破-Vector的toArray()方法
四、结局-掀起你的盖头来
五、小结
六、附件
一、 疑问-我们真的了解java 泛型吗?
我以为对泛型已经很熟悉了。如果别人问泛型是什么?我会举一个简单的例子,比如
Vector<String> sv = new Vector<String>();
就用到了泛型,这样写代码的一个明显的好处就是以后不用类型检查。比如
String s = sv.get(i);
再“深”一点
for (Iterator<String> it = sv.iterator(); it.hasNext(); ) {
s = it.next();
}
另外jsdk还提供了Arrays和Collections两个类,其中包含了大量操作数组和Collection的方法。总之,在java中使用泛型很方便,也很简单。
Java Tutorial中介绍了java泛型的很多好处,其中印象最深的是这句
Historically, collections frameworks have been quite complex...
We believe that the Java Collections Framework breaks with this tradition.
今天我才明白,JavaTutorial介绍的是Collections Framework,不是真正的泛型。Java使用泛型实现了Collections Framework,并封装起来,我们所能看到的仅仅是冰山一角。
二、 困惑-不菜的泛型菜问题
这得从我前天在csdn看到的一个问题(一个泛型的菜问题)说起。楼主看到一条这样的语句,不知道是什么意思。
public static <K,V> Map<K,V> newHashMap()
我也觉得很奇怪。当时第一放映,这只是个语法结构的描述,不是真正意义的语句。在真正语句里<K, V>应该用具体的类来代替。因为不知道出处,为了证明,只好自己写代码。
首先,根据我的思路,我写了一个static方法,
public static <String, Integer> Map<String, Integer> newHashMap1() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
return map;
}
编译通过。但还没来得及高兴,发现问题了。当我在其中加入这两条语句时,
symbol : method valueOf(int)
map.put("1", Integer.valueOf(1));
却无法编译,提示如下信息:
TestGenericSyntax.java:10: cannot find symbol
其中symbol指的是map.put("1", Integer.valueOf(1))。这怎么可能?我又查了API Spec,没错。在别的地方插入这条语句也没错,单单是在这里不行。
于是,兴趣来了。又做了一些测试(见附件)。最后,一个令我非常吃惊的发现。
public static <K, V> Map<K, V> newHashMap4() {
HashMap<K, V> map = new HashMap<K, V>();
return map;
}
居然编译通过。但令人不解的是,public static Map<K, V> newHashMap5()却不能通过编译。
当时手头有别的事,没有时间深究,只把我做的测试和疑问回复过去了。一心等待楼主写明出处贴,令我失望的是帖子沉的很深了,楼主始终没漂上来。
三、 突破-Vector的toArray()方法
没想到今天一个关于泛型的帖子(关于Collection中的toArray()方法的困惑)使我找到了突破口。回复了bryantd (Delphi菜鸟) 的问题,我突然发现API Spec中关于vector.oArray方法的声明是这样的,
public <T> T[] toArray(T[] a)
这个<T>是什么?以前没认真考虑,但今天我注意了,这不是那个<K, V>吗?接着我又想起泛型的始祖,C++中的Template(使用Collections Framework太顺手,把这岔儿给忘了)。于是我就想到了一个问题,我们知道
Vector<Integer> vi = new Vector<Integer>();
创建了一个储存Integer的Vector,而
Vector<String> vs = new Vector<String>();
又创建了一个储存String的Vector。那么,这种功能,在Vector类的内部是怎么实现的?回到前面的问题,
public <K, V> Map<K, V> newHashMap()
我断定前面的<K, V>是对Map<K, V>中的<K, V>的类型声明,或者准确的说是泛化。没有原因,我一下想到了继承,于是,又写了两个类,
class A {
public <K, V> Map<K, V> newHashMap() {
HashMap<K, V> map = new HashMap<K, V>();
return map;
}
}
class B extends A{
public Map<Integer, String> newHashMap() {
HashMap<Integer, String> map = new HashMap<Integer, String> ();
map.put(1, "A");
map.put(2, "B");
return map;
}
}
天总算亮了。
四、 结局-掀起你的盖头来
到了这里,其实问题也就明白了,看下面的代码,
A[] aa = new A[2];
aa[0] = new B();
aa[1] = new C(); // C也是继承自A,见附件
for (int i=0; i<aa.length; i++) {
Map map = aa[i].newHashMap();
Set keyset = map.keySet();
for (Iterator it = keyset.iterator(); it.hasNext();) {
Object k = it.next();
Object v = map.get(k);
System.out.println(k + " " + v);
}
}
再看这里,
class D extends A {
public Map<S, T> newHashMap() {
HashMap<S, T> map = new HashMap<S, T> ();
S s = new S();
T t = new T();
map.put(s, t);
return map;
}
}
class S extends JLabel{}
class T extends Component{}
如果你在设计类库时声明了class D,那么在该类后续的使用中,开发人员可以拥有很大的自由度。这种功能是不是很强大?
还是时间的原因,不能再深究下去了,需要掌握的东西还很多,一下子不能扎得太深。再说,老婆也不会允许我掀别人的盖头。^_^
好吧,就此别过,后会有期。
五、 小结
其实该说的都说了,没什么可总结的。留待大家讨论吧。
六、 附件
1) 测试1
// TestGenericSyntax.java
import java.util.*;
import java.lang.reflect.*;
public class TestGenericSyntax {
static String s = "Hello";
static Integer I = 0;
//static HashMap<s, I> hMap;
// 这也能过?
public static <s, I> Map<String, Integer> newHashMap() {
HashMap<String, Integer> map =
// TestGenericSyntax.java:12: incompatible types
// found : java.util.Map<java.lang.String,java.lang.Integer>
// required: java.util.HashMap<java.lang.String,java.lang.Integer>
//newHashMap2();
// TestGenericSyntax.java:19: incompatible types; no instance(s) of type variable(s) String,Integer exist so that java.util.Map<String,Integer> conforms to java.util.HashMap<java.lang.String,java.lang.Integer>
// found : <String,Integer>java.util.Map<String,Integer>
// required: java.util.HashMap<java.lang.String,java.lang.Integer>
// newHashMap1();
// 通过
new HashMap<String, Integer>();
map.put("A", 1);
map.put("B", 2);
return map;
}
public static <String, Integer> Map<String, Integer> newHashMap1() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
//map =
// new HashMap<String, Integer>(newHashMap2());
// err msg
// TestGenericSyntax.java:10: cannot find symbol
// symbol : method valueOf(int)
// map.put("1", Integer.valueOf(1));
// err msg
// TestGenericSyntax.java:14: cannot find symbol
// symbol : method put(java.lang.String,java.lang.Integer)
// map.put(s, I);
// err msg
// TestGenericSyntax.java:15: incompatible types
// map = newHashMap2();
return map;
}
public static Map<String, Integer> newHashMap2() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("1", Integer.valueOf(1));
// err msg
// symbol : constructor HashMap(java.util.Map<java.lang.Object,java.lang.Object>)
// map = new HashMap<String, Integer>(newHashMap1());
map = new HashMap<String, Integer>(newHashMap3());
return map;
}
public static Map<String, Integer> newHashMap3() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("1", Integer.valueOf(1));
return map;
}
// 这是什么?居然通过了。
public static <K, V> Map<K, V> newHashMap4() {
HashMap<K, V> map = new HashMap<K, V>();
return map;
}
// 通不过,错误一大堆。
/*
public static Map<K, V> newHashMap5() {
HashMap<K, V> map = new HashMap<K, V>();
return map;
}
*/
public static void main(String[] args) {
// TestGenericSyntax.java:73: incompatible types; no instance(s) of type variable(s) String,Integer exist so that java.util.Map<String,Integer> conforms to java.util.HashMap
// found : <String,Integer>java.util.Map<String,Integer>
// required: java.util.HashMap
// HashMap map = newHashMap1();
// hMap = newHashMap1();
Class c = TestGenericSyntax.class;
Method[] methods;
/*
methods = c.getMethods();
for (int i=0; i<methods.length; i++) {
System.out.println(methods[i]);
}
*/
methods = c.getDeclaredMethods();
for (int i=0; i<methods.length; i++) {
System.out.println(methods[i]);
Type rt = methods[i].getGenericReturnType();
System.out.println(rt);
System.out.println();
}
}
}
2) 测试2
// TestGenericSyntax_2.java
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class TestGenericSyntax_2 {
public static void main(String[] args) {
A[] aa = new A[2];
aa[0] = new B();
aa[1] = new C();
for (int i=0; i<aa.length; i++) {
Map map = aa[i].newHashMap();
Set keyset = map.keySet();
for (Iterator it = keyset.iterator(); it.hasNext();) {
Object k = it.next();
Object v = map.get(k);
System.out.println(k + " " + v);
}
}
HashMap<S, T> map1 = new HashMap<S, T>();
map1.put(new S(), new T());
}
}
class A {
public <K, V> Map<K, V> newHashMap() {
HashMap<K, V> map = new HashMap<K, V>();
return map;
}
}
class B extends A{
public Map<Integer, String> newHashMap() {
HashMap<Integer, String> map = new HashMap<Integer, String> ();
map.put(1, "A");
map.put(2, "B");
return map;
}
}
class C extends A{
public Map<Long, String> newHashMap() {
HashMap<Long, String> map = new HashMap<Long, String> ();
map.put(1L, "S");
map.put(2L, "T");
return map;
}
}
class D extends A {
public Map<S, T> newHashMap() {
HashMap<S, T> map = new HashMap<S, T> ();
S s = new S();
T t = new T();
// TestGenericSyntax_2.java:54: cannot find symbol
// symbol : method put(S,T)
map.put(s, t);
return map;
}
}
class S extends JLabel{}
class T extends Component{}