无法使用Java泛型选择适当的方法

无法使用Java泛型选择适当的方法,java,generics,Java,Generics,这个程序不符合我的要求。它会打印两次“悲伤”,而我希望它会打印“快乐”,然后再打印“悲伤” public-class-Woof{ 公共静态类Arf{ 雅普; 公共Arf(yap){ this.yap=yap; } 公共弦纬{ /* *应根据是否 *正好是一个整数,或者别的什么。 */ 返回doYapStuff(yap); } /*doYapStuff()的特例实现,其中T是整数*/ 公共字符串doYapStuff(整数x){ 返回“快乐”; } /*doYapStuff()的默认实现,其中T是其

这个程序不符合我的要求。它会打印两次“悲伤”,而我希望它会打印“快乐”,然后再打印“悲伤”

public-class-Woof{
公共静态类Arf{
雅普;
公共Arf(yap){
this.yap=yap;
}
公共弦纬{
/*
*应根据是否
*正好是一个整数,或者别的什么。
*/
返回doYapStuff(yap);
}
/*doYapStuff()的特例实现,其中T是整数*/
公共字符串doYapStuff(整数x){
返回“快乐”;
}
/*doYapStuff()的默认实现,其中T是其他值*/
公共字符串doYapStuff(tx){
返回“悲伤”;
}
}
公共静态void main(字符串[]args){
整数i=5;
Arf arf1=新的Arf(i);
System.out.println(arf1.woof());//应该打印“happy”
字符串s=“foo”;
Arf arf2=新的Arf;
System.out.println(arf2.woof());//应打印“sad”
}
}

当您使用Integer为T实例化泛型时,由于Java使用类型擦除实现泛型的方式,T总是会覆盖Integer。

本博客对此进行了解释:

相关报价:

这怎么会发生?我们将String类型的参数传递给重载的方法,然后调用type对象的版本。原因是编译器只为每个泛型类型或方法创建一个字节码表示,并将泛型类型或方法的所有实例化映射到该表示

在我们的示例中,通用方法转换为以下表示形式:

(编辑:我更改了方法以匹配此问题)

考虑到这种转换,调用重载方法的对象版本的原因应该是显而易见的。将什么类型的对象传递给泛型方法,然后再传递给重载方法,这是完全无关的。我们将始终观察重载方法的对象版本的调用

更一般地说:重载解析发生在编译时,也就是说,编译器决定必须调用哪个重载版本。当泛型方法被转换为其唯一的字节码表示形式时,编译器会这样做。在转换期间,将执行类型擦除,这意味着如果未指定绑定,则类型参数将替换为最左侧的绑定或对象。因此,最左边的绑定或对象决定调用重载方法的哪个版本。运行时传递给方法的对象类型与重载解析完全无关

如果查看编译的字节码,您可以看到:

 4  getfield Woof$Arf.yap : java.lang.Object [16]
 7  invokevirtual java.io.PrintStream.println(java.lang.Object) : void [32]
10  aload_0 [this]
11  aload_0 [this]
12  getfield Woof$Arf.yap : java.lang.Object [16]
15  invokevirtual Woof$Arf.doYapStuff(java.lang.Object) : java.lang.String [37]
18  areturn
为了实现您想要的,您可能应该使用策略模式

public String doYapStuff(Object x) {
            return "sad";
}
 4  getfield Woof$Arf.yap : java.lang.Object [16]
 7  invokevirtual java.io.PrintStream.println(java.lang.Object) : void [32]
10  aload_0 [this]
11  aload_0 [this]
12  getfield Woof$Arf.yap : java.lang.Object [16]
15  invokevirtual Woof$Arf.doYapStuff(java.lang.Object) : java.lang.String [37]
18  areturn
public interface YapSound{
     String     doYapSound();
}

public class HappySound implements YapSound{

    @Override
    public String doYapSound() {
          return "happy";
     }

}

public class SadSound implements YapSound{

    @Override
    public String doYapSound() {
        return "sad";
    }

}

public class Arf {
    YapSound yap;
    public Arf(YapSound yap) {
        this.yap = yap;
    }

    public String woof() {
        /*
         * Should select which doYapStuff() based on whether T
         * happens to be an Integer, or something else.
         */
        return yap.doYapSound();
    }


}

public static void main(String[] args) {

    Arf arf1 = new Arf(new HappySound());
    System.out.println(arf1.woof()); // Should print "happy"

    Arf arf2 = new Arf(new SadSound());
    System.out.println(arf2.woof()); // Should print "sad"
}