代码质量不佳会导致不可预测的行为。对于用户来说,通常表现为可用性差。对于攻击者来说,提供了以意外方式对系统施加压力的机会。
notify()
时将唤醒哪个线程并不确定。notify()
无法指定将唤醒哪个线程。 notifyJob()
调用 notify()
。
public synchronized notifyJob() {
flag = true;
notify();
}
...
public synchronized waitForSomething() {
while(!flag) {
try {
wait();
}
catch (InterruptedException e)
{
...
}
}
...
}
wait()
的线程,但是 notify()
可能会通知另外的线程。run()
方法,以此替代 start()
。Thread
对象的 run()
方法会是一个 bug。程序员本想启用新的控制线程,却意外地调用了 run()
,而不是 start()
,因此,在调用者的控制线程中执行了 run()
方法。run()
,而没有调用 start()
。
Thread thr = new Thread() {
public void run() {
...
}
};
thr.run();
stop()
方法,这可能会导致资源泄露。Thread
对象的 stop()
方法会是一个 bug。程序员希望阻止线程运行,但是没有意识到这种阻止线程的方式并不合适。Thread
中的 stop()
函数会导致 Thread
对象中的任意位置出现 ThreadDeath
异常,这可能会导致对象出现不一致状态,并且会泄露资源。由于此 API 本质上并不安全,因此很久以前就已弃用。Thread.stop()
。
...
public static void main(String[] args){
...
Thread thr = new Thread() {
public void run() {
...
}
};
...
thr.start();
...
thr.stop();
...
}
clone()
方法,但没有实现 Cloneable
接口。Cloneable
接口,因为它已经实现了一个名称为 clone()
的方法。然而,该类并没有实现 Cloneable
接口,同时 clone()
方法也无法正常运行。 clone()
方法将导致一个 CloneNotSupportedException.
异常
public class Kibitzer {
public Object clone() throws CloneNotSupportedException {
...
}
}
ICloneable
接口为其 Clone
方法指定的约定并不安全,应避免使用。ICloneable
接口不能保证实现深层克隆。对实施该接口的类进行克隆时,可能得不到预期的结果。这是因为这些类虽然实施了 ICloneable
接口,却只执行浅层克隆(只克隆某一对象而不克隆其当前引用的其他对象),这可能会导致意外的结果。由于深层克隆(克隆某一对象及其引用的所有对象)通常被认为是克隆方法的默认行为,因此为了避免发生错误,应避免使用 ICloneable
接口。clone()
方法会调用可以被覆盖的函数。clone()
函数调用了可覆盖的函数后,会导致克隆初始化仅部分完成,或者破坏该克隆。clone()
函数调用了可覆盖的方法。
...
class User implements Cloneable {
private String username;
private boolean valid;
public Object clone() throws CloneNotSupportedException {
final User clone = (User) super.clone();
clone.doSomething();
return clone;
}
public void doSomething(){
...
}
}
doSomething()
和其封装类并非 final
,这意味着该函数是可覆盖的,这将导致其克隆对象 clone
呈部分初始化状态,如果没有通过意外方式变通逻辑,则会导致错误。equals()
方法比较框式基元,可能会导致意外行为。equals()
方法,而非使用运算符 ==
和 !=
。Java 规范具有关于框式转换的如下说明: Boolean
或 Byte
),则仅会缓存或记住一个值区间。对于值的子集,使用 ==
或 !=
会返回正确的值,而对于此子集外的所有其他值,将返回对象地址的比较结果。
...
Integer mask0 = 100;
Integer mask1 = 100;
...
if (file0.readWriteAllPerms){
mask0 = 777;
}
if (file1.readWriteAllPerms){
mask1 = 777;
}
...
if (mask0 == mask1){
//assume file0 and file1 have same permissions
...
}
...
Example 1
中的代码会使用框式基元 Integer
尝试比较两个 int
值。如果 mask0
和 mask1
都等于 100
,则 mask0 == mask1
将返回 true
。但是,如果 mask0
和 mask1
都等于 777
,则 mask0 == maske1
现在将返回 false
,因为这些值不在这些框式基元的缓存值范围内。