Как остановить объект дочернего класса, вызывающий метод из родительского класса, несмотря на то, что тот же метод также находится в дочернем классе

У меня есть объект типа ElectronicProduct, который расширяет Product, я пытаюсь вызвать метод loadFromFile() из дочернего класса, указав точное имя и типы аргументов, но вместо этого объект дочернего класса вызывает loadFromFile() из родительского класса. Как мне остановить это?

Код выглядит следующим образом:

ElectronicProduct eProduct = new ElectronicProduct();
eProduct.loadFromFile(eProduct,bin); 

однако он вызывает метод в родительском классе ниже:

public Product loadFromFile(Product aProduct, BufferedReader bin) throws IOException, ParseException{ 

   //some code 

}

вместо дочернего класса, показанного ниже:

public ElectronicProduct loadFromFile(Product aProduct, BufferedReader bin) throws IOException, ParseException{

// Some code

}

Я пытался использовать @Override в методе дочернего класса, но поскольку один возвращает продукт, а другой возвращает электронный продукт, переопределение, похоже, не работает. Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ

Это очень странно, так как теперь он начал работать так, как я хотел, ничего не меняя. Другой сценарий, но подобное случалось раньше, когда выдается предупреждение об ошибке, я удаляю код и пишу то же самое, и тогда это работает. Я не хочу, чтобы это произошло случайно, поскольку это оцениваемое задание. Не хочу уходить от темы, но это должно быть связано. Пожалуйста, сообщите, если кто-нибудь знает, что только что произошло?

РЕДАКТИРОВАТЬ*2

В ответ на комментарий от Tiffado, причина, по которой передается объект Product, а не объект ElectronicProduct, заключается в том, что в методе дочернего класса объект Product передается родительскому классу. Если вместо этого я передам объект дочернего класса в дочерний метод, который затем передаст объект родительскому методу, он может не сработать, поскольку я узнал, что родительские классы не «видят» дочерние классы. Пожалуйста, поправьте меня, если это неправильно.

public ElectronicProduct loadFromFile(Product aProduct, BufferedReader bin) throws IOException, ParseException{


ElectronicProduct eProduct = new ElectronicProduct();

eProduct = (ElectronicProduct)super.loadFromFile(aProduct,bin);

eProduct.setGuarunteeDuration(Integer.valueOf(bin.readLine()));

return eProduct;

}

person InitialisingAttributes    schedule 05.02.2020    source источник
comment
Методы переопределения могут возвращать более конкретный тип (начиная с Java 5). Мы не знаем, что вы делали раньше, поэтому не можем сказать, что вы сделали не так.   -  person Holger    schedule 05.02.2020


Ответы (2)


У компилятора нет возможности узнать разницу между двумя вашими методами: вам нужно указать разный порядок параметров в сигнатуре метода, количество параметров, но никакие типы параметров подкласса или типы возврата подкласса не будут иметь значения:

Метод:

public Product loadFromFile(Product aProduct, BufferedReader bin) throws IOException, ParseException{ 

Точно так же, как

public ElectronicProduct loadFromFile(Product aProduct, BufferedReader bin) throws IOException, ParseException{

поскольку возвращаемый тип (ElectronicProduct) является подклассом Product, поэтому использование полиморфизма не является частью сигнатуры метода.

См. также: «Сигнатуры методов Java принимают только имя метода, номер и тип параметров», доступно по адресу: https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html

См. следующий пример, который за счет переопределения правил вызовет дочерний метод, но, поскольку существует жестко запрограммированный вызов родительского метода, он также вызовет родительский:

public class Product {

  static int productIdentifier = 0;
  static int electronicProductIdentifier = 0;

    public Product loadFromFile( Product aProduct ) {

    System.out.println("Call loadFromFile from Product");
        Product product = new Product();
        return product;

    }

  public Product ()  {
    System.out.println("Creating a Product with ID " + 
            ( ++ productIdentifier ) );
  }

}


public class ElectronicProduct extends Product {

    public ElectronicProduct loadFromFile( Product aProduct ) {

    System.out.println("Call loadFromFile from ElectronicProduct");
        ElectronicProduct eProduct = new ElectronicProduct();
    super.loadFromFile( eProduct ); // Hardcoded call to parent!
        return eProduct;

    }

  public ElectronicProduct ()  {
    System.out.println("Creating an ElectronicProduct with ID " + 
            ( ++ electronicProductIdentifier ) );
  }

}

Product p = new Product();
ElectronicProduct ep = new ElectronicProduct();
ep.loadFromFile( ep );

Выход:

Creating a Product with ID 1
Creating a Product with ID 2
Creating an ElectronicProduct with ID 1
Call loadFromFile from ElectronicProduct
Creating a Product with ID 3
Creating an ElectronicProduct with ID 2
Call loadFromFile from Product
Creating a Product with ID 4

(Есть вызов loadFromFile() из продукта, поскольку он явно вызывается из ElectronicProduct.loadFromFile() )

Если вы закомментируете строку вызова super.loadFromFile(), вы не увидите вызова Product.loadFromFile():

Creating a Product with ID 1
Creating a Product with ID 2
Creating an ElectronicProduct with ID 1
Call loadFromFile from ElectronicProduct
Creating a Product with ID 3
Creating an ElectronicProduct with ID 2
person Victor Polo De Gyves Montero    schedule 05.02.2020
comment
Спасибо за это понимание, однако я думал, что компилятор автоматически выбирает метод дочернего класса, если ему предоставляется выбор. это неправильно? - person InitialisingAttributes; 05.02.2020
comment
Ты прав. поскольку это переопределение метода, он всегда будет вызывать подкласс (переопределение метода экземпляра имеет приоритет). У меня глупый вопрос, но вы жестко запрограммировали вызов super.loadFromFile() внутри ElectronicProduct, поэтому вы принудительно вызываете вызов Product.loadFromFile(), поэтому правильно ожидать, что вызов Product.loadFromFile() будет вызван. Изменю мой ответ, чтобы дать вам пример. - person Victor Polo De Gyves Montero; 05.02.2020
comment
Я не думаю, что правильно видеть вызов Product.loadFromFile(), несмотря на то, что он жестко закодирован в ElectronicProduct.loadFromFile(), потому что они имеют разные тела методов и возвращают разные объекты, но кому-то еще может понадобиться это проверить. - person InitialisingAttributes; 05.02.2020
comment
Типы возвращаемых значений не являются частью сигнатур методов. Вот почему это пример переопределения метода, и он всегда будет вызывать экземпляр метода ElectronicProduct вместо Product, см.: docs.oracle.com/javase/tutorial/java/IandI/override.html - person Victor Polo De Gyves Montero; 05.02.2020

Возможно, вам следует использовать такой метод:

public ElectronicProduct loadFromFile(ElectronicProduct aProduct, BufferedReader bin) throws IOException, ParseException{

Поскольку основное отличие заключается в объекте, который вы указываете в параметрах, его следует указать.

person Tiffado    schedule 05.02.2020
comment
Я внес изменения в вопрос, если я передам дочерний объект, это может не сработать, поскольку .super используется для передачи этого родительскому методу, который не может «видеть» дочерний объект. - person InitialisingAttributes; 05.02.2020