从泛型方法问题调用重载方法

Ser*_*nko 4 c# java generics overloading

我遇到了有趣的事情(在Java和C#中都一样).Java代码:

public class TestStuff {

    public static void main(String[] args) {
        Printer p = new PrinterImpl();
        p.genericPrint(new B());    
    }

}

class PrinterImpl implements Printer {

    void print(A a) {
        System.out.println("a");
    }

    void print(B b) {
        System.out.println("b");
    }

    @Override
    public <T extends A> void genericPrint(T b) {
        print(b);
    }

}

interface Printer {
    public <T extends A> void genericPrint(T a);
}

class A {

}

class B extends A{

}
Run Code Online (Sandbox Code Playgroud)

C#代码:

namespace TestStuff
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var printer = new Printer();
            printer.GenericPrint(new B());
        }

    }

    public class Printer
    {

        public void Print(A a)
        {
            Console.WriteLine("a");
        }

        public void Print(B b)
        {
            Console.WriteLine("b");
        }

        public void GenericPrint<T>(T a) where T : A
        {
            Print(a);
        }

    }

    public class B : A
    {

    }

    public class A
    {

    }

}
Run Code Online (Sandbox Code Playgroud)

当我写这样的东西时,我希望在这两种情况下都能看到"b".但是,正如你所看到的,它是"一个"印刷的东西.

我已经阅读了C#语言规范,它说在编译时选择了重载方法.它解释了为什么它以这种方式工作.

但是,我没有时间在Java语言规范中查看它.

有人可以更详细地解释发生了什么以及为什么?我怎么能实现我想要的?

提前致谢!

sha*_*ams 5

关键是要理解泛型只能在java的编译时使用.它只是编译器在编译时使用的语法糖,但在生成类文件时会丢弃.

因此,代码:

   public <T extends A> void genericPrint(T b) {
      print(b);
   }
Run Code Online (Sandbox Code Playgroud)

编译成:

   public void genericPrint(A b) {
      print(b);
   }
Run Code Online (Sandbox Code Playgroud)

由于参数print是A类型,因此重载版本print(A a)是已解析的版本.我建议对A或者访问者模式的实例使用多态调用来回调用于您的用例的PrinterImpl.

就像是:

interface Visitor {
   void visit(A a);

   void visit(B b);
}

class PrinterImpl implements Printer, Visitor {

   void print(A a) {
      System.out.println("a");
   }

   void print(B b) {
      System.out.println("b");
   }

   public <T extends A> void genericPrint(T b) {
      b.accept(this);
   }

   public void visit(A a) {
      print(a);
   }

   public void visit(B b) {
      print(b);
   }
}

interface Printer {
   public <T extends A> void genericPrint(T a);
}

class A {
   public void accept(Visitor v) {
      v.visit(this);
   }
}

class B extends A {
   public void accept(Visitor v) {
      v.visit(this);
   }
}
Run Code Online (Sandbox Code Playgroud)