corsoJava
  • Corso JAVA
  • Introduzione linguaggio
  • Verifica tipi primitivi vs reference
  • Esercizi su equals
  • Introduzione su oggetti
  • Packages e import
  • Polimorfismo
    • Pit stop
  • Enum
  • String è speciale
  • Eccezioni
  • Nested Classes
  • Array, ArrayList e Hash Table
    • Esempio gioco carte
  • Linked data structures
  • Tipi generici
  • Comparing Java and C# Generics - Jonathan Pryor's web log
  • Contenitori
    • Esempi con classi container
  • Input/Output streams, Files
  • Basic I/O
  • Java IO Tutorial
  • Networking
  • I Thread e concorrenza
    • Esercizi multithreading
    • Thread interference
    • Esercizi thread interference
    • wait(), notify() e notifyAll() per la sincronizzazione tra i thread
    • Verifiche produttore/consumatore
    • Lock esplicito - java.util.concurrent.Locks
    • Semafori
    • Programmare con i thread
    • I Virtual Thread
    • Materiale
  • I Thread e networking
  • Esempi Java Socket Programming
  • Esempi Javascript Socket Programming
  • Messaggi datagram e invio multicast
  • Lambda Expression
  • Java Stream
  • Data Oriented Programming in Java
  • Java improved its 'Hello World' experience
  • Appendice A: utilizzo classe Scanner
  • Java For The Experienced Beginner
  • Modern Java
  • CodeJava - Java Core
  • Is OOP Relevant Today?
  • Book
Powered by GitBook
On this page

Tipi generici

Un tipo generico (generic type) è una classe o un'interfaccia parametrizzata rispetto ai tipi. Vediamo un esempio con una classe Box.

Una semplice classe Box :

public class Box {
    private Object object;

    public void set(Object object) { this.object = object; }
    public Object get() { return object; }
}

Formato per definire una classe generica:

class name<T1, T2, ..., Tn> { /* ... */ }

Le sezione dei type parameters, delimitata da <>, segue il nome della classe. Essa specifica i type parameters (anche detti type variables) T1, T2, .....Tn.

La generic class declaration di Box diventa:

/**
 * Generic version of the Box class.
 * @param <T> the type of the value being boxed
 */
public class Box<T> {
    // T stands for "Type"
    private T t;

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

Come si può vedere, tutte le occorrenze di Object sono sostituite da T . Un tipo variabile può essere qualsiasi tipo non primitivo: qualsiasi tipo classe, tipo interface, tipo array, o anche un altro tipo parametrico.

Per riferirsi a un generic Box nel codice, bisogna eseguire una generic type invocation, che sostituisce il tipo generico T con il tipo concreto, ad esempio Integer:

Box<Integer>  integerBox;

Un altro esempio, di definizione di tipo parametrico:

public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
	     this.key = key;
	     this.value = value;
    }

    public K getKey()	{ return key; }
    public V getValue() { return value; }
}

Ora l'istanziazione del tipo parametrico:

Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<String, String>("hello", "world");

Si può sostituire al parametro di un tipo parametrico (es: T ) con un altro tipo parametrizzato ad esempio List<Integer>, ad esempio:

OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));

Generic methods

Generic methods sono metodi che introducono anche loro tipo parametrici. Sono simili alla dichiarazionedi un tipo parametrico, ma lo scope del tipo parametrico è limitata al metodo dove è dichiarato. Sono parmessi metodi parametrici, di tipo statico e non statico, così come costruttori generici.

La sintassi per un metodo generico include la lista det tipi parametrici prima del tipo di ritorno del metodo.

La classe Util contiene un metodo parametrico compare tra due Pair object:

public class Util {
    public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

public class Pair<K, V> {

    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public void setKey(K key) { this.key = key; }
    public void setValue(V value) { this.value = value; }
    public K getKey()   { return key; }
    public V getValue() { return value; }
}

Per invocare il metodo:

Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);

Il tipo è stato provvisto esplicitamente (<Integer, String>). Generalment si può anche evitare, il compilatore riesce a inferire i tipi cge sono necessari:

Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);
PreviousLinked data structuresNextContenitori

Last updated 3 months ago