La parola polimorfismo è usata in vari contesti e descrive situazioni in cui qualcosa si verifica in diverse forme. In informatica, descrive il concetto che gli oggetti di diversi tipi possono essere accessibili attraverso la stessa interfaccia. Ogni tipo può fornire la propria implementazione indipendente di questa interfaccia. È uno dei concetti fondamentali della programmazione orientata agli oggetti (OOP).,
Se ti stai chiedendo se un oggetto è polimorfico, puoi eseguire un semplice test. Se l’oggetto passa con successo più test is-a o instanceof, è polimorfico. Come ho descritto nel mio post sull’ereditarietà, tutte le classi Java estendono l’oggetto class. A causa di ciò, tutti gli oggetti in Java sono polimorfici perché passano almeno due controlli instanceof.,
Diversi tipi di polimorfismo
Java supporta 2 tipi di polimorfismo:
- statico o in fase di compilazione
- dinamico
polimorfismo Statico
Java, come molte altre di programmazione object-oriented, consente di implementare metodi multipli all’interno della stessa classe che utilizza lo stesso nome ma con un diverso set di parametri. Questo è chiamato overloading del metodo e rappresenta una forma statica di polimorfismo.,
I set di parametri devono differire in almeno uno dei seguenti tre criteri:
- Devono avere un numero diverso di parametri, ad esempio un metodo accetta 2 e un altro 3 parametri.
- I tipi di parametri devono essere diversi, ad esempio un metodo accetta una stringa e un altro un lungo.
- Devono aspettarsi i parametri in un ordine diverso, ad esempio un metodo accetta una stringa e una Lunga e un altro accetta una lunga e una Stringa. Questo tipo di sovraccarico non è raccomandato perché rende l’API difficile da capire.,
Nella maggior parte dei casi, ognuno di questi metodi sovraccaricati fornisce una funzionalità diversa ma molto simile.
A causa dei diversi set di parametri, ogni metodo ha una firma diversa. Ciò consente al compilatore di identificare quale metodo deve essere chiamato e di associarlo alla chiamata al metodo. Questo approccio è chiamato legame statico o polimorfismo statico.
Diamo un’occhiata a un esempio.
Un semplice esempio di polimorfismo statico
Io uso lo stesso progetto CoffeeMachine come ho usato nei post precedenti di questa serie. Puoi clonarlo su https://github.com/thjanssen/Stackify-OopInheritance.,
La classe BasicCoffeeMachine implementa due metodi con il nome brewCoffee. Il primo accetta un parametro di tipo CoffeeSelection. L’altro metodo accetta due parametri, un CoffeeSelection e un int.
Ora quando si chiama uno di questi metodi, il set di parametri fornito identifica il metodo che deve essere chiamato.
Nel seguente frammento di codice, chiamo il metodo solo con un oggetto CoffeeSelection. Al momento della compilazione, il compilatore Java associa questa chiamata al metodo brewCoffee (CoffeeSelection selection).,
BasicCoffeeMachine coffeeMachine = createCoffeeMachine();coffeeMachine.brewCoffee(CoffeeSelection.FILTER_COFFEE);
Se cambio questo codice e chiamo il metodo brewCoffee con un oggetto CoffeeSelection e un int, il compilatore lega la chiamata al metodo all’altro metodo brewCoffee(CoffeeSelection selection, int number).
Polimorfismo dinamico
Questa forma di polimorfismo non consente al compilatore di determinare il metodo eseguito. La JVM deve farlo in fase di runtime.
All’interno di una gerarchia di ereditarietà, una sottoclasse può sovrascrivere un metodo della sua superclasse. Ciò consente allo sviluppatore della sottoclasse di personalizzare o sostituire completamente il comportamento di tale metodo.,
Crea anche una forma di polimorfismo. Entrambi i metodi, implementati dalla super-e sottoclasse, condividono lo stesso nome e parametri ma forniscono funzionalità diverse.
Diamo un’occhiata a un altro esempio dal progetto CoffeeMachine.
Sovrascrittura del metodo in una gerarchia di ereditarietà
La classe BasicCoffeeMachine è la superclasse della classe PremiumCoffeeMachine.
Entrambe le classi forniscono un’implementazione del metodo brewCoffee (CoffeeSelection selection).,
Se leggi il post sull’ereditarietà del concetto OOP, conosci già le due implementazioni del metodo brewCoffee. BasicCoffeeMachine supporta solo CoffeeSelection.FILTER_CAFFÈ. Il metodo brewCoffee della classe PremiumCoffeeMachine aggiunge il supporto per CoffeeSelection.ESPRESSO. Se viene chiamato con qualsiasi altro CoffeeSelection, utilizza la parola chiave super per delegare la chiamata alla superclasse.,
Late binding
Quando si desidera utilizzare tale gerarchia di ereditarietà nel progetto, è necessario essere in grado di rispondere alla seguente domanda: quale metodo chiamerà la JVM?
A cui si può rispondere solo in fase di runtime perché dipende dall’oggetto su cui viene chiamato il metodo. Il tipo di riferimento, che puoi vedere nel tuo codice, è irrilevante. È necessario distinguere tre scenari generali:
- Il tuo oggetto è del tipo di superclasse e viene referenziato come superclasse., Quindi, nell’esempio di questo post, un oggetto BasicCoffeeMachine viene referenziato come BasicCoffeeMachine.
- Il tuo oggetto è del tipo della sottoclasse e viene referenziato come sottoclasse. Nell’esempio di questo post, un oggetto PremiumCoffeeMachine viene referenziato come PremiumCoffeeMachine.
- Il tuo oggetto è del tipo della sottoclasse e viene referenziato come superclasse. Nell’esempio CoffeeMachine, un oggetto PremiumCoffeeMachine viene referenziato come BasicCoffeeMachine.
Superclasse a cui si fa riferimento come superclasse
Il primo scenario è piuttosto semplice., Quando si crea un’istanza di un oggetto BasicCoffeeMachine e memorizzarlo in una variabile di tipo BasicCoffeeMachine, la JVM chiamerà il metodo brewCoffee sulla classe BasicCoffeeMachine. Quindi, puoi solo preparare un caffèselezione.FILTER_CAFFÈ.
Sottoclasse a cui si fa riferimento come sottoclasse
Il secondo scenario è simile. Ma questa volta, istanziare un PremiumCoffeeMachine e fare riferimento come un PremiumCoffeeMachine. In questo caso, la JVM chiama il metodo brewCoffee della classe PremiumCoffeeMachine, che aggiunge il supporto per CoffeeSelection.ESPRESSO.,
Sottoclasse referenziata come superclasse
Questo è lo scenario più interessante e il motivo principale per cui spiego il polimorfismo dinamico in tali dettagli.
Quando si crea un’istanza di un oggetto PremiumCoffeeMachine e lo si assegna alla variabile BasicCoffeeMachine coffeeMachine, è ancora un oggetto PremiumCoffeeMachine. Sembra proprio una BasicCoffeeMachine.
Il compilatore non lo vede nel codice e puoi utilizzare solo i metodi forniti dalla classe BasicCoffeeMachine., Ma se si chiama il metodo brewCoffee sulla variabile coffeeMachine, la JVM sa che si tratta di un oggetto di tipo PremiumCoffeeMachine ed esegue il metodo sovrascritto. Questo è chiamato late binding.
Sommario
Il polimorfismo è uno dei concetti fondamentali nei linguaggi OOP. Descrive il concetto che diverse classi possono essere utilizzate con la stessa interfaccia. Ognuna di queste classi può fornire la propria implementazione dell’interfaccia.
Java supporta due tipi di polimorfismo. È possibile sovraccaricare un metodo con diversi set di parametri., Questo è chiamato polimorfismo statico perché il compilatore lega staticamente la chiamata al metodo a un metodo specifico.
All’interno di una gerarchia di ereditarietà, una sottoclasse può sovrascrivere un metodo della sua superclasse. Se si crea un’istanza della sottoclasse, la JVM chiamerà sempre il metodo sovrascritto, anche se si esegue il cast della sottoclasse nella sua superclasse. Questo è chiamato polimorfismo dinamico.