Calling base class overridden function from base c

2019-01-06 15:53发布

问题:

public class A {
    public void f1(String str) {
        System.out.println("A.f1(String)");
        this.f1(1, str);
    }

    public void f1(int i, String str) {
        System.out.println("A.f1(int, String)");
    }
}



public class B extends A {
    @Override
    public void f1(String str) {
        System.out.println("B.f1(String)");
        super.f1(str);
    }

    @Override
    public void f1(int i, String str) {
        System.out.println("B.f1(int, String)");
        super.f1(i, str);
    }
}


public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.f1("Hello");
    }
}

I'm seeking that this code would output:

B.f1(String)
A.f1(String)
A.f1(int, String)

Yet I'm getting:

B.f1(String)
A.f1(String)
B.f1(int, String)
A.f1(int, String)

I understand that under the context of B "this" in A.f1(String) is B's instance. Do I have the option to do the chain new B1().f1(String) -> (A's) f1(String) -> (A's) f1(int, String) ?

This is a theoretical question, practically the solution would obviously be in A to implement a private function that both f1(String) and f1(int, String) would call.

Thank you,
Maxim.

回答1:

Unfortunately, no

As i'm sure you're aware, but I'll state explicitly for completeness - there are only the 2 keywords to control the method invocation:

  • this - this.method() - looks for method starting from the invoking instance's class (the instance's "top" virtual table - implied default)
  • super - super.method() - looks for method starting from the parent class of the class in which the invoking method is defined (the invoking class' parent's virtual table - not strictly true, but simpler to think of this way - thanks @maaartinus)

I can imagine another keyword (e.g. current?) do what you describe:

  • current - current.method() - looks for method starting from the class in which the invoking method is defined

but Java doesn't have such a keyword (yet?).



回答2:

I'm afraid, it's impossible, but there's a simple workaround:

public class A {
    public void f1(String str) {
        System.out.println("A.f1(String)");
        privateF1(1, str);
    }

    private void privateF1(int i, String str) {
        System.out.println("A.f1(int, String)");
    }

    public void f1(int i, String str) {
        privateF1(i, str);
    }
}


回答3:

Overridden methods in Java are dynamically bound. i.e. the type of the actual instance of the object dictates what will be called. final methods (which can't be overridden) and private methods (which can't be inherited) are statically bound.

In C++, for contrast, you'd have to explicitly make the functions virtual to get the same behaviour.



回答4:

package main;

public class A {
public void f1(String str) {
    System.out.println("A.f1(String)");
    if (this instanceof B)
        new A().f1(1, str);
    else
        this.f1(1, str);
}

public void f1(int i, String str) {
    System.out.println("A.f1(int, String)");
}

}

class B extends A {
@Override
public void f1(String str) {
    System.out.println("B.f1(String)");
    super.f1(str);
}

@Override
public void f1(int i, String str) {
    System.out.println("B.f1(int, String)");
    super.f1(i, str);
}

public static void main(String[] args) {
A a = new B();
    a.f1("Hello");
}
}