泛型类编译Java 6中,而不是Java 7(Generic class compiles in J

2019-06-27 14:40发布

我在Java 6中是正确编译的接口:

public interface IMultiMap<K, V> extends Map<K, Set<V>> {

    public int valueSize();

    public boolean put(K key, V value);

    public void clear(Object key);

    public boolean isEmpty(Object key);
}

但在Java 7,此接口不编译。 我得到一个编译错误的boolean put(K, V)它具有相同的擦除为V put(K, V) 从编译器的完整的错误:

error: name clash: put(K#1,V#1) in IMultiMap and put(K#2,V#2) in Map have the same erasure, yet neither overrides the other
    public boolean put(K key, V value);
  where K#1,V#1,K#2,V#2 are type-variables:
    K#1 extends Object declared in interface IMultiMap
    V#1 extends Object declared in interface IMultiMap
    K#2 extends Object declared in interface Map
    V#2 extends Object declared in interface Map

根据记录,添加任何一种压倒一切的不工作。 我试图重写明确Map.put ,但错误仍然出现。 改变我的返回类型put ,因为这个错误是阻断正在达到有史以来从潜在的错误,如果这个错误是固定的,那么这两个方法不会有相同的名称/参数签名反正是没有实际意义。

我想我可能会尝试在Java 6的一些反思,看看实际的参数类型最终在Java 6中的编译的字节代码之中。 很明显,这两个Java 7的方法正在擦除put(Object, Object) 。 一旦我这样做,我会在这里发表的反射效果。

在此期间,我的临时解决办法将是多么重命名putputSingle ,但这种新的行为是否正确? 做了仿制药的规格变化对Java 7,使旧的Java 6的行为错误的某些部分? 或者,这是Java编译器7的错误?

提前致谢。

编辑:我跑的反射代码。 看看我的回答如下。

Answer 1:

我认为这是在1.6臭虫固定在1.7。 从提取此页 :

剧情简介:一个类不能定义具有相同签名擦除两种方法,但两种不同的返回类型
说明:一个类不能定义两个方法具有相同的擦除签名,无论返回类型是否相同与否。 这是根据JLS,Java SE 7中版,部分8.4.8.3。 在JDK 6编译器允许使用相同的擦除签名,但是返回类型不同的方法; 这种行为是不正确的,已被固定在JDK 7。
例:

class A {
   int m(List<String> ls) { return 0; }
   long m(List<Integer> ls) { return 1; }
}

JDK 5.0和JDK 6下此代码编译,和JDK 7下被拒绝。



Answer 2:

我跑在Java 6的反射代码。

下面的代码:

public static void main(String[] args) {
    Class<IMultiMap> immClass = IMultiMap.class;
    Method[] methods = immClass.getMethods();
    for (Method method : methods) {
        if (method.getName().equals("put"))
            System.out.println(method.toString());
    }
}

下面是类的方法签名:

public abstract boolean IMultiMap.put(java.lang.Object,java.lang.Object)
public abstract java.lang.Object java.util.Map.put(java.lang.Object,java.lang.Object)

或者更简洁:

boolean put(Object, Object)
Object  put(Object, Object)

因此,他们被擦除与不同的返回类型相同的参数。 我想这是一个错误在Java 6 JLS未指定的边缘情况,那么,按照assylias的回答。 我不知道Java 6中如何管理,正确解决运行时这些方法?

编辑:据x4u的评论,调用字节码维持到整个签名的引用时,它的编译,所以这就是为什么正在被JVM的正确方法。 由于编译器可能是能够讲述的哪种方法我打电话由于其源接(并因此到泛型信息),编译器可能通过它的整个签名链接到正确的方法。 兴趣知道!



文章来源: Generic class compiles in Java 6, but not Java 7