简体   繁体   English

为什么我们不应该在 Java 中使用 protected static

[英]Why we should not use protected static in java

I was going through this question Is there a way to override class variables in Java?我正在研究这个问题有没有办法覆盖 Java 中的类变量? The first comment with 36 upvotes was:获得 36 票的第一条评论是:

If you ever see a protected static , run.如果您看到protected static ,请运行。

Can anyone explain why is a protected static frowned upon?谁能解释为什么protected static不受欢迎?

It's more a stylistic thing than a direct problem.这与其说是一个直接的问题,不如说是一个风格问题。 It suggests that you haven't properly thought through what is going on with the class.这表明你没有正确考虑课堂上发生的事情。

Think about what static means:想想static意味着什么:

This variable exists at class level, it does not exist separately for each instance and it does not have an independent existence in classes which extend me .这个变量存在于类级别,它不单独存在于每个实例中,并且它在扩展 me 的类中没有独立存在

Think about what protected means:想想protected意思:

This variable can be seen by this class, classes in the same package and classes which extend me .这个变量可以被这个类、同一个包中的类和扩展 me 的类看到。

The two meanings are not exactly mutually exclusive but it is pretty close.这两种含义并不完全相互排斥,但非常接近。

The only case I can see where you might use the two together is if you had an abstract class that was designed to be extended and the extending class could then modify the behavior using constants defined in the original.我可以看到您可以将两者一起使用的唯一情况是,如果您有一个旨在扩展的抽象类,然后扩展类可以使用原始类中定义的常量修改行为。 That sort of arrangement would most likely end up very messy though and indicates weakness in the design of the classes.不过,这种安排很可能最终会非常混乱,并表明类的设计存在弱点。

In most cases it would be better to have the constants as public since that just makes everything cleaner and allows the people sub-classing more flexibility.在大多数情况下,将常量设为公开会更好,因为这只会让一切变得更干净,并允许人们更灵活地进行子类化。 Quite apart from anything else in many cases composition is preferable to inheritance, while abstract classes force inheritance.在许多情况下,组合比继承更可取,而抽象类强制继承。

To see one example of how this could break things and to illustrate what I mean by the variable not having an independent existence try this example code:要查看这如何破坏事物的一个示例并说明我所说的变量不具有独立存在的含义,请尝试以下示例代码:

public class Program {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println(new Test2().getTest());
        Test.test = "changed";
        System.out.println(new Test2().getTest());
    }
}

abstract class Test {
    protected static String test = "test";
}

class Test2 extends Test {
    public String getTest() {
        return test;
    }
}

You will see the results:你会看到结果:

test
changed

Try it yourself at: https://ideone.com/KM8u8O亲自尝试: https : //ideone.com/KM8u8O

The class Test2 is able to access the static member test from Test without needing to qualify the name - but it does not inherit or get its own copy.Test2能够从Test访问静态成员test而无需限定名称 - 但它不会继承或获得自己的副本。 It is looking at the exact same object in memory.它正在查看内存中完全相同的对象。

It's frowned upon because it's contradictive.它不受欢迎,因为它是矛盾的。

Making a variable protected implies it will be used within the package or it will be inherited within a subclass .使变量protected意味着它将在包中使用或将在子类中继承

Making the variable static makes it a member of the class, eliminating the intentions of inheriting it .将变量static使其成为类的成员,从而消除了继承它的意图 This leaves only the intention of being used within a package , and we have package-private for that (no modifier).这只留下了在 package中使用的意图,我们有package-private为此(没有修饰符)。

The only situation I could find this useful for is if you were declaring a class that should be used to launch the application (like JavaFX's Application#launch , and only wanted to be able to launch from a subclass. If doing so, ensure the method is also final to disallow hiding . But this is not "the norm", and was probably implemented to prevent adding more complexity by adding a new way to launch applications.我发现这对唯一有用的情况是,如果您声明了一个应该用于启动应用程序的类(如 JavaFX 的Application#launch ,并且只希望能够从子类启动。如果这样做,请确保方法也是final禁止隐藏。但这不是“规范”,并且可能是为了通过添加启动应用程序的新方式来防止增加更多复杂性。

To see the access levels of each modifier, see this: The Java Tutorials - Controlling Access to Members of a Class要查看每个修饰符的访问级别,请参阅: Java 教程 - 控制对类成员的访问

I don't see a particular reason why this should be frowned upon.我看不出有什么特别的理由不赞成这样做。 There may always be alternatives to achieve the same behavior, and it will depend on the actual achitecture whether these alternatives are "better" than a protected static method or not.可能总是有实现相同行为的替代方案,并且这些替代方案是否比受保护的静态方法“更好”取决于实际架构。 But one example where a protected static method would be reasonable, at least, could be the following:但是,受保护的静态方法至少是合理的一个示例可能如下所示:

(Edited to split into separate packages, to make the use of protected clearer) (编辑拆分成单独的包,使protected的使用更清晰)

package a;
import java.util.List;

public abstract class BaseClass
{
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeDefaultB(list);
    }

    protected static Integer computeDefaultA(List<Integer> list)
    {
        return 12;
    }
    protected static Integer computeDefaultB(List<Integer> list)
    {
        return 34;
    }
}

Derived from that:从中得出:

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassA extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeOwnB(list);
    }

    private static Integer computeOwnB(List<Integer> list)
    {
        return 56;
    }
}

Another derived class:另一个派生类:

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassB extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeOwnA(list)+computeDefaultB(list);
    }

    private static Integer computeOwnA(List<Integer> list)
    {
        return 78;
    }
}

The protected static modifier can certainly be justified here: protected static修饰符在这里当然是合理的:

  • The methods can be static , because they do not depend on instance variables.方法可以是static ,因为它们不依赖于实例变量。 They are not intended to be used directly as a polymorphic method, but rather are "utility" methods that offer default implementations that are part of a more complex computation, and serve as "building blocks" of the actual implementation.它们不打算直接用作多态方法,而是提供默认实现的“实用”方法,这些默认实现是更复杂计算的一部分,并用作实际实现的“构建块”。
  • The methods should not be public , because they are an implementation detail.方法不应该是public ,因为它们是一个实现细节。 And they can't be private because they should be called by the extending classes.它们不能是private因为它们应该由扩展类调用。 They also can't have "default" visibility, because then they will not be accessible for the extending classes in other packages.它们也不能具有“默认”可见性,因为其他包中的扩展类将无法访问它们。

(EDIT: One could assume that the original comment only referred to fields , and not to methods - then, however, it was too general) (编辑:人们可以假设原始评论只提到fields ,而不是方法- 然而,它太笼统了)

静态成员不是继承的,和受保护成员只有子类可见(当然包含类的),所以一个protected static具有相同的可见性static ,这表明由编码器的误解。

Actually there is nothing fundamentally wrong with protected static .实际上, protected static没有什么根本性的错误。 If you really want a static variable or method that is visible for the package and all subclasses of the declaring class then go ahead and make it protected static .如果您真的想要一个对包和声明类的所有子类可见的静态变量或方法,请继续并使其protected static

Some people generally avoid to use protected for various reasons and some people think non-final static variables should be avoided by all means (I personally sympathize with the latter to some degree), so I guess the combination of protected and static must look bad^2 to those that belong to both groups.有些人出于各种原因一般都避免使用protected ,有些人认为非final的static变量应该尽量避免(我个人在某种程度上同情后者),所以我猜protectedstatic的结合一定很糟糕^ 2属于这两个组的那些。

Protected is used so that it can be used in subclasses.使用 Protected 以便它可以在子类中使用。 There is no logic in defining a protected static when using in the context of concrete classes as you can access the same variable is a static way.However the complier will give a warning to access the super class static variable in a static way.在具体类的上下文中使用时,定义受保护的静态没有逻辑,因为您可以以静态方式访问相同的变量。但是,编译器会警告以静态方式访问超类静态变量。

Well, as most of the people have answered:好吧,正如大多数人所回答的那样:

  • protected means - ' package-private + visibility to subclasses - the property/behaviour is INHERITED ' protected意思是 - '包私有 + 子类的可见性 - 属性/行为是继承的'
  • static means - ' the opposite of instance - it is a CLASS property/behaviour, ie it is NOT INHERITED ' static意味着 - '与实例相反 - 它是一个类属性/行为,即它不是继承的'

Therefore they are slightly contradictive and incompatible.因此,它们略有矛盾和不相容。

However, recently I came up to a use case where it might make sense to use these two together.但是,最近我想到了一个用例,其中将这两者结合使用可能是有意义的。 Imagine that you want to create an abstract class which is a parent for immutable types and it has a bunch of properties which are common to the subtypes.想象一下,你想创建一个abstract类,它是不可变类型的父类,它有一堆子类型共有的属性。 To implement immutability properly and keep readability one might decide to use the Builder pattern.为了正确实现不变性并保持可读性,人们可能会决定使用Builder模式。

package X;
public abstract class AbstractType {
    protected Object field1;
    protected Object field2;
    ...
    protected Object fieldN;

    protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
        private Object field1; // = some default value here
        private Object field2; // = some default value here
        ...
        private Object fieldN; // = some default value here

        public T field1(Object value) { this.field1 = value; return self();}
        public T field2(Object value) { this.field2 = value; return self();}
        ...
        public T fieldN(Object value) { this.fieldN = value; return self();}
        protected abstract T self(); // should always return this;
        public abstract AbstractType build();
    }

    private AbstractType(BaseBuilder<?> b) {
        this.field1 = b.field1;
        this.field2 = b.field2;
        ...
        this.fieldN = b.fieldN;
    }
}

And why protected static ?为什么要protected static Because I want a non-abstract subtype of AbstactType which implements its own non-abstract Builder and is located outside package X to be able to access and reuse the BaseBuilder .因为我想要一个AbstactType的非抽象子类型,它实现自己的非抽象 Builder 并且位于package X之外,以便能够访问和重用BaseBuilder

package Y;
public MyType1 extends AbstractType {
    private Object filedN1;

    public static class Builder extends AbstractType.BaseBuilder<Builder> {
        private Object fieldN1; // = some default value here

        public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
        @Override protected Builder self() { return this; }
        @Override public MyType build() { return new MyType(this); }
    }

    private MyType(Builder b) {
        super(b);
        this.fieldN1 = b.fieldN1;
    }
}

Of course we can make the BaseBuilder public but then we come to another contradictory statements:当然,我们可以将BaseBuilder公之于众,但随后我们又得出了另一个矛盾的陈述:

  • We have a non-instantiatable class (abstract)我们有一个不可实例化的类(抽象)
  • We provide a public builder for it我们为它提供了一个公共构建器

So in both cases with protected static and public builder of an abstract class we combine contradictory statements.因此,在abstract class protected staticpublic构建器的两种情况下,我们结合了矛盾的陈述。 It is a matter of personal preferences.这是个人喜好的问题。

However, I still prefer the public builder of an abstract class because the protected static to me feels more unnatural in a OOD and OOP world !但是,我仍然更喜欢abstract classpublic构建器,因为在 OOD 和 OOP 世界中, protected static对我来说感觉更不自然!

There is nothing wrong with having protected static . protected static并没有错。 One thing a lot of people are overlooking is that you may want to write test cases for static methods that you don't want to expose under normal circumstances.许多人忽略的一件事是,您可能想要为在正常情况下不想公开的静态方法编写测试用例。 I've noticed this is particularly useful for writing tests for static method in utility classes.我注意到这对于在实用程序类中为静态方法编写测试特别有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM