JavaRush /Java Blog /Random-IT /Cosa sono i generici in Java

Cosa sono i generici in Java

Pubblicato nel gruppo Random-IT
Ciao! Oggi parleremo dei generici. Devo dire che imparerai tantissime cose nuove! Non solo, ma anche le prossime conferenze saranno dedicate ai farmaci generici. Cosa sono i generici in Java - 1 Pertanto, se questo argomento ti interessa, sei fortunato: oggi imparerai molto sulle caratteristiche dei farmaci generici. Beh, in caso contrario, calmati e rilassati! :) Questo è un argomento molto importante e devi saperlo. Cominciamo con uno semplice: “cosa” e “perché”. Cosa sono i generici? I generici sono tipi con un parametro. Quando crei un generico, ne specifichi non solo il tipo, ma anche il tipo di dati con cui dovrebbe funzionare. Penso che ti sia già venuto in mente l'esempio più ovvio: questo è ArrayList! Ecco come di solito lo creiamo nel programma:
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
Come puoi immaginare, la particolarità dell'elenco è che non sarà possibile “riempirlo” tutto: funziona esclusivamente con oggetti String. Facciamo ora una breve escursione nella storia di Java e proviamo a rispondere alla domanda: "perché?" Per fare ciò, scriveremo noi stessi una versione semplificata della classe ArrayList. Il nostro elenco può solo aggiungere dati all'array interno e ricevere questi dati:
public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
Diciamo che vogliamo che la nostra lista memorizzi solo numeri Integer. Non abbiamo farmaci generici. Non possiamo specificare esplicitamente l'istanza o di check Integernel file add(). Allora tutta la nostra classe sarà adatta solo per Integer, e dovremo scrivere la stessa classe per tutti i tipi di dati esistenti nel mondo! Decidiamo di affidarci ai nostri programmatori e di lasciare semplicemente un commento nel codice in modo che non aggiungano nulla di superfluo:
//use it ONLY with Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
Uno dei programmatori non ha notato questo commento e ha inavvertitamente provato a inserire nell'elenco numeri mescolati a stringhe, per poi calcolarne la somma:
public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
Output della console: 300 Eccezione nel thread "main" java.lang.ClassCastException: java.lang.String non può essere trasmesso a java.lang.Integer in Main.main(Main.java:14) Qual è la cosa peggiore in questa situazione? Lungi dall'essere la disattenzione di un programmatore. La cosa peggiore è che il codice sbagliato è finito in un posto importante nel nostro programma ed è stato compilato con successo . Ora vedremo l'errore non in fase di codifica, ma solo in fase di test (e questo è nel migliore dei casi!). Correggere i bug in una fase successiva dello sviluppo costa molto di più, sia in termini di denaro che di tempo. Questo è proprio il vantaggio dei generici: una classe generica consentirà a un programmatore sfortunato di rilevare immediatamente un errore. Il codice semplicemente non verrà compilato!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();

       myList1.add(100);
       myList1.add(100);
       myList1.add("Lolkek");//error!
       myList1.add("Shalala");//error!
   }
}
Il programmatore immediatamente “ritornerà in sé” e si correggerà immediatamente. A proposito, non abbiamo dovuto creare la nostra classe Listper vedere questo tipo di errore. Rimuovi semplicemente le parentesi tipo ( <Integer>) da un normale ArrayList!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
Output della console: 300 Eccezione nel thread "main" java.lang.ClassCastException: java.lang.String non può essere convertito in java.lang.Integer in Main.main(Main.java:16) Cioè, anche utilizzando strumenti "nativi" Java, puoi commettere questo errore e creare una raccolta non sicura. Tuttavia, se incolliamo questo codice in IDEa, vediamo un avviso: " Chiamata non selezionata per aggiungere (E) come membro del tipo grezzo di java.util.List " Questo ci dice che qualcosa potrebbe andare storto quando si aggiunge un elemento a a la raccolta senza farmaci generici non è così. Ma cosa significa la frase “tipo grezzo”? La traduzione letterale sarà abbastanza accurata: " tipo grezzo " o " tipo sporco ". Raw typeè una classe generica da cui è stato rimosso il tipo. In altre parole, List myList1questo è Raw type. L'opposto raw typeè generic typeuna classe generica (nota anche come class parameterized type), creata correttamente, con una specifica del tipo. Per esempio, List<String> myList1. Potresti avere una domanda: perché è consentito l'uso raw types? Il motivo è semplice. I creatori di Java hanno lasciato il supporto nel linguaggio raw typesper non creare problemi di compatibilità. Quando fu rilasciato Java 5.0 (i generici apparvero per la prima volta in questa versione), molto codice era già stato scritto utilizzando raw types. Pertanto questa possibilità esiste ancora oggi. Abbiamo già menzionato più di una volta nelle lezioni il classico libro di Joshua Bloch "Effective Java". Essendo uno dei creatori della lingua, non ha ignorato l'argomento dell'uso raw typese nel libro generic types. Cosa sono i generici in Java - 2Il capitolo 23 di questo libro ha un titolo molto eloquente: "Non utilizzare tipi grezzi nel nuovo codice". Questo è qualcosa che devi ricordare. Quando si utilizzano classi generiche, non trasformarle mai generic typein file raw type.

Metodi tipizzati

Java consente di digitare metodi individuali, creando i cosiddetti metodi generici. Perché tali metodi sono convenienti? Innanzitutto perché permettono di lavorare con diversi tipi di parametri. Se la stessa logica può essere applicata in modo sicuro a tipi diversi, un metodo generico è un'ottima soluzione. Diamo un'occhiata a un esempio. Diciamo che abbiamo una sorta di elenco myList1. Vogliamo rimuovere tutti i valori da esso e riempire tutti gli spazi liberi con un nuovo valore. Ecco come apparirà la nostra classe con un metodo generico:
public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Старая строка 1");
       strings.add("Старая строка 2");
       strings.add("Старая строка 3");

       fill(strings, "Новая строка");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
Presta attenzione alla sintassi, sembra un po' insolita:
public static <T> void fill(List<T> list, T val)
Il tipo restituito è preceduto da <T>, che indica un metodo generico. In questo caso, il metodo accetta 2 parametri come input: un elenco di oggetti T e un altro oggetto separato T. Utilizzando <T>, si ottiene la tipizzazione del metodo: non possiamo passare lì un elenco di stringhe e un numero. Un elenco di stringhe e una stringa, un elenco di numeri e un numero, un elenco dei nostri oggetti Cate un altro oggetto Cat: questo è l'unico modo. Il metodo main()dimostra chiaramente che fill()funziona facilmente con diversi tipi di dati. Innanzitutto, richiede come input un elenco di stringhe e una stringa, quindi un elenco di numeri e un numero. Output della console: [Newline, Newline, Newline] [888, 888, 888] Immagina se fill()avessimo bisogno della logica del metodo per 30 classi diverse e non avessimo metodi generici. Saremmo costretti a scrivere lo stesso metodo 30 volte, solo per tipi di dati diversi! Ma grazie ai metodi generici possiamo riutilizzare il nostro codice! :)

Classi digitate

Non solo puoi utilizzare le classi generiche fornite in Java, ma anche crearne di tue! Ecco un semplice esempio:
public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Старая строка");
       System.out.println(stringBox.get());
       stringBox.set("Новая строка");

       System.out.println(stringBox.get());

       stringBox.set(12345);//ошибка компиляции!
   }
}
La nostra classe Box<T>(“box”) viene digitata. Avendogli assegnato un tipo di dati ( ) durante la creazione <T>, non potremo più inserirvi oggetti di altri tipi. Questo può essere visto nell'esempio. Durante la creazione, abbiamo specificato che il nostro oggetto funzionerà con le stringhe:
Box<String> stringBox = new Box<>();
E quando nell'ultima riga di codice proviamo a mettere all'interno della casella il numero 12345, otteniamo un errore di compilazione! Proprio così, abbiamo creato la nostra classe generica! :) Questo conclude la nostra conferenza di oggi. Ma non stiamo dicendo addio ai generici! Nelle prossime lezioni parleremo di funzionalità più avanzate, quindi non dirci addio! ) Buona fortuna per i tuoi studi! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION