Общие правила наследования и переопределения методов 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 IDE постоянно напоминает мне о реализации getAndParse
,
Вот как я хочу, чтобы вышеуказанный код работал. Где-то еще в моем коде есть метод, который ожидает экземпляры объектов, которые реализуют GetAndParse
что конкретно означает, что у них есть getAndParse
метод, который я могу использовать. Когда я звоню getAndParse
в этом случае компилятор проверяет, использовал ли я конкретные экземпляры T
надлежащим образом, в частности, T
должен продлить AnotherClass
и это должно быть SpecificClass
,
6 ответов
Здесь мы имеем два разных метода с индивидуальными параметрами типа каждый.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
Это метод с параметром типа с именем T, ограниченный AnotherClass
, означая каждый подтип AnotherClass
разрешено в качестве параметра типа.
public <SpecificClass> void getAndParse(Args... args)
Это метод с параметром типа с именем SpecificClass
ограничен Object
(имеется в виду, что каждый тип допускается как параметр типа). Вы действительно этого хотите?
Параметр типа используется внутри Args
? Я думаю, что проблема будет там.
Редактировать:
Значение
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
Метод реализует метод родительского класса.
Вы видите эту проблему из-за концепции под названием "Erasure" в Java Generics. Java использует "стирание" для поддержки обратной совместимости. т.е. код Java, который не использовал дженерики.
Процедура стирания:
Компилятор сначала выполняет проверку типа, а затем удаляет (стирает) все параметры типа в максимально возможной степени, а также вставляет 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
Вы не можете переопределить конкретный тип T, потому что на самом деле (на уровне байт-кода, если хотите) только один метод getAndParse из-за стирания типа (см. Другой ответ):
public abstract void getAndParse(AnotherClass... args); // (1)
Для каждого типа T используется один и тот же метод.
Вы можете перегрузить это (я думаю):
public void getAndParse(SpecificClass... args); // (2)
но это не будет отличаться от метода (1) и не будет вызываться общим кодом:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
Нет, это не действительно. Что будет, если кто-то с GetAndParse
ссылка назвала это с другим расширением класса AnotherClass
?
Это становится бессмысленным, когда кто-то ссылается на тип GetAndParse и пытается вызвать метод getAndParse. Если Кошка и Собака расширяют AnotherClass. Я должен ожидать, что смогу вызвать GetAndParse#getAndParse с помощью Cat или Dog. Но реализация попыталась ограничить его и сделать его менее совместимым!
Статический метод не может переопределить
class Vehicle{
static void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
@Override //error
void park(int location) { //error
System.out.println("Car Parking..");
}}
Закрытый метод не может переопределить
class Vehicle{
private void park(int location){
System.out.println("Vehicle parking..");
}
void callPark(){
park(100);
}}
class Car extends Vehicle{
//@Override
void park(int location) {
System.out.println("Car Parking..");
}}
class Demo {
public static void main(String[] args) {
Vehicle v1=new Car();
v1.callPark();
}}
Последний метод не может переопределить
class Vehicle{
final void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
//@Override
void park(int location) { //error
System.out.println("Car Parking..");
}}