简体   繁体   English

具有重载方法的接口未按预期运行

[英]Interface with overloading methods not behaving as expected

I have an implementation of the following interface:我有以下接口的实现:

    Object map(Object object);

    Entity map(Dto object);

    Dto map(Entity object);

When I call map(new Dto()) I would expect that the method Entity map(Dto object) gets called.当我调用map(new Dto())时,我希望方法Entity map(Dto object)被调用。 Altought the method Object map(Object object) gets invoked.调用方法Object map(Object object)

What, in the jungle of typeerasure and overloading, am I missing?在打字和超载的丛林中,我错过了什么?

What you're missing is how java works.您缺少的是 java 的工作原理。

A method's "identity", the thing that is written in the class file, is not just the method name .方法的“身份”,即写在 class 文件中的东西,不仅仅是方法名称 It's the method name, and the 'type' that it comes from, and the erased types (but not names) of the parameters, and the return type.它是方法名称它来自的“类型” 参数的擦除类型(但不是名称),以及返回类型。

So, your 3 map methods there?那么,你的 3 map 方法在那里? They are different methods .它们是不同的方法 They are nothing alike, they are not overloads of each other, they are as different as void foo() {} and void bar() {} are.它们完全不同,它们不是彼此的重载,它们与void foo() {}void bar() {}一样不同。

Java does have dynamic dispatch and overriding, but only if the signatures line up . Java 确实具有动态调度和覆盖,但前提是签名对齐。

javac decides which method id you are invoking (and, remember, the 'id' of a method is the name and the param types and the return type). javac决定您正在调用哪个方法 id(记住,方法的 'id' 是名称参数类型返回类型)。 the runtime ( java ) then picks the most specific override of that method id to run.运行时( java )然后选择该方法 id 的最具体的覆盖来运行。

Here's some java code to drive the point home:这是一些 java 代码来驱动要点:

class Parent {
  void foo(Object o) {
    System.out.println("Parent.foo(Object)");
  }

  void foo(String o) {
    System.out.println("Parent.foo(String)");
  }
}

class Child extends Parent {
  void foo(String o) {
    System.out.println("Child.foo(String)");
  }
}

class Main {
  public static void main(String[] args) {
    Parent a = new Child();
    a.foo("hello"); // prints 'Child.foo(String)'
    Object b = "hello";
    a.foo(b); // prints 'Parent.foo(Object)'
    a.foo((String) b); // prints 'Child.foo(String)'
  }
}

The upshot is that you cannot use 'tightening' the types in an overloaded method for dynamic dispatch.结果是您不能在动态调度的重载方法中使用“收紧”类型。 ie you can't go: "Oh, I want to override the map method, but only if the parameter is this subtype. If it's not of this subtype I just want it to go to parent".即你不能 go:“哦,我想覆盖map方法,但前提是参数是这个子类型。如果它不是这个子类型,我只希望它到 Z34D1F91FB2E514B8576ZFAB176 到父级。” If you want that behaviour, you have to override the method:如果你想要这种行为,你必须重写该方法:

class Parent {
  Object map(Object object) {}
}

class Child {
  Object map(Object object) {
    if (object instanceof Dto dto) return childMap(dto);
    return super.map(object);
  }

  Object childMap(Dto dto) {
     // your code specifically for Dto goes here
  }
}

I strongly advise naming that custom child-based method differently to avoid confusion.我强烈建议以不同的方式命名该自定义的基于子的方法以避免混淆。 The @Override annotation can be used to guard against mistakes. @Override注释可用于防止错误。 If you think a method is an override, always annotate it as such (that method doesn't make a method an override, it merely causes the compiler to error out if it is not. It's compiler-checked documentation).如果您认为一个方法是一个覆盖,请始终对其进行注释(该方法不会使方法成为覆盖,如果不是,它只会导致编译器出错。它是编译器检查的文档)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM