Java泛型中的桥接方法。这个例子正确吗?

Java泛型中的桥接方法。这个例子正确吗?,java,generics,bounds,type-erasure,java-bridge-method,Java,Generics,Bounds,Type Erasure,Java Bridge Method,假设我有一个通用类: class Item<T> { private T item; public void set(T item) { this.item = item; } public T get() { return item; } } 现在,如果我像这样扩展类项: Item<Integer> intItem = new Item<Integer>(); Item<String> stringItem

假设我有一个通用类:

class Item<T> {
  private T item;
  public void set(T item) {
    this.item = item;
  }
  public T get() {
    return item;
  } 
}
现在,如果我像这样扩展类项:

Item<Integer> intItem = new Item<Integer>();
Item<String> stringItem = new Item<String>();
class IntItem extends Item<Integer>{
  private Integer item;
  public void set(Integer item) {
    this.item = item;
  }
  public Integer get() {
   return item;
  } 
}
创建以下桥接方法:

  class IntItem extends Item<Integer>{
      private Integer item;
      //Bridge method 1
      public void set(Object item) {
        this.item = (Integer) item;
      }
      public void set(Integer item) {
        this.item = item;
      }
      //Bridge method 2
      public Object get() {
       return item;
      }
      public Integer get() {
       return item;
      } 
    }
到这里之前我都知道了吗? 我的问题是,为什么以及何时需要桥接方法? 你能用这个Item类做一些例子吗


我已经读过其他答案,但如果没有具体的例子,我仍然无法完全理解。

你几乎把它答对了。几乎是这样,因为桥接方法桥接方法调用并且不复制方法实现。您的IntItem类看起来像以下已删除的版本,您可以使用例如javap来验证这一点:

如前所述,IntItem::setInteger方法不是泛型方法,因为它被非泛型方法重写。因此,调用此方法时不涉及类型擦除。Java编译器只是编译上面的方法调用,用字节码签名setInteger:void调用该方法。就像你预料的那样

但是,当查看以下代码时:

Item<Integer> generic = ...;
generic.set(42);
编译器无法确定泛型变量是否包含IntItem或Item或任何其他兼容类的实例。因此,无法保证具有字节码签名setInteger:void的方法是否存在。这就是Java编译器应用类型擦除并将项视为原始类型的原因。通过查看原始类型,调用了setObject:void方法,该方法是在项本身上定义的,因此始终存在

因此,IntItem类无法确定是使用从Item继承的擦除类型的方法调用其方法,还是使用显式类型的方法调用其方法。因此,隐式实现桥接方法以创建真理的单一版本。通过动态调度网桥,您可以在IntItem的子类中重写setInteger,网桥方法仍然有效


桥接方法也可用于实现方法的协变返回类型。这个特性是在引入泛型时添加的,因为桥接方法已经作为一个概念存在。可以说,这项功能是免费的。桥梁方法的第三种应用是它们的作用。这是克服反射引擎访问限制所必需的。

您几乎做到了正确。几乎是这样,因为桥接方法桥接方法调用并且不复制方法实现。您的IntItem类看起来像以下已删除的版本,您可以使用例如javap来验证这一点:

如前所述,IntItem::setInteger方法不是泛型方法,因为它被非泛型方法重写。因此,调用此方法时不涉及类型擦除。Java编译器只是编译上面的方法调用,用字节码签名setInteger:void调用该方法。就像你预料的那样

但是,当查看以下代码时:

Item<Integer> generic = ...;
generic.set(42);
编译器无法确定泛型变量是否包含IntItem或Item或任何其他兼容类的实例。因此,无法保证具有字节码签名setInteger:void的方法是否存在。这就是Java编译器应用类型擦除并将项视为原始类型的原因。通过查看原始类型,调用了setObject:void方法,该方法是在项本身上定义的,因此始终存在

因此,IntItem类无法确定是使用从Item继承的擦除类型的方法调用其方法,还是使用显式类型的方法调用其方法。因此,隐式实现桥接方法以创建真理的单一版本。通过动态调度网桥,您可以在IntItem的子类中重写setInteger,网桥方法仍然有效


桥接方法也可用于实现方法的协变返回类型。这个特性是在引入泛型时添加的,因为桥接方法已经作为一个概念存在。可以说,这项功能是免费的。桥梁方法的第三种应用是它们的作用。这对于克服反射引擎的访问限制是必要的。

您看到了吗。这里有一个几乎相同的例子。还有什么不清楚的?IntItem有另一个字段项,而不是item.item,所以这个示例有点尴尬。谢谢我阅读了链接。所以桥接方法的唯一目的就是启用多态性?类似项目i=新项目;我们想让i.get从IntItem类调用bridge方法?有更多的桥接方法吗?你似乎不完全掌握了一切。桥接方法是使Java实现泛型良好工作所必需的,这可能是一个太强的语句,但据我所知,似乎是这样的。。。。次要挑剔:正如链接页面中所述,桥接方法在擦除后保留泛型类型的多态性,而不是启用它。您看到了吗。有一个几乎一模一样的前男友
那就足够了。还有什么不清楚的?IntItem有另一个字段项,而不是item.item,所以这个示例有点尴尬。谢谢我阅读了链接。所以桥接方法的唯一目的就是启用多态性?类似项目i=新项目;我们想让i.get从IntItem类调用bridge方法?有更多的桥接方法吗?你似乎不完全掌握了一切。桥接方法是使Java实现泛型良好工作所必需的,这可能是一个太强的语句,但据我所知,似乎是这样的。。。。次要挑剔:正如链接页面中所述,桥接方法在擦除后保留泛型类型的多态性,而不是启用它。
IntItem nonGeneric = new IntItem();
nonGeneric.set(42);
Item<Integer> generic = ...;
generic.set(42);