关于java:getter和setter有什么意义?

What is the point of getters and setters?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why use getters and setters?

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

1
2
3
4
5
6
7
public int getX(){
    return x;
}

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

但是有什么区别呢

1
...(shape.x)...   // basically getX()

1
shape.x = 90;    // basically setX()

如果二传手和getter更好,你能给我解释一下会出现什么实际问题吗?


多种原因:

  • 如果你允许像

    形状:x=90

然后您就不能在将来添加任何逻辑来验证数据。

如果x不能小于100,就不能这样做,但是如果有

1
2
3
4
5
public void setShapeValue(int shapeValue){
  if(shapeValue < 100){
    //do something here like throw exception.
  }
}
  • 不能添加类似copy-on-write逻辑的内容(请参阅copyonwritearraylist)
  • 另一个原因是访问类外部的字段时,您必须将它们标记为公共、受保护或默认,这样您就失去了控制。当数据非常内部的破类封装和一般的OOPS方法。

但是对于常量来说

1
public final String SOMETHING ="SOMETHING";

您将允许字段访问,因为它们不能被更改,例如变量,您将把它们与getter、setter放在一起。

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

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

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


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

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

变异函数包封


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

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

复数可以用实部和虚部写在a + bi的形式上,很好地借给[gs]etRealPart[gs]etImaginaryPart

然而,在某些情况下,很容易解释极性形式re^(iθ)上的复数,给出[gs]etRadius[gs]etAngleθ。

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

这两种形式是可以互换的;您可以很容易地从一种形式转换到另一种形式,因此类用于内部存储的哪种形式与该类的使用者无关。然而,消费者可以使用任何一种形式。如果您选择a+bi形式作为内部表示,并使用字段而不是getter和setter公开这一点,那么您不仅要强制类使用者使用该形式,而且以后也不能轻易地改变主意,并用re^(iθ)替换内部表示,因为这更容易在特定的sc中实现。埃纳里奥您坚持使用您定义的公共API,它要求使用特定字段名公开真实和虚拟部分。


下面的例子可以理解用户getter和setter的另一个好理由。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestGetterSetter{
    private String name ;


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


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

getter和setter的要点是,只有它们被用来访问它们正在获取或设置的私有变量。通过这种方式,您可以提供封装,稍后重构或修改代码将更容易。

假设您使用名称而不是getter。然后,如果您想添加一些类似于默认值的内容(如果以前没有设置默认名称,那么就说默认名称是"guest"),那么您必须同时修改getter和say name函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestGetterSetter{
    private String name ;


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


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

getter和setter不需要从get和set开始——它们只是普通的成员函数。但这是一个惯例。(特别是如果使用Java bean)


对于getter和setter,我能想到的最好的原因之一是类的API的持久性。在类似于Python的语言中,您可以通过成员的名称访问成员,并在以后将其切换到方法。因为函数一旦在Java中访问成员,它的行为就不同于Java中的成员。限制其作用域以后会破坏客户端。

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


最初,getter/setter模式是由encapsulating创建的,以促进良好的面向对象设计,class的内部从其外部interface开始。

  • 隐藏属性的内部表示形式

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


假设你找到了一个图书馆,它能更好地处理你在自己班上所做的事情(你的屁股)。在这一点上要做的自然的事情是使您的类成为该库的包装器接口。它仍然有一个"x"的概念,您的客户机代码需要获取或设置它。当然,此时您几乎必须编写访问函数。

如果您忽略了使用访问函数,并且让客户机代码直接访问yourclass.x,那么现在您必须重写所有曾经接触过您rclass.x的客户机代码。但是,如果您从一开始就使用yourclass.getx()和yourclass.setx(),那么您只需要重写自己的类。

编程的一个关键概念,尤其是面向对象编程,是隐藏实现细节,这样其他类或模块中的代码就不会直接使用它们。这样,如果您更改了实现细节(如上面的示例中所示),客户机代码就不知道区别,也不需要修改。尽管您的客户机代码知道,"x"可能是一个变量,也可能是一个动态计算的值。

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


在回答之前,我们必须先知道一些事情…!"JavaBeansJavaBeans是具有属性的Java类。出于我们的目的,将属性视为私有实例变量。因为它们是私有的,所以只有这样才能访问它们从类的外部通过类中的"方法"。更改属性值的方法称为setter方法,检索属性值的方法称为getter方法。


原因很多。这里只有一些。

  • 访问器,尤其是getter,经常出现在接口中。不能在接口中规定成员变量。
  • 一旦公开了这个成员变量,就不能改变对它实现方式的看法。例如,如果您看到以后需要切换到模式化聚合,而您希望"x"属性实际上来自某个嵌套对象,则最终必须复制该值并尝试保持同步。不好的。
  • 大多数时候,你最好不要暴露二传手。对于X这样的公共字段,您不能这样做。

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

    形状X

    是不对的。采用getter和setter方法获取和设置x值,实现封装。


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

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


    这是通过应用OOP的封装原理来实现的。

    A language mechanism for restricting access to some of the object's components.

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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++;
        }
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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));
        }
    }

    我会说getter/setter和public成员都不是好的面向对象设计。它们都通过向世界公开对象数据来破坏OOP封装,而这些数据可能一开始就不应该访问对象的属性。