Java Setter and Getter

15

通常建议使用getter/setter来访问私有变量。但是,如果将它们声明为公共的并直接访问它们,是否更好呢?毕竟我们仍然使用getter和setter访问它们呢?

7个回答

19

封装。

隐藏内部状态并要求所有交互都通过对象的方法进行执行,这被称为数据封装——面向对象编程的基本原则。

另见:


+1 确切无误。也许稍后可以进行缓存。 - Amir Raminfar
对于私有原始类型、字符串或文件,然后使用公共Getter/Setter对来设置值的情况,我无法看到封装的存在。您正在暴露一个类型化的承诺来更改成员的状态;您可以同样地暴露类型化的成员本身。我认为仅在您编写的代码针对自己无法控制的API时,Getter/Setter封装才会增加价值;否则,请保持简单。 - Lumi

12

@mre的回答很棒,而你的问题是基础的。总结一下:将对象的字段设置为私有可以控制其他对象对其使用方式。您的对象使用setter来:

  • 限制和验证传递给setter的数据
  • 隐藏其内部数据结构(其他对象感兴趣的是服务而不是如何构建服务,这也可能包括优化)
  • 在每个状态下保持其完整性(必要时更改其他字段)

它将使用getter来

  • 按客户端所需的格式输出数据
  • 控制一系列服务的顺序(例如,只有在已建立连接的情况下才提供数据)

欢迎来到面向对象编程的奇妙世界和结构化编程的魔力。

Stéphane


2
如果您将字段设置为私有并为其设置setter/getter,那么您是否仍然将字段暴露给类外的其他内容?这些字段也可以通过setter和getter进行修改...那么为什么将其设置为私有并具有setter/getter会更好地保护它呢? - Glide
在设置器中,您的参数与内部数据结构之间没有任何关系的义务。您可以有一个需要字符串并存储整数的设置器。重点是您可以在将新值存储在字段中之前验证它们。使用getter,人们可以获取您的字段之一的引用并稍后更改它。如果您担心这一点,那么再次强调,没有必要返回您的真实字段,这可以是字段的副本或不可变视图。 - Snicolas

11

以上所有答案都很好,但是我想再补充一点。

你不希望所有的私有变量都拥有公共的getter和setter方法。

你的getter和setter方法指的是外部可见状态。在某些情况下,看起来像一个单一对象在你的公共方法中发布,实际上对应于多个内部私有变量的实现。在一个复杂的对象中,许多私有变量不会映射到任何外部可见的东西。有些人自动为它们编写setter和getter方法,但这是一个坏主意,因为它会暴露你的实现细节。


7

我一直听说IT技术中的主要原因之一是尝试规划未来的变化。它可能最初只是一个简单的

public int getInt() { return _someInt;}

但可能最终变成
public int getInt() { 
  // do some processing
  return _someInt;

这样做可以避免你在访问公共属性时不必进行大量更改,而是使用getter/setter。


5
通常情况下,setter 允许您对分配给私有成员的值的类型进行限制。所以可能不允许使用负值等等。
getter 允许消费者访问该成员的值,因为你已经将其设置为私有变量基于上述原因。

2
更一般地说,任何与获取或设置值相关的行为(验证、触发其他操作等)都可以添加到getter或setter中,而不会破坏接口兼容性。如果使用字段,则必须更改接口以添加行为。 - Chris Shain

4
所有其他答案都很好并且非常正确。以下是我发现它有用的另一个原因。
在对象上使用getter和setter是遵循JavaBean约定的最大部分。虽然完全遵循它通常很困难并且过度,但至少许多第三方框架/库/表达式语言依赖于getter和setter约定来访问对象的字段。如果您一开始就遵循它,那么您可以立即使用这些其他非常有用的库来使用对象,而无需更新对象。
我使用的示例包括:
Jsp Freemarker jXls Spring(尽管Spring非常强大,您不必遵循约定) SpEL(实际上任何表达式语言)

1

我经常使用getter和setter,但显然我们并没有做对。例如:(来自http://java.dzone.com/articles/java-properties-without

使用getter和setter(非常冗长的方式)

public class Teacher {

 @Id @Column(length=5) @Required 
 private String id;

 @Column(length=40) @Required
 private String name;

 @OneToMany(mappedBy="teacher")
 private Collection pupils;

 public String getId() {
     return id;
 }

 public void setId(String id) {
     this.id = id;
 }

 public String getName() {
     return name;
 }

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

 public Collection getPupils() {
     return pupils;
 }

 public void setPupils(Collection pupils) {
     this.pupils = pupils;
 }

}

公共的:(只有13行,包括空行)。

@Entity
public class Teacher {

 @Id @Column(length=5) @Required 
 public String id;

 @Column(length=40) @Required
 public String name;

 @OneToMany(mappedBy="teacher")
 public Collection pupils;

}

使用getter和setter进行调用(不是非常清晰,但C#使其更清晰)。

teacher.setName("M. Carmen");
String result = teacher.getName();

调用公共方法(直接和干净)。

teacher.name = "M. Carmen";
String result = teacher.name;

一个方法是冗长而且会增加更多代码(而代码在工作时间和处理时间上代价高),而另一个方法则更加直接。
在某些情况下,必须使用setter和getter方法,但如果不是必须的话,我认为默认情况下使用它有点过度。

不错的文章。但是,如果你仔细阅读它,你会发现为了让这个成为 getters/setters 的好替代品,你需要在你的项目中包含一些 aspectJ 代码并使用 aspectJ 编译器...此外,你将失去与大多数第三方框架的可移植性。 - grinch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接