Java 为什么一个类有效而另一个无效?

Java 为什么一个类有效而另一个无效?,java,eclipse,generics,overloading,Java,Eclipse,Generics,Overloading,如您所见,具有非void返回类型非常重要 class TestValid { public String f(List<String> list) { return null; } public Integer f(List<Integer> list) { return null; } public void test() { f(Arrays.asList("asdf")); f(Arrays.asList(123)); } }

如您所见,具有非void返回类型非常重要

class TestValid {

public String f(List<String> list) {
    return null;
}

public Integer f(List<Integer> list) {
    return null;
}

public void test() {
    f(Arrays.asList("asdf"));
    f(Arrays.asList(123));
}

}

class TestInvalid {

public void f(List<String> list) {
    System.out.println("strings");
}

public void f(List<Integer> list) {
    System.out.println("numbers");
}

}
类TestValid{
公共字符串f(列表){
返回null;
}
公共整数f(列表){
返回null;
}
公开无效测试(){
f(Arrays.asList(“asdf”);
f(数组.asList(123));
}
}
类TestInvalid{
公共空间f(列表){
System.out.println(“字符串”);
}
公共空间f(列表){
系统输出打印项次(“数字”);
}
}

在编译的类型擦除部分之后,
List
List
都是真正的类型列表;在TestInvalid中,您使用相同的运行时签名创建两个方法。

在第二种情况下,由于类型擦除,无法在运行时区分方法
f


因此,它们都具有完全相同的签名。

TestValid
开头无效:

如果您真的设法编译了
TestValid
,我很想知道您正在使用哪个编译器。

对于TestValid类: 这些函数似乎过载了。如果调用者传递类型定义的参数列表对象,则不会出现编译时错误。例如:新建ArrayList()新建ArrayList()。 由于类型擦除后的签名(返回类型和输入参数)不同。 但是,如果传入新ArrayList(),则会出现编译时错误


第二个定义违反了重载函数的基本原则,即在类型擦除后,两个函数具有相同的签名(返回类型和输入参数)。

不支持JDK1.5之前的协变返回类型;想想Object.clone()方法。以下内容可能值得关注:

public class Base {
    public String f_array(List<String> strings) {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1];
        System.out.println(String.format("%s#%s(strings)", current.getClassName(), current.getMethodName()));
        return null;
    }

    public Integer f_array(List<Integer> ints) {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
        System.out.println(String.format("%s#%s(ints)", current.getClassName(), current.getMethodName()));
        return null;
    }

    public Number f() {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
        System.out.println(String.format("%s#%s()", current.getClassName(), current.getMethodName()));
        return null;
    };

    public static class Child extends Base {
        @Override
        public Integer f() { //note Integer is_a Number
            StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
            System.out.println(String.format("%s#%s()", current.getClassName(), current.getMethodName()));
            return null;
        }
    }

    public static void main(String... args) {
        Base c = new Base();
        c.f_array(Arrays.asList(1));
        c.f_array(Arrays.asList("1"));
        c.f();
        c = new Child();
        c.f_array(Arrays.asList(1));
        c.f_array(Arrays.asList("1"));
        c.f();
    }
}
公共类基{
公共字符串f_数组(列表字符串){
StackTraceElement current=Thread.currentThread().getStackTrace()[1];
System.out.println(String.format(“%s#%s(strings)”,current.getClassName(),current.getMethodName());
返回null;
}
公共整数f_数组(列表整数){
StackTraceElement current=Thread.currentThread().getStackTrace()[1];
System.out.println(String.format(“%s#%s(ints)”,current.getClassName(),current.getMethodName());
返回null;
}
公众号码f(){
StackTraceElement current=Thread.currentThread().getStackTrace()[1];
System.out.println(String.format(“%s#%s()”,current.getClassName(),current.getMethodName());
返回null;
};
公共静态类子扩展基{
@凌驾
公共整数f(){//注意整数是一个数字
StackTraceElement current=Thread.currentThread().getStackTrace()[1];
System.out.println(String.format(“%s#%s()”,current.getClassName(),current.getMethodName());
返回null;
}
}
公共静态void main(字符串…参数){
基础c=新基础();
c、 f_数组(Arrays.asList(1));
c、 f_数组(Arrays.asList(“1”));
c、 f();
c=新子女();
c、 f_数组(Arrays.asList(1));
c、 f_数组(Arrays.asList(“1”));
c、 f();
}
}

Duplicate of Not a Duplicate,因为奇怪的情况是返回类型不是void。TestValid已经在另一个[question][1][1]中讨论过了:有趣的事实:如果您确实设法创建了
TestValid
(使用非标准编译器、ASM字节码工程或其他什么),标准Java编译器将根据泛型类型参数链接到正确的方法。@erickson:泛型参数不是在字节码级别被擦除了吗?你能详细说明一下吗?@aioobe-类型擦除后方法的签名是相同的,这就是为什么股票编译器正确地拒绝了它们。但是,类中还有关于类型参数的信息。您可以通过反射找到这一点,这就是编译器用来告诉您不能将
列表
传递给采用
列表
的(编译并擦除)方法的原因。然而,在我描述的hack中,我认为编译器实际上是在查看返回类型。是的,基本理论认为它不应该工作。它可以在Eclipse3.5中正常编译和运行,但不能在Eclipse3.6中编译。返回类型并不是一个令人费解的问题——这是编译器(错误地)接受它的原因。虽然返回类型不用于重载解析,但由于具有不同的预擦除类型,因此这些方法不是重载等价的。
// Equally invalid
public Integer f() {}
public String f() {}
public class Base {
    public String f_array(List<String> strings) {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1];
        System.out.println(String.format("%s#%s(strings)", current.getClassName(), current.getMethodName()));
        return null;
    }

    public Integer f_array(List<Integer> ints) {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
        System.out.println(String.format("%s#%s(ints)", current.getClassName(), current.getMethodName()));
        return null;
    }

    public Number f() {
        StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
        System.out.println(String.format("%s#%s()", current.getClassName(), current.getMethodName()));
        return null;
    };

    public static class Child extends Base {
        @Override
        public Integer f() { //note Integer is_a Number
            StackTraceElement current = Thread.currentThread().getStackTrace()[1]; 
            System.out.println(String.format("%s#%s()", current.getClassName(), current.getMethodName()));
            return null;
        }
    }

    public static void main(String... args) {
        Base c = new Base();
        c.f_array(Arrays.asList(1));
        c.f_array(Arrays.asList("1"));
        c.f();
        c = new Child();
        c.f_array(Arrays.asList(1));
        c.f_array(Arrays.asList("1"));
        c.f();
    }
}