主题:【评论】Sun发布了最新的Java版本-- 5.0 Tiger版 -- Highway
注意是5.0,而不是1.5。Sun有意的改变了Java版本的命名规则,以表示这是java历史上的一次突破。
在Sun的发言中,有这么一段很有趣:
Sun的这一个记录不是在自己的Sparc 机器 + Soloris操作系统上创造的,而是在AMD芯片的机器上创造的。如果你留意一下就会发现,SPECjbb 2000 单处理器/双处理器的纪录已经被AMD牢牢占领。
看来,AMD确实有了实质性进步!
叫1.5还是5.0区别不大,关键是有多少真正的新东西,和什么时候主流Java工具厂商支持它,否则意义不大。
关键在于,什么时候Java能够出现真正的本机代码编译器,否则性能上很难和.Net竞争,更不要说和C++程序相比较。
另外在语言特性上,Java曾经比C#强一些,现在则基本倒过来了。
按照这样的趋势,Sun还是交出Java的控制权算了。
最大的感受是,这个破公司怎么变成这么大的,产品叫一个破。那bug大的都不像话了。
奉劝大家一句,千万别碰Sun Java App Server,除非象我一样没出息,实在找不到饭辙了。
Java走向何方是个两难的选择。如果要和.NET竞争,那就要不断的增加features,而这样做又违背了java的初衷 -- Simplicity。网上有不少人对这种趋势深表忧虑,这样下去Java不就是又一个C++了吗?
至于性能,抛开图形部分不说,Java喝.NET各有千秋。.NET在数据库操作上有一些优势。不过我的Benchmark用的是SQL Server,可能让.NET占了些便宜!
这样它在市场上的用处就不大了,也就是技术发烧友会对它感兴趣。
本人的经历和年龄决定了发烧时代已经过去,所关注的只是成本和收益。
在诸如Eclipse这类免费Java IDE环境随处可得的情况下,没有多少人会有兴趣继续用Notepad/VI来写程序和用Javac/Java来编译和运行程序了。也就是说,Java工具厂商的支持程度要比Java本身更能够决定一个Java版本的市场接受程度。
这些人或者是太喜欢Java了,或者是太恨Micorsoft了。(在工作中这种人见了不少,甚至还见了不少Delphi的死党)
吃Java这碗饭的Third-party vendor一定早就行动起来了。否则等formal release出来了,你才动手,那就全完了。
过两天有空了,写几个小程序看看.NET 2.0 Beta和Java 5.0 beta 哪个牛?
今天忽然有兴趣,写了两个很简单的Java 1.5程序,用Java 1.5来编译,然后用DJ来反编译所生成的Class文件,以此试试它的Generic是如何实现的,发现整个一个坑蒙拐骗。下面是各自的源程序和反编译出来的程序以及有关说明。
第一个程序的源程序:
import java.util.*;
public class MyClass {
public int sum(int data1,int data2) {
return data1 + data2;
}
public void test()
{
ArrayList<String> al=new ArrayList<String>();
al.add("111");
al.add("222");
System.out.println(al.get(al.size()-1));
System.out.println(al.get(al.size()-2));
ArrayList<Integer> al2=new ArrayList<Integer>();
al2.add(111);
al2.add(222);
System.out.println(al2.get(al2.size()-1));
System.out.println(al2.get(al2.size()-2));
}
public static void main(String[] args) {
MyClass mc=new MyClass();
System.out.println(mc.sum(10,20));
mc.test();
}
}
对应的反编译程序:
import java.io.PrintStream;
import java.util.ArrayList;
public class MyClass
{
public MyClass()
{
}
public int sum(int i, int j)
{
return i + j;
}
public void test()
{
ArrayList arraylist = new ArrayList();
arraylist.add("111");
arraylist.add("222");
System.out.println((String)arraylist.get(arraylist.size() - 1));
System.out.println((String)arraylist.get(arraylist.size() - 2));
ArrayList arraylist1 = new ArrayList();
arraylist1.add(Integer.valueOf(111));
arraylist1.add(Integer.valueOf(222));
System.out.println(arraylist1.get(arraylist1.size() - 1));
System.out.println(arraylist1.get(arraylist1.size() - 2));
}
public static void main(String args[])
{
MyClass myclass = new MyClass();
System.out.println(myclass.sum(10, 20));
myclass.test();
}
}
评论:注意它对类和初始类型的不同处理。
第二个程序的源程序:
这是一个Generic类
public class BasicGeneric <A>
{
private A data;
public BasicGeneric(A data)
{
this.data = data;
}
public A getData()
{
return data;
}
}
它的使用者:
import java.util.*;
public class MyClass2 {
public String test01(String input) {
String data01 = input;
BasicGeneric<String> basicGeneric = new BasicGeneric<String>(data01);
String data02 = basicGeneric.getData(); return data02;
}
public int test02(int input) {
Integer data01 = new Integer(input);
BasicGeneric <Integer> basicGeneric = new BasicGeneric<Integer>(data01);
Integer data02 = basicGeneric.getData();
return data02;
}
public static void main(String [] args) {
MyClass2 sample = new MyClass2();
System.out.println(sample.test01("This generic data"));
System.out.println(sample.test02(12));
}
}
各自对应的反编译程序:
public class BasicGeneric
{
public BasicGeneric(Object obj)
{
data = obj;
}
public Object getData()
{
return data;
}
private Object data;
}
import java.io.PrintStream;
public class MyClass2
{
public MyClass2()
{
}
public String test01(String s)
{
String s1 = s;
BasicGeneric basicgeneric = new BasicGeneric(s1);
String s2 = (String)basicgeneric.getData();
return s2;
}
public int test02(int i)
{
Integer integer = new Integer(i);
BasicGeneric basicgeneric = new BasicGeneric(integer);
Integer integer1 = (Integer)basicgeneric.getData();
return integer1.intValue();
}
public static void main(String args[])
{
MyClass2 myclass2 = new MyClass2();
System.out.println(myclass2.test01("This generic data"));
System.out.println(myclass2.test02(12));
}
}
评论:注意它是如何处理Template的!
这就是Java 1.5的Generic Programming,什么玩意儿啊!
把测试搞得大一些,看看性能有没有提高。因为使用了Generics应该避免了Casting(Boxing和Unboxing),因该有性能上的提升。
我先回家吃饭去了。
DJ所作的只是把Byte Code反编译成Java Source Code,只要逻辑上对,它是不可能错的。
我的例子说明了Java所谓的Generic不过是用Object这个始祖类来做障眼法,这样既可以保证对以前程序的兼容性,又可以以最简单的方式实现所谓的Generic,所牺牲的只是Generic思想。
因此,Java 1.5的性能有可能有所提高,但是绝不是来自Generic。
下面这个例子(源程序和反编译程序)说明了Java 1.5的Boxing/UnBoxing是如何实现的,以这样的方式,它的性能不可能有任何提高。
源程序:
import java.util.*;
public class Freq
{
public static void main(String[] args) {
Map<String, Integer> m = new TreeMap<String, Integer>();
for (String word : args) {
Integer freq = m.get(word);
m.put(word, (freq == null ? 1 : freq + 1));
}
System.out.println(m);
}
}
编译以后,又反编译出的程序:
import java.io.PrintStream;
import java.util.Map;
import java.util.TreeMap;
public class Freq
{
public Freq()
{
}
public static void main(String args[])
{
TreeMap treemap = new TreeMap();
String args1[] = args;
int i = args1.length;
for(int j = 0; j < i; j++)
{
String s = args1[j];
Integer integer = (Integer)treemap.get(s);
treemap.put(s, Integer.valueOf(integer != null ? integer.intValue() + 1 : 1));
}
System.out.println(treemap);
}
}
评论:所谓的Boxing/Unboxing不过是自动做到以前需要手工编码来完成的转换,而没有任何新的东西。这样的进步,确实有可能提高程序员的编程效率,但是绝不可能提高程序的运行性能,因为它没有任何实际的改进。另外,可以注意一下所谓改进的循环是如何实现的,那不过是个简单的展开。
...
ArrayList<String> al=new ArrayList<String>();
al.add("111");
al.add("222");
al.add(new Integer(10));
...
结果在编译的时候,compiler指出了错误。
symbol : method add(java.lang.Integer) location: class java.util.ArrayList<java.lang.String> al.add(new Integer(10)); ^
假如你的推断是正确的话(DJ did right job),那么java 5 改进的只是Compiler,Compiler检查过syntax后,又回到老路子去了。Is that what you are trying to say?
Java 1.5改进的只是它的Compiler,具体实现和以前的毫无二致,这样JVM就不需要任何修改,而能够实现语法上的Generic了。
整个一个障眼法。
平心而论,Java的Generic和C++的Template实现思路是类似的,就是通过预编译来实现语法上的需要(类型待定),而实际代码中依然还是确定的东西。但是C++的Template在预编译以后得到的是具体确定的类型,而Java的Generic在预编译以后得到的却是那个始祖类而不是具体的那个类型,这样Generic/Template的思想就被改变了,因为二者的Generic范围是截然不同的。Template可以做到比较严格的限定(就像是.Net 2.0中做到的那样),这样编译器可以帮助程序员发现可能出错的地方;而Generic却是毫无限定,编译器只是简单地应付交差了事。
这就是为什么我说Java 1.5的Generic实现不怎么样的缘故,因为在三个实现Template的主流编程语言中(C+,C#和Java),它的实现是最差的。
这是微软MSDN杂志上的一片文章,我摘一段下来:
Both C++ templates and the proposed generics equivalent in the Java language are features of their respective compilers. These compilers construct code from references to the generic or template type at compile time. This can cause code bloat as well as reduced type equivalence from one construction to another, even when the type arguments are the same. In contrast, CLR generics do not work this way.
Generics in the CLR are a first-class feature of the platform itself. To implement it this way required changes throughout the CLR including new and modified intermediate language instructions, changes to the metadata, type-loader, just-in-time (JIT) compiler, language compilers, and more. There are two significant benefits to the run-time expansion in the CLR.
First, even though each construction of a generic type, such as Node<Form> and Node<String>, has its own distinct type identity, the CLR is able to reuse much of the actual JIT-compiled code between the type instantiations. This drastically reduces code bloat and is possible because the various instantiations of a generic type are expanded at run time. All that exists of a constructed type at compile time is a type reference. When assemblies A and B both reference a generic type defined in a third assembly, their constructed types are expanded at run time. This means that, in addition to sharing CLR type-identities (when appropriate), type instantiations from assemblies A and B also share run-time resources such as native code and expanded metadata.
Type equivalency is the second benefit of run-time expansion of constructed types. Here is an example: referencing code in AssemblyA.dll that constructs Node<Int32> and referencing code in AssemblyB.dll that constructs Node<Int32> will both create objects of the same CLR type at run time. This way, if both assemblies are used by the same application, their constructions of the Node<T> type resolve to the same type and their objects can be exchanged freely. You should note that compile-time expansion would make this logically simple equivalency either problematic or impossible to implement.
There are a few other benefits to implementing generics at the runtime level, rather than at the compiler level. One such benefit is that generic type information is preserved between compilation and execution and is therefore accessible at all points in the code lifecycle. For example, reflection provides full access to generics metadata. Another benefit is rich IntelliSense® support in Visual Studio® .NET as well as a clean debugging experience with generic code. In contrast, Java generics and C++ templates lose their generic identity by run time.
Another benefit, and mainstay of the CLR, is cross-language use―a generic defined using one managed language can be referenced by code written in another managed language. Meanwhile, the likelihood that a language vendor will put generics support in their compilers is increased by the fact that much of the hard work is done in the platform.
Of all the fringe benefits of run-time type expansion, my favorite is a somewhat subtle one. Generic code is limited to operations that are certain to work for any constructed instantiation of the type. The side effect of this restriction is that CLR generics are more understandable and usable than their C++ template counterparts. Let's look at the constraints around generics in the CLR.
我以前也看到过一篇类似的文章,不过不是在微软的地盘上,而是在Java Community,抱歉想不起来具体的链接了。在那篇文章里,作者以一个C++ Guru的姿态来评论Java 1.5的Generic实现,并且有类似的描述。不过那时候Java 1.5还处于很早的时期,我希望等到正式版出来的时候事情会有所改进,不料都到Beta2了,它的实现还是这个样子。
看老兵的code,有此疑惑?