JavaRush /Java Blog /Random-TW /獲取器和設定器

獲取器和設定器

在 Random-TW 群組發布
你好!在先前的講座中,您已經學習如何使用欄位和方法來建立自己的成熟類別。這是重大進步,幹得好!但現在我必須告訴你一個不愉快的事實。我們沒有完全正確地創建我們的類別!為什麼?乍一看,這個類別沒有錯誤:
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!");
   }
}
事實上,是有的。想像一下,當你坐在工作時寫了一個像這樣的類Cat,表示貓。然後他就回家了。當你不在的時候,另一個程式設計師來工作,創建了他自己的類Main,他開始使用你寫的類別Cat
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
他為什麼這麼做或事情是如何發生的並不重要:也許這個人太累了或沒有得到足夠的睡眠。另一件重要的事情是:我們目前的類別Cat允許您為欄位分配瘋狂的值。結果,程序包含了狀態不正確的對象,例如這隻貓的年齡為-1000歲。我們最終犯了什麼錯誤? 當我們創建該類別時,我們公開了它的資料。 字段nameageweight屬於公共領域。它們可以在程式中的任何位置存取:只需創建一個物件Cat- 就這樣,任何程式設計師都可以透過「.」 運算子直接存取其數據
Cat cat = new Cat();
cat.name = "";
這裡我們直接訪問該字段name並設定其值。 我們需要以某種方式保護我們的資料免受不正確的外部幹擾。 為此需要什麼?首先,所有實例變數(字段)都必須用修飾符標記private。Private是Java中最嚴格的存取修飾符。如果使用它,類別的欄位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 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!
   }
}
編譯器看到這一點並立即產生錯誤。現在這些田地似乎受到了保護。但事實證明,對它們的訪問是「嚴格」關閉的:如果有必要,該程序甚至無法獲得現有貓的重量。這也不是一個選擇:在這種形式下,我們的類別實際上是不可能使用的。理想情況下,我們需要允許對資料進行某種有限的存取:
  • 其他程式設計師應該能夠創建對象Cat
  • 他們應該能夠從已經存在的物件中讀取資料(例如,取得已經存在的貓的名字或年齡)
  • 也應該可以分配字段值。但同時 - 只有正確的價值觀。必須保護我們的物件免受錯誤物件的影響(沒有「年齡 = -1000 歲」之類的內容)。
要求清單很不錯!但事實上,這一切都可以使用特殊方法輕鬆實現——gettersetter
獲取器和設定器 - 2
名稱源自英文「get」-「receive」(即「取得欄位值的方法」)和set-set」(即「設定欄位值的方法」)。讓我們以我們的類別為例看看它們是什麼樣的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;
   }
}
正如您所看到的,一切都非常簡單:) 他們的名字通常由單字get/set + 他們負責的欄位的名稱組成。例如,方法傳回呼叫該方法的物件的getWeight()欄位值。weight程式中的樣子是這樣的:
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);
   }
}
控制台輸出:

Name кота: Барсик
Возраст кота: 5
Вес кота: 4
現在,另一個類別 ( Main) 可以存取這些字段Cat,但只能透過 getters。請注意 getters 有一個存取修飾符public,這意味著它們可以從程式中的任何地方存取。那麼賦值呢?Setter方法負責此操作
public void setName(String name) {
   this.name = name;
}
正如您所看到的,他們的工作也很簡單。setName()我們呼叫物件的方法Cat,將字串作為參數傳遞給它,並將該字串指派給name物件的欄位。
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());
   }
}
這裡我們同時使用了 getter 和 setter。首先,使用 getter,我們接收貓的初始名稱並將其輸出到控制台。然後,使用設定器name為其欄位分配一個新值 - “Vasily”。然後,使用 getter,我們再次獲取名稱以檢查它是否真的發生了變化。控制台輸出:

Изначальное Name кота — Барсик
Новое Name кота — Васorй
這樣看來,有什麼差別呢?即使我們有設定器,我們也可以為物件欄位分配不正確的值:
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");
   }
}
控制台輸出:

Возраст Барсика — -1000 лет
不同之處在於setter 是一種成熟的方法。與欄位不同,在方法中,您可以包含防止出現不可接受的值所需的驗證邏輯。例如,您可以輕鬆停用將負數指定為年齡:
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age cannot be negative!");
   }
}
現在我們的程式碼可以正常運作了!
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");
   }
}
控制台輸出:

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
設定器內部有一個限制,它可以防止嘗試設定不正確的資料。巴爾西克的年齡沒有改變。 應該始終創建 getter 和 setter。即使您的欄位對可能的值沒有限制,也不會有任何損害。想像一種情況:你和你的同事正在一起寫一個程式。您創建了一個Cat具有公共字段的類,所有程式設計師都可以按照自己的意願使用它們。然後有一天,你突然意識到:「該死,遲早有人可能會不小心給變數一個負數weight!我們需要建立 setter 並將所有欄位設為私有!” 你創建了它們,你的同事編寫的所有程式碼都會立即崩潰。畢竟,他們已經編寫了一堆Cat直接存取欄位的程式碼。
cat.name = "Hippopotamus";
現在這些欄位已經變成私有的,編譯器會產生一堆錯誤!
cat.name = "Hippopotamus";//error! The name field of the Cat class has private access!
在這種情況下,最好隱藏欄位並從一開始就建立 getter-setter 。您所有的同事都會使用它們,如果您後來意識到需要限製字段值,您只需在設定器內添加一個檢查即可。而且沒有人會破壞已經寫好的程式碼。當然,如果您想要對某個欄位進行唯讀訪問,您可以為其建立一個 getter。 “外部”,即在類別之外,只有方法應該是可存取的。數據必須隱藏。
getter 和 setter - 4
可以用手機來類比。想像一下,你得到的不是一部打開的普通手機,而是一部有打開外殼的手機,所有電線、電路等都在裡面。伸出來。電話可以工作:如果你努力嘗試並擺弄圖表,你甚至可以撥打電話。但你可能會破壞它。相反,製造公司為您提供了一個介面:客戶只需撥打所需的號碼,用聽筒按綠色按鈕,然後通話就開始了。他並不關心電路和電線內部發生了什麼以及它們如何執行任務。在此範例中,該公司對手機「內部結構」(資料)的存取受到限制,僅將介面(方法)保留在外部。結果,客戶將得到他想要的東西(撥打電話)並且絕對不會破壞裡面的任何東西。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION