Resumos

Apontamentos universitários em formato Markdown do Obsidian.

Introduzione (parte 2)

download Descarregar MD

Package

I package sono il meccanismo attraverso il quale si possono creare librerie di classi correlate (come le librerie C++). Ad esempio java.lang o java.io visti precedentemente.

Tutte le classi facenti parte di un package iniziano con la direttiva package , dove è l'identificativo del package.

Per utilizzare le classi di un package all'interno di altre classi, è necessario specificare direttive import (simile a include del C++) nell'intestazione delle classi utilizzatrici.

È possibile che i package contengano sotto-package.

Ad esempio:

  • import java.util.Scanner importa la classe Scanner, del package java.util (sottopackage di java);
  • import java.io.* importa tutte le classi e gli eventuali sotto-package di java.io;
  • se usiamo una classe che è all'interno dello stesso package non è necessario importarla.

Moduli

A partire da Java 9 è stato introdotto un nuovo livello di astrazione superiore ai package, conosciuto come Java Platform Module System (JPMS), o semplicemente moduli.

I moduli sono gruppi di package legati tra di loro e gruppi di risorse. Orientativamente è come se fossero "package di package".

Ogni modulo è responsabile delle proprie risorse, come ad esempio immagini, eventuali file, ecc.

Per utilizzare i moduli si deve realizzare un file descrittivo che definisce diversi aspetti del modulo che stiamo creando, come il nome del modulo, le dipendenze (altri moduli da cui il modulo dipende), una lista di package pubblici (cioè, package che vogliamo rendere visibili da altri moduli), ecc.

I package all'interno di un modulo sono di default privati, questo significa che dobbiamo esplicitamente renderli pubblici (nel file descrittivo) se vogliamo renderli disponibili anche fuori dal modulo che stiamo creando.

Input da console

import java.util.Scanner;

public class EsempioLetturaInput {
    public static void main (String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("Primo numero");
        int m = in.nextInt();
        System.out.println("Secondo numero");
        int n = in.nextInt();
        in.close();
        int z = m + n;
        System.out.println("Somma: " + z);
    }
}

La classe Scanner della libreria java.util mette a disposizione metodi per iterare oggetti di tipo InputStream tra cui anche System.in.

Esiste un metodo next<...> per quasi tutti i tipi primitivi, ad esempio nextInt, nextLong, ecc.

Per le stringhe ci sono i metodi next (prossima stringa) e nextLine (prossima riga).

Classi

public class Esempio {
    public Esempio() {
    }

    public Esempio(int c) {
        campo = c;
    }
    public int getCampo ( ) {
        return campo;
    }
    public void setCampo (int c) {
        this.campo = c;
    }

    int campo;
    public int campoPubblico;
    private int campoPrivato;
    protected int campoProtected;
}

Abbiamo già visto che ogni file .java contiene, solitamente, una sola dichiarazione e definizione di classe.

La classe si dichiara con l'istruzione public class NomeClasse.

Gli specificatori di accesso (public, private, protected) vanno inseriti prima della dichiarazione del campo o del metodo.

Se un campo o un metodo non ha uno specificatore di accesso, sarà visibile nella sua classe e nelle classi appartenenti allo stesso package.

Gli oggetti di una classe si creano con l'istruzione:

    NomeClasse oggetto = new NomeClasse();
    Esempio e1 = new Esempio();
    Esempio e2 = new Esempio(4);

Riferimenti

Facciamo un esempio, creiamo una stringa:

String mystr = "questa e' una prova";

Quando creiamo una stringa succede quello che segue:

Cosa sono i riferimenti? Concettualmente sono simili ai puntatori del C++: un riferimento rappresenta un indirizzo di memoria dove è stato allocato un oggetto ma a differenza del puntatore non è un indirizzo di memoria.

Importante: non vanno deallocati!

Facciamo un altro esempio, creiamo un oggetto:

Esempio e1 = new Esempio();

Qual è il riferimento di e1? Esempio@6d06d69c

A sinistra del simbolo @ c'è il tipo dell'oggetto, nel nostro caso Esempio. A destra del simbolo @ c'è un valore esadecimale che rappresenta l'indirizzo effettivo dell'oggetto.

Se si prova a stampare e1, si ottiene in output il riferimento di e1.

Assegnamento degli oggetti

Ecco un esempio di assegnamento degli oggetti:

public class Main {
    public static void main(String[] args) {
        Esempio e1 = new Esempio (1);
        Esempio e2 = new Esempio (2);
        System.out.println(e1.getCampo()); // Risultato: 1
        System.out.println(e2.getCampo()); // Risultato: 2
        e2 = e1;
        System.out.println(e2.getCampo()); // Risultato: 1

        e2.setCampo(3) ;
        System.out.println(e2.getCampo()); // Risultato: 3
        System.out.println(e1.getCampo()); // Risultato: 3

        e1.setCampo(5) ;
        System.out.println(e1.getCampo()); // Risultato: 5
        System.out.println(e2.getCampo()); // Risultato: 5
    }
}

Passaggio degli argomenti ai metodi

public class Esempio {
    private int campo;

    public Esempio(int c) {
        campo = c;
    }

    public int getCampo() {
        return campo;
    }

    public void modifica(Esempio e1, Esempio e2) {
        campo = e1.campo + e2.campo;
        e1.campo=0;
        e2.campo=0;
        e1 = new Esempio(8); //Ha effetto solo nel metodo
        System.out.println(e1.getCampo()); // Risultato: 8
    }

    public static void main(String[] args) {
        Esempio e1 = new Esempio(1);
        Esempio e2 = new Esempio(2);
        Esempio e3 = new Esempio(5);
        System.out.println(e3.getCampo()); // Risultato: 5

        e3.modifica(e1, e2);
        System.out.println(e1.getCampo()); // Risultato: 0
        System.out.println(e2.getCampo()); // Risultato: 0
        System.out.println(e3.getCampo()); // Risultato: 3
    }
}

Se l'argomento è un tipo base (int, float, ecc.), allora viene fatta una copia dell'elemento.

Se l'argomento è una variabile riferimento, allora viene fatta una copia del suo riferimento.

Metodi statici

public class MyMath {
    public static int gcd(int m, int n) {
        if(n == 0)
            return m;
        else
            return gcd(n, m%n);
    }
}

public class TestMyMath {
    public static void main(String[] args) {
        int result = MyMath.gcd(60, 24);
        System.out.println(result);
    }
}

I metodi static possono essere invocati utilizzando il nome della classe.

Non possono utilizzare campi o invocare metodi che non siano static.

I campi static sono condivisi da tutte le istanze degli oggetti.

Oggetti speciali: stringhe

Gli oggetti String rappresentano sequenze di caratteri alfanumerici e sono immutabili.

È possibile accedere ad un qualsiasi carattere con il metodo charAt, ma non è possibile modificarlo.

Data una stringa a, gli indici dei caratteri vanno da 0 a a.length() - 1. Esistono metodi per l'uguaglianza e per la concatenazione.

L'istruzione String c = a + b dove crea una nuova stringa con i contenuti di a concatenati a quelli di b.

Esempio di stringhe

import java.util.Scanner;

public class TestString {
    public static void main ( St ring [ ] args ) {
        Scanner in = new Scanner(System.in);
        String text1 = in.nextLine();
        String text2 = in.nextLine();

        // Confronto del riferimento
        if(text1 == text2)
            System.out.println("Confronto ==" );

        // Confronto del valore
        if(text1.equals(text2))
            System.out.println("Confronto equals");

        // Confronta ignorando maiuscole/minuscole
        if(text1.equalsIgnoreCase(text2))
            System.out.println("Confronto equalsIgnoreCase");

        in.close();
    }
}

Classi StringBuffer e StringBuilder

String x = "Testo"; // Un oggetto String
String y = x + "!"; // Un nuovo oggetto String

StringBuffer z = new StringBuffer(x);
z.append("!");
z.setCharAt(0 ,'t' );

StringBuilder w = new StringBuilder(x);
w.append("!");
w.setCharAt(0 ,'u' );

La classe String costruisce oggetti immutabili.

Ogni operazione su oggetti String che ha come risultato String, genera nuovi oggetti.

Le classi StringBuffer e StringBuilder mettono a disposizione oggetti mutabili per la gestione di testi.

StringBuilder è tipicamente più efficiente di StringBuffer ma non garantisce la sincronizzazione nella gestione multi-thread.

Differenze di performance

public class Main {
    private static String stampaConString() {
        String s = "";
        for(int i = 0; i < 100000; i++)
            s += i;
        return s;
    }

    private static String stampaConStringBuilder() {
        StringBuilder s = new StringBuilder();
        for(int i = 0; i < 100000; i++)
            s.append(i);
        return s.toString();
    }

    public static void main(String[] args) {
        long startTime = System.nanoTime();
        stampaConString();
        long stopTime = System.nanoTime();
        double duration = (double) (stopTimestartTime) / 1000000000;
        System.out.println("Durata primo metodo: " + duration + " secondi");
        startTime = System.nanoTime();
        stampaConStringBuilder();
        stopTime = System.nanoTime();
        duration = (double) (stopTimestartTime) / 1000000000;
        System.out.println("Durata secondo metodo: " + duration + " secondi");
    }
}