Códigos de baixa qualidade levam a comportamentos imprevisíveis. Da perspectiva do usuário, isso normalmente se manifesta como usabilidade ruim. Para um invasor, trata-se de uma oportunidade para atacar o sistema de formas imprevistas.
notify()
for chamado.notify()
.notifyJob()
chama notify()
.
public synchronized notifyJob() {
flag = true;
notify();
}
...
public synchronized waitForSomething() {
while(!flag) {
try {
wait();
}
catch (InterruptedException e)
{
...
}
}
...
}
wait()
, mas é possível que notify()
notifique um thread diferente do pretendido.run()
de um thread em vez de chamar start()
.run()
de um objeto Thread
é um bug. O programador pretendia iniciar um novo thread de controle, mas acidentalmente chamou run()
no lugar de start()
e, portanto, o método run()
será executado no thread de controle do chamador.run()
em vez de start()
.
Thread thr = new Thread() {
public void run() {
...
}
};
thr.run();
stop()
de um thread, possivelmente deixando vazar recursos.stop()
de um objeto Thread
é um bug. O programador pretendia parar a execução de um thread, mas não sabia que esta não é uma maneira adequada de fazer isso. A função stop()
dentro de Thread
causa uma exceção ThreadDeath
em qualquer lugar dentro do objeto Thread
, provavelmente deixando objetos em um estado inconsistente e possivelmente deixando vazar recursos. Como essa API é inerentemente insegura, seu uso foi preterido há muito tempo.Thread.stop()
.
...
public static void main(String[] args){
...
Thread thr = new Thread() {
public void run() {
...
}
};
...
thr.start();
...
thr.stop();
...
}
clone()
, mas não implementa a interface Cloneable
.Cloneable
, pois ela implementa um método denominado clone()
. No entanto, a classe não implementa a interface Cloneable
, e o método clone()
não se comportará corretamente.clone()
para essa chamada resultará em uma CloneNotSupportedException.
public class Kibitzer {
public Object clone() throws CloneNotSupportedException {
...
}
}
ICloneable
especifica um contrato fraco para seu método Clone
e deve ser evitada.ICloneable
não garante uma clonagem profunda. As classes que a implementam podem não apresentar o comportamento esperado ao serem clonadas. Classes que implementam ICloneable
e executam apenas uma clonagem superficial (cópias apenas do objeto, o que inclui referências existentes a outros objetos) podem resultar em um comportamento inesperado. Como a clonagem profunda (cópias do objeto e de todos os objetos referenciados) é normalmente o comportamento assumida de um método de clone, o uso da interface ICloneable
é propenso a erros e deve ser evitado.clone()
na classe chama uma função que pode ser substituída.clone()
chama uma função substituível, ela pode fazer com que o clone seja deixado em um estado parcialmente inicializado ou se torne corrompido.clone()
a seguir chama um método que pode ser substituído.
...
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()
e a sua classe delimitadora não são final
, significa que a função pode ser substituída, o que pode deixar o objeto clone
clonado em um estado parcialmente inicializado, capaz de provocar erros, se não estiver trabalhando em torno da lógica de uma forma inesperada.equals()
pode resultar em um comportamento inesperado.equals()
da primitiva encaixotada deve ser chamado em vez dos operadores ==
e !=
. A Especificação Java declara o seguinte sobre conversões de encaixotamento: Boolean
ou Byte
), apenas uma faixa de valores será armazenada em cache ou memorizada. Para um subconjunto de valores, o uso de ==
ou !=
retornará o valor correto. Para todos os outros valores fora desse subconjunto, isso retornará o resultado da comparação dos endereços de objetos.
...
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
usa primitivas encaixotadas Integer
para tentar comparar dois valores int
. Se mask0
e mask1
forem ambos iguais a 100
, mask0 == mask1
retornará true
. No entanto, quando mask0
e mask1
forem ambos iguais a 777
, mask0 == maske1
agora retornará false
, pois esses valores não estão dentro do intervalo de valores armazenados em cache para essas primitivas encaixotadas.