无法从接口调用抽象 class 方法

Unable to call abstract class method from interface

我很难掌握针对接口编程的概念并同时使用抽象 classes。

我有一组 "Retriever" classes 可以从 Internet 检索不同类型的数据。这些检索器 classes 检索 JSON 响应的字符串

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

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

AccountInformation 和 BalanceInformation 都是具有其中显示的方法的接口。我还从抽象 class "DataRetriever" 扩展,它有一个名为

的方法
public String getResponseAsString();

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

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() 方法存在于摘要中 class 这些检索器中的每一个都扩展自,那么为什么我无法访问该方法?我可以访问的唯一方法是界面中的方法。我在这里做错了什么?

这些方法不可见,因为当你构造一个 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() 的通用接口。并一起删除摘要 class 。

public interface Information {
    public String getResponseAsString();
}

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

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

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

AccountRetriever IS-A AccountInformation (实现接口)

AccountRetriever IS-A DataRetriever (扩展摘要 class)

因此 AccountRetriever 引用 可以使用 AccountInformation 和 [=27= 的方法]DataRetriever.

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

但是 没有 IS-A AccountInformation 之间的关系DataRetriever.

因此 AccountInformation 引用 不能使用 DataRetriever 的方法,即使它可能包含 AccountRetriever 实例(通过向上转换).

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

同样的逻辑适用于 BalanceRetriever, BalanceInformationDataRetriever

// 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

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

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 定义的方法。不允许知道 a 是一个 Dog--只能在 运行 时间检查。

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

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

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

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

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

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