Esercitazione JAVA 2019: differenze tra le versioni
(→Esempio sul calcolo della complessità computazione di un metodo) |
|||
(13 versioni intermedie di uno stesso utente non sono mostrate ) | |||
Riga 623: | Riga 623: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | == Esercizio Completo == | ||
+ | Al link seguente è possibile scaricare una cartella compressa contenete i sorgenti java dello scenario ospedaliero con tutte le funzionalità presentate durante il corso. | ||
+ | |||
+ | [http://www.vitoantoniobevilacqua.it/materialedidattico/files/ASDJ/Progetto.zip Download File] | ||
= Esercizi = | = Esercizi = | ||
Riga 1 363: | Riga 1 367: | ||
= Classi astratte e metodi astratti = | = Classi astratte e metodi astratti = | ||
+ | Una classe astratta non può in alcun modo essere istanziata, quindi può essere utilizzata esclusivamente come classe base. Una classe derivata da una classe astratta deve fornire una implementazione per tutti i metodi astratti dichiarati nella superclasse. | ||
+ | |||
+ | Definisco la classe Persona come classe astratta contenente il metodo astratto inserisciNome(). | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | |||
+ | public abstract class Persona { | ||
+ | |||
+ | // Funzione virtuale pura (o astratta) da implementare necessariamente | ||
+ | // nelle classi derivate, pena errore | ||
+ | public abstract void inserisciNome(); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | Definisco due classi derivate dalla classe Persona, Studente e Lavoratore. | ||
+ | '''Nelle classi derivate devo necessariamente implementare i metodi dichiarati come abstract nella classe padre.''' | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | public class Studente extends Persona { | ||
+ | // The type Studente must implement the inherited abstract method Persona.inserisciNome() | ||
+ | @Override | ||
+ | public void inserisciNome() { | ||
+ | // TODO Auto-generated method stub | ||
+ | System.out.println("Stampa Studente"); | ||
+ | |||
+ | } | ||
+ | |||
+ | public void altroMetodo() { | ||
+ | System.out.println("Ciao Studente"); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="java" line> | ||
+ | |||
+ | public class Lavoratore extends Persona{ | ||
+ | |||
+ | @Override | ||
+ | public void inserisciNome() { | ||
+ | // TODO Auto-generated method stub | ||
+ | System.out.println("Stampa Lavoratore"); | ||
+ | } | ||
+ | |||
+ | public void altroMetodo() { | ||
+ | System.out.println("Ciao Lavoratore"); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | Definizione della classe Principale. Poichè abstract, non posso istanziare oggetti di classe Persona. Tuttavia, posso utilizzare riferimenti alla classe Persona per accedere ai metodi ridefiniti nella classi derivate (Overriding). | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | public class Principale { | ||
+ | public static void main(String[] args) { | ||
+ | // TODO Auto-generated method stub | ||
+ | Persona p;//= new Persona(); //ERRORE: Cannot instantiate the type Persona | ||
+ | Studente s = new Studente(); | ||
+ | Lavoratore l = new Lavoratore(); | ||
+ | |||
+ | // Overriding del metodo inserisciNome | ||
+ | p = s; | ||
+ | p.inserisciNome(); | ||
+ | |||
+ | p = l; | ||
+ | p.inserisciNome(); | ||
+ | |||
+ | |||
+ | // Cast per richiamare i metodi della classe derivata | ||
+ | p = s; | ||
+ | ((Studente)p).altroMetodo(); | ||
+ | p = l; | ||
+ | ((Lavoratore)p).altroMetodo(); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = Interfacce = | ||
+ | In Java non è possibile implementare il meccanismo dell'ereditarietà multipla, ovvero che una classe derivi da più classi. Tuttavia, definendo una serie di interfacce, è possibile fare in modo tale che una classe possa implentare più interfacce. | ||
+ | |||
+ | Definisco la classe base Persona contenente la definizione di un solo metodo. | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | public class Persona { | ||
+ | |||
+ | public void altroMetodo() | ||
+ | { | ||
+ | System.out.println("Ciao Persona"); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Adesso definisco due interfacce, rispettivamente Studente e Lavoratore, che dichiarano un paio di metodi ciascuno | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | public interface Studente { | ||
+ | |||
+ | public void inserisciNomeStudente(); | ||
+ | |||
+ | public void altroMetodo(); | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="java" line> | ||
+ | public interface Lavoratore { | ||
+ | |||
+ | public void inserisciNomeLavoratore(); | ||
+ | |||
+ | public void altroMetodo(); | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Definizione della classe StudenteLavoratore, che deriva da Persona e implementa le interfacce di Studente e Lavoratore. | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | |||
+ | public class StudenteLavoratore extends Persona implements Studente, Lavoratore { | ||
+ | |||
+ | @Override | ||
+ | public void inserisciNomeLavoratore() { | ||
+ | // TODO Auto-generated method stub | ||
+ | |||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void inserisciNomeStudente() { | ||
+ | // TODO Auto-generated method stub | ||
+ | |||
+ | } | ||
+ | |||
+ | public void altroMetodo() | ||
+ | { | ||
+ | System.out.println("Ciao Studente Lavoratore"); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | Implementazione della classe Principale | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | |||
+ | public class Principale { | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | // TODO Auto-generated method stub | ||
+ | Persona p = new Persona(); | ||
+ | //p.altroMetodo(); | ||
+ | StudenteLavoratore sl = new StudenteLavoratore(); | ||
+ | p.altroMetodo(); | ||
+ | sl.altroMetodo(); | ||
+ | |||
+ | Persona p2; | ||
+ | StudenteLavoratore sl2 = new StudenteLavoratore(); | ||
+ | |||
+ | p2 = sl2; | ||
+ | p2.altroMetodo(); | ||
+ | |||
+ | //Studente s = new Studente(); ERRORE: Cannot instantiate the type Studente. | ||
+ | //Lavoratore l = new Lavoratore(); ERRORE: Cannot instantiate the type Lavoratore. | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = Esempio sul calcolo della complessità computazione di un metodo = | ||
+ | Si vuole calcolare la complessità O (o-grande) del seguente metodo. | ||
+ | |||
+ | NB. In questo caso, si dà per scontato che almeno un elemento del vettore ''vett'' sia pari ad ''ele''. | ||
+ | <syntaxhighlight lang="java" line> | ||
+ | public int trovaIndice(int[] vett, int ele) | ||
+ | { | ||
+ | int i = 0; | ||
+ | int val = vett[i]; | ||
+ | while (val != ele) | ||
+ | { | ||
+ | i = i+1; | ||
+ | val = vett[i]; | ||
+ | } | ||
+ | return i; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Aggiungiamo un costo unitario per ogni dichiarazione (locale o formale) e/o assegnazione, valore restituito e confronto. | ||
+ | Sia ''n'' la dimensione del vettore. | ||
+ | |||
+ | * int[] a -> +1 | ||
+ | * int ele -> +1 | ||
+ | * int i = 0; -> +1 | ||
+ | * int val = a[i]; -> +1 | ||
+ | * return i; -> +1 | ||
+ | Nel caso peggiore si avrà: | ||
+ | * n confronti nella consizione del while (val != ele) | ||
+ | * n incrementi i = i+1; | ||
+ | * n assegnazioni val = a[i]; | ||
+ | |||
+ | Dopo le varie operazioni, la funzione che descrive la nostra funzione è ''f(n) = 3n + 5'' | ||
+ | |||
+ | Si dice che f(n) è di ordine g(n), ovvero f(n) = O(g(n)) se esiste una costante positiva C tale che valga, salvo che per un numero finito di elementi, la seguente condizione: f(n) <= C g(n). | ||
+ | |||
+ | Allora, data f(n) = 3n+5 considero: | ||
+ | * 3n <= 3n -> per ogni n >= 0 | ||
+ | * 5 < 5n -> per ogni n >= 1 | ||
+ | |||
+ | Per ogni n >= 1 --> f(n) = 3n + 5 <= 8n. | ||
+ | |||
+ | Siano k = 1 e C = 8 --> f(n) <= Cn per ogni n >= k --> f(n) è O(n) |
Versione attuale delle 15:16, 31 mag 2019
Indice
Implementazione completa di uno scenario ospedaliero
Modellazione dello Scenario
Modellazione iniziale delle classi utili all'implementazione delo scenario richiesto.
Classe Persona: classe base da cui far derivare le classi Medico e Paziente.
public class Persona {
protected String nome;
protected String cognome;
protected String CF;
public Persona(String N, String C, String cf)
{
nome = N;
cognome = C;
CF = cf;
}
}
Classe Medico: derivata dalla classe Persona, definisce un medico in base alla propria specializzazione.
public class Medico extends Persona {
private String specializzazione;
public Medico(String N, String C, String cf, String spec) {
super(N, C, cf);
specializzazione = spec;
}
public String getInfo()
{
String info = nome + "\t" + cognome + "\t" + CF + "\t" + specializzazione;
return info;
}
}
Classe Paziente: derivata dalla classe Persona, definisce un paziente in base ad una diagnosi.
public class Paziente extends Persona {
private String diagnosi;
public Paziente(String N, String C, String cf, String D) {
super(N, C, cf);
diagnosi = D;
}
public String getInfo()
{
String info = nome + "\t" + cognome + "\t" + CF + "\t" + diagnosi;
return info;
}
}
Classe Ospedale: deve contenere tutti i medici e tutti i pazienti afferenti ad ogni ospedale. SOno state implementate le funzioni di aggiunta medici e pazienti, oltre alle funzioni di stampa delle informazioni.
import java.util.ArrayList;
import java.util.LinkedList;
public class Ospedale {
private String nomeOspedale;
private ArrayList<Medico> listaMedici;
private LinkedList<Paziente> listaPazienti;
public Ospedale(String N)
{
nomeOspedale = N;
listaMedici = new ArrayList<Medico>();
listaPazienti = new LinkedList<Paziente>();
}
public void aggiungiMedici(Medico M)
{
listaMedici.add(M);
System.out.println("Medico Aggiunto");
}
public void aggiungiMedici(ArrayList<Medico> LM)
{
listaMedici.addAll(LM);
System.out.println("Medici Aggiunti");
}
public void aggiungiPazienti(Paziente P)
{
listaPazienti.add(P);
System.out.println("Paziente Aggiunto");
}
public void aggiungiPazienti(ArrayList<Paziente> LP)
{
listaPazienti.addAll(LP);
System.out.println("Pazienti Aggiunti");
}
public void stampaMedici()
{
System.out.println("Lista Medici:");
for (int i = 0; i < listaMedici.size(); i++)
{
System.out.println((i+1) + ": " + listaMedici.get(i).getInfo());
}
}
public void stampaPazienti()
{
System.out.println("Lista Pazienti:");
for (int i = 0; i < listaPazienti.size(); i++)
{
System.out.println((i+1) + ": " + listaPazienti.get(i).getInfo());
}
}
}
Classe Principale: classe che contiene il metodo main.
import java.util.ArrayList;
public class Principale {
public static void main(String[] args) {
Ospedale o = new Ospedale("Policlinico");
Medico m1 = new Medico("M_Nome1", "M_Cognome1", "M_Codice1", "Chirurgia");
Medico m2 = new Medico("M_Nome2", "M_Cognome2", "M_Codice2", "Radiologia");
Medico m3 = new Medico("M_Nome3", "M_Cognome3", "M_Codice3", "Cardiologia");
ArrayList<Medico> lm = new ArrayList<Medico>();
lm.add(m1);
lm.add(m3);
o.aggiungiMedici(m2);
o.aggiungiMedici(lm);
Paziente p1 = new Paziente("P_Nome1", "P_Cognome1", "P_Codice1", "Frattura");
Paziente p2 = new Paziente("P_Nome2", "P_Cognome2", "P_Codice2", "Tumore");
Paziente p3 = new Paziente("P_Nome3", "P_Cognome3", "P_Codice3", "Infarto");
ArrayList<Paziente> lp = new ArrayList<Paziente>();
lp.add(p1);
lp.add(p2);
o.aggiungiPazienti(p3);
o.aggiungiPazienti(lp);
System.out.println();
System.out.println("////////////////////////////////////////////////");
o.stampaMedici();
System.out.println();
o.stampaPazienti();
}
}
Implementazione della coda
Implementazione della coda delle prenotazioni e update delle classi esistenti
Classe Persona: classe base da cui far derivare le classi Medico e Paziente.
public class Persona {
protected String nome;
protected String cognome;
protected String CF;
public Persona(String N, String C, String cf)
{
nome = N;
cognome = C;
CF = cf;
}
public String getNome()
{
return nome;
}
public String getCognome()
{
return cognome;
}
public String getCF()
{
return CF;
}
}
Classe Medico: derivata dalla classe Persona, definisce un medico in base alla propria specializzazione. Nella classe è stata aggionta la coda delle prenotazioni.
public class Medico extends Persona {
private String specializzazione;
private Prenotazione[] codaPrenotazioni;
// Variabili per la gestione della coda
private int head;
private int tail;
private int length;
private int size;
public Medico(String N, String C, String cf,
String spec, int DimCoda) {
super(N, C, cf);
specializzazione = spec;
length = DimCoda;
head = 0;
tail = 0;
size = 0;
codaPrenotazioni = new Prenotazione[length];
}
public String getInfo()
{
String info = nome + "\t" + cognome + "\t" + CF + "\t" + specializzazione;
return info;
}
public boolean isAvailable()
{
if (size == length)
return false;
return true;
}
public int utentiInCoda()
{
return size;
}
public void stampaStatoCoda()
{
int i = 0;
if (size == 0)
System.out.println("Nessuna prenotazione");
else
{
System.out.println("Prenotazioni in coda:");
for (i = 0; i < size; i++) {
System.out.println((i+1) + "\t" + codaPrenotazioni[(head + i) % length].stampaInfoPrenotazione());
}
}
System.out.println();
}
public void accettaPazienteInCoda(Prenotazione P)
{
codaPrenotazioni[tail] = P;
tail = (tail + 1) % length;
size++;
}
public void curaProssimoPaziente(Ospedale o)
{
if (size == 0)
{
System.out.println("Nessuna Prenotazione in coda");
}
else {
Prenotazione temp = codaPrenotazioni[head];
head = (head + 1) % length;
size--;
eseguiVisita(temp, o);
}
}
private void eseguiVisita(Prenotazione p, Ospedale o)
{
Visita v = new Visita(this.CF, p.getPaziente().getDiagnosi(), p.getTrattamento(), o.getNome());
p.getPaziente().aggiungiVisita(v);
}
}
Classe Paziente: derivata dalla classe Persona, definisce un paziente in base ad una diagnosi. La classe Paziente contiene una lista che mantiene tutte le visite effettuate da ciascun paziente.
import java.util.LinkedList;
public class Paziente extends Persona {
private String diagnosi;
private LinkedList<Visita> cartellaClinica;
public Paziente(String N, String C, String cf, String D) {
super(N, C, cf);
diagnosi = D;
cartellaClinica = new LinkedList<Visita>();
}
public String getInfo()
{
String info = nome + "\t" + cognome + "\t" + CF + "\t" + diagnosi;
return info;
}
public String getDiagnosi()
{
return diagnosi;
}
public void aggiungiVisita(Visita v)
{
cartellaClinica.add(v);
}
public void stampaCartellaClinica()
{
System.out.println("Paziente:\t" + nome + "\t" + cognome);
if (cartellaClinica.size() == 0)
{
System.out.println("Nessuna visita effettuata finora");
}
else
{
for (int i = 0; i < cartellaClinica.size(); i++)
{
cartellaClinica.get(i).stampaInformazioniVisita();
}
}
}
}
Classe Ospedale: deve contenere tutti i medici e tutti i pazienti afferenti ad ogni ospedale. Sono state implementate le funzioni di aggiunta medici e pazienti, oltre alle funzioni di stampa delle informazioni.
L'ospedale assegna la prenotazione al medico che contiene meno prenotazioni in coda.
import java.util.ArrayList;
import java.util.LinkedList;
public class Ospedale {
private String nomeOspedale;
private ArrayList<Medico> listaMedici;
private LinkedList<Paziente> listaPazienti;
public Ospedale(String N)
{
nomeOspedale = N;
listaMedici = new ArrayList<Medico>();
listaPazienti = new LinkedList<Paziente>();
}
public String getNome()
{
return nomeOspedale;
}
public void aggiungiMedici(Medico M)
{
listaMedici.add(M);
System.out.println("Medico Aggiunto");
}
public void aggiungiMedici(ArrayList<Medico> LM)
{
listaMedici.addAll(LM);
System.out.println("Medici Aggiunti");
}
public void aggiungiPazienti(Paziente P)
{
listaPazienti.add(P);
System.out.println("Paziente Aggiunto");
}
public void aggiungiPazienti(ArrayList<Paziente> LP)
{
listaPazienti.addAll(LP);
System.out.println("Pazienti Aggiunti");
}
public void stampaMedici()
{
System.out.println("Lista Medici:");
for (int i = 0; i < listaMedici.size(); i++)
{
System.out.println((i+1) + ": " + listaMedici.get(i).getInfo());
}
}
public void stampaPazienti()
{
System.out.println("Lista Pazienti:");
for (int i = 0; i < listaPazienti.size(); i++)
{
System.out.println((i+1) + ": " + listaPazienti.get(i).getInfo());
}
}
public void assegnaPrenotazioneMedico(Prenotazione P)
{
int idx = trovaMedicoLibero();
if (idx > -1)
listaMedici.get(idx).accettaPazienteInCoda(P);
else
System.out.println("Nessun medico disponibile ad accettare la prenotazione " + P.stampaInfoPrenotazione());
}
private int trovaMedicoLibero ()
{
// Restituisce l'indice della lista dei medici con il medico con meno utenti in coda
int idx_min = -1;
if (listaMedici.size() != 0)
{
// Devo trovare il primo medico disponibile
for(int i = 0; i < listaMedici.size(); i++)
{
if(listaMedici.get(i).isAvailable())
{
idx_min = i;
break;
}
}
}
if (idx_min > -1)
{
for (int i = idx_min + 1; i < listaMedici.size(); i++)
{
if (listaMedici.get(i).isAvailable() && (listaMedici.get(i).utentiInCoda() < listaMedici.get(idx_min).utentiInCoda()))
{
idx_min = i;
}
}
}
return idx_min;
}
public void stampaStatoMedici()
{
for (int i = 0; i < listaMedici.size(); i++)
{
System.out.println("Medico: " + listaMedici.get(i).getCognome());
listaMedici.get(i).stampaStatoCoda();
}
}
}
Classe Prenotazione: modella la prenotazione di un paziente
public class Prenotazione {
private Paziente p;
private String trattamento;
public Prenotazione(Paziente P, String T)
{
p = P;
trattamento = T;
}
public String stampaInfoPrenotazione()
{
String info = "Paziente:\t" + p.getCF() + "\tTrattamento: " + trattamento;
return info;
}
public Paziente getPaziente()
{
return p;
}
public String getTrattamento()
{
return trattamento;
}
}
Classe Visita: Modella la visita di un medico che esegue un trattamento ad un paziente.
public class Visita {
private String medico;
private String diagnosi;
private String trattamento;
private String ospedale;
public Visita(String M, String D, String T, String O)
{
medico = M;
diagnosi = D;
trattamento = T;
ospedale = O;
}
public void stampaInformazioniVisita()
{
System.out.println("Diagnosi: " + diagnosi + " Visita effettuata dal medico: " + medico + " che ha eseguito il seguente trattamento: " + trattamento +
" presso il seguente ospedale: " + ospedale);
}
}
Classe Principale: classe che contiene il metodo main.
import java.util.ArrayList;
public class Principale {
public static void main(String[] args) {
Ospedale o = new Ospedale("Policlinico");
Medico m1 = new Medico("M_Nome1", "M_Cognome1", "M_Codice1", "Chirurgia", 3);
Medico m2 = new Medico("M_Nome2", "M_Cognome2", "M_Codice2", "Radiologia", 3);
Medico m3 = new Medico("M_Nome3", "M_Cognome3", "M_Codice3", "Cardiologia", 5);
ArrayList<Medico> lm = new ArrayList<Medico>();
lm.add(m1);
lm.add(m3);
o.aggiungiMedici(m2);
o.aggiungiMedici(lm);
Paziente p1 = new Paziente("P_Nome1", "P_Cognome1", "P_Codice1", "Frattura");
Paziente p2 = new Paziente("P_Nome2", "P_Cognome2", "P_Codice2", "Tumore");
Paziente p3 = new Paziente("P_Nome3", "P_Cognome3", "P_Codice3", "Infarto");
ArrayList<Paziente> lp = new ArrayList<Paziente>();
lp.add(p1);
lp.add(p2);
o.aggiungiPazienti(p3);
o.aggiungiPazienti(lp);
System.out.println();
System.out.println("////////////////////////////////////////////////");
o.stampaMedici();
System.out.println();
o.stampaPazienti();
Prenotazione pren1 = new Prenotazione(p1, "Trattamento1");
Prenotazione pren2 = new Prenotazione(p2, "Trattamento2");
Prenotazione pren3 = new Prenotazione(p3, "Trattamento3");
Prenotazione pren4 = new Prenotazione(p1, "Trattamento4");
Prenotazione pren5 = new Prenotazione(p1, "Trattamento5");
Prenotazione pren6 = new Prenotazione(p3, "Trattamento6");
o.assegnaPrenotazioneMedico(pren1);
o.assegnaPrenotazioneMedico(pren2);
o.assegnaPrenotazioneMedico(pren3);
o.assegnaPrenotazioneMedico(pren4);
o.assegnaPrenotazioneMedico(pren5);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
System.out.println("-----------------------");
o.stampaStatoMedici();
System.out.println("-----------------------");
m2.curaProssimoPaziente(o);
p1.stampaCartellaClinica();
p2.stampaCartellaClinica();
o.assegnaPrenotazioneMedico(pren6);
o.assegnaPrenotazioneMedico(pren6);
System.out.println("-----------------------");
o.stampaStatoMedici();
System.out.println("-----------------------");
m1.curaProssimoPaziente(o);
m1.curaProssimoPaziente(o);
m1.curaProssimoPaziente(o);
m1.curaProssimoPaziente(o);
p1.stampaCartellaClinica();
p2.stampaCartellaClinica();
p3.stampaCartellaClinica();
}
}
Esercizio Completo
Al link seguente è possibile scaricare una cartella compressa contenete i sorgenti java dello scenario ospedaliero con tutte le funzionalità presentate durante il corso.
Esercizi
Lettura e Scrittura con i File di Testo
Classe Persona: modellazione di una Persona difinita da due attibuti di tipo stringa (nome e cognome)
public class Persona {
private String nome;
private String cognome;
public Persona(String N, String C) {
nome = N;
cognome = C;
}
public void stampaInfo()
{
System.out.println("Nome: " + nome + " Cognome: " + cognome);
}
public String getCognome()
{
return cognome;
}
public String getNome()
{
return nome;
}
}
Classe Principale Legge dal file di testo "nomi.txt" i nomi e i cognomi di tutte le persone. Ogni persona creata viene aggiunta alla lista delle persone. Gli stessi dati vengono poi salvati su un secondo file di testo, nel formato indice: cognome nome, dopo aver stampato a video tutte i dati.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Scanner;
public class Principale {
public static void main(String[] args) {
LinkedList<Persona> lista = new LinkedList<Persona>();
File f = new File("nomi.txt");
File f2 = new File("output.txt");
try {
// Lettura da file di testo
Scanner input = new Scanner(f);
while(input.hasNextLine())
{
String temp = input.nextLine();
String[] lines = temp.split(" ");
Persona p = new Persona(lines[0], lines[1]);
lista.add(p);
}
input.close();
// Stampa a video di tutti i dati
for (int i = 0; i < lista.size(); i++)
{
lista.get(i).stampaInfo();
}
// Stampa su file dei dati nel formato richiesto
PrintWriter output = new PrintWriter(f2);
for (int i = 0; i < lista.size(); i++)
{
output.println((i+1) + ": " + lista.get(i).getCognome() + " " + lista.get(i).getNome());
}
output.close();
} catch (FileNotFoundException e) {
System.out.println("File non trovato !!!");
e.printStackTrace();
}
}
}
Lettura e Scrittura con i File Binari
Esercizio 1:
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;
public class Principale2 {
public static void main(String[] args) {
RandomAccessFile raf;
Scanner input = new Scanner(System.in);
int i;
try {
// Scrittura su file binario di numeri acquisiti da tastiera
raf = new RandomAccessFile("datiLong.dat", "rw");
for (i = 0; i < 10; i++) {
// writeInt scrive un numero intero sul file
raf.writeLong(input.nextLong());
}
raf.close();
raf = new RandomAccessFile("datiLong.dat", "r");
System.out.println("Il file è grande: " + raf.length() + " bytes");
long first, last;
// readInt legge un numero intero dal file
first = raf.readLong();
// seek permette di muoversi all'interno del file
raf.seek(raf.length() - 8);
last = raf.readLong();
raf.close();
System.out.println("Il primo numero vale: " + first);
System.out.println("L'ultimo numero vale: " + last);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Esercizio 2:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
public class Principale3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
RandomAccessFile raf;
try {
raf = new RandomAccessFile("datiLong.dat", "r");
int numEle = (int)(raf.length()/8);
long[] vett = new long[numEle];
for (int i = 0; i < numEle; i++)
vett[i] = raf.readLong();
raf.close();
for (int i = 0; i < numEle-1; i++) {
int i_min = i;
for (int j = i+1; j < numEle; j++) {
if (vett[j] < vett[i_min])
{
long temp = vett[j];
vett[j] = vett[i_min];
vett[i_min] = temp;
}
}
}
PrintWriter output = new PrintWriter(new File("output.txt"));
for (int i = 0; i < numEle; i++)
output.print(vett[i] + "\t");
output.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Implemetazione dei Grafi
Metodo 1
Definizione di una class Node che modella un nodo del grafo, e di una classe Graph contenente un vettore di nodi. Ciascun nondo contiene un riferimento ad un nodo successivo.
public class Node {
private String nodeID;
private Node nextNode;
public Node(String N)
{
nodeID = N;
nextNode = null;
}
public String getNodeID()
{
return nodeID;
}
public void setNextNode(Node NODE)
{
nextNode = NODE;
}
public Node getNextNode()
{
return nextNode;
}
}
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Graph {
private final String[] labels = {"A", "B", "C", "D", "E"};
private int dim;
private Node[] listOfNodes;
public Graph(int DIM, String path) {
dim = DIM;
listOfNodes = new Node[dim];
for (int i = 0; i < dim; i++)
listOfNodes[i] = new Node(labels[i]);
loadFromFile(path);
}
private void loadFromFile(String path)
{
File f = new File(path);
int val = 0;
try {
Scanner input = new Scanner(f);
for (int i = 0; i < dim; i++)
{
Node head = listOfNodes[i];
for (int j = 0; j < dim; j++)
{
val = input.nextInt();
if (val == 1)
{
Node n = new Node(labels[j]);
head.setNextNode(n);
head = head.getNextNode();
}
}
}
input.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void print()
{
for (int i = 0; i < dim; i++) {
System.out.print(listOfNodes[i].getNodeID() + " -> ");
Node temp = listOfNodes[i].getNextNode();
while(temp != null)
{
System.out.print(temp.getNodeID() + " -> ");
temp = temp.getNextNode();
}
System.out.println("NULL");
}
}
}
Classe Principale con il metodo main dove viene istanziato un oggetto di tipo Graph, a partire dalla matrice delle adiacenze presente in un file di testo.
import java.util.Scanner;
public class Principale {
public static void main(String[] args) {
Graph g = new Graph(5, "graph.txt");
g.print();
}
}
Metodo 2
Definizione di una class Node che modella un nodo del grafo, e di una classe Graph contenente un vettore di nodi. Ciascun nodo contiente, in questo caso, una LinkedList contenente i nodi raggiungibili.
import java.util.LinkedList;
public class Node2 {
private String nodeID;
private LinkedList<Node2> list;
public Node2(String N)
{
nodeID = N;
list = new LinkedList<Node2>();
}
public String getNodeID() {
return nodeID;
}
public void addNode(Node2 NODE)
{
list.add(NODE);
}
public LinkedList<Node2> getListOfNodes()
{
return list;
}
}
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.Scanner;
public class Graph2 {
private final String[] labels = {"A", "B", "C", "D", "E"};
private int dim;
private Node2[] head;
public Graph2(int DIM, String path) {
dim = DIM;
head = new Node2[dim];
for (int i = 0; i < dim; i++)
head[i] = new Node2(labels[i]);
loadFromFile(path);
}
private void loadFromFile(String path)
{
File f = new File(path);
int val = 0;
try {
Scanner input = new Scanner(f);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
val = input.nextInt();
if (val == 1)
{
Node2 n = new Node2(labels[j]);
head[i].addNode(n);
}
}
}
input.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void print()
{
for (int i = 0; i < dim; i++) {
System.out.print(head[i].getNodeID() + " -> ");
Iterator<Node2> iterator = head[i].getListOfNodes().iterator();
while(iterator.hasNext())
{
System.out.print(iterator.next().getNodeID() + " -> ");
}
System.out.println("NULL");
}
}
}
Implementazione della classe Principale.
import java.util.Scanner;
public class Principale {
public static void main(String[] args) {
Graph2 g2 = new Graph2(5, "graph.txt");
g2.print();
}
}
Metodo 3
Implementazione di un grafo tramite una HashMap. Ciascun nodo è definito da una Stinga corrispondente alla label che lo identifica.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Scanner;
public class Graph4 {
private final String[] labels = {"A", "B", "C", "D", "E"};
private int dim;
private HashMap<String, LinkedList<String>> heads;
public Graph4(int DIM, String path) {
dim = DIM;
heads = new HashMap<String, LinkedList<String>>();
for (int i = 0; i < dim; i++)
{
heads.putIfAbsent(labels[i], new LinkedList<String>());
}
loadFromFile(path);
}
private void loadFromFile(String path)
{
File f = new File(path);
int val = 0;
try {
Scanner input = new Scanner(f);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
val = input.nextInt();
if (val == 1)
{
heads.get(labels[i]).add(labels[j]);
}
}
}
input.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void print()
{
for (int i = 0; i < dim; i++) {
System.out.print(labels[i] + " -> ");
Iterator<String> iterator = heads.get(labels[i]).iterator();
while(iterator.hasNext())
{
System.out.print(iterator.next() + " -> ");
}
System.out.println("NULL");
}
}
public String[] getNodeLabels() {
return labels;
}
public String[] getNextNodes(int startIDX, String[] labels)
{
ArrayList<String> nextNodes = new ArrayList<String>();
Iterator<String> iterator = heads.get(labels[startIDX]).iterator();
while(iterator.hasNext())
{
nextNodes.add(iterator.next());
}
String[] nextLabels = new String[nextNodes.size()];
for (int i = 0; i < nextNodes.size(); i++)
nextLabels[i] = nextNodes.get(i);
return nextLabels;
}
}
In questa implementazione della classe principale è implementato un meccanismo di navigazione del grafo. A partire da un determinato nodo, posso scegliere di muovermi su uno dei nodi raggiungibili. Anche in questo caso, la matrice delle adiacenze viene caricata da un file di teso.
import java.util.Scanner;
public class Principale {
public static void main(String[] args) {
Graph4 g4 = new Graph4(5, "graph.txt");
g4.print();
System.out.println(//////////////////////);
// Try Navigate
// Inserisci il nodo di partenza
Scanner input = new Scanner(System.in);
String[] availableLabels = g4.getNodeLabels();
System.out.print("Inserisci nodo di partenza: ");
for (int i = 0; i < availableLabels.length; i++)
System.out.print(i + " per nodo " + availableLabels[i] + "; ");
int node = input.nextInt();
availableLabels = g4.getNextNodes(node, availableLabels);
while(availableLabels.length > 0)
{
for (int i = 0; i < availableLabels.length; i++)
System.out.print(i + " per nodo " + availableLabels[i] + "; ");
node = input.nextInt();
if (node == -1)
break;
availableLabels = g4.getNextNodes(node, availableLabels);
}
if (node == -1)
System.out.println("Hai scelto di terminare il percorso !");
else
System.out.println("Hai raggiunto un nodo terminale");
input.close();
}
}
Grafi e file binari
Generare un file binario contenete la matrice delle adiacenze di un grafo con dim nodi. Nello specifico, ciascuna posizione M(i,j) della matriece conterrà 0 se non esiste un percoso da i a j, altrimenti un numero maggiore di 0 che indica il costo per andare dal nodo i al nodo j. Successivamente creare il grafo a partire dalla matrice contenuta nel file binario, navigarlo e salvare il percorso e il relativo costo su un file di testo.
Definizione della classe FileGenerator che implementerà le funzioni di scrittura del file binario e del file di testo.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
public class FileGenerator {
public void generateGraphFile() {
try {
RandomAccessFile raf = new RandomAccessFile("dati.dat", "rw");
System.out.println("Inserisci Dimensione: ");
Scanner input = new Scanner(System.in);
int dim = input.nextInt();
raf.writeInt(dim);
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++)
{
System.out.print("Inserisci costo per andare da " + (char)('A'+i) + " a " + (char)('A'+j) + ": ");
raf.writeInt(input.nextInt());
}
}
//input.close();
raf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void savePathToFile(LinkedList<Character> percorso, int costo)
{
try {
PrintWriter output = new PrintWriter(new File("output.txt"));
Iterator<Character> listIterator = percorso.iterator();
while (listIterator.hasNext())
{
output.print(listIterator.next() + " -> ");
}
output.println("END");
output.println("Costo del percorso: " + costo);
output.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Implmentazione della classe Graph. In questo caso, il grafo è gestito come una matrice di interi.
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
public class Graph {
private int dim;
private int[][] matrix;
public Graph(String path) {
try {
RandomAccessFile inputFile = new RandomAccessFile(path, "r");
inputFile.seek(0);
dim = inputFile.readInt();
matrix = new int[dim][dim];
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
matrix[i][j] = inputFile.readInt();
}
}
inputFile.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void printGraph()
{
System.out.println("/////////////////");
System.out.println("Graph");
for (int i = 0; i < dim; i++)
System.out.print((char)('A'+i) + "\t");
System.out.println();
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
}
public int getDim()
{
return dim;
}
public ArrayList<Integer> getNextNodes(int node)
{
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 0; i < dim; i++)
{
if (matrix[node][i] > 0)
temp.add(i);
}
return temp;
}
public int getCosto(int i, int j)
{
return matrix[i][j];
}
}
Implmentazione della classe Principale, dove sono richiamate le opportune funzioni.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;
public class Principale {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
FileGenerator fg = new FileGenerator();
//fg.generateGraphFile();
Graph g = new Graph("dati.dat");
g.printGraph();
System.out.println(System.currentTimeMillis() - startTime);
///////////////////////////////////////
// Try Navigate
// Inserisci il nodo di partenza
Scanner input = new Scanner(System.in);
LinkedList<Character> percorso = new LinkedList<Character>();
ArrayList<Integer> nextNodes = new ArrayList<Integer>();
int costo = 0;
System.out.print("Inserisci nodo di partenza: ");
for (int i = 0; i < g.getDim(); i++)
System.out.print(i + " per nodo " + (char)('A'+i) + "; ");
int node = input.nextInt();
percorso.add(((char)('A'+node)));
nextNodes = g.getNextNodes(node);
System.out.println("Sei sul nodo: " + (char)('A'+node));
while(nextNodes.size() > 0)
{
for (int i = 0; i < nextNodes.size(); i++)
System.out.print(i + " per nodo " + (char)('A'+nextNodes.get(i)) + "; ");
int temp = node;
node = input.nextInt();
if (node == -1)
break;
percorso.add(((char)('A'+node)));
costo = costo + g.getCosto(temp, nextNodes.get(node));
System.out.println("Sei sul nodo: " + (char)('A'+nextNodes.get(node)));
nextNodes = g.getNextNodes(node);
}
if (node == -1)
System.out.println("Hai scelto di terminare il percorso !");
else
System.out.println("Hai raggiunto un nodo terminale");
System.out.println("Costo del percorso effettuato: " + costo);
input.close();
fg.savePathToFile(percorso, costo);
}
}
Classi astratte e metodi astratti
Una classe astratta non può in alcun modo essere istanziata, quindi può essere utilizzata esclusivamente come classe base. Una classe derivata da una classe astratta deve fornire una implementazione per tutti i metodi astratti dichiarati nella superclasse.
Definisco la classe Persona come classe astratta contenente il metodo astratto inserisciNome().
public abstract class Persona {
// Funzione virtuale pura (o astratta) da implementare necessariamente
// nelle classi derivate, pena errore
public abstract void inserisciNome();
}
Definisco due classi derivate dalla classe Persona, Studente e Lavoratore. Nelle classi derivate devo necessariamente implementare i metodi dichiarati come abstract nella classe padre.
public class Studente extends Persona {
// The type Studente must implement the inherited abstract method Persona.inserisciNome()
@Override
public void inserisciNome() {
// TODO Auto-generated method stub
System.out.println("Stampa Studente");
}
public void altroMetodo() {
System.out.println("Ciao Studente");
}
}
public class Lavoratore extends Persona{
@Override
public void inserisciNome() {
// TODO Auto-generated method stub
System.out.println("Stampa Lavoratore");
}
public void altroMetodo() {
System.out.println("Ciao Lavoratore");
}
}
Definizione della classe Principale. Poichè abstract, non posso istanziare oggetti di classe Persona. Tuttavia, posso utilizzare riferimenti alla classe Persona per accedere ai metodi ridefiniti nella classi derivate (Overriding).
public class Principale {
public static void main(String[] args) {
// TODO Auto-generated method stub
Persona p;//= new Persona(); //ERRORE: Cannot instantiate the type Persona
Studente s = new Studente();
Lavoratore l = new Lavoratore();
// Overriding del metodo inserisciNome
p = s;
p.inserisciNome();
p = l;
p.inserisciNome();
// Cast per richiamare i metodi della classe derivata
p = s;
((Studente)p).altroMetodo();
p = l;
((Lavoratore)p).altroMetodo();
}
}
Interfacce
In Java non è possibile implementare il meccanismo dell'ereditarietà multipla, ovvero che una classe derivi da più classi. Tuttavia, definendo una serie di interfacce, è possibile fare in modo tale che una classe possa implentare più interfacce.
Definisco la classe base Persona contenente la definizione di un solo metodo.
public class Persona {
public void altroMetodo()
{
System.out.println("Ciao Persona");
}
}
Adesso definisco due interfacce, rispettivamente Studente e Lavoratore, che dichiarano un paio di metodi ciascuno
public interface Studente {
public void inserisciNomeStudente();
public void altroMetodo();
}
public interface Lavoratore {
public void inserisciNomeLavoratore();
public void altroMetodo();
}
Definizione della classe StudenteLavoratore, che deriva da Persona e implementa le interfacce di Studente e Lavoratore.
public class StudenteLavoratore extends Persona implements Studente, Lavoratore {
@Override
public void inserisciNomeLavoratore() {
// TODO Auto-generated method stub
}
@Override
public void inserisciNomeStudente() {
// TODO Auto-generated method stub
}
public void altroMetodo()
{
System.out.println("Ciao Studente Lavoratore");
}
}
Implementazione della classe Principale
public class Principale {
public static void main(String[] args) {
// TODO Auto-generated method stub
Persona p = new Persona();
//p.altroMetodo();
StudenteLavoratore sl = new StudenteLavoratore();
p.altroMetodo();
sl.altroMetodo();
Persona p2;
StudenteLavoratore sl2 = new StudenteLavoratore();
p2 = sl2;
p2.altroMetodo();
//Studente s = new Studente(); ERRORE: Cannot instantiate the type Studente.
//Lavoratore l = new Lavoratore(); ERRORE: Cannot instantiate the type Lavoratore.
}
}
Esempio sul calcolo della complessità computazione di un metodo
Si vuole calcolare la complessità O (o-grande) del seguente metodo.
NB. In questo caso, si dà per scontato che almeno un elemento del vettore vett sia pari ad ele.
public int trovaIndice(int[] vett, int ele)
{
int i = 0;
int val = vett[i];
while (val != ele)
{
i = i+1;
val = vett[i];
}
return i;
}
Aggiungiamo un costo unitario per ogni dichiarazione (locale o formale) e/o assegnazione, valore restituito e confronto. Sia n la dimensione del vettore.
- int[] a -> +1
- int ele -> +1
- int i = 0; -> +1
- int val = a[i]; -> +1
- return i; -> +1
Nel caso peggiore si avrà:
- n confronti nella consizione del while (val != ele)
- n incrementi i = i+1;
- n assegnazioni val = a[i];
Dopo le varie operazioni, la funzione che descrive la nostra funzione è f(n) = 3n + 5
Si dice che f(n) è di ordine g(n), ovvero f(n) = O(g(n)) se esiste una costante positiva C tale che valga, salvo che per un numero finito di elementi, la seguente condizione: f(n) <= C g(n).
Allora, data f(n) = 3n+5 considero:
- 3n <= 3n -> per ogni n >= 0
- 5 < 5n -> per ogni n >= 1
Per ogni n >= 1 --> f(n) = 3n + 5 <= 8n.
Siano k = 1 e C = 8 --> f(n) <= Cn per ogni n >= k --> f(n) è O(n)