我遇到了有趣的事情(在 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{
}
C# code:
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
{
}
}
当我写这样的东西时,我希望看到在两种情况下都打印“b”。
但是,正如您所看到的,打印的是“a”。
我读过 C# 语言规范,它说重载方法是在编译时选择的。它解释了为什么它会这样工作。
不过我没时间去查看Java语言规范。
有人可以更详细地解释发生了什么以及为什么吗?我怎样才能实现我想要的?
提前致谢!
关键是要理解泛型仅在 java 中的编译时可用。它只是编译器在编译时使用的语法糖,但在生成类文件时被丢弃。
因此,代码:
public <T extends A> void genericPrint(T b) {
print(b);
}
被编译为:
public void genericPrint(A b) {
print(b);
}
自从争论到print
属于A型,重载版本print(A a)
是解决的问题。我建议对 A 或 A 的实例使用多态调用访客模式 http://en.wikipedia.org/wiki/Visitor_pattern回调到 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);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)