更好的做法和原因是:通过受保护字段或私有字段上的公共getter访问基类变量。
(无论如何,吸气者都会公开)
答案 0 :(得分:60)
如果无论如何都会有一个公众的吸气者,你为什么要比绝对必要的更广泛地揭露这个领域呢?这意味着它可以立即由子类写入(除非它是最后的开头)。
我个人认为我的所有字段都是私有的:它提供了API和实现之间更清晰的分离。我认为超类和子类之间的关系类似于调用者和被调用者的关系 - 对底层实现的更改不应该破坏子类,而不应该破坏调用者。字段的名称是一个实现细节,不应影响其他类。
不可否认,我的观点偶尔会被视为极端......
答案 1 :(得分:16)
您应该始终针对类的公共API进行编程,即使用公共方法。
原因很简单。将来的某一天,您或其他人可能希望更改实施。这应该总是可行的。如果依赖实例变量,则限制自己。
此外,在访问变量时,您无法控制该变量是否为只读,也不能在更改此变量时添加检查。
如果您使用setter / getters,您可以继续添加验证,稍后检查等。您也可以只提供一个getter来使变量只读。
答案 2 :(得分:10)
不首选直接现场访问。使用public
或protected
设置者和获取者。
getter不一定是public
- 如果你想隐藏“外人”中的数据,但是将数据提供给子类,请使用protected
答案 3 :(得分:5)
Sun关于控制字段访问的一些建议是here.请注意,保护字段也会将其暴露给包,而不仅仅是子类。一般来说,如上面的链接所述,除非有充分的理由不这样做,否则字段应该是私有的。
答案 4 :(得分:5)
Effective Java 2nd Edition说
第13项:尽量减少班级和成员的可访问性
经验法则很简单:让每个班级或成员都无法访问 可能。换句话说,使用与之一致的最低可能访问级别 正在编写的软件正常运行。
因此,如果您不确定为什么需要受保护的类成员(即,您不需要在同一个包中可以访问子类或类的字段),那么将其声明为private。如果您希望从课外设置它,那么请创建一个公共设置器。
但是,如果您的成员是最终成员,那么在某些情况下保护它可能是正常的(即它不会泄露敏感信息)。
我想提一个潜在的安全问题是,如果你有一个数组声明受保护的final(甚至是public final),那么数组引用是final(无法修改),但数组中保存的对象不是final(入侵者可以改变数组内容。
如果您了解c ++,您可能知道
const int * someMember
与
不同 int * const someMember
后者就像是java中的最终数组。
上述安全漏洞的修复方法是返回数组的深层副本或将其作为只读列表返回。
答案 5 :(得分:1)
通常,您应该使用Sun的建议。有一个很大的例外:如果您正在为Android编程。
原因是表现。对于每个虚方法调用,使用查找表将方法路由到其对象都会产生开销。访问本地变量时不涉及此开销。
以下是一些可以更深入地解释这一点的链接:
http://developer.android.com/training/articles/perf-tips.html#GettersSetters
http://blog.leocad.io/why-you-shouldnt-use-getters-and-setters-on-android/
了解您要完成的任务非常重要:
在简单的Java中,getter和setter完成这两项任务。但Android不同。如果你正在做#1,那么你应该使用公共getter和setter。如果你正在做#2,那么你应该使用受保护的字段。如果您同时使用它们,请使用两者。
答案 6 :(得分:1)
我想向您介绍一些保护Java中“受保护”字段的参数: “在需要避免价值验证的情况下,与公共访问器相比,您可能更喜欢使用受保护的字段来访问基类成员”。 但是,如果不是这种情况,则应使用具有公共访问器的私有字段来补充隐喻。
getter和setter的原理是对输入和输出到类成员的值进行验证。但是,在OOP语言中,我们对对象而非类进行操作。基类和专用类代表一个对象,这就是为什么在受保护的字段上访问特定的类成员是完全可以的。
考虑以下有关汽车的抽象示例: -您有一个基类 Car 和一个派生类 Porshe 。 - Car 类可能具有类似于 engine 的字段,该字段未在Cars构造函数中设置(可能只有在对象初始化后才知道引擎的类型) -您创建一个 Porshe 类对象,该对象包含一些用于使用某些外部数据计算 engine 类型的逻辑。
在此示例中,预计 engine 字段具有公共获取者,因此汽车用户知道汽车拥有的发动机。但是,由于我们希望汽车驾驶员不要对发动机发脾气,因此没有公众的二传手!因此,将 engine 设置为受保护的字段是完全可以的,因此 Porshe 类可以在将来的某个时间设置其值。
是的,有些人可能会说“然后使用受保护的二传手!”。 我将重复一遍:在OOP语言中,我们使用的对象不是类。 单一责任原则-是的,但作为对象而不是类。 如果您说:“在某些时候,如果我们使用超过3或5个继承级别的受保护字段,那么如果每个类都对其执行某些操作,则难以理解该字段会发生什么情况”。然后我回答:这是另一种反模式-您的对象此时可能太大,并且使“单一责任”原则无效。
答案 7 :(得分:0)
从子类访问受保护的字段是继承违反封装的方法之一。因此,使用公共API更好。