In Java la risoluzione del sovraccarico (overloading) e dell'override dei metodi (overriding) avviene secondo regole specifiche. Nello sovraccarico (overloading) il compilatore seleziona il metodo più appropriato tra tutte le versioni al momento della compilazione, in base al tipo degli argomenti al punto di chiamata.
Punti importanti:
Esempio:
class Super { void print(Number n) { System.out.println("Super Number"); } } class Sub extends Super { void print(Integer i) { System.out.println("Sub Integer"); } } ... Sub s = new Sub(); s.print(5); // Sub Integer s.print(5.0); // Super Number
Qui print(Integer) sarà chiamato per l'argomento di tipo Integer, mentre per il tipo Double verrà chiamato il metodo della superclasse.
Se il metodo è stato sovrascritto (override) e sovraccaricato (overload) nella classe derivata, quale sarà chiamato in caso di polimorfismo?
Risposta: Nel polimorfismo viene sempre selezionata la versione del metodo in base al tipo reale dell'oggetto per i metodi sovrascritti (overriding). Per i metodi sovraccaricati, la scelta avviene al momento della compilazione in base al tipo di riferimento.
class A { void test(Number n) { System.out.println("A:Number"); } } class B extends A { void test(Integer n) { System.out.println("B:Integer"); } @Override void test(Number n) { System.out.println("B:Number"); } } ... A obj = new B(); obj.test(1); // Richiamerà B:Number, nonostante esista test(Integer)
Storia
Un sviluppatore ha aggiunto una versione sovraccaricata del metodo nella subclass, aspettandosi che fosse chiamata per tutti gli eredi. In produzione è diventato chiaro che la chiamata tramite riferimento della classe genitore portava alla scelta del metodo in base al tipo di riferimento e non all'oggetto. Di conseguenza, la logica necessaria non veniva eseguita.
Storia
In un progetto di grandi dimensioni, è stato erroneamente sovraccaricato il metodo equals(Object) con la firma equals(MyClass obj), credendo che sostituisse il normale equals. Durante il confronto nelle collezioni HashSet veniva utilizzato il default equals(Object), causando incoerenze nella logica e perdite di dati.
Storia
Aggiungendo una nuova versione del metodo con varargs nella gerarchia delle classi, sembrava che per gli array fosse stata chiamata la versione corretta. Tuttavia, nel momento in cui veniva passato esplicitamente un array, il compilatore selezionava il sovraccarico sbagliato, portando a un'elaborazione scorretta e il bug rimaneva a lungo inosservato.