可以考虑将此代码用于 Java 中的成员覆盖吗?
Posted
技术标签:
【中文标题】可以考虑将此代码用于 Java 中的成员覆盖吗?【英文标题】:Can this code be considered for member overriding in Java? 【发布时间】:2021-03-02 12:37:45 【问题描述】:理论上,Java 不支持成员覆盖,所以我在想这段代码 sn-p 是否可以用于覆盖类的成员。但是,我不太确定在什么情况下此代码可能会失败。我的意思是,如果这能完美运行,那么它就不会被忽视,对吧? 这可能是一个愚蠢的问题,但我真的很想知道这段代码在我无法想到的不同情况下会做什么。 因此,如果有人可以向我解释,那就太好了。 谢谢!
类A类 诠释 i = 10; 无效吃() System.out.println("在 A 类:吃"); 无效树皮() System.out.println("在 A 类中:吠叫"); 类 ClassB 扩展 ClassA //int i = 20; 类B() 超级我 = 20; //改变A类中i的值。 无效吃() System.out.println("B 类:吃"); 公共类主 公共静态无效主要(字符串[]参数) ClassB b = new ClassB(); System.out.println(b.i); 打(); b.树皮(); ClassA ua = new ClassB(); System.out.println(ua.i); ua.eat(); ua.bark(); ClassA a = new ClassA(); System.out.println(a.i);【问题讨论】:
【参考方案1】:如果您覆盖一个方法然后尝试从父级调用它,父级调用派生方法,即使它在定义时不知道它。
class A
public void foo()
System.out.println("A.foo");
public void callFoo()
this.foo();
class B
public void foo()
System.out.println("B.foo");
B instance = new B();
instance.callFoo(); // Prints "B.foo"
现在,如果我们尝试对实例字段做同样的事情,我们会得到原始字段。
class A
public String foo = "A.foo";
public void printFoo()
System.out.println(this.foo);
class B
public String foo = "B.foo";
B instance = new B();
instance.printFoo(); // Prints "A.foo"
所以我们实际上并没有覆盖任何东西;我们只是简单地创建了一个新变量,它恰好与现有变量的名称混淆。如果它是真正的覆盖,那么我们将能够增强使用该变量但不知道子类的A
方法的行为。
【讨论】:
我想作者明白这一点。 Tejas 没有询问覆盖成员字段。【参考方案2】:您的问题的简单答案是“是”,您的 ClassA 类的 eat 方法在 ClassB 类中被覆盖。验证的简单选项是使用 @Override 注释。
在子类中,您可以覆盖和重载实例方法。覆盖意味着,您是替换继承行为的子类。重载意味着,您正在扩展继承的方法。
如果你修改你的ClassB如下,它会编译成功。
class ClassB extends ClassA
//int i = 20;
ClassB()
super.i = 20; //Changing the value of i in class A.
@Override // **Added line is here**
void eat()
System.out.println("In Class B: Eating");
【讨论】:
【参考方案3】:我不太确定这段代码在什么情况下可能会失败。
它(有点)在人类读者/概念层面上失败了。
Java 语言就是这样。这意味着 Java 程序员知道该期待什么,该做什么,不该做什么。
继承的基本规则之一(在 java 中,但在一般情况下也是如此):对于超类的字段,您非常谨慎。成员字段应被视为类的内部实现细节。你不会把它暴露给外部世界。你不要把它暴露给你的孩子班级,除非有一个很好的理由这样做。如果您真的想在 java 中这样做,那么正确的方法是:为该字段使用 protected
关键字。
您的想法基本上是子类“知道”超类字段,更糟糕的是:在创建时更改“内部状态”。
因此,在现实世界中,这样的代码可能会很快导致各种令人讨厌的意外。因为现实世界中的人不会期望子类会做类似的事情,因此在调试问题时,他们可能会惊讶地发现“我应该是 10,为什么是 20”大型应用程序。
长话短说:你可以做某事并不意味着你应该去做。相反:好的编程是以“标准”方式做事,不会让你的读者感到惊讶。
【讨论】:
+1。实现 OP 结果的一种标准的、不令人惊讶的方法是让 ClassA 具有类似private final int i;
public ClassA() this.i = 10;
protected ClassA(int i) this.i = i;
的东西,这为其子类提供了一种清晰、明显、明确定义的方式来将 i
设置为需要。以上是关于可以考虑将此代码用于 Java 中的成员覆盖吗?的主要内容,如果未能解决你的问题,请参考以下文章