我正在开发一个库,在将返回类型重写为子元素列表时遇到了问题。
最初看起来像这样,
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)型可以解决这个问题。但这是更干净的方法吗?
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/