Java泛型代码编译与javac,失败与Eclipse Helios [英] Java generics code compiles with javac, fails with Eclipse Helios

查看:136
本文介绍了Java泛型代码编译与javac,失败与Eclipse Helios的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下测试类,它使用泛型来重载一个方法。它在使用javac编译时工作,并且无法在Eclipse Helios中编译。我的java版本是1.6.0_21。



我阅读的所有文章都表明Eclipse是正确的,此代码不应该工作。但是当使用javac编译并运行时,将选择正确的方法。



这可能如何?



谢谢!

  import java.util.ArrayList; 

public class Test {
public static void main(String [] args){
Test t = new Test();
ArrayList< String> ss = new ArrayList< String>();
ss.add(hello);
ss.add(world);
ArrayList< Integer> is = new ArrayList< Integer>();
is.add(1);
is.add(2);
System.out.println(t.getFirst(ss));
System.out.println(t.getFirst(is));
}
public String getFirst(ArrayList< String> ss){
return ss.get(0);
}
public Integer getFirst(ArrayList< Integer> ss){
return ss.get(0);
}
}


解决方案

Java语言规范,第8.4.2节写:


这是一个编译时错误,用
override等效签名来声明两个方法
(定义



如果m1是m2的子签名,或m2是m1的子签名,则两个方法签名m1和m2都是超等效的。



方法m1的签名是方法m2的签名的子签名,如果




  • m2具有与m1相同的签名,或者


  • m1的签名与删除m2签名相同。



显然,这些方法不会超越等效,因为 ArrayList< String> 不是 ArrayList (擦除 ArrayList< Integer> )。



所以声明方法是合法的。此外,方法调用表达式是有效的,因为这是一个最具体的方法,因为只有一种匹配参数类型的方法。



编辑:Yishai正确地指出,在这种情况下,还有另外一个限制。 Java语言规范,第8.4.8.3节写道:


如果类型声明T具有成员方法
m1,则存在编译时错误,并且存在在T中声明的方法m2
或T的超类型,例如
,所有以下条件
保持:




  • m1和m2具有相同的名称。

  • m2可从T访问。

  • m1的签名不是子签名(§ (或直接或间接的)方法m1的覆盖与m2或某些方法m2的重写(直接或间接)相同。 / li>

附录:关于缺乏



与流行的概念相反,方法签名中的泛型不会被删除。泛型被删除在字节码(Java虚拟机的指令集)。方法签名不是指令集的一部分;它们被写入源代码中指定的类文件。 (除此之外,这些信息也可以在运行时使用反射查询)。



想想:如果类型参数完全从类文件中删除,代码如何在您选择的IDE中完成显示 ArrayList.add(E)采用类型为 E 的参数,而不是如果您没有附加JDK源代码,则对象(=删除 E )当方法参数的静态类型不是 E 的子类型时,编译器会如何发出编译错误?


I have the following test class that uses generics to overload a method. It works when compiled with javac and fails to compile in Eclipse Helios. My java version is 1.6.0_21.

All the articles I read indicate that Eclipse is right and this code should not work. However when compiled with javac and run, the right method is selected.

How is this possible?

Thanks!

import java.util.ArrayList;

public class Test {
    public static void main (String [] args) {
        Test t = new Test();
        ArrayList<String> ss = new ArrayList<String>();
        ss.add("hello");
        ss.add("world");
        ArrayList<Integer> is = new ArrayList<Integer>();
        is.add(1);
        is.add(2);
        System.out.println(t.getFirst(ss));
        System.out.println(t.getFirst(is));
    }   
    public String getFirst (ArrayList<String> ss) {
        return ss.get(0);
    }
    public Integer getFirst (ArrayList<Integer> ss) {
        return ss.get(0);
    }
}

解决方案

The Java Language Specification, section 8.4.2 writes:

It is a compile-time error to declare two methods with override-equivalent signatures (defined below) in a class.

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

The signature of a method m1 is a subsignature of the signature of a method m2 if either

  • m2 has the same signature as m1, or

  • the signature of m1 is the same as the erasure of the signature of m2.

Clearly, the methods are not override equivalent, since ArrayList<String> isn't ArrayList (the erasure of ArrayList<Integer>).

So declaring the methods is legal. Also, the method invocation expression is valid, as there trivially is a most specific method, since there is only one method matching the argument types.

Edit: Yishai correctly points out that there is another restriction closely skirted in this case. The Java Language Specification, section 8.4.8.3 writes:

It is a compile time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following conditions hold:

  • m1 and m2 have the same name.
  • m2 is accessible from T.
  • The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.
  • m1 or some method m1 overrides (directly or indirectly) has the same erasure as m2 or some method m2 overrides (directly or indirectly).

Appendix: On ersure, and the lack thereof

Contrary to popular notion, generics in method signatures are not erased. Generics are erased in bytecode (the instruction set of the Java virtual machine). Method signatures are not part of the instruction set; they are written to the class file as specified in the source code. (As an aside, this information can also be queried at runtime using reflection).

Think about it: If type parameters were erased from class files entirely, how could the code completion in the IDE of your choice display that ArrayList.add(E) takes a parameter of type E, and not Object (=the erasure of E) if you didn't have the JDKs source code attached? And how would the compiler know to throw a compilation error when the static type of the method argument wasn't a subtype of E?

这篇关于Java泛型代码编译与javac,失败与Eclipse Helios的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆