Почему один класс действует, а другой нет?
Как вы можете видеть, важно иметь непустой тип возврата.
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");
}
}
Ответы
Ответ 1
TestValid
недействителен для начала:
TestValid.java:9: name clash: f(List<Integer>) and f(List<String>)
have the same erasure
public Integer f(List<Integer> list) {
^
Таким образом, тип возврата - это красная селедка. Если для определения сигнатур для перегрузки учитывались типы возврата, то это было бы действительно, но в настоящее время оно недействительно:
// Equally invalid
public Integer f() {}
public String f() {}
Если вам действительно удалось получить TestValid
для компиляции, мне было бы интересно узнать, какой компилятор вы используете.
Ответ 2
Во втором случае методы f
не могут быть выделены во время выполнения из-за стирания типа.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
Таким образом, они оба имеют точно такую же подпись.
Ответ 3
После части стирания стилей, List<String>
и List<Integer>
, оба действительно являются типами List; в TestInvalid вы создаете два метода с одинаковой сигнатурой времени выполнения.
Ответ 4
Для класса TestValid:
функции выглядят перегруженными. Вы не получите ошибку времени компиляции, если вызывающий объект передает объект списка List, который является type defined.eg: новый ArrayList <Integer> () или новый ArrayList <String> ().
поскольку подпись (тип возврата и входные параметры) после стирания типа не одинакова.
Однако вы получите ошибку времени компиляции, если вы перейдете в новый ArrayList().
Второе определение нарушает основной принцип перегрузки функции, где две функции с одинаковой сигнатурой (тип возврата и входные параметры) после стирания типа.
Ответ 5
Возвращаемый тип Covariant до 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();
}
}