Java:调用超级方法,该方法调用被重写的方法

发布于 2024-10-10 10:37:59 字数 932 浏览 7 评论 0原文

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();
    }
}

我的预期输出:

子类方法1
超类方法1
超类方法2

实际输出:

子类方法1
超类方法1
子类方法2

我知道从技术上讲我已经重写了一个公共方法,但我认为因为我正在调用超级方法,所以超级中的任何调用都会保留在超级中,这不会发生。关于如何实现它有什么想法吗?

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();
    }
}

my expected output:

subclass method1
superclass method1
superclass method2

actual output:

subclass method1
superclass method1
subclass method2

I know technically I have overriden a public method, but I figured that because I was calling the super, any calls within the super would stay in the super, this isn't happening. Any ideas as to how I can make it happen?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

享受孤独 2024-10-17 10:37:59

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

这意味着没有直接方法可以从 SuperClass.method1() 调用 SuperClass.method2() 而无需通过 SubClass.method2() 除非您正在使用 SuperClass 的实际实例。

您甚至无法使用反射达到预期的效果(请参见java.lang.reflect.Method.invoke(Object, Object...) 的文档 )。

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

当您调用 foo() 时,您实际上调用了 this.foo()。 Java 只是让您省略 this。在问题的示例中,this 的类型是 SubClass

所以当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);
    }
}

如果您跟踪调用堆栈,您可以看到 this 永远不会改变,它始终是在 main() 中创建的实例。

The keyword super doesn't "stick". Every method call is handled individually, so even if you got to SuperClass.method1() by calling super, that doesn't influence any other method call that you might make in the future.

That means there is no direct way to call SuperClass.method2() from SuperClass.method1() without going though SubClass.method2() unless you're working with an actual instance of SuperClass.

You can't even achieve the desired effect using Reflection (see the documentation of java.lang.reflect.Method.invoke(Object, Object...)).

[EDIT] There still seems to be some confusion. Let me try a different explanation.

When you invoke foo(), you actually invoke this.foo(). Java simply lets you omit the this. In the example in the question, the type of this is SubClass.

So when Java executes the code in SuperClass.method1(), it eventually arrives at this.method2();

Using super doesn't change the instance pointed to by this. So the call goes to SubClass.method2() since this is of type SubClass.

Maybe it's easier to understand when you imagine that Java passes this as a hidden first parameter:

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);
    }
}

If you follow the call stack, you can see that this never changes, it's always the instance created in main().

梦一生花开无言 2024-10-17 10:37:59

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

因此:要么不要重写 method2() ,要么在重写的版本中调用 super.method2()

You can only access overridden methods in the overriding methods (or in other methods of the overriding class).

So: either don't override method2() or call super.method2() inside the overridden version.

枉心 2024-10-17 10:37:59

我是这样想的

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

让我将该子类向左移动一点以显示下面的内容......
(伙计,我确实喜欢 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).

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

super.Identifier 形式指的是名为 Identifier 的字段
当前对象,但将当前对象视为
当前类的超类。

T.super.Identifier 形式指的是名为 Identifier 的字段
对应于 T 的词法封闭实例,但是这样
实例被视为 T 超类的实例。

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

因此,如果您从超类中使用 super ,您将从执行的 superduper 类(祖父母)中获取代码),而如果您使用 this (或者如果它是隐式使用的)超类它一直指向子类(因为没有人改变它 - 没有人可以)。

I think of it this way

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

Let me move that subclass a little to the left to reveal what's beneath...
(Man, I do love ASCII graphics)

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).

In other words, quoting from the Java Language Specification:

The form super.Identifier refers to the field named Identifier of the
current object, but with the current object viewed as an instance of
the superclass of the current class.

The form T.super.Identifier refers to the field named Identifier of
the lexically enclosing instance corresponding to T, but with that
instance viewed as an instance of the superclass of T.

In layman's terms, this is basically an object (*the** object; the very same object you can move around in variables), the instance of the instantiated class, a plain variable in the data domain; super is like a pointer to a borrowed block of code that you want to be executed, more like a mere function call, and it's relative to the class where it is called.

Therefore if you use super from the superclass you get code from the superduper class [the grandparent] executed), while if you use this (or if it's used implicitly) from a superclass it keeps pointing to the subclass (because nobody has changed it - and nobody could).

泛泛之交 2024-10-17 10:37:59

您使用的 this 关键字实际上指的是“您正在使用的对象的当前运行实例”,也就是说,您正在调用 this.method2(); 在你的超类上,也就是说,它将在你正在使用的对象(即子类)上调用 method2() 。

You're using the this keyword which actually refers to the "currently running instance of the object you're using", that is, you're invoking this.method2(); on your superclass, that is, it will call the method2() on the object you're using, which is the SubClass.

甜是你 2024-10-17 10:37:59

如果您不希望 superClass.method1 调用 subClass.method2,请将 method2 设置为私有,这样它就无法被覆盖。

这里有一个建议:

public class SuperClass {

  public void method1() {
    System.out.println("superclass method1");
    this.internalMethod2();
  }

  public void method2()  {
    // this method can be overridden.  
    // It can still be invoked by a childclass using super
    internalMethod2();
  }

  private void internalMethod2()  {
    // this one cannot.  Call this one if you want to be sure to use
    // this implementation.
    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");
  }
}

如果它不以这种方式工作,多态性将是不可能的(或者至少没有一半有用)。

If you don't want superClass.method1 to call subClass.method2, make method2 private so it cannot be overridden.

Here's a suggestion:

public class SuperClass {

  public void method1() {
    System.out.println("superclass method1");
    this.internalMethod2();
  }

  public void method2()  {
    // this method can be overridden.  
    // It can still be invoked by a childclass using super
    internalMethod2();
  }

  private void internalMethod2()  {
    // this one cannot.  Call this one if you want to be sure to use
    // this implementation.
    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");
  }
}

If it didn't work this way, polymorphism would be impossible (or at least not even half as useful).

忆梦 2024-10-17 10:37:59
class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        SuperClass se=new SuperClass();
        se.method2();
    }

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


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

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

调用

SubClass mSubClass = new SubClass();
mSubClass.method1();

输出

子类方法1
超类方法1
超类方法2

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

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


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

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

calling

SubClass mSubClass = new SubClass();
mSubClass.method1();

outputs

subclass method1
superclass method1
superclass method2

晨曦÷微暖 2024-10-17 10:37:59

由于避免方法被重写的唯一方法是使用关键字 super,因此我考虑将 method2() 从 SuperClass 移至另一个新的 >Base 类,然后从 SuperClass 调用它:

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

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

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();
    }
}

输出:

subclass method1
superclass method1
superclass method2

Since the only way to avoid a method to get overriden is to use the keyword super, I've thought to move up the method2() from SuperClass to another new Base class and then call it from SuperClass:

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

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

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();
    }
}

Output:

subclass method1
superclass method1
superclass method2
泪痕残 2024-10-17 10:37:59

this 始终引用当前正在执行的对象。

为了进一步说明这一点,这里有一个简单的草图:

+----------------+
|  Subclass      |
|----------------|
|  @method1()    |
|  @method2()    |
|                |
| +------------+ |
| | Superclass | |
| |------------| |
| | method1()  | |
| | method2()  | |
| +------------+ |
+----------------+

如果您有一个外部盒子的实例,一个 Subclass 对象,无论您碰巧在盒子内部冒险,甚至进入 Superclass 对象, code>'area',仍然是外框的实例。

更重要的是,在这个程序中,三个类中只有一个对象被创建,因此 this 只能引用一个东西,它是:

在此处输入图像描述

如图所示在 Netbeans“Heap Walker”中。

this always refers to currently executing object.

To further illustrate the point here is a simple sketch:

+----------------+
|  Subclass      |
|----------------|
|  @method1()    |
|  @method2()    |
|                |
| +------------+ |
| | Superclass | |
| |------------| |
| | method1()  | |
| | method2()  | |
| +------------+ |
+----------------+

If you have an instance of the outer box, a Subclass object, wherever you happen to venture inside the box, even into the Superclass 'area', it is still the instance of the outer box.

What's more, in this program there is only one object that gets created out of the three classes, so this can only ever refer to one thing and it is:

enter image description here

as shown in the Netbeans 'Heap Walker'.

以为你会在 2024-10-17 10:37:59

我不相信你能直接做到这一点。一种解决方法是在超类中拥有 method2 的私有内部实现,并调用它。例如:

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

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

}

I don't believe you can do it directly. One workaround would be to have a private internal implementation of method2 in the superclass, and call that. For example:

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

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

}
大海や 2024-10-17 10:37:59

“this”关键字指的是当前类引用。这意味着,当它在方法内部使用时,“当前”类仍然是 SubClass,因此,答案得到了解释。

"this" keyword refers to current class reference. That means, when it is used inside the method, the 'current' class is still SubClass and so, the answer is explained.

扎心 2024-10-17 10:37:59

总而言之,this指向当前对象,java中的方法调用本质上是多态的。因此,执行方法的选择完全取决于 this 指向的对象。因此,从父类调用方法method2()会调用子类的method2(),因为this指向子类的对象。无论使用哪个类,它的定义都不会改变。

附言。与方法不同,类的成员变量不是多态的。

To summarize, this points to current object and the method invocation in java is polymorphic by nature. So, method selection for execution, totally depends upon object pointed by this. Therefore, invoking method method2() from parent class invokes method2() of child class, as the this points to object of child class. The definition of this doesn't changes, irrespective of whichever class it's used.

PS. unlike methods, member variables of class are not polymorphic.

过度放纵 2024-10-17 10:37:59

在我对类似案例的研究过程中,我最终通过检查子类方法中的堆栈跟踪来找出调用的来源。可能有更聪明的方法可以做到这一点,但这对我来说很有效,而且是一种动态方法。

public void method2(){
        Exception ex=new Exception();
        StackTraceElement[] ste=ex.getStackTrace();
        if(ste[1].getClassName().equals(this.getClass().getSuperclass().getName())){
            super.method2();
        }
        else{
            //subclass method2 code
        }
}

我认为对案件提出解决方案的问题是合理的。当然,有多种方法可以使用不同的方法名称甚至不同的参数类型来解决问题,就像线程中已经提到的那样,但就我而言,我不喜欢通过不同的方法名称来混淆。

During my research for a similar case, I have been ending up by checking the stack trace in the subclass method to find out from where the call is coming from. There are probably smarter ways to do so, but it works out for me and it's a dynamic approach.

public void method2(){
        Exception ex=new Exception();
        StackTraceElement[] ste=ex.getStackTrace();
        if(ste[1].getClassName().equals(this.getClass().getSuperclass().getName())){
            super.method2();
        }
        else{
            //subclass method2 code
        }
}

I think the question to have a solution for the case is reasonable. There are of course ways to solve the issue with different method names or even different parameter types, like already mentioned in the thread, but in my case I dindn't like to confuse by different method names.

暗地喜欢 2024-10-17 10:37:59

进一步扩展所提出问题的输出,这将使您对访问说明符和覆盖行为有更多的了解。

            package overridefunction;
            public class SuperClass 
                {
                public void method1()
                {
                    System.out.println("superclass method1");
                    this.method2();
                    this.method3();
                    this.method4();
                    this.method5();
                }
                public void method2()
                {
                    System.out.println("superclass method2");
                }
                private void method3()
                {
                    System.out.println("superclass method3");
                }
                protected void method4()
                {
                    System.out.println("superclass method4");
                }
                void method5()
                {
                    System.out.println("superclass method5");
                }
            }

            package overridefunction;
            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");
                }
                // @Override
                private void method3()
                {
                    System.out.println("subclass method3");
                }
                @Override
                protected void method4()
                {
                    System.out.println("subclass method4");
                }
                @Override
                void method5()
                {
                    System.out.println("subclass method5");
                }
            }

            package overridefunction;
            public class Demo 
            {
                public static void main(String[] args) 
                {
                    SubClass mSubClass = new SubClass();
                    mSubClass.method1();
                }
            }

            subclass method1
            superclass method1
            subclass method2
            superclass method3
            subclass method4
            subclass method5

Further more extended the output of the raised question, this will give more insight on the access specifier and override behavior.

            package overridefunction;
            public class SuperClass 
                {
                public void method1()
                {
                    System.out.println("superclass method1");
                    this.method2();
                    this.method3();
                    this.method4();
                    this.method5();
                }
                public void method2()
                {
                    System.out.println("superclass method2");
                }
                private void method3()
                {
                    System.out.println("superclass method3");
                }
                protected void method4()
                {
                    System.out.println("superclass method4");
                }
                void method5()
                {
                    System.out.println("superclass method5");
                }
            }

            package overridefunction;
            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");
                }
                // @Override
                private void method3()
                {
                    System.out.println("subclass method3");
                }
                @Override
                protected void method4()
                {
                    System.out.println("subclass method4");
                }
                @Override
                void method5()
                {
                    System.out.println("subclass method5");
                }
            }

            package overridefunction;
            public class Demo 
            {
                public static void main(String[] args) 
                {
                    SubClass mSubClass = new SubClass();
                    mSubClass.method1();
                }
            }

            subclass method1
            superclass method1
            subclass method2
            superclass method3
            subclass method4
            subclass method5
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文