我正在解决这个问题,有没有一种方法可以覆盖Java中的类变量? 关于36个投票的第一条评论是:
如果您看到
protected static
,请运行。
谁能解释为什么protected static
皱眉呢?
final
并不意味着该字段是不变的。您始终可以object
通过final
引用变量来修改引用。
我正在解决这个问题,有没有一种方法可以覆盖Java中的类变量? 关于36个投票的第一条评论是:
如果您看到
protected static
,请运行。
谁能解释为什么protected static
皱眉呢?
final
并不意味着该字段是不变的。您始终可以object
通过final
引用变量来修改引用。
Answers:
这是一个风格上的问题,而不是直接的问题。这表明您没有正确考虑班上正在发生的事情。
考虑一下什么static
意思:
该变量存在于类级别,在每个实例中并不单独存在,并且在扩展me的类中没有独立存在。
考虑一下什么protected
意思:
该变量可以在此类,同一包中的类以及扩展我的类中看到。
这两种含义并不完全互斥,但非常接近。
我唯一可以看到的是可以将两者一起使用的情况是,如果您有一个设计成可扩展的抽象类,然后扩展类可以使用原始对象中定义的常量来修改行为。这种安排很可能最终会变得非常凌乱,并表明类的设计存在缺陷。
在大多数情况下,最好将常量设为public,因为这样会使所有内容更清洁,并使子类的子类具有更大的灵活性。在许多情况下,组合比继承要好得多,而抽象类则强制继承。
要查看一个示例,说明如何破坏事物,并说明变量没有独立存在的含义,请尝试以下示例代码:
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
无需限定名称-但它没有继承或让自己的副本。它正在查看内存中完全相同的对象。
Rectangle
)以调整宽度/高度以确保相等(对于Square
)将产生不良结果。
人们对此不屑一顾,因为它是矛盾的。
生成变量protected
意味着它将在包中使用或在子类中继承。
使变量static
成为类的成员,消除了继承它的意图。这只剩下要在package中使用的意图,而我们有这个意图package-private
(没有修饰符)。
我认为这对您有用的唯一情况是,如果您声明了一个应用于启动应用程序的类(例如JavaFX的类Application#launch
,并且只希望能够从子类中启动。如果这样做,请确保该方法也可以final
用于不允许隐藏,但是,这不是“规范”,并可能实施,以防止通过向应用推出一种新的方式增加更多的复杂性。
要查看每个修饰符的访问级别,请参见:Java教程-控制对类成员的访问
static
消除继承它的意图。因为我在另一个包中的子类仍然需要protected
访问super字段,即使它是static
。package-private
不禁
protected static
。但这是代码的味道,因此是“ 运行 ”部分。访问修饰符和继承是两个不同的主题。是的,如果是,您将无法从超类访问静态成员package-private
。但是,您首先不应该依赖继承来引用static
字段。这是不良设计的标志。您会注意到尝试覆盖static
方法不会产生任何结果,这清楚表明继承不是基于类的。如果您需要访问课程或课程包之外的地方,应该是public
private static
最初有一个带有一些util函数的类,但是我认为有人可能想从我的类中进行改进或自定义,这些util函数也可能为他们提供便利。public
可能不适合,因为util方法不适用于我的类的实例的用户。您能帮我找出一个好的设计protected
吗?谢谢
我不认为有什么理由不赞成这一点。可能总是存在实现相同行为的替代方法,并且这些替代方法是否比受保护的静态方法“更好”取决于实际结构。但是,至少可以使用一个受保护的静态方法合理的示例如下:
(编辑成单独的软件包,以使使用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
因为扩展类应该调用它们。它们也不能具有“默认”可见性,因为那样一来,其他软件包中的扩展类将无法访问它们。(编辑:可以假定原始注释仅涉及字段,而不涉及方法 -但是,它太笼统了)
protected final
(因为您不希望它们被覆盖),而不是static
。方法不使用实例变量的事实并不意味着它应该是static
(尽管可以)。
final
,它不仅使该方法无意被重写,而且还使读者清楚该方法未使用实例变量。如此简洁:根本没有理由不使其保持静态。
protected
,不是显示继承,而是将其保留在单个包中-不公开。我猜想密封接口在Java中使用时会以这种方式变得有用
protected
意味着“继承类(即使在不同的包中)” ...
静态成员不会被继承,并且受保护的成员仅对子类(当然是包含的类)protected static
可见,因此,a 具有与相同的可见性static
,表明编码人员存在误解。
protected
不一样。如果您只是说static
,则该字段仅对同一包中的子类可见。
protected static
允许在包内或从子类访问。将变量设为静态将消除子类化的意图,而唯一的意图是从包内部进行访问。
使用Protected以便可以在子类中使用它。在具体类的上下文中使用时,定义受保护的静态变量是没有逻辑的,因为您可以访问相同的变量是一种静态方式,但是编译器会发出警告以静态方式访问超类静态变量。
好吧,因为大多数人都回答了:
protected
意味着-' 包私有+子类的可见性-属性/行为是继承的 'static
意味着-' 与实例相反-这是CLASS属性/行为,即不是INHERITED '因此,它们有点矛盾且不兼容。
但是,最近我想到了一个用例,可以将两者一起使用。想象一下,您想创建一个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
公开,但随后我们又提出了另一对矛盾的说法:
因此,在这两种情况下与protected static
和public
建设者的abstract class
我们结合自相矛盾的说法。这是个人喜好问题。
但是,我仍然更喜欢public
anabstract class
的构建器,因为protected static
在OOD和OOP世界中,对我而言,感觉更不自然!
final
。跨类共享的可变静态字段绝对令人担忧。更新静态字段的多个类不太可能可靠或易于遵循,特别是因为任何受保护的字段或方法的存在都意味着该类应由其他包中的类扩展,可能是不受其控制的类。包含保护字段的类的作者。