有关重载方法的泛型查询

时间:2015-09-26 08:50:26

标签: java generics

我正在从JavaDocs阅读此示例在第一个示例中,文档说它将调用setData(Object)方法,但是当我尝试代码时,它从不调用该方法,而是调用{{ 1}}方法。

但是当我实现这个例子时,它给出了运行时异常

  

n.setData的java.lang.ClassCastException(" Hello");

setData(Integer data)

public class Node<T> {
    public T data;

    public Node(T data) {
        this.data = data;
    }

    public void setData(T data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

但是医生说:

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) {
        super(data);
    }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

ClassCast异常将在第4行发生。它没有那样发生。

2 个答案:

答案 0 :(得分:2)

在同一个教程中已经解释了所发生的事情。

  
      
  • n.setData("Hello");导致方法setData(Object)在类MyNode的对象上执行。 (MyNode类继承了setData(Object)的{​​{1}}。)
  •   
  • Node的正文中,setData(Object)引用的对象的data字段已分配给n
  •   
  • 可以访问同一个对象的String字段,通过data引用,并且应该是一个整数(因为mnmn,这是一个MyNode Node<Integer>
  •   
  • 尝试将String分配给Integer会导致Java编译器在分配时插入的强制转换ClassCastException
  •   

所以,正如你所看到的,这就是你所经历的。在尝试将String分配给整数时,方法调用会导致异常。

令人困惑的是,代码中的注释可能是错误的。它试图告诉你代码不会到达第4行,因为这一点会引发异常。但是,如果评论在第3行,那么实际上会抛出异常,那就更清楚了。

答案 1 :(得分:1)

当使用泛型参数覆盖方法并且重写方法具有更多特定绑定时,会发生以下情况。在基本类字节码中,您可以使用带有擦除签名的方法:

Object data;

public void setData(Object data) {
    System.out.println("Node.setData");
    this.data = data;
}

由于子类不再是通用的,所以字节码中的方法与源中的方法完全相同:

public void setData(Integer data) {
    System.out.println("MyNode.setData");
    super.setData(data);
}

但是,您可以看到此方法不会覆盖超类方法,因为参数类型不同。尽管如此,它必须被覆盖。为此,java编译器在MyNode类中生成一个特殊的合成桥方法:

public void setData(Object data) {
    this.setData((Integer)data);
}

所以,你的演员阵容失败了。当你调用n.setData("Hello")时,它是一个虚拟调用,并调用这个合成方法,当然会抛出异常。

您可能认为替代解决方案不是引入桥接方法,而是在编译期间更改MyNode中的参数类型:

public void setData(Object data) {
    System.out.println("MyNode.setData");
    super.setData(data);
}

此类解决方案会引入更多问题,尤其是代码二进制兼容性问题。您MyNode的用户不应该知道您的类扩展了某些通用参数,它是一个实现细节。他们应该能够使用正常setData参数调用您的Integer。您可以稍后更改超类以删除Node中的泛型参数(假设所有节点现在都是整数),MyNode类的用户仍然可以正常工作而无需重新编译。