Java:调用一个调用重写方法的超级方法

jso*_*fry 86 java inheritance overriding super

public class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        this.method2();
    }

    public void method2()
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的预期输出:

子类method1
超类method1
超类method2

实际产量:

子类method1
超类method1
子类方法2

我在技术上知道我已经覆盖了一个公共方法,但我认为因为我正在调用super,所以超级中的任何调用都会保留在super中,这种情况不会发生.关于如何实现这一点的任何想法?

Aar*_*lla 72

关键字super不会"粘".每个方法调用都是单独处理的,因此即使您SuperClass.method1()通过调用进行调用super,也不会影响将来可能进行的任何其他方法调用.

这意味着没有直接的方法来调用SuperClass.method2()SuperClass.method1()没有去,虽然SubClass.method2(),除非你有一个实际的实例工作SuperClass.

您甚至无法使用Reflection实现所需的效果(请参阅文档java.lang.reflect.Method.invoke(Object, Object...)).

[编辑]似乎仍有一些混乱.让我尝试不同的解释.

当你调用时foo(),你实际上是在调用this.foo().Java只是让你省略this.在问题的例子中,类型thisSubClass.

因此,当Java执行代码时SuperClass.method1(),它最终会到达this.method2();

使用super不会更改指向的实例this.所以,电话将转入SubClass.method2()因为this是类型SubClass.

当您想象Java this作为隐藏的第一个参数传递时,可能更容易理解:

public class SuperClass
{
    public void method1(SuperClass this)
    {
        System.out.println("superclass method1");
        this.method2(this); // <--- this == mSubClass
    }

    public void method2(SuperClass this)
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1(SubClass this)
    {
        System.out.println("subclass method1");
        super.method1(this);
    }

    @Override
    public void method2(SubClass this)
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1(mSubClass);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您按照调用堆栈,您可以看到this永远不会更改,它始终是创建的实例main().

  • @laycat:不需要图表.请记住,Java对于`super`没有"记忆".每次调用一个方法时,它都会查看实例类型,并开始搜索这种类型的方法,无论你多久调用一次`super`.所以当你在`SubClass`的实例上调用`method2`时,它总会首先看到来自`SubClass`的那个. (2认同)

Sea*_*oyd 14

您只能在重写方法(或重写类的其他方法)中访问重写方法.

所以:要么不覆盖method2()或调用super.method2()被覆盖的版本.


Jos*_*iaz 8

你正在使用this实际引用"你正在使用的对象的当前运行实例" 的关键字,也就是说,你正在调用this.method2();你的超类,也就是说,它会调用你对象上的method2()重新使用,这是SubClass.

  • 是的,不使用`this`也无济于事.不合格的调用隐式使用`this` (8认同)
  • @Shervin他没有说错什么,他只是不清楚如果你遗漏"这个"会发生什么 (4认同)
  • 答案是正确的,指出`this`指的是"具体运行实例类"(在运行时已知)而不是(如海报似乎相信)"当前编译单元类"(使用关键字) ,在编译时知道).但它也可能具有误导性(正如Shervin指出的那样):`this`也是用普通方法调用隐式引用的; `method2();`与`this.method2();`相同 (4认同)
  • 这为什么会被投票?这不是这个问题的答案.当你编写`method2()`时,编译器会看到`this.method2()`.所以,即使你删除了"this",它仍然无效.@Sean Patrick Floyd所说的是正确的 (3认同)

Una*_*ivi 6

我是这样想的

+----------------+
|     super      |
+----------------+ <-----------------+
| +------------+ |                   |
| |    this    | | <-+               |
| +------------+ |   |               |
| | @method1() | |   |               |
| | @method2() | |   |               |
| +------------+ |   |               |
|    method4()   |   |               |
|    method5()   |   |               |
+----------------+   |               |
    We instantiate that class, not that one!
Run Code Online (Sandbox Code Playgroud)

让我将该子类向左移动一点,以显示下面的内容...(老兄,我确实喜欢ASCII图形)

We are here
        |
       /  +----------------+
      |   |     super      |
      v   +----------------+
+------------+             |
|    this    |             |
+------------+             |
| @method1() | method1()   |
| @method2() | method2()   |
+------------+ method3()   |
          |    method4()   |
          |    method5()   |
          +----------------+

Then we call the method
over here...
      |               +----------------+
 _____/               |     super      |
/                     +----------------+
|   +------------+    |    bar()       |
|   |    this    |    |    foo()       |
|   +------------+    |    method0()   |
+-> | @method1() |--->|    method1()   | <------------------------------+
    | @method2() | ^  |    method2()   |                                |
    +------------+ |  |    method3()   |                                |
                   |  |    method4()   |                                |
                   |  |    method5()   |                                |
                   |  +----------------+                                |
                   \______________________________________              |
                                                          \             |
                                                          |             |
...which calls super, thus calling the super's method1() here, so that that
method (the overidden one) is executed instead[of the overriding one].

Keep in mind that, in the inheritance hierarchy, since the instantiated
class is the sub one, for methods called via super.something() everything
is the same except for one thing (two, actually): "this" means "the only
this we have" (a pointer to the class we have instantiated, the
subclass), even when java syntax allows us to omit "this" (most of the
time); "super", though, is polymorphism-aware and always refers to the
superclass of the class (instantiated or not) that we're actually
executing code from ("this" is about objects [and can't be used in a
static context], super is about classes).
Run Code Online (Sandbox Code Playgroud)

换句话说,引用Java语言规范

该表单super.Identifier引用Identifier当前对象的命名字段,但是将当前对象视为当前类的超类的实例。

表单T.super.Identifier是指与Identifier相对应的词汇包围实例的名称字段T,但将该实例视为的超类的实例T

用外行的话来说,this基本上是一个对象(* the **对象;您可以在变量中移动的同一对象),实例化类的实例,数据域中的普通变量;super就像是指向要执行的借用代码块的指针,更像是单纯的函数调用,它相对于被调用的类。

因此,如果您super从超类使用,则从超级duper类[祖父母]获得代码,而如果您this从超类使用(或隐式使用)代码,则该代码将始终指向子类(因为没有人更改它,并且没人可以)。