1. Tutte le classi ereditanoObject
Tutte le classi in Java ereditano implicitamente la Object
classe.
Analizzeremo cos'è l'ereditarietà e come funziona in Java nella ricerca Java Core. Per ora, considereremo un semplice fatto che ne consegue:
Un oggetto di qualsiasi classe può essere assegnato a una Object
variabile. Esempio:
Codice | Nota |
---|---|
|
La o variabile memorizza un riferimento a un Scanner oggetto |
|
La o variabile memorizza un riferimento a un String oggetto |
|
La o variabile memorizza un riferimento a un Integer oggetto |
|
La o variabile memorizza un riferimento a un String oggetto |
È qui che finisce la buona notizia. Il compilatore non tiene traccia del tipo originale di oggetto salvato in una Object
variabile, quindi non sarai in grado di chiamare metodi sull'oggetto salvato diversi dai metodi della Object
classe.
Se devi chiamare i metodi associati al tipo originale dell'oggetto, devi prima salvare un riferimento ad esso in una variabile del tipo corretto, quindi chiamare i metodi su quella variabile:
Codice | Nota |
---|---|
|
Il programma non verrà compilato. La Object classe non ha nextInt() metodo. |
|
Questo funzionerà. Qui salviamo un riferimento a un Scanner oggetto in una Scanner variabile usando un operatore typecast . |
Non puoi semplicemente andare e assegnare una Object
variabile a una variabile Scanner, anche se la Object
variabile memorizza un riferimento a un Scanner
oggetto. Ma puoi farlo se usi l' operatore typecast , che già conosci. Questo è il suo aspetto generale:
Type name1 = (Type) name2;
Dove name1
è il nome di una Type
variabile ed name2
è il nome di una Object
variabile che memorizza un riferimento a un Type
oggetto.
Tipografia
Se il tipo di variabile e il tipo di oggetto non corrispondono, ClassCastException
verrà lanciato a. Esempio:
Codice | Nota |
---|---|
|
Si verificherà un errore in fase di esecuzione: a ClassCastException verrà lanciato qui |
C'è un modo per evitare questo errore in Java: lo facciamo controllando il tipo dell'oggetto memorizzato in una variabile :
name instanceof Type
L' instanceof
operatore controlla se la name
variabile è un Type
oggetto.
Ad esempio, troviamo una stringa in un array di oggetti diversi:
Codice | Nota |
---|---|
|
Autoboxing convertirà questi valori rispettivamente in Integer , String e Double . Passa sopra l'array di oggetti Se l'oggetto è un String Salvalo in una String variabile Visualizza la variabile sullo schermo. |
2. Perché sono apparsi i generici: le raccolte
Torniamo alle collezioni.
Non appena gli sviluppatori Java hanno creato la ArrayList
classe, hanno voluto renderla universale, in modo che potesse memorizzare qualsiasi tipo di oggetto. Quindi hanno usato un array di Object
s per memorizzare gli elementi.
Il punto di forza di questo approccio è che puoi aggiungere un oggetto di qualsiasi tipo alla collezione.
Naturalmente, ci sono diversi punti deboli.
Svantaggio 1.
Era sempre necessario scrivere un operatore di conversione del tipo durante il recupero di elementi da una raccolta:
Codice | Nota |
---|---|
|
Crea una raccolta per memorizzare i riferimenti agli Object oggetti Riempi la raccolta con i numeri 10 , 20 , ... 100 ; Somma gli elementi della collezione Il typecasting è necessario |
Svantaggio 2.
Non c'era alcuna garanzia che una raccolta contenesse un tipo specifico di elemento
Codice | Nota |
---|---|
|
Creare una collezione per memorizzare i riferimenti agli Object oggetti Riempiamo la collezione con i numeri rappresentati come Double oggetti: 0.0 , 2.5 , 5.0 , ... Somma gli elementi della collezione Ci sarà un errore: a Double cannot be cast to anInteger |
I dati possono essere inseriti nella raccolta ovunque:
- in un altro metodo
- in un altro programma
- da un file
- sulla rete
Svantaggio 3.
I dati nella raccolta possono essere modificati accidentalmente.
Puoi passare una raccolta piena dei tuoi dati a un metodo. Quel metodo, scritto da un programmatore diverso, aggiunge i suoi dati alla tua raccolta.
Il nome della raccolta non indica chiaramente quali tipi di dati possono essere archiviati in essa. E anche se dai alla tua variabile un nome chiaro, un riferimento ad essa può essere passato a una dozzina di metodi, e quei metodi sicuramente non sapranno nulla del nome originale della variabile.
3. Generici
In Java, tutti questi problemi vengono eliminati da questa cosa interessante chiamata generici.
In Java, generici significa la possibilità di aggiungere parametri di tipo ai tipi. Il risultato è un tipo composito complesso. La visione generale di un tale tipo composito è questa:
ClassName<TypeParameter>
Questa è una classe generica. E può essere utilizzato ovunque si utilizzino normalmente le classi.
Codice | Descrizione |
---|---|
|
Creazione di variabili |
|
Creare oggetti |
|
Creazione di array |
Solo Integer
le variabili possono essere memorizzate in una tale raccolta:
Codice | Descrizione |
---|---|
|
ArrayList raccolta con Integer elementi Questo è consentito E anche questo funzionerà
Autoboxing
Ma questo non è consentito: errore di compilazione |
Imparerai come creare le tue classi con parametri di tipo nella quest Java Collections. Per ora, vedremo come usarli e come funzionano.
4. Come funzionano i generici
In realtà, i generici sono terribilmente primitivi.
Il compilatore sostituisce semplicemente i tipi generici con tipi ordinari. Ma quando vengono utilizzati metodi di un tipo generico, il compilatore aggiunge un operatore typecast per trasmettere i parametri ai parametri di tipo:
Codice | Cosa fa il compilatore |
---|---|
|
|
|
|
|
|
|
|
Supponiamo di avere un metodo che somma i numeri in una raccolta di numeri interi:
Codice | Cosa fa il compilatore |
---|---|
|
|
In altre parole, i generici sono una specie di zucchero sintattico, proprio come l'autoboxing, ma un po' di più. Con l'autoboxing, il compilatore aggiunge metodi per convertire an int
in an Integer
e viceversa, e per i generici aggiunge operatori typecast.
Dopo che il compilatore ha compilato le classi generiche con parametri di tipo, vengono semplicemente convertite in classi ordinarie e operatori di typecast. Le informazioni sugli argomenti di tipo passati alle variabili di tipi generici vengono perse. Questo effetto è anche chiamato cancellazione del tipo .
A volte i programmatori che scrivono classi generiche (classi con parametri di tipo) hanno davvero bisogno delle informazioni sui tipi passati come argomenti. Nella ricerca Java Collections, imparerai come affrontare questo problema e cosa comporta.
5. Alcuni fatti sui generici
Ecco alcuni fatti più interessanti sui generici.
Le classi possono avere diversi parametri di tipo. Assomiglia a questo:
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
In realtà, questo non è davvero sorprendente. Ovunque il compilatore possa aggiungere un operatore per eseguire il cast a un tipo, può aggiungere più operatori di typecast.
Esempi:
Codice | Nota |
---|---|
|
Il put primo parametro del metodo è an Integer e il secondo è aString |
I tipi generici possono essere utilizzati anche come parametri . Assomiglia a questo:
ClassName<TypeParameter<TypeParameterParameter>>
Supponiamo di voler creare un elenco che memorizzerà elenchi di stringhe. In questo caso, otterremo qualcosa del genere:
// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");
// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");
// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
I tipi generici (tipi con parametri di tipo) possono essere utilizzati anche come tipi di matrice. Assomiglia a questo:
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
Non sta accadendo nulla di magico qui: le parentesi angolari indicano solo il nome del tipo:
Codice | Controparte non generica |
---|---|
|
|
|
|
|
|