Tipi riferimento, ereditarietà

di il
8 risposte

Tipi riferimento, ereditarietà

Avrei queste domande a cui non riesco a dare una risposta completa:

Come viene determinata la compatibilità dei tipi riferimento in Java? Come è influenzata questa regola dalla struttura delle istanze?
Differenza tra tipo statico e dinamico di un'espressione. Come viene modificato da un cast? In che modo questi tipi definiscono la risoluzione delle chiamate?
Se la classe A estende la classe B, quali sono le variabili e i metodi di B?
A quest'ultima mi viene da rispondere: B ha i suoi metodi e variabili, in più può utilizzare instanze della sottoclasse A in ogni punto del codice in cui possono essere utilizzate le isntanze di B. è giusto?

8 Risposte

  • Re: Tipi riferimento, ereditarietà

    Giuso ha scritto:


    Come viene determinata la compatibilità dei tipi riferimento in Java? Come è influenzata questa regola dalla struttura delle istanze?
    Differenza tra tipo statico e dinamico di un'espressione. Come viene modificato da un cast? In che modo questi tipi definiscono la risoluzione delle chiamate?
    Se la classe A estende la classe B, quali sono le variabili e i metodi di B?
    A quest'ultima mi viene da rispondere: B ha i suoi metodi e variabili, in più può utilizzare instanze della sottoclasse A in ogni punto del codice in cui possono essere utilizzate le isntanze di B. è giusto?
    Alt ... andiamo con ordine.

    La "compatibilità" tra i tipi reference innanzitutto dipende ovviamente dalla relazione di ereditarietà che c'è tra due tipi.
    Java ha la ereditarietà singola di classe ed ha la ereditarietà multipla di interfaccia.
    Vuol dire che una classe può solo estendere un'altra classe ma può dichiarare di implementare N interfacce. Inoltre una interfaccia può estendere N altre interfacce.

    La classe Integer ad esempio è:

    public final class Integer extends Number implements Comparable<Integer>

    mentre Number è:

    public abstract class Number implements java.io.Serializable

    Quindi: Integer deriva da Number e Number deriva (implicitamente) da Object. Ma Integer è anche Comparable<Integer> ed in più eredita il fatto di essere anche Serializable.

    In sostanza le relazioni IS-A ("è-un") sono:
    Integer è-un Number
    ma anche
    Integer è-un Object
    ma anche
    Integer è-un Comparable
    ma anche
    Integer è-un Serializable

    Quindi un oggetto Integer si può assegnare ad una variabile di uno di quei 5 tipi: Integer stesso, oppure Number, o Object, o Comparable o Serializable.

    Se tu fai:

    Object o = new Integer(123);

    Il tipo "statico" (nel senso che è noto a livello di compilazione) del reference è Object, questo è il tipo della variabile 'o'. Il tipo "dinamico" (che vuol dire quello noto a runtime) è Integer.

    Sulla variabile 'o' si possono invocare SOLO i metodi noti in Object. Java funziona così, è un linguaggio tipizzato staticamente.
    Noi sappiamo che Integer ha il intValue() ma su o direttamente non si può invocare, perché non è di Object. Il compilatore infatti non può "provare" a livello di compilazione che è lecito invocare intValue() su o. L'oggetto realmente istanziato ed assegnato ad o potrebbe essere un altro.

    Se vuoi poter invocare intValue() si deve fare un cast (un down-cast o "narrowing").

    Integer i = (Integer) o;
    System.out.println(i.intValue()); // ok

    Questo cast è controllato a runtime. La JVM si chiede: l'oggetto referenziato da o è davvero realmente un Integer? Se sì, allora il cast ha successo e quella assegnazione avviene. Se no, viene lanciato ClassCastException (e l'assegnazione NON avviene).
    Il cast NON cambia nulla nell'oggetto in sé. Cambia solo il modo di "vedere" l'oggetto, ovvero cambia il tipo "statico" (noto a livello di compilazione) con cui si referenzia l'oggetto. E' come mettere un paio di occhiali differenti (migliori o peggiori): cambiando occhiali l'oggetto osservato NON cambia in sé .... cambia come lo "vede" chi indossa gli occhiali.
  • Re: Tipi riferimento, ereditarietà

    Chiaro, grazie
  • Re: Tipi riferimento, ereditarietà

    Aggiungo solo una cosa per completezza.

    Object o = new Integer(123);
    String s = (String) o;

    Il cast sopra è lecito per il compilatore ma poi a runtime fallisce. Per il compilatore è lecito perché una variabile di tipo Object potrebbe fare riferimento ad un String. A runtime fallisce perché l'oggetto realmente istanziato (Integer) non è ovviamente un String.

    Mentre invece:

    Number n = new Integer(123);
    String s = (String) n;

    Il cast qui sopra invece è ILLEGALE per il compilatore. Il codice NON compila proprio. Questo perché il compilatore può già "provare" a livello di compilazione che il cast non avrà MAI successo. Number e String sono due tipi slegati, non in relazione. Number NON deriva da String, e nemmeno String deriva da Number. Quindi non è possibile che una variabile di tipo Number possa fare riferimento ad un String.
  • Re: Tipi riferimento, ereditarietà

    Perfetto, grazie ancora!
  • Re: Tipi riferimento, ereditarietà

    Mi sapreste dare una definizione o spiegazione delle così dette "interfacce contratto"?
  • Re: Tipi riferimento, ereditarietà

    Giuso ha scritto:


    Mi sapreste dare una definizione o spiegazione delle così dette "interfacce contratto"?
    Le interfacce sovente/tipicamente vengono usate per definire un "contratto". Dal momento che sono delle astrazioni "pure" (tutti metodi astratti ... dimentichiamo per un momento le novità di Java 8/9) esse descrivono cosa un oggetto deve fare ma non come lo deve fare.

    Prendiamo la interfaccia es. Runnable, essa ha un solo metodo public void run(). Chi implementa concretamente Runnable DEVE implementare il run(), con quella forma esatta. E chi riceve in qualche modo un Runnable "sa" solo che sicuramente l'oggetto ha il run() con quella forma e siccome Runnable descrive qualcosa che è "eseguibile", allora chi ha in mano il Runnable lo userà per eseguire il lavoro invocando il run().
    Questo è il "contratto" di Runnable.
  • Re: Tipi riferimento, ereditarietà

    Un ultima cosa: oltre ai monitor per gestire i threads esistono altri metodi più avanzati, ma non trovo da nessuna parte quali sono...
  • Re: Tipi riferimento, ereditarietà

    Giuso ha scritto:


    oltre ai monitor per gestire i threads esistono altri metodi più avanzati, ma non trovo da nessuna parte quali sono...
    Ci sono tanti altri meccanismi di sincronizzazione di più "alto" livello nel package java.util.concurrent e sotto-package.
Devi accedere o registrarti per scrivere nel forum
8 risposte