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

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

我的预期产出:

子类method1
超类方法1
超类method2

实际产量:

子类method1
超类方法1
子类method2

我知道技术上我已经覆盖了一个公共的方法,但我想到,因为我打电话给超级,超级内的任何电话将停留在超级,这不会发生。 任何想法,我怎么能做到这一点?

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

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

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

[编辑]似乎还有一些困惑。 让我尝试一个不同的解释。

当你调用foo() ,你实际上调用this.foo() 。 Java只是让你省略this 。 在问题的例子中,这个types是SubClass

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

使用super不会改变这个指向的实例。 所以调用SubClass.method2()因为thisSubClasstypes。

当你想象Java把this作为一个隐藏的第一个parameter passing的时候,也许会更容易理解:

 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()创build的实例。

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

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

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

如果您不想让superClass.method1调用subClass.method2,请将method2设置为private,以使其不能被覆盖。

这里有一个build议:

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

如果不这样做,多态性将是不可能的(或者至less不是有效的一半)。

由于避免方法获取重写的唯一方法是使用关键字 ,我想从SuperClass上移动method2()到另一个新的类,然后从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 
  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"); } } public class Demo { public static void main(String[] args) { SubClass mSubClass = new SubClass(); mSubClass.method1(); } } 

输出:

子类method1
超类方法1
超类method2

this总是指当前正在执行的对象。

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

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

如果你有一个外框的实例,一个Subclass对象,无论你碰巧在框内冒险,甚至进入Superclass “区域”,它仍然是外框的实例。

更重要的是,在这个程序中,只有一个对象是从三个类中创build的,所以this只能涉及到一件事,它是:

在这里输入图像说明

如Netbeans的 “堆行者”所示。

我不相信你可以直接做。 一种解决方法是在超类中有一个私有的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"); } } 

“this”关键字引用当前类的引用。 这意味着,当它在方法内部使用时,“当前”类仍然是子类,所以解释了答案。

我这样想

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

让我稍微移动这个子类到左边来揭示下面的东西…(人,我喜欢ASCIIgraphics)

 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.Identifierforms引用当前对象的名为Identifier的字段,但将当前对象视为当前类的超类的一个实例。

formsT.super.Identifier引用与T对应的词法封闭实例的名为Identifier的字段,但将该实例视为T的超类的实例。

通俗地说, this基本上是一个对象(* **对象;可以在variables中移动的对象),实例化类的实例,数据域中的普通variables; super就像是一个指向你想要执行的借用代码块的指针,更像是一个单纯的函数调用,它和它所在的类相对。

因此,如果你使用super类的超类,你可以从祖父类的祖先中获得代码,而如果你使用this (或者如果它是隐式使用的),它会一直指向子类(因为没有人改变它)没有人可以)。

总而言之,这指向当前对象,而java中的方法调用本质上是多态的。 所以,执行的方法select完全取决于这个指向的对象。 因此,从父类调用方法method2()调用子类的method2(),因为这指向了子类的对象。 这个定义不会改变,不pipe使用哪一个类。

PS。 与方法不同,类的成员variables不是多态的。

在我研究类似案例的过程中,我一直通过检查子类方法中的堆栈跟踪来结束调用的来源。 有可能是更聪明的方式来做到这一点,但对我来说,这是一个dynamic的方法。

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

我认为这个问题有一个解决scheme是合理的。 当然有方法可以用不同的方法名称甚至不同的参数types来解决这个问题,就像线程中已经提到的那样,但是在我的情况下,我不想用不同的方法名称来混淆。