西西河

主题:【游戏】不看不知道,一看吓一跳!!! -- Highway

共:💬47 🌺6
全看树展主题 · 分页首页 上页
/ 4
下页 末页
家园 我们应该使用哪个版本的好呢?

我昨天又照你说的做了第二题,结果与你后来公布的相同。可能是两个cchere.net地址的问题,现在看不到我回答那个帖子了。

现在的问题是,我们该用哪个版本比较好?

SUN应该尽快出一个稳健的版本吧?

还是说我们要重新整理我们一贯的思维方式?

家园 这个题目的意思是让我们注意一下class dependence

的问题,有时候问题并不是那么想当然。单就这个问题而言,我觉得是Java设计的不够好。当然,这个“特点”Java在他的技术文档里指出了,没搞对还是我们的错。

Java 5.0有不少新的feature,但是也带来一些困惑。这可能就是成长的代价吧!

家园 题目给的有问题阿

第一个题目没有说明i和j是什么数据类型的,如果照Highway兄的解释,那就是这个题目的前提条件没有给够。如果i和j都是long或者其他简单数据类型的话,应该是不会死循环的。如果i和j都是object类型的话,程序员是应该提供合适的比较方法,否则系统用默认的方法比较,出了错就是程序员自己的责任了。这个在C++bible等OO Programing的书里面应该都是讲过的。第二个题目,怎么看都觉得把他称为java5。0的feature太过牵强了:)

家园 你有所不知。在以前的Java中,<=,>=这些操作符只能用于原始数据类型

也就是int,long这一类的东西。

Java 5.0中出现了box/un-boxing feature,这个题就是让你主意这个feature带来的新变化。不能用原来的思维考虑了。

家园 这个倒是,不过

不过在我所知道的OO语言中(C++,C#...),object的比较一般都是要求programmer提供比较函数或操作符,语言本身只提供基本的相等和不等的比较。所以不管这个box/unbox是不是java5。0的新feature,如果看到object之间的比较的case,就应该check一下所使用的比较操作符或者是比较函数是否是想要的。我想这个在以前的java的版本中应该也是成立的吧:)另外,Highway兄给的那个例子有点特殊,Integer这种object类型很有迷惑性的阿,如果i和j是什么Employee型的东西,估计大家就能一眼看出关键所在了:)

家园 这正是迷惑所在之处。Integer和Integer比较,<=, >=比较的是

内部的值,而!=比较的是两个Object(可能是Hash value)。如果是Employee class,由于不能auto unboxing,编译就不能通过。

我个人不喜欢这种设计,非常容易出错,并且很隐蔽。

家园 My 2 cents

问题一: 是Java设计的问题. 操作符重载应由程序员实现, 除了最基本的外Java不应该狗拿耗子多管闲事, javac对这段代码应该直接报错.

问题二: 是程序员的问题. 关键字final会导致编译器做优化处理, 这是完全合理的.

问题三: 还是Java的问题. C/C++编译器会在预处理时将86400000000 hard coded into object file, 根本不会等到运行时再去计算MICROS_PER_DAY. 而且中间结果存放在int里也是很弱智的设计.

家园 有些问题你可能不知道。第一题在以前一直都是错误的。但

问题是Java 5.0引入了boxing/un-boxing feature。于是出现了一些“不伦不类”的东西。Java 5.0中有好多东西并不是非常自然的,完全是出于市场上的需要。因为.net有,而Java没有,那在市场宣传上会显得很难看。

第二题有些争议。因为java的最根本本质是dynamic linking。编译器那样优化,性能上是有所提高,但违反了Basic principle,合适吗?

第三题你Java的看法是不对的。事实上,Java和C/C++一样,是先将那两个变量算出来作为常量的。但Java没有“智能”,不知道将中间结果放到long临时变量中。

反编译的Java code是这样的。

public class LongDivision
{
    public LongDivision() {}

    public static void main(String args[])
    {
        System.out.println(5L);
    }

    private static final long MILLIS_PER_DAY = 0x5265c00L;
    private static final long MICROS_PER_DAY = 0x1dd76000L;
}

在.NET中,编译的时候,编译器会给出错误提示The operation overflows at compile time in checked mode 。看来这点上,.NET要聪明一些。

家园 再补充两句,C/C++其实和Java一样“笨”。

不信你自己试试看。(注意,C/C++的long long和Java的long一样,是64位的长整数)

#include <iostream>

//static or nor doesn't matter
static long long MILL_PER_DAY = 60 * 60 * 24 * 1000;
static long long MACRO_PER_DAY = 60 * 60 * 24 * 1000 * 1000;

int main(int args, char *argv[])
{
	printf("The result = %d",MACRO_PER_DAY/MILL_PER_DAY);
}

我用的是gcc编译器,结果和java一样,是5。(IDE是免费的Dev-C++ 4.9.9.2)

如果用微软的Visual C++(VS 2005),结果也是5。不过编译的时候会给出警告。

Warning 1	warning C4307: '*' : integral constant overflow	c:\temp\longdivison\longdivison\longdivison.cpp	7

奇怪吗?

家园 呵呵, 我们是从程序员的角度来看问题的

marketing的事我们不管. 第一题里的boxing/unboxing也许在某些情况下有用, 但这个功能实在是可有可无. 真正复杂的类操作符还是得由程序员来重载, 而象Integer这样的我宁可用基本数据类型.

第二题和Java Language Specification的13.4.8和14.20小节里的例子一样, 书中指出了误用final关键字会导致break compatibility with existing binaries. 既然人家都那么说了, 只好怪程序员读书不仔细了.

当然这样的设计是值得推敲的. 在实际中如果Words和PrintWords是由不同的程序员/公司开发的, 后者也许只能得到Words.class或是不知道前者修改了Words.java, 麻烦就来了. 这有点类似"DLL Hell".

C++里的const关键字就没有此问题. 下面a.cpp和b.cpp完全可以分开独立编译, 怎么修改a.cpp都没事. C也是一样, 用extern const char*不会使编译器做错误优化. 其实常量在C/C++里面都是用头文件定义, 我对Java不提供#define这样的directives很有意见.

h.h:

#include <stdio.h>

class Words {

public:

static const char* FIRST;

static const char* SECOND;

static const char* THIRD;

};

a.cpp

#include "h.h"

const char* Words::FIRST="the";

const char* Words::SECOND=NULL;

const char* Words::THIRD="set";

b.cpp

#include "h.h"

main()

{

printf("%s\n",Words::FIRST);

printf("%s\n",Words::SECOND);

printf("%s\n",Words::THIRD);

}

所以此题对Java和程序员各打五十大板.

第三题说明不光是java.exe而且javac.exe也是用int保存中间结果. 这太土了, 简直是个bug, 自动类型转换从来是就高不就低的.

P.S. 看了Highway的大作后发现C/C++也一样土, 真是没想到啊. 不知Fortran是否会好一些?

家园 谢谢参与。希望什么时候能看到阁下的原创大作!!!
家园 发错了, 空贴
家园 FT, 的确如此

#include <iostream>

using namespace std;

long long MILL_PER_DAY = 60 * 60 * 24 * 1000;

long long MACRO_PER_DAY = 60LL * 60 * 24 * 1000 * 1000;

main()

{

cout << MILL_PER_DAY << endl;

cout << MACRO_PER_DAY << endl;

cout << MACRO_PER_DAY/MILL_PER_DAY << endl;

}

结果就对了(M$的那个__int64也一样). 看来C/C+里加一个L还不够, 得加两个!

如果不用中间结果:

#include <iostream>

using namespace std;

long long MILL_PER_DAY = 86400000;

long long MACRO_PER_DAY = 86400000000;

main()

{

cout << MILL_PER_DAY << endl;

cout << MACRO_PER_DAY << endl;

cout << MACRO_PER_DAY/MILL_PER_DAY << endl;

}

gcc会报错, cl会正确编译运行.

虽然C/C++也很土, 不过至少不会用16-bit int去存32-bit long的中间结果. C是70年代设计的, C++是80年代设计的, Java是90年代设计的, 评判标准当然不一样了.

家园 看来好多东西要动手才行。

Long life Programming!!!

家园 My 1.99 cents 8-)

问题一出得不好,变量名故意引人往错处想.

真正编程时很难想象熟手会写出这样的程

序,但就题论题,生手熟手都可能答错.属于

刁钻的trick question.

问题二责任归谁要看程序类型.如果程序的设

计用途就是hot swappable,(比如在web applet 里),

那么程序员不应该用'final'.如果是stand-alone

application,错误应该在编译管理:有dependency

的class没有重新编译.C/C++的makefile没写好也

会出现同样问题.如果用ant或eclipse,两个class

都会重新编译的.

问题三是编译器的问题.编译器在做constant

substitution的除法时是直接把两个变量的定义

字符串展开再计算的.如果先求两个变量的值再

代入就不会错了.估计是把gcc的现成算法照抄了

全看树展主题 · 分页首页 上页
/ 4
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河