为什么我们不应该在Java中使用受保护的静态为什么我们不应该在Java中使用受保护的静态(Why w

2019-05-13 03:46发布

我所经历的这个问题有没有办法来覆盖Java类的变量? 36个upvotes第一个评论是:

如果你看到一个protected static运行。

谁能解释为什么一个protected static令人难以接受的?

Answer 1:

它比直接的问题文体的事情。 这表明,你已经无法正常通过正在发生的事情与类思想。

想想static方式:

这个变量存在于类级,它不为每个实例分别存在并且它不具有其中延伸我类的独立存在

想想什么protected手段:

此变量可以由这个类中可以看出,在相同的封装和类的延伸我

两个含义并不完全相互排斥的,但它是非常接近。

我可以看到你可以使用这两个的唯一情况在一起,如果你有这样的设计被延伸再延伸的类可以修改使用原定义的常量行为的抽象类。 即使如此,它是一个非常微弱的原因,虽然你仍然几乎肯定是具有常量,公众更好。 这只是让一切更清洁,让人们亚分级更大的灵活性。

为了扩大并解释第一点 - 尝试这个例子的代码:

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;
    }
}

您将看到的结果:

test
changed

自己尝试一下在: https://ideone.com/KM8u8O

Test2是能够访问静态成员test ,从Test ,而无需限定名称-但它没有继承或让自己的副本。 这是在看完全相同的变量。



Answer 2:

它在,因为它是矛盾的皱起了眉头。

制作一个可变protected意味着它将在包内使用,否则就会一个子类中继承

使该变量static使得它的类中的一员, 消除继承它的意图 。 这样,只有在一个包中使用的意图,我们有package-private为(无修改)。

我能找到这个有用的唯一情况是,如果你是宣称应该用于启动应用程序(如JavaFX的的一类Application#launch ,只希望能够从一个子类启动,如果这样做,确保方法也final不允许隐藏 ,但是这不是“规范”,并可能实施,以防止通过添加启动应用程序的一种新的方式增加更多的复杂性。

为了查看修改的访问级别,看到这一点: Java教程-控制访问类的成员



Answer 3:

我没有看到一个特别的原因这应该会让人不悦。 有可能总是替代品来达到同样的行为,这将取决于实际achitecture这些替代品是否大于受保护的静态方法或没有“更好”。 但是一个例子,其中一个受保护的静态方法是合理的,至少,可能是以下几点:

(编辑分割成单独的包,使应用的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;
    }
}

从派生:

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;
    }
}

另一个派生类:

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;
    }
}

protected static修饰符肯定可以在这里有道理:

  • 该方法可以是static ,因为它们不依赖于实例变量。 它们不适合直接作为多态的方法,而是属于“实用”的方法,提供默认的实现是一个更复杂的计算的一部分,并作为实际执行的“积木”。
  • 该方法不应该是public的,因为他们是一个实现细节。 他们不能private ,因为他们应该被扩展类调用。 他们也不能有“默认”的知名度,因为那时他们不会在其他包的扩展类访问。

(编辑:有人可能会认为原来的注释仅指领域 ,而不是方法 -那么,但是,它太笼统)



Answer 4:

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



Answer 5:

其实没有什么根本性的错误protected static 。 如果你真的想要一个静态变量或方法是可见的包和声明类的子类,然后继续前进,使protected static

有些人通常避免使用protected因各种原因,有些人认为非最终static变量应该通过各种手段来避免(我个人后者同情在一定程度上),所以我猜的组合, protectedstatic必须看坏^ 2那些属于这两个组。



Answer 6:

受保护的使用,以便它可以在子类中使用。 在这里,定义在混凝土中使用类的上下文时,你可以访问相同的变量是静态的way.However编译器会给出警告访问以静态方式超类静态变量一个受保护的静态无逻辑。



Answer 7:

没有什么错与具有protected static 。 有一件事很多人都俯瞰的是,你可能需要编写测试用例,你不希望在正常情况下暴露的静态方法。 我注意到这是在实用工具类的静态方法编写测试特别有用。



Answer 8:

那么,作为大多数人的回答:

  • protected手段- “ 包私人+能见度子类-属性/行为是遗传的
  • static装置- “ 实例的相反-它是一个类属性/特性,即,它是不能继承

因此,他们稍微矛盾和不兼容的。

然而,最近我想出了一个使用情况下这可能是有意义的使用这两个在一起。 想象一下,你想创建一个abstract类,这是不可改变的类型父,它有一堆这些都是常见的亚型属性。 要正确实现不变性和保持可读性一个可能决定使用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;
    }
}

为什么protected static ? 因为我想的非抽象亚型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;
    }
}

当然,我们可以使BaseBuilder公开,但后来我们来到另一个矛盾的陈述:

  • 我们有一个非实例化的类(abstract)
  • 我们为它提供一个公共建设者

因此,在这两种情况下使用protected staticpublic的建设者abstract class ,我们结合自相矛盾的说法。 这是个人喜好的问题。

不过,我还是比较喜欢public的建设者abstract class ,因为protected static给我感觉在OOD和OOP世界变得更加不自然!



文章来源: Why we should not use protected static in java