好的,这是我的问题:
我有一个包含接口的列表 - List<Interface> a
- 以及扩展该接口的接口列表:List<SubInterface> b
。我想设置a = b
。我不希望使用addAll()
或任何会花费更多内存的东西,因为我正在做的事情已经非常耗费成本。我真的需要能够说a = b
。我尝试了List<? extends Interface> a
,但后来我无法将接口添加到列表a
,只能添加SubInterfaces。有什么建议吗?
我希望能够做到这样的事情:
List<SubRecord> records = new ArrayList<SubRecord>();
//add things to records
recordKeeper.myList = records;
类RecordKeeper是包含接口列表的那个(非子接口)
public class RecordKeeper{
public List<Record> myList;
}
答案 0 :(得分:6)
这有效:
public class TestList {
interface Record {}
interface SubRecord extends Record {}
public static void main(String[] args) {
List<? extends Record> l = new ArrayList<Record>();
List<SubRecord> l2 = new ArrayList<SubRecord>();
Record i = new Record(){};
SubRecord j = new SubRecord(){};
l = l2;
Record a = l.get( 0 );
((List<Record>)l).add( i ); //<--will fail at run time,see below
((List<SubRecord>)l).add( j ); //<--will be ok at run time
}
}
我的意思是它会编译,但是 必须在添加任何内容之前投射List<? extends Record>
。如果要转换为的类型是Record
的子类,Java将允许转换,但它无法猜测它将是哪种类型,您必须指定它。
List<Record>
只能包含Records
(包括subRecords
),而List<SubRecord>
只能包含SubRecords
。
但是A List<SubRecord
&gt;不是List<Record>
它不能包含Records
,而子类应该总是做超类可以做的事情。这是重要的,因为继承是specilisation,如果List<SubRecords>
是List<Record>
的子类,它应该能够包含`但它不是。
List<Record>
和List<SubRecord>
都是List<? extends Record>
。但是在List<? extends Record>
中你无法添加任何内容,因为java无法知道List
是哪个类型的精确类型。想象一下,你可以得到以下声明:
List<? extends Record> l = l2;
l.add( new Record() );
正如我们刚刚看到的那样,这只适用于List<Record>
而不适用于任何List<Something that extends Record>
,例如List<SubRecord>
。
此致 斯特凡
答案 1 :(得分:2)
只是解释为什么Java不允许这样做:
List<Record>
是一个列表,您可以在其中放置任何实现Record
的对象,并且您获得的每个对象都将实现Record
。List<SubRecord>
是一个列表,您可以在其中放置任何实现SubRecord
的对象,并且您获得的每个对象都将实现SubRecord
。如果允许简单地使用List<SubRecord>
作为List<Record>
,则允许以下内容:
List<SubRecord> subrecords = new ArrayList<SubRecord>();
List<Record> records = subrecords;
records.add(new Record()); // no problem here
SubRecord sr = subrecords.get(0); // bang!
你知道,这不是类型安全的。 List(或参数化类的任何opject,实际上)不能类型安全地更改其参数类型。
在您的情况下,我看到了这些解决方案:
List<Record>
。 (您可以毫无问题地向此添加SubRecord
个对象。)
List<? super Subrecord>
作为添加内容的方法。 List<Record>
是此类型的子类型。复制清单:
List<Record> records = new ArrayList<Record>(subrecords);
稍微考虑一下变化:
void addSubrecords(List<? super Subrecord> subrecords) {
...
}
List<Record> records = new ArrayList<Record>();
addSubrecords(records);
recordkeeper.records = records;
答案 2 :(得分:1)
您不能这样做并且安全,因为List<Interface>
和List<SubInterface>
是Java中的不同类型。即使您可以将SubInterface类型添加到Interface列表中,也不能将这两个列表等同于不同的接口,即使它们是彼此的子/超级接口。
为什么你想做b =这么糟糕?您是否只想存储SubInterface列表的引用?
另外,我建议您在oracle网站上阅读此文档:http://download.oracle.com/javase/tutorial/java/generics/index.html 它很好地解释了泛型并深入到泛型中。
答案 3 :(得分:0)
没有办法做类型安全的事。
List<SubInterface>
无法添加任意Interface
个。毕竟这是SubInterface
的列表。
如果您确信这样做是安全的,即使它不是类型安全的,您也可以
@SuppressWarnings("unchecked")
void yourMethodName() {
...
List<Interface> a = (List<Interface>) b;
...
}
答案 4 :(得分:0)
所以,我的一位朋友找到的相当简单的解决方案是:
recordKeeper.myList = (List<Record>)(List<? extends Record>)records;
这是我理解的,因为它需要婴儿步骤。 List<SubRecord>
是List<? extends Record>
,List<? extends Record>
是List<Record>
。它可能不太漂亮,但它仍然有效。
答案 5 :(得分:0)
这个工作,但你应该警告!!!!
@Override
// Patient is Interface
public List<Patient> getAllPatients() {
// patientService.loadPatients() returns a list of subclasess of Interface Patient
return (List<Patient>)(List<? extends Patient>)patientService.loadPatients();
}
您可以通过这种方式从对象列表转换为接口列表。
但是,如果您在代码中的某个位置获得此列表,并且如果您尝试向此列表添加内容,那么您会添加什么?这个接口的Inteface或Subclass?你实际上是松散了列表类型的信息,因为你让它保持接口,所以你可以添加任何实现这个接口的东西,但是列表只保存子类,如果你尝试进行操作,你很容易得到类强制转换异常喜欢使用其他子类添加或获取此列表。解决方案是:将源列表的类型更改为list<Interface>
而不是强制转换,然后您可以自由选择:)