java - 扩展接口(interface)时返回子元素列表

标签 java generics overloading generic-list

我正在开发一个库,在将返回类型重写为子元素列表时遇到了问题。

最初看起来像这样,

    Class Student {
    }

    public interface A {
        public Student isCurrentStudent(String name);
        public List<Student> getStudentList();
    }

    public interface B extends A {
        public List<Student> getColleges();
        public Student getBestFriend();
    }

然后我想引入SeniourStudent类和用于访问SeniourStudent的API,所以我想出了以下内容,

Class SeniorStudent extends Student{
}

public interface C extends A {
    public SeniorStudent isCurrentStudent(String name);
    public List<SeniorStudent> getStudentList();
    public void addStudent(Attributes s);
}

public interface D extends B,C {
    public List<SeniorStudent> getColleges();
    public Student getBestFriend();
}

问题始于接口(interface) C 和 D。由于 java 支持协变返回类型,因此 C 的第一个方法不会给出错误。但是当返回类型是“List”时,就会出现麻烦。所以我改变了上面的接口(interface)来使用泛型。

public interface A <T extends Student> {
    public Student isCurrentStudent(String name);
    public List<T> getStudentList();
}

public interface B<T extends Student> extends A<T> {
    public List<T> getColleges();
    public Student getBestFriend();
}

public interface C extends A<SeniorStudent> {
    public SeniorStudent isCurrentStudent(String name);
    public List<SeniorStudent> getStudentList();
    public void addStudent(Attributes s);
}

public interface D extends B<SeniorStudent>,C {
    public List<SeniorStudent> getColleges();
    public SeniorStudent getBestFriend();
}

我相信这个设计可以改进,这样B类的实现者就可以被限制为只能使用Student类。

我最终想要的是,提供可以像这样使用的干净的 API,

B bObject = getBObject();
List<Student> studentList = bObject.getColleges();

D dObject = getDObject();
List<SeniourStudent> seniorStudentList = dObject.getColleges();

如果有一种方法可以覆盖子元素列表的返回类型,那么整个问题就可以解决。

由于我的实际代码要大得多,因此我在这里使用简单的示例来描述问题。希望它足够清楚。

<小时/>

编辑

为 B 引入 BS 父类(super class)型可以解决这个问题。但这是更干净的方法吗?

class diagram when introducing SB

public interface A <T extends Student> {
    public Student isCurrentStudent(String name);
    public List<T> getStudentList();
}

public interface BS<T extends Student> extends A<T> {
    public List<T> getColleges();
    public Student getBestFriend();
}

public interface B extends BS<Student> {
    public List<Student> getColleges();
    public Student getBestFriend();
}

public interface C extends A<SeniorStudent> {
    public SeniorStudent isCurrentStudent(String name);
    public List<SeniorStudent> getStudentList();
    public void addStudent(Attributes s);
}

public interface D extends BS<SeniorStudent>,C {
    public List<SeniorStudent> getColleges();
    public SeniorStudent getBestFriend();
}

谢谢

最佳答案

正如 Plínio Pantaleão 在评论中所说(或者实际上想要),您可以定义接口(interface)来返回 List<? extends Student>

import java.util.List;

class Attributes {}
class Student { }

interface A {
    Student isCurrentStudent(String name);
    List<? extends Student> getStudentList();
}

interface B extends A {
    List<? extends Student> getColleges();
}


class SeniorStudent extends Student{ }

interface C extends A {

    @Override
    SeniorStudent isCurrentStudent(String name);

    @Override
    List<SeniorStudent> getStudentList();

    void addStudent(Attributes s);
}

interface D extends B,C {
    @Override
    List<SeniorStudent> getColleges();
}
public class CovariantList
{
    public static void main(String[] args)
    {
        B b = null;
        List<? extends Student> collegesB = b.getColleges();

        D d = null;
        List<SeniorStudent> collegesD = d.getColleges();
    }
}

如果你只知道最“基础”的接口(interface)(本例中为B)你只能得到List<? extends Student> 。如果您知道特定类型(如 D 中),则可以获得协变类型 List<SeniorStudent> .

<小时/>

编辑根据评论和编辑的问题进行更新:

可以通过以下方式实现 API 可以在主要问题的编辑部分中使用的要求:

import java.util.List;

public class StudentsReturnTypesTest
{
    public static void main(String[] args)
    {
        B bObject = getBObject();
        List<Student> studentList = bObject.getColleges();

        D dObject = getDObject();
        List<SeniorStudent> seniorStudentList = dObject.getColleges();        
    }

    private static D getDObject() { return null; }
    private static B getBObject() { return null; }
}

interface A<T extends Student> {
    public Student isCurrentStudent(String name);
    public List<T> getStudentList();
}

interface AS extends A<Student> { }

interface B extends AS {
    public List<Student> getColleges();
}

interface C extends A<SeniorStudent> {
    public SeniorStudent isCurrentStudent(String name);
    public List<SeniorStudent> getStudentList();
    public void addStudent(Attributes s);
}

interface D extends C /* B Not possible, see below */  {
    public List<SeniorStudent> getColleges();
}

interface Attributes {}
interface Student {}
interface SeniorStudent extends Student {}

但是在其中一条评论中,您提到

“对于接口(interface) D,我也想从 B 继承方法”

这会很困难。您基本上遇到的问题是方法 getColleagues()然后将以不同的返回类型继承:一次为 List<Student>和一次 List<SeniorStudent> 。这样做根本不是类型安全的。

目前,接口(interface) B 中定义的唯一方法是 getColleagues() 。并且由于此方法(具有不同的返回类型)已经从接口(interface) C 继承,我假设“...也从 B 继承方法”的意图指的是当前不包含在您发布的示例代码。

对此的解决方案可能是将“来自 B 的方法”提取到专用接口(interface)中。这里的关键点是避免两次继承具有不同返回类型的方法。这可以像本示例中那样实现,其中各个方法都总结在一个具有漂亮名称 AdditionalMethodsThatHaveBeenInB 的界面中。 ...

import java.util.List;

public class StudentsReturnTypesTest
{
    public static void main(String[] args)
    {
        B bObject = getBObject();
        List<Student> studentList = bObject.getColleges();
        bObject.methodThatWasInB();

        D dObject = getDObject();
        List<SeniorStudent> seniorStudentList = dObject.getColleges();
        dObject.methodThatWasInB();
    }

    private static D getDObject() { return null; }
    private static B getBObject() { return null; }
}

interface A<T extends Student> {
    public Student isCurrentStudent(String name);
    public List<T> getStudentList();
}

interface AS extends A<Student> { }

interface B extends AS, AdditionalMethodsThatHaveBeenInB {
    public List<Student> getColleges();
}

interface AdditionalMethodsThatHaveBeenInB {
    void methodThatWasInB();
}

interface C extends A<SeniorStudent> {
    public SeniorStudent isCurrentStudent(String name);
    public List<SeniorStudent> getStudentList();
    public void addStudent(Attributes s);
}

interface D extends C, AdditionalMethodsThatHaveBeenInB {
    public List<SeniorStudent> getColleges();
}

interface Attributes {}
interface Student {}
interface SeniorStudent extends Student {}

当然,很难判断这在您的真实代码中是否可行,但也许类似的方法也适用。

关于java - 扩展接口(interface)时返回子元素列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21684631/

相关文章:

Java HttpClient - 减少调试输出

Delphi TObjectDictionary 具有类实例键

java - 违反检查通用对象列表的方法

C++11:重载无法解析递归 decltype

java - Java使用模板引擎解析多行日志文件

java - 为什么 JDialog 不触发关键监听器的 keyPressed 方法?

java - 使用 Thread 作为 Collection 中的键

java - 什么是原始类型,为什么我们不应该使用它呢?

使用 Return void 和 object (string) 的 C# 重载

php - "Overloading"PHP 中的私有(private)方法