Java 为什么一个类有效而另一个无效?
如您所见,具有非void返回类型非常重要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)); } }
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();
}
}