Interfacce notevoli

  • Comparable

    • Impone un ordinamento naturale degli oggetti tramite il metodo: int compareTo(T b), che restituisce un valore >, = o < 0 se l’oggetto è rispettivamente maggiore, uguale o minore di b (T è un tipo generico; può essere qualsiasi tipo)
  • Clonabile

    • Le classi che implementano quest’interfaccia dichiarano al metodo clone() di Object che è legale effettuare una copia campo-a-campo delle istanze della classe
    • Il metodo clone() invocato su oggetti di classi che non implementano Cloneable solleva una CloneNotSupportedException
  • Serializzabile

    • Quest’interfaccia non possiede metodi o campi e serve soltanto ad identificare il fatto che l’oggetto è serializzabile, cioè memorizzabile su un certo supporto

Passare funzioni in input mediante le interfacce

  • Le interfacce permettono il passaggio in input di funzioni con una determinata intestazione

Ex.

public interface Runnable
{
	void run()
}

Le enumerazioni possono estendere interfacce

  • Posso rendere le enumerazioni estendibili quanto voglio
public interface OperatoreBinario
{
	double applica(double a, double b);
}
 
public enum OperatoreDiBase implements OperatoreBinario
{
	SOMMA {public double applica (double a, double b) {return a+b}}
}

Sovrascrivere il metodi clone

  • L’operatore di assegnazione = non effettua una copia dell’oggetto, ma solo del riferimento (shallow copy)

  • Per creare una copia di un oggetto è necessario richiamare clone() (deep copy)

  • x.clone() != x sarĂ  sempre vero

  • clone non richiama il costruttore della classe

  • Tuttavia l’implementazione nativa di default id Object.clone copia l’oggetto campo per campo

    • Ottimo se i campi sono tutti primitivi
    • Problematico se i campi sono riferimenti
  • Per implementare la copia in una propria classe è necessario sovrascrivere clone()che è protetta (quindi visibile solo in gerarchia e nel package)

    • Se il nostro oggetto contiene riferimenti e vogliamo evitare che la copia contenga un riferimento allo stesso oggetto membro, non possiamo chiamare semplicemente (o non chiamiamo proprio) super.clone()
  • E’ necessario implementare l’interfaccia “segnaposto” Cloneable altrimenti Object.clone emetterĂ  semplicemente l’eccezione CloneNotSupportedException

Classi top-level

  • Le classi usate finora sono dette top-level perchĂ© si trovano in alto rispetto a tutte le altre
  • Questo tipo di classi richiede un file .java dedicato con lo stesso nome della classe che esso contiene

Classi annidate (nested class)

  • Java consente di scrivere classi all’interno di altre classi
  • Le classi presenti all’interno sono chiamate classi annidate (nested class)
  • Possono essere static
  • Oppure non-static: in questo caso vengono dette classi interne (inner class)

Classi interne

  • Per poter creare un oggetto della casse interna è necessario istanziare la classe esterna (top-level) che la contiene

  • Ciascuna classe interna, infatti, ha un riferimento implicito all’oggetto della classe cha la contiene

  • Dalla classe interna è possibile accede a tutte le variabili e a tutti metodi della classe esterna

  • Come tutti i membri di una classe, le classi interne possono essere dichiarate public, protected o private

  • L’accesso a campi e metodi sia dell’oggetto della classe interna che dell’oggetto della classe esterna a cui è legato a doppio filo avviene normalmente

  • Per disambiguare casi di ambiguitĂ  (es. campi con lo stesso nome nella classe interna ed esterna):

    • Se dalla classe interna viene usato soltanto this si fa riferimento ai campi e ai metodi di quella classe
    • Per far riferimento alla classe esterna è necessario far precedere this dal nome della classe esterna e il punto
  • Per istanziare la classe interna dalla classe esterna è sufficiente utilizzare l’operatore new

  • Per istanziare la classe interna a partire da un’altra classe si utilizza la sintassi riferimentoOggettoClasseEsterna.new ClasseInterna()

Classi anonime

  • Sono classi senza nome che implementano un’intefaccia o estendono una classe
  • Utilizzate esclusivamente per creare un’unica istanza
  • Utili in determinati contesti (ex. creare un iteratore al volo)Ăą
TipoDaEstedere unicoRiferimentoAOggetto = new TipoDaEstendere()
{
		//codice della classe anonima (implementazione 
		// dell'interfaccia o dell'estsione della classe)
}

Espressioni lambda

() -> {System.out.printl ("hello, lambda!");}
  • Tali espressioni creano oggetti anonimi assegnabili a riferimenti a interfacce funzionali compatibili con l’intestazione (input/output) della funzione creata
Runnable r = () -> {System.out.println("hello, lambda!");};
r.run(); //"stampa hello lambda!"