[英]Overriding, redeclaring, hiding and redefining of methods in classes, interfaces and classes implementing interfaces
Would it be correct to say that static methods in a class extended with a class, in an interface extended with an interface and in an interface implemented by a class can only be redeclared in the extending/implementing part (hiding the original method), and任何其他方法只能在那里被覆盖? 重新定义与覆盖相同吗?
如果没有,有人可以用流程图解释这些概念吗(我看过其他解释,他们没有给我我正在寻找的概述)?
说 static 方法在 class 扩展中是否正确
No. static 方法基本上是不可继承的,不可覆盖的。 或者更确切地说,从概念上讲,它只是不适用。
说:“这个 static 方法是一种替代方法”有点像说:“这闻起来很蓝”——甚至不清楚这意味着什么。
覆盖本质上只与动态调度的概念有关。 动态调度是这样的想法:
class Dog {
void bark() { System.out.println("Woof"); }
}
class Bulldog extends Dog {
void bark() { System.out.println("Grrrr"); }
}
Dog d = new Bulldog();
d.bark(); // prints "Grrrr"
这就是工作中的动态调度。 d
是一个变量。 像 java 中的所有非基元一样,它是一个参考。 意思是,存储在此变量中的值是引用- 一个指针。 地址簿中的地址,可让您到达房子,而不是房子本身。 d
的类型是Dog
。 它的值是对某些 object 的实际实例的引用(并且 java 保证无论它是一个实例的实际类型,该类型是Dog
或Dog
的子类型)。 该引用为您提供了Bulldog
的实例。 那么,在这里调用bark()
时,会发生什么?
动态调度:Java 找到该方法最具体的实现,并调用. 这样打印Grrrr
,而不是Woof
。
然而,当谈到 static 方法时,整个概念并不适用。 发生动态调度是因为引用的类型(这里是Dog
,即变量d
的类型)和引用指向的事物的类型(即Bulldog
)之间存在差异。 覆盖作为一个概念存在是因为这两种类型可能不同。
调用 static 方法时,这不会出现。 你总是写SomeType.someStaticMethod()
,那么动态调度甚至是什么?
旁注:您可以使用表达式合法地调用 static 方法。 这是合法的:
List.of("a", "b"); // this is how you normally do it
List<Integer> list = new ArrayList<Integer>();
list.of("a", "b"); // this compiles and works
但不要搞错 - 编译器对待它是一样的,只关心list
的类型,而不关心变量指向的 object 。 事实上, list = null; list.of("a", "b");
list = null; list.of("a", "b");
工作正常,没有 NullPointerException,证明这样做时list
不会被取消引用。 所有风格指南都强烈建议不要这样做,这是有充分理由的。
旁注2:不幸的是,java 允许您将 static 方法声明为final
,这很奇怪: final
意味着:不能被覆盖,我们刚刚发现“覆盖”在概念上对 ZA821259CEF456E959 方法没有意义。 就是这样 - 这是原始 java 规范和 java 中的设计错误,除非有非常好的理由这样做,否则不喜欢进行破坏现有代码的更改,虽然这个规范很烦人,但它不会伤害很多。 只是不要将您的 static 方法声明为final
。 它甚至添加了一个更奇怪的规则(子类型不能声明具有相同签名的 static 方法)。 再次,无视这一点 - java 规范错误没有得到修复,因为不值得头疼。
重新定义与覆盖相同吗?
是的。 2个词代表同一件事。 正确的术语是“覆盖”——java 语言规范都使用这个术语,社区中的绝大多数人都这样做。 如果我是任何教程、博客文章、文档或演示文稿的编辑,你会得到这个“重新定义”的术语,我会编辑它。 除非作者特意讲这个:
class Parent {
static void foo() {}
}
class Child extends Parent {
static void foo() {}
}
在这种情况下,“覆盖”是使用错误的术语(鉴于 static 方法和覆盖是正交概念),尽管我也不会使用“重新定义”。 您只是在一个 class 中定义了一个名为foo
的方法,还在另一个 class 中定义了一个名为foo
的方法。 一个是另一个孩子的事实是无关紧要的。 现在两者都有一个foo
方法。 child 中的 foo 方法不会覆盖或重新定义任何东西; static
世界中没有这样的东西。
有流程图
流程图需要某种流程图来绘制。 由此得名。 这里没有这样的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.