简体   繁体   English

类、接口和实现接口的类中方法的覆盖、重新声明、隐藏和重新定义

[英]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 any other method can only be overridden there? 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任何其他方法只能在那里被覆盖? And is redefining the same as overriding?重新定义与覆盖相同吗?

If not, can someone please explain these concepts with a flowchart (I've looked at other explanations and they don't give me the overview I'm looking for)?如果没有,有人可以用流程图解释这些概念吗(我看过其他解释,他们没有给我我正在寻找的概述)?

Would it be correct to say that static methods in a class extended说 static 方法在 class 扩展中是否正确

No. static methods fundamentally are un-inheritable, and un-overridable. No. static 方法基本上是不可继承的,不可覆盖的。 Or rather, conceptually it just doesn't apply.或者更确切地说,从概念上讲,它只是不适用。

Saying: "This static method is an override" is a bit like stating: "This smells blue" - it's not clear what that would even mean.说:“这个 static 方法是一种替代方法”有点像说:“这闻起来很蓝”——甚至不清楚这意味着什么。

overriding is relevant essentially only for the notion of dynamic dispatch.覆盖本质上只与动态调度的概念有关。 Dynamic dispatch is this idea:动态调度是这样的想法:

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"

That's dynamic dispatch at work.这就是工作中的动态调度。 d is a variable. d是一个变量。 Like all non-primitives in java, it is a reference .像 java 中的所有非基元一样,它是一个参考 Meaning, values stored in this variable are the reference - a pointer.意思是,存储在此变量中的值是引用- 一个指针。 An address in an addressbook that lets you get to a house, not the house itself.地址簿中的地址,可让您到达房子,而不是房子本身。 d 's type is Dog . d的类型是Dog Its value is a reference to an actual instance of some object (and java guarantees that whatever the actual type it is an instance of, that type is Dog or a subtype of Dog ).它的值是对某些 object 的实际实例的引用(并且 java 保证无论它是一个实例的实际类型,该类型是DogDog的子类型)。 That reference gets you an instance of Bulldog .该引用为您提供了Bulldog的实例。 So, when invoking bark() here, what happens?那么,在这里调用bark()时,会发生什么?

Dynamic dispatch: Java finds the most specific implementation of this method, and calls that .动态调度:Java 找到该方法最具体的实现,并调用. So that prints Grrrr , and not Woof .这样打印Grrrr ,而不是Woof

However, when talking about static methods, the entire concept doesn't apply.然而,当谈到 static 方法时,整个概念并不适用。 Dynamic dispatch occurs because there is a discrepancy between the type of the reference (which is Dog here, that's the type of variable d ) and the type of the thing the reference is pointing at (which is Bulldog ).发生动态调度是因为引用的类型(这里是Dog ,即变量d的类型)和引用指向的事物的类型(即Bulldog )之间存在差异。 Overriding as a concept exists because these 2 types may not be the same.覆盖作为一个概念存在是因为这两种类型可能不同。

When invoking static methods, this doesn't come up .调用 static 方法时,这不会出现 You always write SomeType.someStaticMethod() , so what would dynamic dispatch even be?你总是写SomeType.someStaticMethod() ,那么动态调度甚至是什么?

SIDENOTE: You can legally invoke static methods using an expression.旁注:您可以使用表达式合法地调用 static 方法。 This is legal:这是合法的:

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

But make no mistake - the compiler treats it the same and cares only about the type of list , not about the object the variable is pointing at.但不要搞错 - 编译器对待它是一样的,关心list的类型,而不关心变量指向的 object 。 In fact, list = null; list.of("a", "b");事实上, list = null; list.of("a", "b"); list = null; list.of("a", "b"); works fine, no NullPointerException, proving the point that list doesn't get dereferenced when you do this.工作正常,没有 NullPointerException,证明这样做时list不会被取消引用。 All style guides strongly recommend not doing this, for good reason.所有风格指南都强烈建议不要这样做,这是有充分理由的。

SIDENOTE 2: Unfortunately java lets you declare a static method as final which is weird: final means: Cannot be overridden, and we just figured out that 'override' conceptually doesn't make sense for static methods.旁注2:不幸的是,java 允许您将 static 方法声明为final ,这很奇怪: final意味着:不能被覆盖,我们刚刚发现“覆盖”在概念上对 ZA821259CEF456E959 方法没有意义。 It's just what it is - it's a design error in the original java spec and java does not like making changes that break existing code unless there is an incredibly good reason to do so, and whilst this spec brainfart is annoying, it doesn't hurt much.就是这样 - 这是原始 java 规范和 java 中的设计错误,除非有非常好的理由这样做,否则不喜欢进行破坏现有代码的更改,虽然这个规范很烦人,但它不会伤害很多。 Just don't declare your static methods final .只是不要将您的 static 方法声明为final It even adds a rule (subtypes cannot declare a static method with the same signature) which is even more bizarre.它甚至添加了一个更奇怪的规则(子类型不能声明具有相同签名的 static 方法)。 Again, disregard that - java spec error that doesn't get fixed because not worth the headache.再次,无视这一点 - java 规范错误没有得到修复,因为不值得头疼。

And is redefining the same as overriding?重新定义与覆盖相同吗?

Yes.是的。 2 words for the same thing. 2个词代表同一件事。 The correct term is 'override' - both the java lang spec uses this term, and the vast majority of the community does.正确的术语是“覆盖”——java 语言规范都使用这个术语,社区中的绝大多数人都这样做。 If I was an editor of whatever tutorial, blogpost, documentation, or presentation you got this 'redefine' term from, I'd edit it.如果我是任何教程、博客文章、文档或演示文稿的编辑,你会得到这个“重新定义”的术语,我会编辑它。 Unless the author was specifically talking about this:除非作者特意讲这个:

class Parent {
  static void foo() {}
}

class Child extends Parent {
  static void foo() {}
}

In which case 'override' is the wrong term to use (given that static methods and override are orthogonal concepts), though I wouldn't use 'redefine' either.在这种情况下,“覆盖”是使用错误的术语(鉴于 static 方法和覆盖是正交概念),尽管我也不会使用“重新定义”。 You're just defining a method named foo in one class, and also defining a method named foo in another.您只是在一个 class 中定义了一个名为foo的方法,还在另一个 class 中定义了一个名为foo的方法。 The fact that one is a child of the other is irrelevant;一个是另一个孩子的事实是无关紧要的。 both have a foo method now.现在两者都有一个foo方法。 The foo method in child does not override or redefine anything; child 中的 foo 方法不会覆盖或重新定义任何东西; there's no such thing in static world. static世界中没有这样的东西。

with a flowchart有流程图

A flowchart requires some sort of flow to chart.流程图需要某种流程图来绘制。 Hence the name.由此得名。 No such thing here.这里没有这样的东西。

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

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