在Java中是否可以将方法设为非虚拟的?

huangapple go评论72阅读模式
英文:

Is it possible to make methods non-virtual in Java?

问题

在Java中,所有非静态方法默认都是虚方法,类似于C++中的虚函数。要达到您期望的输出,可以将父类的methodAmethodB方法标记为final,这样它们就不能被子类重写。这将防止子类在调用这些方法时执行它们自己的实现。以下是修改后的代码:

public class ParentClass {
    public final void methodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public final void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        methodA();
    }
}

public class ChildClass extends ParentClass{
    @Override
    public void methodA() {
        System.out.println("This is Child A Method and I am Calling Parents Method A");
        whoAmI();
        super.methodA();
    }

    @Override
    public void methodB() {
        System.out.println("This is Child B Method and I am Calling Parents Method B");
        whoAmI();
        super.methodB();
    }
}

然后,您可以运行以下代码以获得期望的输出:

ChildClass c = new ChildClass();
c.methodB();

这将产生如下输出:

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method
英文:

i am newbie in java and i usually used c++ i just wondering this code works

public class ParentClass {
    public void methodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        methodA();
    }
}

public class ChildClass extends ParentClass{
    @Override
    public void methodA() {
        System.out.println("This is Child A Method and I am Calling Parents Method A");
        whoAmI();
        super.methodA();
    }

    @Override
    public void methodB() {
        System.out.println("This is Child B Method and I am Calling Parents Method B");
        whoAmI();
        super.methodB();
    }
}
ChildClass c = new ChildClass();
c.methodB();

and I expected output like this

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

but was

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Child A Method and I am Calling Parents Method A
This is Parent A Method

so i realized that in java all non-static methods are by default virtual functions like virtual keyword in c++.

is there any way to make output like this?

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

答案1

得分: 1

你可以将 ParentClassmethodA 的实现包装在一个单独的私有方法中:

public class ParentClass {
    public void methodA() {
        interMethodA();
    }

    private void interMethodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        interMethodA();
    }
}

ChildClass 保持不变。

英文:

You can wrap the methodA's impl of ParentClass in a seperate private method:

public class ParentClass {
    public void methodA() {
        interMethodA();
    }

    private void interMethodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        interMethodA();
    }
}

And the ChildClass remains the same.

答案2

得分: 1

代码 - 如所示 - 由于方法 whoAmI() 未定义而无法编译。通过删除对此方法的调用,我能够复制输出


据我理解,您希望确保在 Parent 中的 methodAParent 中的 methodB 中被调用。由于在 Java 中使用了 动态分派 来确定调用哪个实际实现,我们必须强制 methodA 不能被覆盖。正如 @MarquisofLorne 所指出的,C++ 也使用了动态分派,如果在 Parent 中将 methodA 定义为 virtual

为了确保动态分派始终调用 ParentmethodA,我想到了两种常见的方法:将 methodA 声明为 final 和将 methodA 声明为 private


方法一:将 Parent 中的 methodA 声明为 final

选择这种方法时,Child 无法重新定义 methodA,即如果不从 Child 中删除 methodA,则代码将导致编译时错误。

Ideone 示例


方法二:将 Parent 中的 methodA 声明为 private

这种方法类似于第一种方法,但允许您在 Child 中保留 methodA,尽管必须删除 @Override 注解,因为私有方法无法被覆盖。

Ideone 示例

英文:

The code - as is - does not compile since method whoAmI() is undefined. By removing the calls to this method, I was able to reproduce the output.


From what I understand, you want to ensure that methodA in Parent is called from methodB in Parent. Since dynamic dispatching is used in Jjava to determine which actual implementation is called, we have to enforce that methodA cannot be overridden. As @MarquisofLorne pointed out, C++ uses dynamic dispatch aswell, if methodA is defined as virtual in Parent.

To enforce that dynamic dispatch always results in a call to Parent's methodA, there are two general approaches that come to my mind: declaring methodA as final and declaring methodA as private.


Approach one: declare methodA in Parent as final

When going down this route, Child cannot re-define methodA, i.e. the code would result in a compile-time error if methodA is not removed from Child.

<kbd>Ideone demo</kbd>


Approach two: declare methodA in Parent as private

This approach is similar to the first approach, but allows you to retain methodA in Child, albeit the @Override-annotation must be removed since private methods cannot be overridden.

<kbd>Ideone demo</kbd>

答案3

得分: 0

这是Child B方法,我正在调用Parent方法B
这是Parent方法B,我正在调用方法A
这是Child A方法,我正在调用Parent方法A
这是Parent方法A

英文:

You got:

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Child A Method and I am Calling Parents Method A
This is Parent A Method 

Instead of

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

Simply Bacause, In Java calling methodA() or this.methodA() in your methodB() of ParentClass calls the method off of the calling object or instance, Yet the instance is an instanceof ChildClass. Java treats methodA() and this.methodA() as same. The this keyword in Java actually refers to the "currently running instance of the object you're using". Meaning, the overridding methodA() of ChildClass will be called instead of methodA() of ParentClass.

Here is a suggestion, to get the expected output, simply apply modifications on the overridding methodA() of ChildClass by commenting out the printing line.
Otherwise reference this for more details.

huangapple
  • 本文由 发表于 2020年8月8日 17:09:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/63313639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定