使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处?

如果getter和setter所做的不仅仅是简单的get/set,我可以很快地解决这个问题,但我不是100%清楚如何做到:

public String foo;

比:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

而前者需要的样板代码要少得多。


当前回答

我们使用getter和setter:

可重用性在编程的后期执行验证

Getter和setter方法是访问私有类成员的公共接口。


封装咒语

封装的口头禅是将字段私有化,将方法公开化。

Getter方法:我们可以访问私有变量。Setter方法:我们可以修改私有字段。

尽管getter和setter方法没有添加新的功能,但我们可以稍后再改变主意,制作该方法

较好的更安全的;和更快。


只要可以使用值,就可以添加返回该值的方法。而不是:

int x = 1000 - 500

use

int x = 1000 - class_name.getValue();

用外行的话来说

假设我们需要存储此人的详细信息。此人具有姓名、年龄和性别字段。要做到这一点,需要创建姓名、年龄和性别的方法。现在,如果我们需要创建另一个人,就需要重新创建姓名、年龄和性别的方法。

我们可以使用getter和setter方法创建一个bean类(Person),而不是这样做。因此,明天我们只要在需要添加新人员时创建这个Bean类(Person类)的对象即可(见图)。因此,我们重用bean类的字段和方法,这要好得多。

其他回答

此外,这是为了“未来证明”你的课程。特别是,从字段更改为属性是ABI中断,因此如果您稍后决定需要更多的逻辑而不仅仅是“设置/获取字段”,那么您需要中断ABI,这当然会给针对您的类编译的任何其他内容带来问题。

原因有很多。我最喜欢的是当你需要改变行为或调整你可以设置的变量时。例如,假设您有一个setSpeed(intspeed)方法。但你希望你只能将最大速度设置为100。您可以执行以下操作:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

现在,如果代码中的每个地方都使用公共字段,然后意识到需要上述要求,该怎么办?寻找公共领域的每一种用法,而不仅仅是修改你的setter。

我的2美分:)

Getter和setter用于实现面向对象编程的两个基本方面,即:

抽象封装

假设我们有一个Employee类:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

与公共属性不同,全名的实现细节对用户隐藏,用户无法直接访问。

编辑:我回答这个问题是因为有很多学习编程的人都在问这个问题,大多数答案在技术上都很好,但如果你是新手,就不那么容易理解了。我们都是新手,所以我想我会尝试一个更适合新手的答案。

两个主要的是多态性和验证。即使它只是一个愚蠢的数据结构。

假设我们有一个简单的类:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

这是一个非常简单的类,它包含有多少液体,容量是多少(毫升)。

当我这样做时会发生什么:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

嗯,你不会指望这会奏效,对吧?你想进行某种理智检查。更糟糕的是,如果我从未指定最大容量呢?哦,亲爱的,我们有问题。

但也有另一个问题。如果瓶子只是一种容器呢?如果我们有几个容器,所有容器都有容量和液体量,会怎么样?如果我们能做一个接口,我们就可以让程序的其他部分接受这个接口,而瓶子、偷工减料和各种各样的东西就可以互换使用了。那不是更好吗?由于接口需要方法,这也是一件好事。

我们最终会得到这样的结果:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

太棒了现在我们把瓶子换成这个:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

我将把BottleOverflowException的定义作为练习留给读者。

现在请注意这是多么的强大。我们现在可以通过接受LiquidContainer而不是Bottle来处理代码中的任何类型的容器。这些瓶子是如何处理这种东西的呢。您可以有在磁盘发生变化时将其状态写入磁盘的瓶子,也可以有保存在SQL数据库或GNU知道其他内容的瓶子。

所有这些都可以有不同的方法来处理各种各样的百日咳。瓶子只是检查,如果它溢出,就会抛出RuntimeException。但这可能是错误的做法。(关于错误处理有一个很有用的讨论,但我有意保持非常简单。评论中的人可能会指出这种简单方法的缺点。;)

是的,我们似乎从一个非常简单的想法迅速得到更好的答案。

请注意,您不能更改瓶子的容量。它现在被镶嵌在石头上。您可以通过将int声明为final来实现这一点。但如果这是一个列表,你可以清空它,添加新的东西,等等。你不能限制接触内脏的权限。

还有第三件事不是每个人都解决过:getter和setter使用方法调用。这意味着它们看起来像其他地方的正常方法。DTO和其他东西没有奇怪的特定语法,而是到处都有相同的语法。

访问器和赋值器的一个优点是可以执行验证。

例如,如果foo是公共的,我可以很容易地将其设置为null,然后其他人可以尝试调用对象上的方法。但它已经不在了!使用setFoo方法,我可以确保foo从未设置为null。

访问器和赋值器也允许封装-如果你不应该在值设置后看到它(也许它在构造函数中设置,然后被方法使用,但不应该被更改),那么任何人都不会看到它。但如果您允许其他类查看或更改它,则可以提供适当的访问器和/或赋值器。