简体   繁体   中英

How to pass multiple Types that implement the same interface?

Firstly apologies about the not so great title, I am new to Java and wasn't sure how to title this.

I have a interface class "TestInterface":

ublic interface TestInterface {

    String getForename();

    void setForename(String forename);

    String getSurname();

    void setSurname(String surname);
}

"TestImpl" implements "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;
    }
}

Then I have a call called "ExtendTest" which extends "TestImpl":

public class ExtendTest extends TestImpl{

    private String firstLineAddress;

    public String getFirstLineAddress() {
        return firstLineAddress;
    }

    public void setFirstLineAddress(String firstLineAddress) {
        this.firstLineAddress = firstLineAddress;
    }
}

I then have this "Entity" class:


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;
    }
}

and finally this "DoStuff" class where the dostuff method accepts a parameter of type List

import java.util.List;

public class DoStuff {

    public void doStuff(List<TestInterface> testData) {

    }
}

I try to test this like so:

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());

        }
}

However where the comment is "Does not work" their is an error

Required type:
List<TestInterface>
Provided:
List<ExtendTest>

My question is how do I make it so that I can pass it in. My understanding was that becase they all implement TestInterface that it would work but I think I am wrong with this.

Thanks for any help and learnings here :)

You've run afoul of PECS . I recommend reading the linked answer for a more detailed explanation, but here's the bits specific to your use case.

When you have a generic type ( List , in your case), if you only read from it, you should write List<? extends MyInterface> List<? extends MyInterface> . If you only write to it, you should write List<? super MyInterface> List<? super MyInterface> . If you do both, then you want List<MyInterface> . Why do we do this? Well, look at your code.

public void doStuff(List<TestInterface> testData) { ... }

This function takes a List<TestInterface> . The List interface has a ton of capability. You can add and remove things to it in addition to just reading from it. And doStuff expects a list of TestInterface . So it's entirely fair game for the implementation of doStuff to do

testData.add(new ClassIJustMadeUp());

assuming ClassIJustMadeUp implements TestInterface . So we definitely can't pass this function a List<ExtendTest> , since that list type can't contain ClassIJustMadeUp .

However, if your function does only read from the list and isn't planning to add anything to it, you can write the signature as

public void doStuff(List<? extends TestInterface> testData) { ... }

and now you can pass a List of any type which extends TestInterface . It's fine to read from this list, since any type which extends TestInterface clearly can be upcast safely to TestInterface . But if we try to add a list element, that's a compiler error since the list doesn't necessarily support that particular type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM