【IT168 技术分析】JVM上目前已经有许多语言了:JRuby,Jython;还有一些特定于JVM平台的语言,如Scala和Groovy等等。但是,为什么JVM上没有C#语言呢?按理说,这门和Java十分相似,却又强大许多的语言更容易被Java程序员接受才对。您可能会说,Sun和微软是对头,怎么可能将C#移植到JVM平台上呢?嗯,有道理,但是为什么社区里也没有人这么做呢(要知道JVM上其他语言都是由社区发起的)?其实在我看来,这还是受到了技术方面的限制。
泛型是Java和C#语言的重要特性,它使得程序员可以方便地进行类型安全的编程,而不需要像以前那样不断进行类型转换。例如,我们要在Java中写一个泛型字典的封装便可以这么做:
public class DictWrapper {
private HashMap m_container = new HashMap();
public V get(K key) {
return this.m_container.get(key);
}
public void put(K key, V value) {
this.m_container.put(key, value);
}
}
private HashMap m_container = new HashMap();
public V get(K key) {
return this.m_container.get(key);
}
public void put(K key, V value) {
this.m_container.put(key, value);
}
}
看上去和C#并没有什么区别,不是吗?不过,如果我们观察编译后生成的bytecode(类似于.NET平台上的IL),便会发现一丝奇妙之处。使用javap -c DictWrapper得到的结果是:
Compiled from "DictWrapper.java"
public class jeffz.practices.DictWrapper extends java.lang.Object{
public jeffz.practices.DictWrapper();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: aload_0
5: new #2; //class java/util/HashMap
8: dup
9: invokespecial #3; //Method java/util/HashMap."":()V
12: putfield #4; //Field m_container:Ljava/util/HashMap;
15: return
public java.lang.Object get(java.lang.Object);
Code:
0: aload_0
1: getfield #4; //Field m_container:Ljava/util/HashMap;
4: aload_1
5: invokevirtual #5; //Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
8: areturn
public void put(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: getfield #4; //Field m_container:Ljava/util/HashMap;
4: aload_1
5: aload_2
6: invokevirtual #6; //Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
9: pop
10: return
}
public class jeffz.practices.DictWrapper extends java.lang.Object{
public jeffz.practices.DictWrapper();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: aload_0
5: new #2; //class java/util/HashMap
8: dup
9: invokespecial #3; //Method java/util/HashMap."":()V
12: putfield #4; //Field m_container:Ljava/util/HashMap;
15: return
public java.lang.Object get(java.lang.Object);
Code:
0: aload_0
1: getfield #4; //Field m_container:Ljava/util/HashMap;
4: aload_1
5: invokevirtual #5; //Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
8: areturn
public void put(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: getfield #4; //Field m_container:Ljava/util/HashMap;
4: aload_1
5: aload_2
6: invokevirtual #6; //Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
9: pop
10: return
}
从bytecode中可以看出,其中并没有包含任何与K,V有关的信息。get/put方法的参数和返回值都是Object类型,甚至内置的HashMap也是如此。那么调用DictWrapper的代码是如何做到“强类型”的呢?例如:
public static void main(String[] args) {
DictWrapper dict = new DictWrapper();
dict.put("Hello", "World");
String world = dict.get("Hello");
}
DictWrapper dict = new DictWrapper();
dict.put("Hello", "World");
String world = dict.get("Hello");
}
它的bytecode便是:
public static void main(java.lang.String[]);
Code:
0: new #2; //class jeffz/practices/DictWrapper
3: dup
4: invokespecial #3; //Method jeffz/practices/DictWrapper."":()V
7: astore_1
8: aload_1
9: ldc #4; //String Hello
11: ldc #5; //String World
13: invokevirtual #6; //Method jeffz/practices/DictWrapper.put:(Ljava/lang/Object;Ljava/lang/Object;)V
16: aload_1
17: ldc #4; //String Hello
19: invokevirtual #7; //Method jeffz/practices/DictWrapper.get:(Ljava/lang/Object;)Ljava/lang/Object;
22: checkcast #8; //class java/lang/String
25: astore_2
26: return
}
Code:
0: new #2; //class jeffz/practices/DictWrapper
3: dup
4: invokespecial #3; //Method jeffz/practices/DictWrapper."":()V
7: astore_1
8: aload_1
9: ldc #4; //String Hello
11: ldc #5; //String World
13: invokevirtual #6; //Method jeffz/practices/DictWrapper.put:(Ljava/lang/Object;Ljava/lang/Object;)V
16: aload_1
17: ldc #4; //String Hello
19: invokevirtual #7; //Method jeffz/practices/DictWrapper.get:(Ljava/lang/Object;)Ljava/lang/Object;
22: checkcast #8; //class java/lang/String
25: astore_2
26: return
}
看到标号为22的那行代码没有?这条checkcast指令便是将上一句invokevirtual的结果转化为String类型——DictWrapper.get所返回的是个最普通不过的Object。