Java/Errori e miti
equals() vs ==
modificaPer approfondire, vedi Oggetti. |
- Quando utilizzare equals() e quando utilizzare ==?
La risposta si trova pensando che il metodo equals() confronta gli oggetti, mentre l'operatore == confronta i loro reference. Se abbiamo definito
Integer a = new Integer(0), b = new Integer(0);
allora
a.equals(b) == true
mentre
(a == b) == false
poiché si stanno confrontando due oggetti diversi.
Questo comportamento si spiega considerando che l'operatore ==
non confronta non i due oggetti, ma i loro reference. I reference di due oggetti diversi sono diversi a loro volta, di conseguenza l'operatore ==
restituisce false
; ma i due oggetti rappresentano[1] concettualmente lo stesso numero intero 0, quindi il comportamento più naturale per il metodo java.lang.Integer.equals()
è quello di restituire true
.
In generale, ecco le principali differenze:
- equals() determina se i valori simboleggiati dai due oggetti sono uguali; == determina se i due reference puntano allo stesso oggetto. (Di conseguenza, se == restituisce true, anche equals() deve restituire true.)
- il metodo equals() è un normale metodo, definito dalla classe di cui è istanza l'oggetto su cui lo stiamo invocando. Questo significa che
- se a è di tipo A e b è di tipo B e la classe A non è stata progettata per controllare i valori di B (ad es. perché appartenenti a due librerie diverse sviluppate da due società diverse), allora a.equals(b) restituirà false, anche se A e B fanno capo allo stesso concetto o a concetti idealmente simili;
- per conoscere l'esatto significato di a.equals(b) (cioè quando restituisce true e quando restituisce false), si deve fare riferimento alla documentazione della classe A; in mancanza, controllare la documentazione della superclasse (e così via, su per la gerarchia delle classi, fino ad arrivare ad Object).
Metodi statici vs metodi di istanza: prestazioni
modificaIn linguaggi come il C, è consueto fare uso dei metodi cosiddetti virtuali solo quando necessario, utilizzando di norma solo metodi non virtuali. Questo permette di risparmiare memoria e cicli di CPU a run-time.
Tuttavia, in Java ha poco senso sostituire un metodo di istanza con uno statico, se non ci sono motivazioni di progettazione della classe dietro questa decisione. Ecco alcuni dei motivi:
- le macchine virtuali odierne adottano tecniche di ottimizzazione che rendono superfluo questo accorgimento: soprattutto la compilazione just-in-time e un'intensa ottimizzazione che viene applicata al bytecode, prima di essere eseguito o anche durante la sua esecuzione. Queste tecniche non vengono normalmente adottate per un programma C/C++;
- questo accorgimento altera il design della classe e l'usabilità del codice che viene scritto (peggiorandolo significativamente).
break; negli switch
modificaL'istruzione switch ha un difetto: è molto facile dimenticare di digitare l'istruzione break; al termine di una clausola case:
switch(espressione) {
case valore1:
// ... istruzioni
break;
case valore2:
// ... istruzioni
case valore3:
// ... istruzioni
break;
// ... altre clausole case
default:
// ...
}
Il problema è che il compilatore non ha modo di sapere se questo è il reale intento del programmatore, perché questo codice è del tutto legittimo. Fortunatamente, però, esistono compilatori che controllano casi come questo e avvertono l'utente (con una warning, ovviamente, non con un errore) se incontrano una situazione in cui il programmatore potrebbe aver scritto qualcosa di diverso da ciò che era intenzionato a scrivere.
Double-checked locking
modificaQuesta sezione è ancora vuota; aiutaci a scriverla! |
Note
modifica- ↑ (attenzione: rappresentano, non sono!)