【问题标题】:How to stop child class object invoking method from parent class despite same method also being in child class尽管相同的方法也在子类中,如何停止子类对象从父类调用方法
【发布时间】:2020-05-21 14:24:01
【问题描述】:

我有一个扩展 Product 的 ElectronicProduct 类型的对象,我尝试从子类中调用 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;

}

【问题讨论】:

  • 允许重写方法返回更具体的类型(从 Java 5 开始)。我们不知道你之前做了什么,所以我们不能说你做错了什么。

标签: java object inheritance polymorphism


【解决方案1】:

编译器无法知道你的两个方法之间的区别:你需要在方法签名、参数数量上指定不同的参数顺序,但没有子类参数类型或子类返回类型会有所不同:

方法:

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

【讨论】:

  • 感谢您的洞察力,但我确实认为编译器会自动选择子类方法,如果有选择的话。这是不正确的吗?
  • 你是对的。因为这是方法覆盖,所以它总是调用子类(覆盖实例方法优先)。我有一个愚蠢的问题,但是您在 ElectronicProduct 中硬编码了对 super.loadFromFile() 的调用,因此您强制调用 Product.loadFromFile(),因此期望看到 Product.loadFromFile() 被调用是正确的。将修改我的答案给你一个例子。
  • 我认为看到调用 Product.loadFromFile() 是不正确的,尽管它被硬编码到 ElectronicProduct.loadFromFile() 中,因为它们有不同的方法体,并返回不同的对象,但是有人否则可能需要验证这一点。
  • 返回类型不是方法签名的一部分。这就是为什么这是一个方法覆盖的例子,它总是调用 ElectronicProduct 的方法实例而不是 Product,参见:docs.oracle.com/javase/tutorial/java/IandI/override.html
【解决方案2】:

也许你应该使用这样的方法:

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

由于主要区别在于您放入参数的对象,因此您应该指定它。

【讨论】:

  • 我已经对问题进行了编辑,如果我传入子对象可能无法正常工作,因为 .super 用于将其传递给无法“看到”子对象的父方法。
猜你喜欢
  • 2012-07-13
  • 2011-04-17
  • 2017-11-09
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 2012-02-22
  • 1970-01-01
相关资源
最近更新 更多