【问题标题】:Unable to call abstract class method from interface无法从接口调用抽象类方法
【发布时间】:2017-11-24 03:46:40
【问题描述】:

我有点难以理解编程接口和同时使用抽象类的概念。

我有一组“检索器”类,用于从 Internet 检索不同类型的数据。这些检索器类检索 JSON 响应字符串

public class AccountRetriever extends DataRetriever implements AccountInformation{
     List<String> getAccountInformation{
      ....
   }
}

public class BalanceRetriever extends DataRetriever implements BalanceInformation{
     List<String> getBalanceInformation{
      ....
   }
}

AccountInformation 和 BalanceInformation 都是其中显示的方法的接口。我还从一个抽象类“DataRetriever”扩展而来,它有一个名为

的方法
public String getResponseAsString();

在我的主要使用接口中实例化这些类之后:

AccountInformation ai = new AccountRetriever(apiRequest);
List<String> aiList = ai.getAccountInformation();   <----this works
ai.getResponseAsString();      <----this doesn't work. Why??

BalanceInformation bi = new BalanceRetriever(apiRequest);
List<String> biList = bi.getBalanceInformation();   <----this works
bi.getResponseAsString();      <----this doesn't work. Why??

getResponseAsString() 方法存在于每个检索器扩展的抽象类中,为什么我无法访问该方法?我可以访问的唯一方法是界面中的方法。我在这里做错了什么?

【问题讨论】:

  • 并非所有AccountInformation 实例都是DataRetriever 的实例。

标签: java class interface abstract


【解决方案1】:

这些方法是不可见的,因为当你构造一个AccountRetriever 时,你的ai 变量只有AccountInformation 类型,接口只有getAccountInformation() 而不是getResponseAsString()

AccountInformation ai = new AccountRetriever(apiRequest);
List<String> aiList = ai.getAccountInformation();   <----this works
ai.getResponseAsString();      <----this doesn't work. Why??

但如果您将变量类型更改为DataRetriever,则getAccountInformation() 将可见但getAccountInformation() 将不可见。

DataRetriever ai = new AccountRetriever(apiRequest);
List<String> aiList = ai.getAccountInformation();   <----this wont work
ai.getResponseAsString();      <---- this will work

您需要将变量类型更改为AccountRetriever,它既扩展了DataRetriever,又实现了AccountInformation

AccountRetriever ai = new AccountRetriever(apiRequest);
List<String> aiList = ai.getAccountInformation();   <----this will work
ai.getResponseAsString();      <---- this will work

或者,更改您的设计,使AccountInformationBalanceInformation 都扩展定义getResponseAsString() 的公共接口。并一起删除抽象类。

public interface Information {
    public String getResponseAsString();
}

public interface AccountInformation extends Information {
    public List<String> getAccountInformation();
}

public interface BalanceInformation extends Information {
    public List<String> getBalanceInformation();
}

【讨论】:

  • 但这不是否定了“编程到接口”的整个推理吗?
  • 一点也不。我想你把你的继承权拿回了前面。 iv编辑了答案,将举例说明如何调整它。您可以出于不同的原因以各种不同的方式实现事物。我认为您只需要一种简单的自下而上的接口方法,根本不需要抽象类。
  • 没问题。界面很酷。我发现抽象类没那么有用。尽量不要过度使用它们。
  • 感谢您的反馈。也许我只是想太花哨......我现在正在编辑我的代码
【解决方案2】:

你的就是多重继承的一个例子。

AccountRetriever IS-A AccountInformation (实现接口)

AccountRetriever IS-A DataRetriever (扩展抽象类)

所以 AccountRetriever 引用 可以同时使用 AccountInformationDataRetriever 的方法。

// Will work
AccountRetriever ar = new AccountRetriever(apiRequest);
List<String> arList = ar.getAccountInformation();
ar.getResponseAsString();

但是 AccountInformationDataRetriever没有 IS-A 关系/em>。

所以 AccountInformation 参考 不能使用 DataRetriever 的方法,即使它可能包含 AccountRetriever 实例 (通过向上转型)

// Won't Work
AccountInformation ai = new AccountRetriever(apiRequest); //upcasting
ai.getResponseAsString(); //error

同样的逻辑适用于 BalanceRetrieverBalanceInformationDataRetriever 的情况 也是。

// Will work
BalanceRetriever br = new BalanceRetriever(apiRequest);
List<String> brList = br.getBalanceInformation();   
br.getResponseAsString(); 

// Won't work
BalanceInformation bi = new BalanceRetriever(apiRequest); //upcasting
bi.getResponseAsString(); //error

【讨论】:

    【解决方案3】:

    您的问题本质上与我们收到很多问题的一个简单得多的问题相同。像这样的:

    class Animal { ... }
    class Dog extends Animal {
        public void bark() { ... }  // new method not inherited from Animal
    }
    
    Animal a = new Dog();
    a.bark(); // ILLEGAL
    

    新程序员无法弄清楚为什么a.bark() 不合法。答案当然是,当编译器看到a.bark() 时,它只知道a 是一个Animal,所以它不能确定a 有一个bark 方法。 a 允许的唯一方法是为 Animal 定义的方法。不允许知道aDog——只能在运行时检查。

    你的问题是一样的,虽然它涉及更多的复杂性。

    AccountInformation ai = new AccountRetriever(apiRequest);
    ai.getResponseAsString();      <----this doesn't work. Why??
    

    ai 被声明为AccountInformation;因此,可以在其上使用的唯一方法是为AccountInformation 接口声明的方法。毕竟,您可以声明另一个实现 AccountInformation 但不扩展 DataRetriever 的类,并且 ai 可能是该类的对象,在这种情况下将没有 @987654339 @方法。

    请注意,如果您有一个 AccountInformation 对象并且您确定它也是一个 DataRetriever,则可以强制转换为它。

    public void someMethod(ai: AccountInformation) {
        ((DataRetriever)ai).getResponseAsString();  // LEGAL
    

    这将在运行时检查ai 是否是扩展DataRetriever 的某个类的成员,如果不是则抛出异常。

    【讨论】:

      猜你喜欢
      • 2017-07-07
      • 1970-01-01
      • 1970-01-01
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 2013-09-17
      • 1970-01-01
      相关资源
      最近更新 更多