# Packages e import

### I package

Un package è un insieme di entità di Java (classi, interface, enum, exceptions e errors) che si pensa siano correlate. I package sono usati per:

1. Risolvere problemi di conflitti di classi mettendo il nome del package come prefisso al nome della classe. Per esempio  `com.zzz.Circle` e  `com.yyy.Circle` sono due classi distinte. Sebbene condividano lo stesso nome di classe `Circle` ma appartengono a due packega differenti: `com.zzz` e `com.yyy`. Queste due classi possono essere usate nello stesso programma e distinte utilizzando il nome completo (*fully-qualified class name*), il nome del pacchetto più il nome della classe.
2. Controllo visibilità: oltre a *public* e *private* per i modificatori di accesso Java ha *protected* e *default* che sono collegati alla funzionalità di package. Una entity protected (attributo e metodo di un oggetto) di una classe è accedibile da classi nello stesso package e da sottoclassi della medesima classe. Una entità senza nessun specificatore d'accesso (default)  è accedibile da solo le classi nello stesso package.
3. Per distribuire una collezione di classi riutilizzabili in un formato conosciuto come *Java Archive* (JAR).

#### Package name & struttura delle directory

Il nome del package rispecchia la struttura delle directory utilizzate per salvare la classe. Per esempio il codice sorgente della classe `Circle` del package `com.zzz` è salvato in "`$BASE_DIR/com/zzz/Circle.java`", dove `$BASE_DIR` denota la directory base del pacchetto. Chiaramente, al "punto" nel nome del package corrisponde una sub directory nel file system.

La directory base (`$BASE_DIR`) può essere stabilita ovunque nel vostro file system. Il compilatore Java e il runtime deve essere informato della posizione della `$BASE_DIR` così che può trovare le classi. Questo avviene tramite la variabile d'ambiente chiamata `CLASSPATH`. (`CLASSPATH` è simile ad un altra variabile d'ambiente `PATH`, che è usata dalla shell dei comandi per cercare gli eseguibili).

#### Creazione dei package

Per far si che una classe appartenga a un package, bisogna mettere lo statement del package come prima riga del codice sorgente. Esempio della classe `com.zzz.Circle`:

{% code title="com/zzz/Circle.java" %}

```java
package com.zzz;

public class Circle {

}
```

{% endcode %}

Notate lo statement `package` all'inizio del codice sorgente della classe.

Come già detto un' altra classe `Circle` potrebbe essere definita ma dovrebbe stare in un altro package, ad esempio, `com.yyy`:

{% code title="com/yyy/Circle.java" %}

```java
package com.yyy;

public class Circle {

}
```

{% endcode %}

Come si può notare, la classe è stata definita in un altro package.

Se volessimo utilizzare una delle due classi all'interno di un altra classe, ad esempio di nome `TestCircle`, dobbiamo:

* Se la classe è nello stesso package di una delle due `Circle`, se non specificato diversamente (tramite istruzione **import**), utilizza la classe del suo stesso package - perché di default gli è visibile; per utilizzare la classe nell'altro package devo fare l'import della classe nell'altro package in modo da specificare il nome completo e renderla visibile (in questo modo non c'è ambiguità);
* Se la classe `TestCircle` è in altro package rispetto alla classe `Circle` che si vuole utilizzare, è obbligatorio eseguire l'**import** per renderla visibile;
* Se la classe `TestCircle` vuole utilizzare contemporaneamente le due versioni di `Circle`, quella in package `com.zzz` e `com.yyy`, deve specificare ogni volta il nome completo, per togliere l'ambiguità su quella a cui ci si riferisce.&#x20;

Alcuni casi, esemplificativi, qui sotto, con due classi `Circle` in due package diversi:

{% code title="com/yyy/Circle.java" %}

```java
package com.yyy;

public class Circle {
	
	public Circle() {
		System.out.println(this.getClass());
	}
}

```

{% endcode %}

{% code title="com/zzz/Circle.java" %}

```java
package com.zzz;

public class Circle {
	
	public Circle() {
		System.out.println(this.getClass());
	}
}

```

{% endcode %}

Eseguendo il programma `com.yyy.TestCircle`, utilizzo le due versioni di `Circle`:

{% code title="com/yyy/TestCircle.java" %}

```java
package com.yyy;

public class TestCircle {

	public static void main(String[] args) {
		
		// com.yyy.Circle perchè nello stesso package
		new Circle();
        
		// utilizzo anche versione altro package
		new com.zzz.Circle();
	}

}

```

{% endcode %}

ottengo come output:

```
class com.yyy.Circle
class com.zzz.Circle
```

Eseguendo il programma `com.zzz.TestCircle`, per utilizzare la versione di `Circle` di un altro package, devo importarla esplicitamente::

{% code title="com/zzz/TestCircle.java" %}

```java
package com.zzz;

import com.yyy.Circle;

public class TestCircle {

	public static void main(String[] args) {
		
		new Circle();

	}

}

```

{% endcode %}

ottengo a console;

```
class com.yyy.Circle
```

Mentre, eseguendo il programma `com.ppp.TestCircle`:

{% code title="com/ppp/TestCircle.java" %}

```java
package com.ppp;

public class TestCircle {

	public static void main(String[] args) {
		
		new com.yyy.Circle();
		
		new com.zzz.Circle();

	}

}
```

{% endcode %}

ottengo l'output:

```
class com.yyy.Circle
class com.zzz.Circle
```

Mentre non si sarebbe potuto eseguire due import perché avrebbe generato ambiguità:

```java
package com.ppp;

import com.yyy.Circle;
import com.zzz.Circle; // error collision

public class TestCircle2 {

	public static void main(String[] args) {
		
		// che Circle è? com.yyy o com.zzz
		new Circle();
		new Circle();

	}

}
```

### Esercizi sui package

[http://www3.ntu.edu.sg/home/ehchua/programming/java/J9c\_PackageClasspath.html](https://www3.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html)

### I package della Standard library&#x20;

I package principali del JDK (detta anche la standard library, libreria standard che si ha a disposizione installato il Java Development Kit ) sono:

| Package     | Descrizione                                                                                                                        |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| *java.lang* | Classi principali di java ad esempio `Object` o tutti i tipi wrapper.                                                              |
| *java.util* | Classi molto utili generalmente per lo sviluppo come le collection (Vector, List, Map)                                             |
| *java.io*   | Classi per le funzionalità di Input/Output (IO), ad esempio `File`, `InputStream`, `OutputStream`, `InputReader` e `OutputReader`. |
| *java.net*  | Classi per le funzionalità di rete ad esempio `Socket`.                                                                            |

Per utilizzare queste classi è necessario fare l'**import** dando tutto il nome compreso il package.&#x20;

Come per qualsiasi altra classe di cui avessi bisogno e non è nello stesso package della classe utilizzatrice, ho bisogno di scrivere nel codice **import \<Class-name>** dove classe name comprende il package ad esempio, `import java.io.FileInputStream`, qualora ti servisse la classe FileInputStream per leggere il contenuto dei file.

Esempio programma, che legge il contenuto di un file di testo e lo stampa a video:

```java
package prova;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ProgramReader {

	public static void main(String[] args) {
		
		try {
			BufferedReader in
			   = new BufferedReader(new FileReader("./test/divina_commedia.txt"));
			
			String line = null;
			while((line = in.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

```

In questo caso ho importato le classi `java.io.BufferedReader`, `java.io.FileReader` e `java.io.IOException`, per le operazioni di input. Le classi `String` e `System` non è necessario importarle in quanto sono del package `java.lang` e sono sempre importate.

Se volessi importare tutte la classi del package `java.io` potrei anche scrivere `java.io.*` . Quindi il programma precedente può anche essere scritto nel seguente modo:

```java
package prova;

import java.io.*;

public class ProgramReader {

	public static void main(String[] args) {
		
		try {
			BufferedReader in
			   = new BufferedReader(new FileReader("./test/divina_commedia.txt"));
			
			String line = null;
			while((line = in.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}
```

Nota bene:

1. non c'è distinzione tra classi standard (della standard library) e classi scritte da noi o prese utilizzando librerie di terze parti: se ho bisogno di una classe che sia richiamata dalle mia classe e la classe di cui ho bisogno si trova in un altro package, allora per accedere alla classe devo importarla (*import \<Class-name>*), comprensiva del nome del package;
2. per le classi sotto *java.lang.\** non è  necessario eseguire l'import in quanto sono sempre importate;

Vedete ad esempio le classi della libreria standard <https://docs.oracle.com/javase/7/docs/api/> come sono organizzate in package. Selezionando il package nella documentazione accederete alle diverse classi del package. Vedete anche che spiega come è organizzata la documentazione della libraria standard [Documentation & JavaDoc](http://www3.ntu.edu.sg/home/ehchua/programming/java/J9b_Javadocs.html).

### Classi di terze parti

Finora abbiamo parlato di utilizzo di classi scritte da noi e l'utilizzo di classi della standard library, ad esempio, *java.util.Vector*, cosa dobbiamo fare per utilizzare una libraria scritta da altri, ad esempio, che è possibile scaricare da internet e ci fornisce una funzionalità di cui abbiamo bisogno ( e non abbiamo il tempo o la voglia o richiede competenze così specifiche che non abbiamo)?

Concetto di **CLASSPATH**

{% embed url="<https://github.com/checksound/ProectPackages>" %}

### Import e Static import

Vediamo ora un'estensione della direttiva static che può essere comoda. Abbiamo visto che import rende possibile riferire una classe come `java.util.Scanner` utilizzando il nome semplice `Scanner`. Ma dobbiamo ancora utilizzare i nomi composti alle variabili statiche come `System.out` o ai metodi statici come `Math.sqrt`.&#x20;

C'è un'altra forma di import che può essere utilizzata per importare membri statici di una classe nello stesso modo di come che la direttiva **import** è utilizzata per importare classi di un package. La direttiva è chiamata **static import** e ha la sintassi:

```java
import static <package-name>.<class-name>.<static-member-name>;
```

per importare un membro statico da una classe, o

```java
import static <package-name>.<class-name>.*;
```

per importare tutti i membri statici di una classe. Per esempio, se mettiamo

```java
import static java.lang.System.out;
```

allora possiamo usare nel codice, il semplice nome `out`, invece del nome composito, `System.out`. Vuol dire che possiamo scrivere `out.println` invece di `System.out.println`. Se nel codice dobbiamo utilizzare molti metodi della classe Math, si può usare la sintassi:

```java
import static java.lang.Math.*;
```

Questo permette di utilizzare direttamente `sqrt` invece di `Math.sqrt`, `log` invece di `Math.log` e `PI` invece di `Math.PI`.
