任何与线程有关的内容... :)
还包括:
与C/C++相比,Java中的未定义行为非常少,它是一个更加明确定义的平台。原因在于C/C++编译器旨在为非常不同的平台生成代码,因此被授予了相当广泛的自由度,以防止过于严格的要求迫使编译器为给定平台生成次优代码。
Java通过以非常精确的方式定义几乎每个行为并仅允许小的自由度来牺牲了一些自由度。当然,这使得该平台更容易处理。
未定义行为发生的主要领域是多个线程的精确时间和调度(正如Tom Hawtin已经提到的那样)。
还有一些地方行为不明显,但看起来可能是未定义的,但实际上不是(Oscar Reyes给出的字符串比较示例就是一个很好的例子)。
还有一些地方的行为被定义为未定义的(例如HashMap中元素的顺序被定义为实现相关,并且不需要是恒定的)。
我认为Java(TM) Puzzlers: Traps, Pitfalls, and Corner Cases这本书会非常有用,它解释了许多Java中隐藏的细节和未定义的行为。
对象相等性测试:
== 用于测试引用(这两个对象引用是否指向同一个对象)
而 equals 用于测试对象的相等性。
例如:
new String("test") == new String("test")
是 false,而
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中使用脚本时看到过这种情况,新手程序员不明白为什么验证会失败。
<%if( param == "continue" ) { %>
从未发生过
我知道两种未定义行为:
a)方法重载,其参数是与重载方法中的同一参数的子类。例如:
void doSomething(Object obj);
void doSomething(String str);
在doSomething("Hello world!")中,无法确定将调用哪个方法,因为两个签名都是有效的。此外,这种行为可能会从VM到VM甚至从执行到执行发生变化。
b) 在构造函数中调用同一类的非final方法。如果该方法在子类中被覆盖,则会出现未定义的行为。请注意,构造发生在超类到子类之间。如果子类方法使用一些本地子类属性,则情况会变得特别复杂。在Oracle VM的情况下,将构造本地属性,超类构造函数将完成其执行,然后当子类的构造函数被调用时,属性将再次被构造,覆盖先前定义的值。