Стандартные методы наследования и переопределения методов Java
У меня есть абстрактный класс, который имеет общий метод, и я хочу переопределить общий метод, заменив определенные типы для общего параметра. Поэтому в псевдокоде у меня есть следующее:
public abstract class GetAndParse {
public SomeClass var;
public abstract <T extends AnotherClass> void getAndParse(T... args);
}
public class Implementor extends GetAndParse {
// some field declarations
// some method declarations
@Override
public <SpecificClass> void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Но почему-то мне не разрешают это делать? Я делаю какую-то синтаксическую ошибку или это наследование и переопределение недопустимы? В частности, я получаю сообщение об ошибке @Override
, потому что среда eclipse продолжает напоминать мне о внедрении getAndParse
.
Вот как я хочу, чтобы приведенный выше код работал. Где-то еще в моем коде есть метод, который ожидает экземпляры объектов, которые реализуют getAndParse
, что конкретно означает, что у них есть метод getAndParse
, который я могу использовать. Когда я вызываю getAndParse
в этом экземпляре, компилятор проверяет, правильно ли я использовал конкретные экземпляры T
, поэтому в частности T
должен расширять AnotherClass
и должен быть SpecificClass
.
Ответы
Ответ 1
Что мы имеем здесь, это два разных метода с индивидуальными параметрами каждого.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
Это метод с параметром типа с именем T и ограниченный AnotherClass
, что означает, что каждый подтип AnotherClass
разрешен как параметр типа.
public <SpecificClass> void getAndParse(Args... args)
Это метод с параметром типа с именем SpecificClass
, ограниченный Object
(что означает, что каждый тип разрешен как параметр типа). Вы действительно этого хотите?
Является ли параметр типа, используемым внутри Args
? Я думаю, проблема будет там.
Edit:
Значение
public abstract <T extends AnotherClass> void getAndParse(T... args);
заключается в том, что вызывающий метод может решить, с каким параметром типа он хочет вызвать метод, если это какой-то подтип AnotherClass
. Это означает, что на самом деле метод можно вызывать с любыми объектами типа AnotherClass
.
Поскольку вызывающий может решить параметр типа, вы не можете в подклассе сузить тип параметра до SpecificClass
- это не будет реализация метода, а другой метод с тем же именем (перегрузка).
Возможно, вы хотите что-то вроде этого:
public abstract class GetAndParse<T extends AnotherClass> {
public SomeClass var;
public abstract void getAndParse(T... args);
}
public class Implementor extends GetAndParse<SpecificClass> {
// some field declarations
// some method declarations
@Override
public void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Теперь метод getAndParse
реализует метод родительского класса.
Ответ 2
Вы видите эту проблему из-за концепции "Erasure" в Java Generics.
Java использует "стирание" для поддержки обратной совместимости. т.е. Java-код, который не использовал дженерики.
Процедура Erasure:
Компилятор сначала проверит проверку типов, а затем удалит (стирает) все параметры типа как можно больше, а также добавит TypeCasting, где это необходимо.
Пример:
public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);
станет
public abstract void getAndParse(AnotherClass paramAnotherClass);
В классе "Implementor.java",
Код
public <SpecificClass> void getAndParse(T paramAnotherClass)
станет
public void getAndParse(SpecificClass paramAnotherClass){ }
компилятор увидит, что вы не внедрили абстрактный метод правильно.
Существует несоответствие типа абстрактного метода и реализованного метода. Вот почему вы видите ошибку.
Более подробную информацию можно найти здесь.
http://today.java.net/pub/a/today/2003/12/02/explorations.html
Ответ 3
Нет, это неверно. Что произойдет, если кто-то с ссылкой GetAndParse
назвал его другим классом, расширяющим AnotherClass
?
Ответ 4
Это становится бессмыслицей, когда кто-то ссылается на тип GetAndParse и пытается вызвать метод getAndParse. Если Cat и Dog продлят AnotherClass. Я должен ожидать, что вы сможете вызвать GetAndParse # getAndParse либо с кошкой, либо с собакой. Но реализация попыталась ограничить его и сделать его менее совместимым!
Ответ 5
Вы не можете переопределить конкретный тип T, потому что на самом деле (на уровне байт-кода, если хотите) используется только один метод getAndParse из-за стирания типа (см. другой ответ):
public abstract void getAndParse(AnotherClass... args); // (1)
Для каждого типа T используется тот же метод.
Вы можете перегрузить его (я думаю):
public void getAndParse(SpecificClass... args); // (2)
но это не будет отличаться от (1) ant, он не будет вызываться общим кодом:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass