在Java中重载一个已覆盖的方法

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

Overloading an Overridden method in Java

问题

我有一个实现了接口A的类B,如下所示:

public interface A {

    Map<String, Object> doStuff(Integer param1, Integer Param2);
}

public class B implements A {

    public Map<String, Object> doStuff(Integer param1, Integer param2) {
        return doStuff(param1, param2, newParam3);
    }

    public Map<String, Object> doStuff(Integer param1, Integer Param2, boolean param3) {
        if (param3)
            doSomething;
        return doneStuff;
    }
}

但是当我尝试访问重载但未覆盖的方法时,我会得到编译时错误。这不应该是完全没问题的吗?

英文:

I have a class B that implements interface A such that:

public interface A {

    Map&lt;String, Object&gt; doStuff(Integer param1, Integer Param2);
}

public class B implements A {

    public Map&lt;String, Object&gt; doStuff(Integer param1, Integer param2) {
        return doStuff(param1, param2, newParam3);
    }

    public Map&lt;String, Object&gt; doStuff(Integer param1, Integer Param2, boolean param3) {
        if (param3)
            doSomething;
        return doneStuff;
    }
}

But when I try to access the overloaded but not overridden method I get compile time errors. Shouldn't this be perfectly fine?

答案1

得分: 1

在Java方法调用中,有两个完全分离的步骤。

步骤1是:将方法调用(在您的源代码中)转换为完全限定的方法标识。这完全在编译时发生。

步骤2是:既然我们有了完全限定的方法标识,通过动态查找在对象的实际实例类型(x.getClass())开始,并沿着继承层次向上查找实现,找到该标识的实际实现。这完全在运行时发生。

完全限定的方法标识包括包、类、方法名称、参数类型和返回类型。

因此,在您的B类中,有2个不同的方法标识。不同的方法标识代表不同的方法;名称相同的事实是无关紧要的。

换句话说,这个:

A x = new B();
x.doStuff(param1, param2);

被存储为对方法 com.foo.pkg.A::doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Map; 的INVOKEVIRTUAL/INVOKEINTERFACE调用。这实际上在类文件中;查看一下javap的输出,或者用十六进制编辑器打开那个文件,您会在那里找到这个字符串,至少从doStuff开始。

然后只有在运行时,INVOKEINTERFACE com.foo.pkg.A doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Map 字节码指令才会检查您的x变量指向的对象的类型,确定它是com.foo.pkg.B的实例,然后实际上调用B类对此方法的实现来完成工作。

您的第二个doStuff方法的方法标识是 B doStuff(Ljava/lang/Integer;Ljava/lang/Integer;Z)Ljava/util/Map; - 请注意这完全是另一个方法(这个方法中有一个Z)。

因此,这个:

A x = new B();
x.doStuff(1, 2, true);

会导致编译错误:A接口根本没有这个方法。

英文:

There are two entirely separated steps in java method invocation.

Step 1 is: Turn the method invocation (in your source code) into the fully qualified method ID. This occurs entirely at compile time.

Step 2 is: Now that we have a fully qualified method ID, find the actual implementation for this ID by doing a dynamic lookup, starting at the object's actual instance type (x.getClass()), and going upwards in the hierarchy until you find an implementation. This occurs entirely at runtime.

A fully qualified method ID includes the package, class, method name, parameter types and return type.

So, in your class B you have 2 different method IDs. And different method IDs are different methods; the fact that the name is the same is irrelevant.

In other words, this:

A x = new B();
x.doStuff(param1, param2);

is stored as an INVOKEVIRTUAL/INVOKEINTERFACE to method com.foo.pkg.A::doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Map;. That's literally in the class file; have a look at the output of javap or actually go open that thing with a hex editor and you'll find that string in there, at least, starting at doStuff.

Then at runtime only, that 'INVOKEINTERFACE com.foo.pkg.A doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Mapbytecode instruction ends up checking the type of the object that yourxvariable is pointing to, figures out it&#39;s an instance ofcom.foo.pkg.B`, and will then actually call B's implementation of this method to do the job.

Your second doStuff method has method ID B doStuff(Ljava/lang/Integer;Ljava/lang/Integer;Z)Ljava/util/Map; - note how this is just a completely different method (this one has a Z in it).

Thus, this:

A x = new B();
x.doStuff(1, 2, true);

is a compilation error: The A interface doesn't have that method at all.

huangapple
  • 本文由 发表于 2020年10月14日 00:47:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/64339632.html
匿名

发表评论

匿名网友

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

确定