如何传递实现同一接口的多个类型?

Tal*_*ose 1 java generics pecs

首先,我对这个不太好的标题表示歉意,我是 Java 新手,不知道如何命名它。

我有一个接口类“TestInterface”:

ublic interface TestInterface {

    String getForename();

    void setForename(String forename);

    String getSurname();

    void setSurname(String surname);
}

Run Code Online (Sandbox Code Playgroud)

“TestImpl”实现“TestInterface”:

public class TestImpl implements TestInterface{

    private String forename;

    private String surname;

    @Override
    public String getForename() {
        return forename;
    }

    public void setForename(String forename) {
        this.forename = forename;
    }

    @Override
    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个名为“ExtendTest”的调用,它扩展了“TestImpl”:

public class ExtendTest extends TestImpl{

    private String firstLineAddress;

    public String getFirstLineAddress() {
        return firstLineAddress;
    }

    public void setFirstLineAddress(String firstLineAddress) {
        this.firstLineAddress = firstLineAddress;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有这个“Entity”类:


import java.util.List;

public class Entity {

    private List<TestInterface> testInterfaces;

    private List<ExtendTest> extendTests;

    public List<TestInterface> getTestInterfaces() {
        return testInterfaces;
    }

    public void setTestInterfaces(List<TestInterface> testInterfaces) {
        this.testInterfaces = testInterfaces;
    }

    public List<ExtendTest> getExtendTests() {
        return extendTests;
    }

    public void setExtendTests(List<ExtendTest> extendTests) {
        this.extendTests = extendTests;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是这个“DoStuff”类,其中 dostuff 方法接受 List 类型的参数

import java.util.List;

public class DoStuff {

    public void doStuff(List<TestInterface> testData) {

    }
}

Run Code Online (Sandbox Code Playgroud)

我尝试像这样测试:

public class Main {


        public static void main(String[] args) {
            System.out.println("Hello, World!");

            DoStuff doStuff = new DoStuff();


            Entity entity = new Entity();

            // Works
            doStuff.doStuff(entity.getTestInterfaces());

            // Does not work
            doStuff.doStuff(entity.getExtendTests());

        }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果评论是“不起作用”,则这是一个错误

Required type:
List<TestInterface>
Provided:
List<ExtendTest>
Run Code Online (Sandbox Code Playgroud)

我的问题是如何制作它以便我可以将其传递进去。我的理解是,因为它们都实现了 TestInterface,所以它会起作用,但我认为我错了。

感谢您在这里的任何帮助和学习:)

Sil*_*olo 6

你已经与PECS发生冲突了。我建议阅读链接的答案以获取更详细的解释,但这里是特定于您的用例的部分。

当你有一个泛型类型(List在你的情况下),如果你只读取它,你应该写List<? extends MyInterface>。如果你只它,你应该写List<? super MyInterface>. 如果你两者都做,那么你想要List<MyInterface>。我们为什么要做这个?好吧,看看你的代码。

public void doStuff(List<TestInterface> testData) { ... }
Run Code Online (Sandbox Code Playgroud)

该函数需要一个List<TestInterface>. 该List界面具有大量功能。除了从中读取内容之外,您还可以向其中添加和删除内容。并doStuff期望一个TestInterface. 所以对于执行doStuffto do来说这是完全公平的游戏

testData.add(new ClassIJustMadeUp());
Run Code Online (Sandbox Code Playgroud)

假设ClassIJustMadeUp实现TestInterface. 所以我们绝对不能传递这个函数 a List<ExtendTest>,因为该列表类型不能包含ClassIJustMadeUp.

但是,如果您的函数仅从列表中读取并且不打算向其中添加任何内容,则可以将签名编写为

public void doStuff(List<? extends TestInterface> testData) { ... }
Run Code Online (Sandbox Code Playgroud)

现在你可以传递任何扩展的List类型。从此列表中读取是很好的,因为任何明确扩展的类型都可以安全地向上转换为. 但是,如果我们尝试添加列表元素,则会出现编译器错误,因为列表不一定支持该特定类型。TestInterfaceTestInterfaceTestInterface