JavaRush /Java Blog /Random-IT /Getter e setter

Getter e setter

Pubblicato nel gruppo Random-IT
Ciao! Nelle lezioni precedenti hai già imparato come creare le tue classi complete, con campi e metodi. Questo è un progresso serio, ben fatto! Ma ora devo dirti una spiacevole verità. Non abbiamo creato le nostre lezioni nel modo giusto! Perché? A prima vista, non ci sono errori in questa classe:
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}
In effetti, c'è. Immagina che mentre sei seduto al lavoro hai scritto una classe come questa Cat, che denota i gatti. E andò a casa. Mentre eri via, un altro programmatore è venuto a lavorare, ha creato la sua classe Main, dove ha iniziato a utilizzare la classe che hai scritto Cat.
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Non importa perché lo ha fatto o come è successo: forse la persona era stanca o non ha dormito abbastanza. Un'altra cosa è importante: la nostra classe attuale Catpermette di assegnare valori pazzeschi ai campi. Di conseguenza, il programma contiene oggetti con uno stato errato, come questo gatto con un'età di -1000 anni. Che errore abbiamo finito per fare? Quando abbiamo creato la classe, ne abbiamo esposto i dati. I campi namee agesono weightdi pubblico dominio. È possibile accedervi ovunque nel programma: basta creare un oggetto Cat- e il gioco è fatto, qualsiasi programmatore ha accesso ai suoi dati direttamente tramite l'operatore " ."
Cat cat = new Cat();
cat.name = "";
Qui accediamo direttamente al campo namee ne impostiamo il valore. Dobbiamo in qualche modo proteggere i nostri dati da interferenze esterne errate. Cosa è necessario per questo? Innanzitutto, tutte le variabili di istanza (campi) devono essere contrassegnate con un modificatore private. Private è il modificatore di accesso più rigoroso in Java. Se lo usi, i campi della classe Catnon saranno accessibili al di fuori di essa.
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";//error! The name field in the Cat class has private access!
   }
}
Il compilatore lo vede e produce immediatamente un errore. Adesso i campi sembrano tutelati. Ma si scopre che l’accesso ad essi è “strettamente” chiuso: il programma non può nemmeno misurare il peso di un gatto esistente, se necessario. Anche questa non è un'opzione: in questa forma la nostra classe è praticamente impossibile da utilizzare. Idealmente dobbiamo consentire una sorta di accesso limitato ai dati:
  • Altri programmatori dovrebbero essere in grado di creare oggettiCat
  • Dovrebbero essere in grado di leggere i dati da oggetti già esistenti (ad esempio, ottenere il nome o l'età di un gatto già esistente)
  • Dovrebbe anche essere possibile assegnare valori ai campi. Ma allo stesso tempo - solo valori corretti. I nostri oggetti devono essere protetti da quelli errati (no “età = -1000 anni” e simili).
L'elenco dei requisiti è decente! Ma in realtà, tutto ciò è facilmente ottenibile utilizzando metodi speciali: getter e setter .
Getter e setter - 2
Il nome deriva dall'inglese " get " - " ricevere " (ovvero "metodo per ottenere il valore di un campo") e set - " set " (ovvero "metodo per impostare il valore di un campo"). Vediamo come appaiono usando la nostra classe come esempio Cat:
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       this.weight = weight;
   }
}
Come puoi vedere, tutto è abbastanza semplice :) I loro nomi sono spesso costituiti dalla parola get/set + il nome del campo di cui sono responsabili. Ad esempio, un metodo getWeight()restituisce il valore weightdel campo dell'oggetto per il quale è stato chiamato. Questo è quello che appare nel programma:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       String barsikName = barsik.getName();
       int barsikAge = barsik.getAge();
       int barsikWeight = barsik.getWeight();

       System.out.println("Cat name: " + barsikName);
       System.out.println("Cat's age: " + barsikAge);
       System.out.println("Weight of the cat: " + barsikWeight);
   }
}
Uscita console:

Name кота: Барсик
Возраст кота: 5
Вес кота: 4
Ora da un'altra classe ( Main) si accede ai campi Cat, ma solo tramite getter . Tieni presente che i getter hanno un modificatore di accesso public, il che significa che sono accessibili da qualsiasi punto del programma. E l'assegnazione dei valori? I metodi setter sono responsabili di ciò
public void setName(String name) {
   this.name = name;
}
Anche il loro lavoro, come puoi vedere, è semplice. Chiamiamo un metodo setName()su un oggetto Cat, gli passiamo una stringa come argomento e questa stringa viene assegnata a un campo namedel nostro oggetto.
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);

       System.out.println("The original name of the cat is " + barsik.getName());
       barsik.setName("Basil");
       System.out.println("The new name of the cat -" + barsik.getName());
   }
}
Qui abbiamo usato sia getter che setter. Innanzitutto, utilizzando un getter, abbiamo ricevuto e inviato alla console il nome iniziale del gatto. Quindi, utilizzando un setter, nameè stato assegnato un nuovo valore al suo campo: "Vasily". E poi, usando un getter, abbiamo recuperato il nome per verificare se fosse davvero cambiato. Uscita console:

Изначальное Name кота — Барсик
Новое Name кота — Васorй
Sembrerebbe, qual è la differenza? Possiamo anche assegnare valori errati ai campi oggetto, anche se disponiamo di setter:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Uscita console:

Возраст Барсика — -1000 лет
La differenza è che un setter è un metodo a tutti gli effetti . E in un metodo, a differenza di un campo, puoi inserire la logica di verifica necessaria per impedire valori inaccettabili. Ad esempio, puoi facilmente disattivare l'assegnazione di un numero negativo come età:
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age cannot be negative!");
   }
}
E ora il nostro codice funziona correttamente!
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Uscita console:

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
C'è una restrizione all'interno del setter e protegge dai tentativi di impostare dati errati. L'età di Barsik è rimasta invariata. Getter e setter dovrebbero sempre essere creati. Anche se i tuoi campi non hanno restrizioni sui possibili valori, non ci saranno danni da essi. Immagina una situazione: tu e i tuoi colleghi state scrivendo un programma insieme. Hai creato una classe Catcon campi pubblici e tutti i programmatori li usano come vogliono. E poi un bel giorno ti viene in mente: “Accidenti, prima o poi qualcuno potrebbe accidentalmente assegnare un numero negativo a una variabile weight! Dobbiamo creare setter e rendere tutti i campi privati!” Li crei e tutto il codice scritto dai tuoi colleghi si rompe immediatamente. Dopotutto, avevano già scritto un sacco di codice in cui accedevano Catdirettamente ai campi.
cat.name = "Hippopotamus";
E ora i campi sono diventati privati ​​e il compilatore produce un sacco di errori!
cat.name = "Hippopotamus";//error! The name field of the Cat class has private access!
In una situazione del genere, sarebbe meglio nascondere i campi e creare fin dall'inizio getter-setter . Tutti i tuoi colleghi li userebbero e se ti rendessi conto tardi che hai bisogno di limitare i valori dei campi, aggiungeresti semplicemente un segno di spunta all'interno del setter. E nessuno infrangerebbe il codice già scritto. Naturalmente, se desideri l'accesso in sola lettura a un determinato campo, puoi creare un getter per esso. “Fuori”, cioè fuori dalla classe, dovrebbero essere disponibili solo i metodi. I dati devono essere nascosti.
Getter e setter - 4
Si può fare un’analogia con un telefono cellulare. Immagina che invece di un normale telefono cellulare acceso, ti venga dato un telefono con la custodia aperta, dove si trovano tutti i fili, i circuiti, ecc. sporgente. Il telefono funziona: se ti sforzi e giochi con i diagrammi, potresti anche riuscire a fare una chiamata. Ma probabilmente lo romperai e basta. L'azienda produttrice ti fornisce invece un'interfaccia: il cliente semplicemente compone i numeri richiesti, preme il pulsante verde con la cornetta e inizia la chiamata. E non gli interessa cosa succede all’interno con i circuiti e i fili e come svolgono il loro compito. In questo esempio, l’azienda ha accesso limitato alla parte “interna” (dati) del telefono e ha lasciato all’esterno solo l’interfaccia (metodi). Di conseguenza, il cliente otterrà ciò che voleva (farà una chiamata) e sicuramente non romperà nulla al suo interno.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION