[英]Java using generics with lists and interfaces
好的,所以这是我的问题:
我有一个包含接口的列表 - List<Interface> a
- 以及扩展该接口的接口List<SubInterface> b
: List<SubInterface> b
。 我想设置a = b
。 我不希望使用addAll()
或任何会花费更多内存的东西,因为我正在做的事情已经非常耗费成本。 我真的需要能够说a = b
。 我试过List<? extends Interface> a
List<? extends Interface> a
,但是我不能将接口添加到列表a
,只能添加SubInterfaces。 有什么建议?
我希望能够做到这样的事情:
List<SubRecord> records = new ArrayList<SubRecord>();
//add things to records
recordKeeper.myList = records;
RecordKeeper类是包含接口列表(NOT子接口)的类
public class RecordKeeper{
public List<Record> myList;
}
这有效:
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>
在添加任何内容之前List<? extends Record>
。 如果要转换为的类型是Record
的子类,Java将允许转换,但它无法猜测它将是哪种类型,您必须指定它。
List<Record>
只能包含Records
(包括subRecords
), List<SubRecord>
只能包含SubRecords
。
但是A List<SubRecord
>不是List<Record>
,它不能包含Records
,而子类应该总是做超类可以做的事情。 这很重要,因为继承是specilisation,如果List<SubRecords>
将是List<Record>
的子类,它应该能够包含`但它不是。
List<Record>
和List<SubRecord>
都是List<? extends Record>
List<? extends Record>
。 但是在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>
。
此致,Stéphane
只是为了解释为什么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
地将SubRecord
对象添加SubRecord
。)
List<? super 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;
这个工作,但你应该警告!!!!
@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>
而不是cast,然后你可以自由地去:)
你不能这样做并且安全,因为List<Interface>
和List<SubInterface>
是Java中的不同类型。 即使您可以将SubInterface类型添加到Interface列表中,也不能将这两个列表等同于不同的接口,即使它们是彼此的子/超级接口。
你为什么要这么做b =这么糟糕? 您是否只想存储SubInterface列表的引用?
另外,我建议你在oracle网站上阅读这篇文档: http : //download.oracle.com/javase/tutorial/java/generics/index.html它解释并深入了解泛型。
没有办法做类型安全的。
List<SubInterface>
不能添加任意Interface
。 毕竟它是一个SubInterface
列表。
如果您确信这样做是安全的,即使它不是类型安全的,您也可以这样做
@SuppressWarnings("unchecked")
void yourMethodName() {
...
List<Interface> a = (List<Interface>) b;
...
}
所以,我的朋友找到的相当简单的解决方案是这样的:
recordKeeper.myList = (List<Record>)(List<? extends Record>)records;
这是我理解的,因为它需要婴儿步骤。 List<SubRecord>
是一个List<? extends Record>
List<? extends Record>
,并List<? extends Record>
List<? extends Record>
是List<Record>
。 它可能不漂亮,但它仍然有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.