JavaRush /Java 博客 /Random-ZH /获取器和设置器

获取器和设置器

已在 Random-ZH 群组中发布
你好!在之前的讲座中,您已经学习了如何使用字段和方法创建自己的成熟类。这是重大进步,干得好!但现在我必须告诉你一个令人不快的事实。我们没有完全正确地创建我们的类!为什么?乍一看,这个类没有错误:
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