Java 保护字段与公共 getter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2279662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 05:37:13  来源:igfitidea点击:

Java protected fields vs public getters

java

提问by DD.

What is better practise and why: accessing base class variables through a protected field or a public getter on the private field.

什么是更好的做法以及为什么:通过受保护的字段或私有字段上的公共 getter 访问基类变量。

(The getter will be public regardless)

(无论如何,getter 将是公开的)

采纳答案by Jon Skeet

If there's going to be a public getter anyway, why would you want to expose the field itself more widely than absolutely necessary? That means it's immediately writable by subclasses (unless it's final to start with).

如果无论如何都会有一个公共吸气剂,为什么你要比绝对必要的更广泛地公开这个领域本身?这意味着它可以立即被子类写入(除非它是最终的)。

Personally I like all my fields to be private: it provides a cleaner separation between API and implementation. I regard the relationship between a superclass and a subclass as similar to that of a caller and callee - changes to the underlying implementation shouldn't break subclasses any more than they should break callers. The name of a field is an implementation detail which shouldn't impact other classes.

我个人喜欢我的所有字段都是私有的:它在 API 和实现之间提供了更清晰的分离。我认为超类和子类之间的关系类似于调用者和被调用者的关系 - 对底层实现的更改不应该破坏子类,就像它们不应该破坏调用者一样。字段的名称是一个实现细节,不应影响其他类。

Admittedly my view is occasionally seen as somewhat extreme...

诚然,我的观点偶尔会被视为有些极端......

回答by Bozho

Direct field access is not preferred. Use publicor protectedsetters and getters.

直接现场访问不是首选。使用publicprotectedsetter 和 getter。

The getter need not be public- if you wan to hide the data from "outsiders", but give the data to subclasses, use protected

getter 不一定是public- 如果您想对“局外人”隐藏数据,但将数据提供给子类,请使用protected

回答by phisch

You should always program against the public API of a class, that is, use the public methods.

您应该始终针对类的公共 API 进行编程,即使用公共方法。

The reason is simple. Someday in the future, you or someone else might want to change the implementation. This should always be possible. If you rely on instance variable, you limit yourself.

原因很简单。在未来的某一天,您或其他人可能想要更改实现。这应该总是可能的。如果你依赖实例变量,你就会限制自己。

Also, when accessing the variable, you can not control if that variable is read-only nor can you add checks when this variable is changed.

此外,在访问变量时,您无法控制该变量是否为只读,也无法在更改此变量时添加检查。

If you use setters/getters, you can allways add validation, checking etc later on. You can also only provide a getter to make a variable read only.

如果您使用 setter/getter,您可以随时添加验证、检查等。您也可以只提供一个 getter 来使变量只读。

回答by Feanor

Some of Sun's recommendations on controlling access to fields are here.Note that making a field protected exposes it to the package as well, not only to subclasses. Generally, as stated at the link above, fields should be private unless there is a very good reason not to do so.

Sun 关于控制对字段的访问的一些建议在这里。请注意,使字段受保护也会将其公开给包,而不仅仅是对子类。通常,如上面的链接所述,字段应该是私有的,除非有很好的理由不这样做。

回答by Daniel

Accessing protected fields from a subclass is one of the ways that inheritance violates encapsulation. Using the public API is better for this reason.

从子类访问受保护的字段是继承违反封装的方式之一。出于这个原因,使用公共 API 会更好。

回答by Adrian

Effective Java 2nd Edition says

Effective Java 2nd Edition 说

Item 13: Minimize the accessibility of classes and members

The rule of thumb is simple: make each class or member as inaccessible as possible. In other words, use the lowest possible access level consistent with the proper functioning of the software that you are writing.

第 13 条:最小化类和成员的可访问性

经验法则很简单:使每个类或成员尽可能不可访问。换句话说,使用与您正在编写的软件的正常功能一致的尽可能低的访问级别。

So if you are not sure why you need a protected class member (ie you don't need the field to be accessible to subclasses or classes in the same package), then declare it private. If you wish to set it from outside the class, then make a public setter.

因此,如果您不确定为什么需要受保护的类成员(即您不需要该字段可被同一包中的子类或类访问),则将其声明为私有。如果您想从课堂外设置它,请创建一个公共设置器。

However, if your member is final, then making it protected might be ok in some cases (ie it doesn't reveal sensitive information).

但是,如果您的成员是最终成员,那么在某些情况下对其进行保护可能没问题(即它不会泄露敏感信息)。

One potential security issue I would like to mention is that if you have an array declared protected final (even public final), the array reference is final (cannot be modified), but the objects held in the array are not final (an intruder could change the array contents).

我想提到的一个潜在的安全问题是,如果您有一个声明为 protected final(甚至是 public final)的数组,则该数组引用是最终的(不能修改),但保存在数组中的对象不是最终的(入侵者可以更改数组内容)。



If you know c++, you probably know that

如果你知道 C++,你可能知道

const int * someMember

is different from

int * const someMember

const int * someMember

不同于

int * const someMember

The latter is like the final array in java.

后者就像java中的最终数组。



The fix for the aforementioned security hole is to return a deep copy of the array or return it as a read only list.

上述安全漏洞的修复方法是返回数组的深层副本或将其作为只读列表返回。

回答by Karl Giesing

Generally, you should use Sun's recommendations. There is one big exception: if you're programming for Android.

通常,您应该使用 Sun 的建议。有一个很大的例外:如果您正在为 Android 编程。

The reason is performance. With every virtual method invocation, there is overhead involved in using the lookup table to route the method to its object. This overhead is not involved when accessing a local variable.

原因是性能。对于每个虚拟方法调用,使用查找表将方法路由到其对象都会涉及开销。访问局部变量时不涉及此开销。

Here are some links that explain this in a little more depth:

以下是一些更深入地解释这一点的链接:

http://developer.android.com/training/articles/perf-tips.html#GettersSetters

http://developer.android.com/training/articles/perf-tips.html#GettersSetters

http://blog.leocad.io/why-you-shouldnt-use-getters-and-setters-on-android/

http://blog.leocad.io/why-you-shouldnt-use-getters-and-setters-on-android/

It's important to know what you're trying to accomplish:

了解您要实现的目标很重要:

  1. The field's value should be accessible to client code, using a public interface.
  2. The field is meant to be used by subclasses.
  1. 客户端代码应该可以使用公共接口访问该字段的值。
  2. 该字段旨在供子类使用。

In plain ol' Java, getters and setters accomplish both tasks. But Android is different. If you're doing #1, then you should use public getters and setters. If you're doing #2, then you should use protected fields. If you're doing both, use both.

在普通的 Java 中,getter 和 setter 可以完成这两项任务。但安卓不一样。如果你在做 #1,那么你应该使用公共 getter 和 setter。如果你在做 #2,那么你应该使用受保护的字段。如果两者都使用,请同时使用。

回答by Andrey Borisovich

I would like to present you with some arguments protecting "protected" fields in Java: "You may favor accessing base class members using protected fields over public accessors in situation where you need to avoid value validation". However if this is not the case, then private fields with public accessors should be used, to compliment hermetization.

我想向您展示一些保护 Java 中“受保护”字段的参数:“在需要避免值验证的情况下,您可能更喜欢使用受保护字段而不是公共访问器来访问基类成员”。但是,如果情况并非如此,则应使用具有公共访问器的私有字段来补充密封。

The principle of getters and setters is to provide validation to the values inputted and outputted to the class member. However, in OOP languages, we operate on objects not classes. Base class and specialized class represent a single object, that is why it is perfectly fine to access specific class members over protected field.

getter 和 setter 的原理是为类成员输入和输出的值提供验证。然而,在 OOP 语言中,我们操作的是对象而不是类。基类和专用类代表单个对象,这就是为什么通过受保护的字段访问特定类成员是完全没问题的。

Consider the following abstract example with a car: - you have a base class Carand the derived class Porshe. - Carclass may have field like engine, which value is not set in Cars constructor (maybe the type of engine is known only after object initialization) - You create a Porsheclass object that contains some logic used to calculate enginetype using some external data.

考虑以下带有汽车的抽象示例: - 您有一个基类Car和派生类Porshe。- Car类可能有像engine一样的字段,它的值没有在 Cars 构造函数中设置(也许引擎的类型只有在对象初始化后才知道) - 你创建一个Porshe类对象,它包含一些用于使用一些外部数据计算引擎类型的逻辑.

In this example, it is expected that enginefield has a public getter, so car users know what engine the car has. However, there is no public setter as we expect car drivers not to temper with the engine! That is why, it is perfectly fine to make enginea protected field, so the Porsheclass can set its value at some time in future.

在这个例子中,预计engine字段有一个公共的 getter,所以汽车用户知道汽车有什么引擎。但是,没有公共二传手,因为我们希望汽车司机不要对引擎进行调整!这就是为什么将engine 设置为受保护字段是完全没问题的,这样Porshe类可以在将来的某个时间设置它的值。

Yes, some people will probably say "then use protected setter!". And I will repeat: in OOP languages we work with objects not classes. Single responsibility principle - yes, but as object not as class. If you say: "at some point if we use protected fields over 3 or 5 inheritance levels, it may be troublesome to understand what happens to the field if each class performs some operation with it". And then I answer: That is another antipattern - your object is probably too big at this point and voids Single Responsibility principle.

是的,有些人可能会说“然后使用受保护的 setter!”。我将重复:在 OOP 语言中,我们使用对象而不是类。单一职责原则 - 是的,但作为对象而不是类。如果您说:“在某些时候,如果我们使用超过 3 或 5 个继承级别的受保护字段,如果每个类对其执行某些操作,那么理解该字段会发生什么可能会很麻烦”。然后我回答:这是另一种反模式——此时你的对象可能太大了,并且违背了单一职责原则。