Testo
Scrivere una classe Telefono per rappresentare oggetti con attributi costo, modello e annoUscita. Fra gli attributi prevedete anche un ID numerico autoincrementante che viene assegnato all’oggetto in fase di creazione e non più modificabile. Prevedete un costruttore parametrizzato che setta tutti gli attributi (escluso ID che è automatico) e opportune implementazioni dei metodi equals, hashCode e compareTo. Il metodo compareTo si baserà sul costo dell’oggetto (un oggetto più costoso è “maggiore” di un oggetto meno costoso), i metodi equals ed hashCode sui valori degli attributi (esclusi ID e costo). Scrivete infine una classe che contiene al suo interno una Map e metodi per inserire una coppia con ID come chiave e l’oggetto come valore, rimuovere un oggetto in base all’ID, stampare l’elenco degli articoli ordinati per prezzo crescente.
Svolgimento
Nella prima parte viene richiesta una classe chiamata Telefono con attributi costo, modello e annoUscita.
public class Telefono{
private double costo;
private String modello;
private int annoUscita;
}
Creiamo un file chiamato “Telefono.java” e scriviamo al suo interno una semplice classe chiamata Telefono con 3 attributi privati, il primo di tipo double (costo), il secondo di tipo String (modello) e l’ultimo (annoUscita) di tipo int.
Subito dopo viene richiesto fra gli attributi un ID numerico autoincrementante che viene assegnato all’oggetto in fase di creazione e non è più modificabile.
public class Telefono{
private static int count = 0;
private final int ID;
private double costo;
private String modello;
private int annoUscita;
}
Inseriamo quindi un attributo intero chiamato appunto ID, lo definiamo sempre privato ma questa volta aggiungiamo, prima del tipo di attributo (int), la parola chiave final che serve a rendere l’attributo non più modificabile. Poi dichiariamo anche un attributo sempre privato e intero, che in questo caso ho chiamato count, e aggiungiamo la parola chiave static che serve a rendere tale attributo condiviso fra tutte le istanze della classe stessa. Infine attribuiamo a count il valore da cui desideriamo far partire i nostri ID. La richiesta verrà conclusa nel costruttore al passo successivo.
Successivamente viene richiesto un costruttore parametrizzato, ovvero il metodo che viene chiamato quando si crea un nuovo oggetto della classe.
public class Telefono{
private static int count = 0;
private final int ID;
private double costo;
private String modello;
private int annoUscita;
public Telefono(double costo, String modello, int annoUscita){
this.ID = count++;
setCosto(costo);
setModello(modello);
setAnnoUscita(annoUscita);
}
}
Inseriamo un costruttore che ha in ingresso tre degli attributi definiti precedentemente (double costo, String modello, int annoUscita) e al suo interno attribuiamo con il riferimento this all’ID della classe l’attributo count con subito a fianco due +; questo farà si che, una volta invocato il costruttore, prima venga assegnato l’ID e successivamente incrementato l’attributo count, pronto per essere assegnato all’ID del prossimo oggetto che verrà creato. Passiamo infine i tre valori in ingresso come parametro a tre metodi set che andremo a definire in seguito.
Poi viene richiesto il metodo equals, ovvero il metodo che confronta l’oggetto su cui viene invocato con l’oggetto passato come parametro e restituisce un valore booleano. Viene anche specificato di implementare il metodo sui valori degli attributi modello e annoUscita.
public class Telefono{
private static int count = 0;
private final int ID;
private double costo;
private String modello;
private int annoUscita;
public Telefono(double costo, String modello, int annoUscita){
this.ID = count++;
setCosto(costo);
setModello(modello);
setAnnoUscita(annoUscita);
}
@Override
public boolean equals(Object o){
if (o == this)
return true;
if (!(o instanceof Telefono))
return false;
Telefono tel = (Telefono)o;
return this.modello.equals(tel.modello) && this.annoUscita == tel.annoUscita;
}
}
Essendo il metodo equals ereditato dalla classe Object (tutte le classi che creiamo estendono Object), inseriamo @Override per essere sicuri di andare a sovrascrivere proprio quel metodo. Subito sotto andiamo a dichiarare un metodo pubblico, che restituisce obbligatoriamente un booleano, che si chiama appunto equals e nel quale mettiamo come parametro in ingresso un oggetto di tipo Object con il nome che preferiamo. All’interno andiamo a stabilire in base a quali parametri decidere se due oggetti della stessa classe sono uguali o meno. Prima di tutto andiamo a verificare se l’oggetto passato come parametro è lo stesso oggetto che invoca il metodo, se così fosse andiamo subito a restituire il valore vero (true). Poi andiamo a controllare se l’oggetto passato come parametro non è un’istanza della classe dell’oggetto che invoca il metodo, ovvero andiamo a verificare se l’oggetto passato come parametro non è di tipo Telefono, e in tal caso restituiamo subito il valore falso (false) visto che sicuramente due oggetti di tipo diverso sono diversi. Infine effettuiamo un cast da Object a Telefono per poter chiamare i metodi propri della classe Telefono ed effettuiamo la verifica sull’attributo modello e annoUscita come richiesto dal testo dell’esercizio. Trattandosi di due stringhe sfruttiamo il metodo equals delle stringhe e, dovendo essere verificate contemporaneamente le due condizioni, inseriamo in mezzo l’operatore and (&&), il tutto direttamente dopo la parola chiave return.
Dopo viene richiesto il metodo hashCode, ovvero il metodo che restituisce un codice hash dell’oggetto ed è pensato per fornire supporto alla gestione delle strutture dati di tipo hash. In generale deve avere le seguenti caratteristiche:
- se invocato sullo stesso oggetto più di una volta durante un’esecuzione di un’applicazione Java, il metodo hashCode deve restituire lo stesso valore intero;
- se due oggetti sono uguali secondo il metodo equals, l’invocazione del metodo hashCode su ciascuno dei due oggetti deve produrre lo stesso risultato intero;
- non è necessario che il metodo hashCode produca risultati distinti quando invocato su oggetti che risultino non uguali secondo il metodo equals.
Viene anche specificato di implementare il metodo sui valori degli attributi modello e annoUscita.
public class Telefono{
private static int count = 0;
private final int ID;
private double costo;
private String modello;
private int annoUscita;
public Telefono(double costo, String modello, int annoUscita){
this.ID = count++;
setCosto(costo);
setModello(modello);
setAnnoUscita(annoUscita);
}
@Override
public boolean equals(Object o){
if (o == this)
return true;
if (!(o instanceof Telefono))
return false;
Telefono tel = (Telefono)o;
return this.modello.equals(tel.modello) && this.annoUscita == tel.annoUscita;
}
@Override
public int hashCode() {
int result = 17;
if (this.modello != null) {
result = 31 * result + this.modello.hashCode();
}
if (this.annoUscita != null) {
result = 31 * result + this.annoUscita;
}
return result;
}
}
Essendo il metodo hashCode ereditato dalla classe Object (tutte le classi che creiamo estendono Object), inseriamo @Override per essere sicuri di andare a sovrascrivere proprio quel metodo. Subito sotto andiamo a dichiarare un metodo pubblico, che restituisce obbligatoriamente un intero, che si chiama appunto hashCode e con nessun parametro in ingresso. All’interno è possibile scegliere le operazioni che si reputano migliori, l’importante è attenersi alle caratteristiche citate prima. In questo caso è stata creata una variabile intera con nome result alla quale è stato attribuito il numero 17, dopo tramite un if si è verificato se l’attributo modello sia non null e, in tal caso, si è attribuito a result il prodotto di 31 per result stesso più il metodo hashCode della classe String, essendo l’attributo modello una stringa appunto. Lo stesso procedimento viene ripetuto per l’altro attributo, essendo anch’esso una stringa. Infine viene restituita la variabile result.
Per terminare la classe, viene richiesto il metodo compareTo. Inoltre per completezza creiamo anche i metodi set e get.
public class Telefono{
private static int count = 0;
private final int ID;
private double costo;
private String modello;
private int annoUscita;
public Telefono(double costo, String modello, int annoUscita){
this.ID = count++;
setCosto(costo);
setModello(modello);
setAnnoUscita(annoUscita);
}
public void setCosto(double costo){
if(costo < 0){
throw new IllegalArgumentException();
}
this.costo = costo;
}
public void setModello(String modello){
this.modello = modello;
}
public void setAnnoUscita(int annoUscita){
this.annoUscita = annoUscita;
}
public double getCosto(){
return this.costo;
}
public String getModello(){
return this.modello;
}
public String geetAnnoUscita(){
return this.annoUscita;
}
public int getID(){
return this.ID;
}
@Override
public boolean equals(Object o){
if (o == this)
return true;
if (!(o instanceof Telefono))
return false;
Telefono tel = (Telefono)o;
return this.modello.equals(tel.modello) && this.annoUscita == tel.annoUscita;
}
@Override
public int hashCode() {
int result = 17;
if (this.modello != null) {
result = 31 * result + this.modello.hashCode();
}
if (this.annoUscita != null) {
result = 31 * result + this.annoUscita;
}
return result;
}
@Override
public int compareTo(Telefono other){
if(this.costo<other.costo)
return -1;
else if(other.costo<this.costo)
return 1;
return 0;
}
}
Dovendo implementare il metodo compareTo come prima cosa inseriamo nella definizione iniziale della classe la dicitura “implements Comparable<Telefono>”, che serve per specificare che la classe Telefono implementa l’interfaccia Comparable che contiene il metodo compareTo e quindi permette di comparare oggetti diversi di tale classe.
Essendo il metodo compareTo proprio dell’interfaccia Comparable, inseriamo @Override per essere sicuri di andare a sovrascrivere proprio quel metodo. Subito sotto andiamo a dichiarare un metodo pubblico, che restituisce obbligatoriamente un intero, che si chiama appunto compareTo e nel quale mettiamo come parametro in ingresso un oggetto di tipo Telefono con il nome che preferiamo. All’interno andiamo a stabilire quando l’oggetto passato come parametro è maggiore, minore o uguale rispetto all’oggetto che chiama il metodo restituendo rispettivamente -1, 1 o 0. L’esercizio richiede di eseguire la comparazione tramite l’attributo costo, quindi inseriamo due if con le condizioni dette prima per verificare i primi due casi e infine un return 0 poichè, se si non rientra nei primi due, allora sicuramente si rientrerà nel terzo. Completiamo la classe con i metodi set per gli attributi costo, modello e annoUscita e con i metodi get per tutti gli attributi tranne, ovviamente, il contatore (count).
Infine a completamento dell’esercizio viene richiesta una classe con una Map e metodi per inserire una coppia con ID come chiave e l’oggetto come valore, rimuovere un oggetto in base all’ID, stampare l’elenco degli articoli ordinati per prezzo crescente.
import java.util.*;
public class Database{
private Map<Integer, Telefono> map = new HashMap<Integer, Telefono>();
public Telefono add(Telefono tv){
return map.put(tv.getID(), tv);
}
public Telefono remove(int ID){
return map.remove(ID);
}
public void print(){
List<Telefono> televisori = new ArrayList<>(map.values());
Collections.sort(televisori);
for(Object tv : televisori){
System.out.println(tv);
}
}
public static void main(String[] args){
Database db = new Database();
db.add(new Telefono(12.9, "Samso", "400x400"));
db.add(new Telefono(110.9, "Samso", "400x400"));
db.add(new Telefono(10.9, "Samso", "400x400"));
db.print();
db.remove(0);
db.print();
}
}
Creiamo un file e diamogli il nome che preferiamo ricordando di inserire l’estensione .java e che questo sarà lo stesso nome della nostra classe; in questo caso il file è stato chiamato “Database.java”.
Dovendo utilizzare una Map, per prima cosa importiamola scrivendo “import java.util.*“. Subito dopo scriviamo la classe chiamata Database e come unico attributo mettiamo la Map richiesta dall’esercizio. Per farlo creiamo un nuovo oggetto Map con Integer e Telefono e lo istanziamo con HashMap. Dopo creiamo il metodo per aggiungere elementi alla Map semplicemente richiamando, appunto, il metodo add e passandogli in ingresso l’oggetto passato come parametro al metodo stesso. Stesso procedimento per il metodo di rimozione elementi ma con remove al posto di add e con l’ID passato al metodo stesso.
Adesso andiamo a definire il metodo che stamperà l’elenco dei televisori presenti nella Map in ordine crescente di prezzo. Creiamo un metodo pubblico di tipo void e con nessun parametro in ingresso e chiamiamolo per esempio print. Al suo interno creiamo una List, in questo caso chiamata televisori, e istanziamola come ArrayList passando al costruttore map.values, ovvero tutti i valori presenti all’interno della Map. Questo procedimento è stato fatto per permetterci di usare il metodo sort di Collections che opera sulle List. Quindi subito dopo invochiamo tale metodo con la List creata prima come parametro in ingresso e grazie al metodo compareTo implementato al passo precedente, adesso la List sarà ordinata per come desideriamo noi. Quindi usiamo un ciclo for migliorato per stampare tutti gli elementi della List.
Infine creiamo un breve metodo main per testare le funzioni appena implementate e di conseguenza anche quelle implementate nella classe Telefono.
L’intero codice sorgente dell’esercizio si trova su Github qui!
Sei in possesso di altri compiti d’esame o esercizi e vuoi che li svolga? Contattami e inserisci il link per il download qui!
Per qualsiasi dubbio non esitare a lasciare un commento!





