Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么要使用getter和setter/accessor?_Java_Oop_Setter_Getter_Abstraction - Fatal编程技术网

Java 为什么要使用getter和setter/accessor?

Java 为什么要使用getter和setter/accessor?,java,oop,setter,getter,abstraction,Java,Oop,Setter,Getter,Abstraction,使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处 如果getter和setter所做的不仅仅是简单的get/set,那么我可以很快地找出这一点,但我并不完全清楚如何: public String foo; 比以下情况更糟: private String foo; public void setFoo(String foo) { this.foo = foo; } public String getFoo() { return foo; } 而前者所需

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

如果getter和setter所做的不仅仅是简单的get/set,那么我可以很快地找出这一点,但我并不完全清楚如何:

public String foo;
比以下情况更糟:

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

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

因为从现在起两周(月、年)后,当您意识到您的setter需要做的不仅仅是设置值,您还将认识到,该属性已直接用于238个其他类:-)

访问器和变异器的一个优点是您可以执行验证

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


访问器和变异器也允许封装——如果您不希望在值设置之后看到它(可能它是在构造函数中设置的,然后由方法使用,但不希望更改),那么任何人都不会看到它。但是,如果您可以允许其他类查看或更改它,您可以提供适当的访问器和/或变体。

OO设计的基本原则之一:封装


它给您带来了许多好处,其中之一是您可以在幕后更改getter/setter的实现,但只要数据类型保持不变,任何具有该值的使用者都将继续工作。

使用不支持“属性”的语言(C++,Java)或者在将字段更改为属性(C#)时需要重新编译客户端,使用get/set方法更容易修改。例如,向setFoo方法添加验证逻辑不需要更改类的公共接口


在支持“真实”属性的语言中(Python、Ruby,可能是Smalltalk?),获取/设置方法是没有意义的。

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

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

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}
public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}
现在,如果您在代码中的任何地方都使用公共字段,然后您意识到您需要上述要求,该怎么办?找到公共字段的每一个用法,而不仅仅是修改你的setter


我的2美分:)

另一个用途(在支持属性的语言中)是setter和getter可以暗示操作是非平凡的。通常,您希望避免在属性中执行任何计算代价高昂的操作。

取决于您的语言。您将其标记为“面向对象”而不是“Java”,因此我想指出CHSSPy76的答案与语言有关。例如,在Python中,没有理由使用getter和setter。如果需要更改行为,可以使用属性,该属性围绕基本属性访问包装getter和setter。大概是这样的:

简单类(对象):
def_获取_值(自身):
返回self.\u值-1
定义设置值(自身、新值):
自身价值=新价值+1
def_del_值(自身):
self.old_value.append(self._value)
del self.\u值
值=属性(获取值、设置值、删除值)

到目前为止,我在回答中遗漏了一个方面,即访问规范:

  • 对于成员,设置和获取都只有一个访问规范
  • 对于setter和getter,您可以对其进行微调并单独定义

<强>实际上考虑使用访问器< /强>有很多很好的理由,而不是直接暴露类的字段——而不仅仅是封装的参数,并使将来的更改更容易。 以下是我知道的一些原因:

  • 封装与获取或设置属性相关的行为-这允许以后更容易添加其他功能(如验证)
  • 隐藏属性的内部表示,同时使用替代表示公开属性
  • 将公共接口与更改隔离—允许公共接口在实现更改时保持不变,而不会影响现有使用者
  • 控制属性的生命周期和内存管理(处置)语义-在非托管内存环境(如C++或ObjeVoC)中尤为重要。
  • 为属性在运行时更改提供调试截取点—在某些语言中,如果没有此功能,调试属性何时何地更改为特定值可能非常困难
  • 改进了与设计用于针对属性getter/setter进行操作的库的互操作性—想到了模拟、序列化和WPF
  • 允许继承者更改属性行为的语义,并通过重写getter/setter方法公开
  • 允许getter/setter作为lambda表达式而不是值传递
  • getter和setter可以允许不同的访问级别,例如get可能是公共的,但是set可以被保护

它对于延迟加载非常有用。假设所讨论的对象存储在数据库中,除非需要,否则您不想去获取它。如果对象由getter检索,则内部对象
person.name = "Joe";
int getVar() const { return var ; }
doSomething( obj->getVar() ) ;
doSomething( obj->var ) ;
int x = 1000 - 500
int x = 1000 - class_name.getValue();
public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}
0
0
4
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();
    }
}
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();
    }
 }
Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms
Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms
Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms