我正在开发一个库,当我将返回类型重写为子元素列表时,我遇到了一个问题。
最初看起来像这样,
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的SeniorStudent类和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();
}
问题从接口C和D开始。由于java支持协变返回类型,因此C的第一个方法不会产生错误。但是当返回类型为“List”时,就会出现问题。所以我更改了上面的接口以使用泛型。
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超类型可以解决问题。但这是更清洁的方式吗?
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();
}
谢谢,
答案 0 :(得分:1)
我有点困惑你正在努力做什么。但我猜,您的问题可以通过不使接口C
和D
通用来解决。你可以像这样使用你的界面:
interface A<T extends Student> {
public T isCurrentStudent(String name);
public List<T> getStudentList();
}
interface B<T extends Student> extends A<T> {
public List<T> getColleges();
}
interface C extends B<Student> {
public Student isCurrentStudent(String name);
public List<Student> getStudentList();
public List<Student> getColleges();
}
interface D extends B<SeniorStudent> {
public SeniorStudent isCurrentStudent(String name);
public List<SeniorStudent> getStudentList();
public List<SeniorStudent> getColleges();
}
然后,分别为C
和D
创建类实现接口Student
和SeniorStudent
。这是我能想到的最好方法。看看你是否可以相处,否则我们可以尝试进一步即兴。
答案 1 :(得分:1)
正如PlínioPantaleão在评论中所说(或实际上想要说),您可以定义界面以返回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();
}
}
如果您只知道最“基本”的界面(在本例中为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 {}
然而在其中一条评论中,您提到了
“对于接口D我也希望从B继承方法”
这很难。您基本上遇到的问题是,方法getColleagues()
将以不同的返回类型继承:一次使用List<Student>
,一次使用List<SeniorStudent>
。这样做根本不是类型安全的。
目前,接口B中定义的唯一方法是getColleagues()
。并且由于此方法(具有不同的返回类型)已经从接口C继承,我假设“... 从B继承方法”的意图引用了当前未包含的方法您发布的示例代码。
对此的解决方案可能是将“B方法”提取到专用接口中。这里的关键是避免继承具有不同返回类型的方法两次。这可以像在这个例子中那样实现,其中各个方法总结在一个名为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 {}
当然,很难说你的真正的代码是否也可以这样做,但也许类似的方法适用于那里。