Java: Calling function in “this” class rather than

2020-03-26 05:43发布

Is it possible in Java to invoke an overridable method in such a way that it always executes the "locally defined" version rather than an overridden version from a subclass? I.e. is there an analog to super that refers to this class, rather than the super class?

Let me give a code example to hopefully make it clear what I'm trying to do:

class A {
    void foo() {
        System.out.println("Foo from A");
    }

    void bar() {
        foo();  // <-- This is the important line!
    }
}

class B extends A {
    @Override
    void foo() {
        System.out.println("Foo from B");
    }
}

If I do new B().bar(), it will call the bar() method defined in A, which calls foo() as overridden in B to print "Foo from B".

Is there a way that I can force the bar() method to call the foo() method as defined in A rather than B? Just like I can use super.foo() in B to call the foo() method as defined in A? Unfortunately using this.foo() still calls the version of the subclass. Even something like ((A) this).foo() or A.this.foo() doesn't work.

Clearly, I could simply define a private or final version of foo() in A and call that instead. But I am hoping for a solution, where all I do is change the "important line" in the code sample above to a different way of invoking foo() to have it print "Foo from A", preferably without some trick like reflection.

8条回答
Emotional °昔
2楼-- · 2020-03-26 05:54

foo() always invokes instance method of the class used in new ... statement.

In short I think that the answer to your question is NO, it can't be done. It would prevent you from overriding parts of behaviour completely.

class A {

method1() {
...
method2();
...
}

class B extends A {

// You can override method2 here to change the behaviour of method1 
// because it will call **your** version of method2
// You **don't** have to override method1 to achieve that

method2() {
...
}

}
查看更多
We Are One
3楼-- · 2020-03-26 05:55

As far as I know, a B object will always call its own foo() method. With that said, B.foo() can be defined to call the superclass' foo() method. For example, you could define B as follows:

class B extends A {
    @Override public void foo() {
        super.foo();
    }
}

And doing so will have B call foo from A. But doing so will have it always do so.

查看更多
叼着烟拽天下
4楼-- · 2020-03-26 05:57

You can have an "internal" foo() in A that is called.

class A {
    private void fooInternal() {
        System.out.println("Foo from A");
    }

    void foo() {
        fooInternal();
    }

    void bar() {
        fooInternal();
    }
}

class B extends A {
    @Override
    void foo() {
        System.out.println("Foo from B");
    }
}

new B().bar() will now print "Foo from A" while new B().foo() will print "Foo from B".

查看更多
Ridiculous、
5楼-- · 2020-03-26 06:06

Either make your methods static (baadddddd), either change your design.

Indeed, it makes no sense to provide the default behavior for a subclass that it is defined to adapt itself to the concerned method.

As your foo() method seems to vary, you may implement a Strategy Pattern like this:

interface BarProcess{
    void foo();
}

public class DefaultBarProcess implements BarProcess{
    void foo() {
       System.out.println("Foo from A");
    }
}

public class AnotherBarProcess implements BarProcess{
    void foo() {
       System.out.println("Foo from B");
    }
}

class A {

    private BarProcess barProcess;

    public A(Bar barProcess){
      this.barProcess = barProcess;
    }

    void bar() {
        barProcess.foo();
    }
}

class B extends A {  //deprecated! No need to exist

}
查看更多
女痞
6楼-- · 2020-03-26 06:07

this references "this object", not "this class".

That means if you have an object B that extends A, when it executes a method in the superclass A that mentions this, it will actually point to the instance of B, so will execute the method on B.

You can think of the method in A as a default method. If the method is overridden in your actual object B, then it will always be called instead.

I suggest you change your design and use composition instead of inheritance: that would ensure a clear separation of concern, and make your code a lot easier to understand and test.

查看更多
家丑人穷心不美
7楼-- · 2020-03-26 06:11

Your object is a B. It isn't an A! Here's an example:

public class Apple {
    public void printColor() {
        System.out.println("I am red");
    }

    public void bar() {
       printColor();
    }
}

Then the subclass:

public class GrannySmithApple extends Apple {
    public void printColor() {
        System.out.println("I am green");
    }
}

GrannySmithApples are green, always (unless they are rotten, but that's a whole other can of bananas)! Once you have a GrannySmithApple, it's not an Apple anymore, except in the sense that you can do all the same things with it that you could a regular Apple (printColor, eat, etc.) Make sense? And anything that hasn't changed between the conversion from regular Apple to GrannySmithApple is obviously still the same.

查看更多
登录 后发表回答