80

可能重复:
为什么要使用 getter 和 setter?

我读过有关 Java 的书籍,说为变量创建 setter 和 getter 是很好的,例如xy. 例如:

public int getX(){
    return x;
}

public void setX(int x){
    this.x = x;
}

但这和那有什么区别?

...(shape.x)...   // Basically getX()

shape.x = 90;    // Basically setX()

如果 setter 和 getter 更好,会出现什么实际问题?

4

13 回答 13

87

多种原因:

  • 如果您允许字段访问,例​​如

    形状.x = 90

那么您以后不能添加任何逻辑来验证数据。

说如果 x 不能小于 100 你不能这样做,但是如果你有像这样的二传手

public void setShapeValue(int shapeValue){
  if(shapeValue < 100){
    //do something here like throw exception.
  }
}
  • 您不能在写入逻辑上添加类似复制的内容(请参阅CopyOnWriteArrayList
  • 另一个原因是要访问类之外的字段,您必须将它们标记为公共、受保护或默认,因此您失去了控制权。当数据在打破类封装和一般OOPS方法的内部非常重要时。

虽然对于像这样的常量

public final String SOMETHING = "SOMETHING";

您将允许字段访问,因为它们无法更改,例如变量,您将它们与 getter、setter 一起放置。

  • 另一种情况是,当您希望您的类是不可变的时,如果您允许字段访问,那么您将破坏您的类的不可变性,因为值可以更改。但是,如果你用 getter 和没有 setter 仔细设计你的类,你就可以保持不变性。

尽管在这种情况下,您必须在 getter 方法中小心,以确保您不会给出对象的引用(以防您的类将对象作为实例)。

我们可以使用 getter 和 setter 在任何包中使用私有变量。

于 2012-05-02T04:54:29.947 回答
12

使用 getter 和 setter 函数允许约束和封装。可以说x是半径。shape.x = -10 没有多大意义。此外,如果有人试图设置非法值,您可以打印错误、设置默认值或什么也不做。

将成员变量设为私有是一种很好的做法,这样它们就不能被使用它们的程序直接修改。

突变函数
封装

于 2012-05-02T04:51:41.970 回答
6

很多人提到封装实现的细节,对我来说这是在类中使用 getter 和 setter 的最大原因。有了这个,您还可以获得许多其他好处,包括能够随心所欲地抛弃和替换实现,而无需触及使用您的类的每一段代码。在一个小项目中,这不是一个很大的好处,但如果您的代码最终成为一个使用良好的(内部或公共)库,它可能是一个巨大的好处。

一个具体的例子:数学中的复数。有些语言将它们作为语言或框架功能,而另一些则没有。我将在这里使用一个可变类作为示​​例,但它也可以很容易地成为不可变的。

复数可以a + bi用实部和虚部写在表格上,非常适合[gs]etRealPart[gs]etImaginaryPart

然而,在某些情况下,在极坐标上更容易推理复数re^(iθ),给出[gs]etRadius(r) 和[gs]etAngle(θ)。

您还可以公开方法,如[gs]etComplexNumber(realPart, imaginaryPart)[gs]etComplexNumber(radius, angle)。根据参数类型,这些可能需要也可能不需要不同的名称,但是类的使用者可以根据需要使用其中任何一个。

这两种形式可以互换;您可以相当轻松地从一个转换到另一个,因此该类用于内部存储的形式与该类的消费者无关。但是,消费者可以使用任何一种形式。如果您选择 a+bi 作为内部表示形式,并使用字段而不是 getter 和 setter 来公开它,那么您不仅会强制类消费者使用该形式,而且以后也不能轻易改变主意并将内部表示替换为re^(iθ) 因为这在您的特定场景中更容易实现。你被你定义的公共 API 卡住了,它要求使用特定的字段名称来公开实部和虚部。

于 2012-05-02T08:37:41.527 回答
4

我能想到的关于 getter 和 setter 的最好理由之一是类 API 的持久性。在像 python 这样的语言中,您可以通过成员的名称访问成员并稍后将它们切换到方法。因为一旦你访问了一个属性,函数的行为就与 java 中的成员不同。稍后限制其范围会破坏客户端。

通过提供 getter 和 setter,程序员可以灵活地自由修改成员和行为,只要遵守公共 API 描述的合同。

于 2012-05-02T05:06:54.910 回答
4

用户的另一个很好的理由gettersetter可以通过以下示例来理解

public class TestGetterSetter{
    private String name ;


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


    public String getName(){
        return this.name ;
    }
}

getter 和 setter 的要点是,只有它们才能用于访问它们正在获取或设置的私有变量。这样您就可以提供封装,以后重构或修改代码会容易得多。

想象一下,您使用 name 而不是它的getter. 然后,如果您想添加类似默认值的内容(例如,如果之前未设置默认名称为“Guest”),那么您必须同时修改 thegettersayName函数。

public class TestGetterSetter{
    private String name ;


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


    public String getName(){
        if (this.name == null ){
            setName("Guest");
        }
        return this.name ;
    }
}

getter 和 setter 不需要以 get 和 set 开头——它们只是普通的成员函数。然而,这样做是一个惯例。(特别是如果您使用 Java Beans)

于 2012-05-02T05:18:08.750 回答
3

假设,假设您找到了一个库,该库可以更好地完成您在自己的班级(YourClass)中所做的工作。此时要做的自然的事情是使 YourClass 成为该库的包装器接口。它仍然具有您的客户端代码需要获取或设置的“X”概念。自然,此时您几乎必须编写访问器函数。

如果您忽略了使用访问器函数并让您的客户端代码直接访问 YourClass.x,那么您现在将不得不重写您曾经接触过 YourClass.x 的所有客户端代码。但是如果你从一开始就使用 YourClass.getX() 和 YourClass.setX(),你只需要重写 YourClass。

编程的关键概念之一,尤其是面向对象的编程,是隐藏实现细节,这样它们就不会被其他类或模块中的代码直接使用。这样,如果您更改了实现细节(如上面的示例),客户端代码不知道差异,也不必修改。你的客户端代码都知道,“x”可能是一个变量,也可能是一个动态计算的值。

这是一种过度简化,并没有涵盖隐藏实现有益的所有场景,但它是最明显的例子。隐藏实现细节的概念现在与 OOP 紧密相关,但你可以找到关于它的讨论可以追溯到 OOP 出现之前的几十年。它回到软件开发的核心概念之一,就是把一个模糊的大问题,分解成易于解决的、定义明确的小问题。访问器函数有助于使您的小子任务保持分离和明确定义:您的类对彼此内部的了解越少越好。

于 2012-05-02T05:07:08.273 回答
3

encapsulating最初,创建 getter/setter 模式是为了通过a 的内部class从其外部促进良好的面向对象设计interface

  • 隐藏属性的内部表示

这是您问题的最佳答案为什么使用getter和setter?

于 2012-05-02T05:20:31.760 回答
1

有很多原因。这里仅仅是少数。

  1. 访问器,尤其是 getter,经常出现在接口中。您不能在接口中规定成员变量。
  2. 一旦你公开了这个成员变量,你就无法改变它是如何实现的。例如,如果您稍后发现需要切换到聚合之类的模式,您希望“x”属性实际上来自某个嵌套对象,那么您最终必须复制该值并尝试使其保持同步。不好。
  3. 大多数时候你最好不要暴露二传手。你不能用像 x 这样的公共字段来做到这一点。
于 2012-05-02T04:54:16.650 回答
1

在得到答案之前,我们必须先知道一些事情......!“ JavaBeans ”。
JavaBean 是具有属性的 java 类。出于我们的目的,将属性视为私有实例变量。由于它们是私有的,因此可以从类外部访问它们的唯一方法是通过类中的“方法”。
更改属性值的方法称为setter 方法,检索属性值的方法称为getter 方法

于 2012-05-02T04:57:37.230 回答
0

我会说 getter/setter 和公共成员都不是好的面向对象设计。它们都通过将对象数据暴露给可能不应该首先访问对象属性的世界来打破 OOP 封装。

于 2012-05-02T04:56:21.263 回答
0

这是通过应用 OOP 的封装原理来完成的。

一种语言机制,用于限制对某些对象组件的访问。

这意味着,您必须定义类的属性和方法的可见性。有 3 种常见的可见性:

  • 私有:只有类可以看到和使用属性/方法。
  • 受保护:只有类及其子类可以看到和使用属性/方法。
  • 公共:每个类都可以看到和使用属性/方法。

当您声明私有/受保护属性时,我们鼓励您创建获取值(get)和更改值(set)的方法。关于可见性的一个例子是[ArrayList][2]类:它有一个size属性可以知道内部数组的实际大小。只有类必须更改其值,因此代码类似于

public class ArrayList<E> {
    private int size;
    private Object[] array;
    public getSize() {
        return this.size;
    }
    public void add(E element) {
        //logic to add the element in the array...
        this.size++;
    }
}

在此示例中,您可以看到大小值只能在类方法内部更改,您可以通过在代码中调用它(而不是改变它)来获取实际大小:

public void someMethod() {
    List<String> ls = new ArrayList<String>();
    //adding values
    ls.add("Hello");
    ls.add("World");
    for(int i = 0; i < ls.size(); i++) {
        System.out.println(ls.get(i));
    }
}
于 2012-05-02T04:57:03.057 回答
0

Getter 和 setter 封装了类的字段,使它们只能通过其公共方法访问,并使值本身保持私有。这被认为是一个很好的 OO 原则。

当然,如果它只是设置或返回一个值,它通常看起来像是多余的代码。但是,setter 还允许您进行输入验证或清理。将它放在一个地方可以提高对象的数据完整性,

于 2012-05-02T04:57:03.157 回答
0

因为我们使用的是面向对象的编程语言。这里我们使用数据隐藏和封装。该变量不应从外部世界直接访问(用于实现数据隐藏),因此我们将其创建为私有的

形状.x

是不正确的。getter 和 setter 方法用于获取和设置 x 的值,这是实现封装的方式。

于 2012-05-02T05:06:11.827 回答