Java程序员应该了解哪些常见的未定义行为

时间:2008-12-17 22:48:29

标签: java undefined

this问题相同,但对于java

更新 基于少数人的评论和回应,很明显Java几乎没有未定义的行为。

所以我想问一下哪些行为不明显。请在回答时区分两者:)

10 个答案:

答案 0 :(得分:14)

与线程有关......:)

此外:

  • 覆盖方法并期望它们在版本之间以相同的方式使用
  • 关于底层平台的假设(例如文件分隔符)
  • 垃圾收集/完成的详细信息
  • 有关课程初始化的一些细节
  • Integer.valueOf(等)是否返回相同的对象
  • 性能,延迟和内存使用

答案 1 :(得分:11)

Java中存在非常非常少的未定义行为,与C / C ++相比,它是一个更加明确的平台。原因是C / C ++编译器旨在为非常不同的平台生成代码,因此被授予相当宽的自由度,以防止过于严格的要求,迫使编译器为给定平台生成次优代码。

Java通过以非常精确的方式定义几乎所有行为并且仅允许很小的自由度来牺牲其中一些。这当然使平台更容易处理。

发生未定义行为的主要区域是多个线程的确切时间和调度(正如Tom Hawtin已经提到的那样)..

有几个地方行为不明显,'但是,它可能看起来未定义,但不是(Oscar Reyes给出的字符串比较示例就是一个很好的例子)。

行为定义为未定义的一些地方(例如,HashMap中元素的顺序被定义为依赖于实现,不需要是常量)。

答案 2 :(得分:8)

我认为Java(TM) Puzzlers: Traps, Pitfalls, and Corner Cases本书非常有用,它解释了java的许多隐藏点和未定义的行为。

答案 3 :(得分:4)

Serialization。它本身并不是未定义的(有确定性的算法)。但是,对于不经意的观察者来说,什么会或不会导致serialVersionUID发生变化并不是很明显,从而挫败了你使用RMI,JMS和各种其他缩写词的所有尝试。

因此,当您知道需要序列化对象时,consider your options通常是个好主意。我特别喜欢“总是把它作为一个领域”技术:

private static final long serialVersionUID = 1L;

当您(开发人员知道)对您的代码进行兼容性更改时,只更改该字段的值。不要让JDK为你做出决定....

答案 4 :(得分:3)

我并不完全确定“未定义的行为”是什么意思,但正如其他人所指出的那样,核心语言在跨平台,语言版本和JVM的版本中都是可预测的。

然而,对于图形(Swing,AWT)来说并非如此,这些图形往往是不可预测的,并且不一定在不同平台上可重现。我从事基于Java的图形密集型可视化应用程序,我花了很多时间“一次编写,随处调试”。

此外,Object.clone()存在一些主要问题,在大多数情况下不鼓励使用它。请参阅Joshua Bloch的“Effective Java”中的第11项,以获得完整的答案。

答案 5 :(得分:2)

我知道有两种未定义的行为:

a)使用参数重载方法,该参数是重载方法中相同参数的子类。例如:

void doSomething(Object obj);
void doSomething(String str);

由于两个签名都有效,因此无法知道在doSomething(“Hello world!”)中调用哪个方法。此外,此行为可以从VM更改为VM,甚至从执行更改为执行。

b)在构造函数中调用同一个类的非final方法。如果在子类中覆盖此方法,则会发生未定义的行为。请注意,构造从超类发生到子类。如果子类方法使用一些本地子类属性,则该案例特别令人讨厌。对于Oracle VM,将构造本地属性,超类构造函数将完成其执行,然后,当到达子类的构造函数时,将再次构造属性,覆盖先前定义的值。

答案 6 :(得分:1)

定义明确但不明显:

对等测试:

==用于测试引用(这两个对象引用指向同一个对象)

虽然equals用于测试对象的相等性。

例如

new String("test") == new String("test")  

是假的,而

new String("test").equals( new String("test") )

是真的

字符串对象被实现,因此以下内容返回true:

String a = "test";
String b = "test";

a == b  // returns true 

但是如果字符串是在其他地方创建的(例如从数据库中创建)

String a = "test";
String b = getFromDataBase(); // internally the remote returns "test"

a == b  // returns false.

验证是错误的。

我已经在jsp中看到过用scriplets发生这种情况,并且新程序员无法获得验证的原因

 <%if( param == "continue" ) { %>

永远不会发生

答案 7 :(得分:-1)

我记得的一件事是关于jvm与jni的兼容性。我们有和jdk1.4开发的应用程序,当安装在ibm jvm(我相信的jikes)的机器上时,jni调用只是puked!那是在2006年。我相信这与java作为一种语言没什么关系,但更多的是与java作为一个平台。

答案 8 :(得分:-1)

添加dynamic vs. static binding以及如何将其应用于重载和覆盖的方法不明显

答案 9 :(得分:-1)

未定义,但意外的行为是转换为整数时双精度的四舍五入。 0.6d总是向下舍入到0;实际上0.9d也会向下舍入到0.但0.99999999999999995及更高将会向上舍入为1.

将Math.random()调用的结果转换为beaware时,这只是一个有趣的行为。