java 抽象类中的受保护数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3525765/
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-10-30 02:15:13  来源:igfitidea点击:

protected data in abstract class

javaabstractprotected

提问by cvsdave

My question involves specifically Java, abstract classes, and the use of protected data. I am being told that all the data should be private, and protected getters/setters used only.

我的问题特别涉及 Java、抽象类和受保护数据的使用。我被告知所有数据都应该是私有的,并且只使用受保护的 getter/setter。

Now, I understand we want to shield data from direct manipulation by casual users of the class, and that public data members in general are a questionable practice. I have looked at "Java protected fields vs public getters" ( Java protected fields vs public getters), but I still am dubious that:

现在,我明白我们想要保护数据免受类的临时用户的直接操作,并且公共数据成员通常是一种有问题的做法。我看过“Java protected fields vs public getters”(Java protected fields vs public getters),但我仍然怀疑:

protected int i;  

is worse in an abstract class than:

在抽象类中比:

private int i;  
protected int geti();  
protected void seti(int j); 

I am just not seeing the down side when the abstract class is there precisely to provide parent/common facility to the children classes, and the protected scope is meant to provide access to children, while protecting the data from casual users. I note in the question referenced above, that most of the answers seem to address the issue of why data in general should be private rather than public. I am trying to focus my question specifically on data existing in an abstract parent intended for use by the children. The sole reasonable comment I have heard to date is that using the parents protected data (e.g., int i above) leaves you with code in the child class that references a variable not declared in the child class. Less compelling is the argument (see Common protected data member in base class?) that you may want to change the access some day, and now you have to honor your interface. This is an abstract class, and is intended to be extended 100% of the time.

当抽象类正好为子类提供父类/公共设施时,我只是没有看到不利的一面,而受保护的范围旨在提供对子类的访问,同时保护数据免受临时用户的侵害。我在上面提到的问题中注意到,大多数答案似乎解决了为什么数据一般应该是私有的而不是公开的问题。我试图将我的问题专门集中在供孩子使用的抽象父级中存在的数据上。迄今为止,我听到的唯一合理的评论是,使用父类受保护的数据(例如,上面的 int i)会在子类中留下代码,这些代码引用了未在子类中声明的变量。这个论点不太引人注目(请参阅基类中的通用受保护数据成员?) 您可能希望有一天更改访问权限,现在您必须尊重您的界面。这是一个抽象类,旨在 100% 的时间进行扩展。

Thanks! Specific Title/page# references to books are far more helpful that references to "..any basic Java programming text..."

谢谢!对书籍的特定标题/页面# 引用比对“..任何基本的 Java 编程文本...”的引用更有帮助

========================================== 10-13-2010
This was as much a question about abstract classes as it is about protected data. I find it disappointing that the focus seems to have shifted in the responses to whether data hiding is a good thing in OOP (answer: yes). There's a lot of depth here involving the nature of the abstract class, and how it differs from a regular non-final class, and what possible advantages there might be for fixing the names and types of data-items in the abstract parent for use by the child classes. I think there is the possibility here for innovation and greater control being extended down from the abstract parent to the implementing child classes. I am concerned that general principles, such as the advantages of data-hiding, can become dogma, and inhibit innovation and the development of new patterns and ideas.

============================================ 10-13-2010
这是一个关于抽象类的问题,也是关于受保护数据的问题。我感到失望的是,焦点似乎已经转移到对数据隐藏在 OOP 中是否是一件好事的反应上(答案:是)。这里有很多深度涉及抽象类的性质,以及它与常规非最终类的区别,以及修复抽象父类中数据项的名称和类型以供使用的可能优势儿童班。我认为这里有可能将创新和更大的控制从抽象父类扩展到实现子类。我担心一般原则,例如数据隐藏的优势,可能会成为教条,并抑制创新和新模式和想法的发展。

Thanks to all who contributed.

感谢所有做出贡献的人。

回答by alex

If the field is private and access is through getters and setters, you will be able to reimplement getters and setters (for instance, dropping the field and updating/reading the value from an external source), and thus change how the "field" works without touching any child classes.

如果该字段是私有的并且通过 getter 和 setter 访问,您将能够重新实现 getter 和 setter(例如,删除该字段并从外部源更新/读取值),从而更改“字段”的工作方式不接触任何子类。

Whether this is worth it, that's up to you.

这是否值得,这取决于你。

回答by KeatsPeeks

Think of protected methods as an interfacefor subclasses, in the same way that public methods are an interface for everyone else.

将受保护的方法视为子类的接口,就像公共方法是其他所有人的接口一样。

Providing accessors enables the base class to maintain its state: there's no way a subclass would corrupt it without an intentional trick.

提供访问器使基类能够保持其状态:如果没有故意的伎俩,子类不可能破坏它。

回答by Skip Head

Having less access isn't a drawback, it's a benefit. Classes should always limit access to as much of their internal state as possible. Don't think of why internals should be hidden, instead think of why they should be exposed. In this case as in every case, unless there is a really good reason to expose the variable then don't expose it.

访问较少不是缺点,而是优点。类应该始终限制对尽可能多的内部状态的访问。不要去想为什么要隐藏内部,而要考虑为什么要暴露它们。在这种情况下,就像在任何情况下一样,除非有充分的理由公开变量,否则不要公开它。

回答by Rontologist

In Java protected members are accessible to all members in the same package in addition to any extending classes. Making the field private will prevent classes in the same package from directly accessing it.

在 Java 中,除了任何扩展类之外,受保护的成员还可以被同一包中的所有成员访问。将该字段设为私有将防止同一包中的类直接访问它。

As well there is the point that alex raised earlier.

还有一点是亚历克斯之前提出的。

回答by Colin Hebert

If you don't need your child to directlyaccess it, why would you let them ?

如果你不需要你的孩子直接访问它,你为什么要让他们?

It isn't a down side to use protected. But if it isn't necessary, maybe it's better to avoid it and control access on your fields.

使用protected 并不是坏事。但如果没有必要,也许最好避免它并控制对您的字段的访问。

回答by Serplat

If someone subclasses your class, and puts the subclass in the same package as your current class, they may want to override your getters and setters. For example, they wantto make sure that imay only be set to a value greater than 1.

如果有人对您的类进行子类化,并将子类与您当前的类放在同一个包中,他们可能想要覆盖您的 getter 和 setter。例如,他们想确保i只能将其设置为大于 1 的值。

Other than that, it's really up to you. The convention is that there are getters and setters for everything though.

除此之外,这真的取决于你。惯例是,所有东西都有 getter 和 setter。

回答by Andy Thomas

Information hiding is valuable, even among classes related by inheritance.

信息隐藏很有价值,即使在通过继承相关的类之间也是如此。

In addition to allowing re-implementation, as noted by alex above:

除了允许重新实现之外,正如上面的 alex 所指出的:

  • You can set breakpoints in methods.
  • You can add constraints in one place.
  • 您可以在方法中设置断点。
  • 您可以在一处添加约束。

回答by BlindWanderer

You want to use getters/setters because using protected int i;allows for field overriding (which you want to avoid at all costs).

您想使用 getter/setter,因为 usingprotected int i;允许字段覆盖(您想不惜一切代价避免)。

You want to disallow field overriding because it works differently than method overriding. Field overriding does not make the overridden field inaccessible (the type of the reference determines which instance of the field you are working with).

您希望禁止字段覆盖,因为它的工作方式与方法覆盖不同。字段覆盖不会使覆盖的字段不可访问(引用类型决定了您正在使用的字段实例)。

Accessible fields should be final or in a class that is final.

可访问的字段应该是最终的或在最终的类中。

public class OverridingFun {
    public static class Base {
        public int i = 1;
        public int getI(){ return i; }
    }
    public static class A extends Base {
        public int i = 2;
        public int getI(){ return i; }
    }
    public static class B extends A {
        public int i = 3;
        public int getI(){ return i; }
    }
    public static void main(String [] args){
        B b = new B();
        A bAsA = b;
        Base bAsBase = b;

        System.out.println(b.getI());//3
        System.out.println(bAsA.getI());//3
        System.out.println(bAsBase.getI());//3

        System.out.println(b.i);//3
        System.out.println(bAsA.i);//2
        System.out.println(bAsBase.i);//1

        b.i = 4;
        bAsA.i = 5;
        bAsBase.i = 6;

        System.out.println(b.i);//4
        System.out.println(bAsA.i);//5
        System.out.println(bAsBase.i);//6
    }
}

At first glance this looks like something that would just make code hard to read but it has implications on functionality. Say the field does get overridden by a derived class, since setters are not being used, there is no way to automagically update the base field and no way to detect if someone has changed the base field (since the base value is still accessible) and update the derived field. It's easy to imagine that the base and derived states could get out of sync and that the errors would be hard to track down. Simply put it makes for a very brittle API.

乍一看,这看起来只会使代码难以阅读,但它对功能有影响。假设该字段确实被派生类覆盖,因为没有使用 setter,所以无法自动更新基字段,也无法检测是否有人更改了基字段(因为基值仍然可以访问)和更新派生字段。很容易想象,基础状态和派生状态可能会不同步,并且很难追踪错误。简单地说,它使 API 变得非常脆弱。

Unfortunately there is no way to guard against this since the finalkeyword, which protects against overriding, also makes fields write-once. So no writable non-overloadable fields.

不幸的是,没有办法防止这种情况发生final,因为防止覆盖的关键字也使字段只写一次。所以没有可写的不可重载字段。

Personally I'm rather surprised the language designers allowed field overriding at all. The advantage of using setters is that each level can guaranty the integrity of it's own state and trust that derived classes haven't fouled it up. Field overriding is just asking for trouble.

就我个人而言,我对语言设计者竟然允许字段覆盖感到惊讶。使用 setter 的好处是每个级别都可以保证它自己状态的完整性,并且相信派生类没有弄乱它。字段覆盖只是自找麻烦。