Java 使用带有列表和接口的泛型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6474784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:01:45  来源:igfitidea点击:

Java using generics with lists and interfaces

javagenericsparameters

提问by MirroredFate

Ok, so here is my problem:

好的,这是我的问题:

I have a list containing interfaces - List<Interface> a- and a list of interfaces that extend that interface: List<SubInterface> b. I want to set a = b. I do not wish to use addAll()or anything that will cost more memory as what I am doing is already very cost-intensive. I literally need to be able to say a = b. I have tried List<? extends Interface> a, but then I cannot add Interfaces to the list a, only the SubInterfaces. Any suggestions?

我有一个包含接口的列表 - List<Interface> a- 以及扩展该接口的接口列表:List<SubInterface> b. 我想设置a = b。我不希望使用addAll()或任何会花费更多内存的东西,因为我正在做的事情已经非常耗费成本。我真的需要能够说a = b。我试过了List<? extends Interface> a,但后来我无法将接口添加到列表中a,只能添加子接口。有什么建议?

I want to be able to do something like this:

我希望能够做这样的事情:

List<SubRecord> records = new ArrayList<SubRecord>();
//add things to records
recordKeeper.myList = records;

The class RecordKeeper is the one that contains the list of Interfaces (NOT subInterfaces)

RecordKeeper 类是包含接口列表(不是子接口)的类

public class RecordKeeper{
    public List<Record> myList;
}

采纳答案by MirroredFate

So, the rather simple solution a friend of mine found was this:

所以,我的一个朋友找到的相当简单的解决方案是这样的:

recordKeeper.myList = (List<Record>)(List<? extends Record>)records;

This works as I understand it because it takes baby steps. List<SubRecord>is a List<? extends Record>, and List<? extends Record>is a List<Record>. It might not be pretty, but it works nonetheless.

按照我的理解,这很有效,因为它需要一些小步骤。List<SubRecord>List<? extends Record>List<? extends Record>List<Record>。它可能不漂亮,但它仍然有效。

回答by Snicolas

This works :

这有效:

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

    }

}

I mean it compiles, but you willhave to cast your List<? extends Record>before adding anything inside. Java will allow casting if the type you want to cast to is a subclass of Record, but it can't guess which type it will be, you have to specify it.

我的意思是它编译,但是你不得不投你List<? extends Record>添加任何内部之前。如果您要转换的类型是 的子类,Java 将允许转换Record,但它无法猜测它将是哪种类型,您必须指定它。

A List<Record>can only contain Records(including subRecords), A List<SubRecord>can only contain SubRecords.

AList<Record>只能包含Records(包括subRecords),AList<SubRecord>只能包含SubRecords

But A List<SubRecord> is not a List<Record>has it cannot contains Records, and subclasses should always do what super classes can do. This is importantas inheritance is specilisation, if List<SubRecords>would be a subclass of List<Record>, it should be able to contain ` but it'S not.

但是 A List<SubRecord> 不是List<Record>has it cannot contains Records,子类应该总是做超类可以做的事情。这很重要,因为继承是特殊化的,如果它List<SubRecords>是 的子类List<Record>,它应该能够包含 ` 但它不是。

A List<Record>and a List<SubRecord>both are List<? extends Record>. But in a List<? extends Record>you can't add anything as java can't know which exact type the Listis a container of. Imagine you could, then you could have the following statements :

AList<Record>和 aList<SubRecord>都是List<? extends Record>。但是在 a 中List<? extends Record>你不能添加任何东西,因为 java 不知道它List是一个容器的确切类型。想象一下你可以,然后你可以有以下陈述:

List<? extends Record> l = l2;
l.add( new Record() );

As we just saw, this is only possible for List<Record>not for any List<Something that extends Record>such as List<SubRecord>.

正如我们刚刚看到的,这仅适用于List<Record>not 对于任何List<Something that extends Record>诸如List<SubRecord>.

Regards, Stéphane

问候, 斯蒂芬

回答by Pa?lo Ebermann

Just to explain why Java does not permit this:

只是为了解释为什么 Java 不允许这样做:

  • A List<Record>is a list in which you can put any object implementing Record, and every object you get out will implement Record.
  • A List<SubRecord>is a list in which you can put any object implementing SubRecord, and every object you get out will implement SubRecord.
  • AList<Record>是一个列表,您可以在其中放置任何对象实现Record,并且您得到的每个对象都将实现Record
  • AList<SubRecord>是一个列表,您可以在其中放置任何对象实现SubRecord,并且您得到的每个对象都将实现SubRecord

If it would be allowed to simply use a List<SubRecord>as a List<Record>, then the following would be allowed:

如果允许简单地使用 aList<SubRecord>作为 a 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!

You see, this would not be typesafe. A List (or any opject of a parametrized class, in fact) can not typesafely change its parameter type.

你看,这不是类型安全的。列表(或任何参数化类的对象,实际上)不能类型安全地更改其参数类型。

In your case, I see these solutions:

在你的情况下,我看到这些解决方案:

  • Use List<Record>from start. (You can add SubRecordobjects to this without problems.)
    • as a variation of this, you can use List<? super Subrecord>for the method which adds stuff. List<Record>is a subtype of this.
  • copy the list:

    List<Record> records = new ArrayList<Record>(subrecords);
    
  • List<Record>从头开始使用。(您可以SubRecord毫无问题地向其中添加对象。)
    • 作为此的变体,您可以使用List<? super Subrecord>添加内容的方法。List<Record>是这个的一个子类型。
  • 复制列表:

    List<Record> records = new ArrayList<Record>(subrecords);
    


To exand a bit on th variation:

稍微扩展一下变体:

void addSubrecords(List<? super Subrecord> subrecords) {
    ...
}


List<Record> records = new ArrayList<Record>();
addSubrecords(records);
recordkeeper.records = records;

回答by Krzysiek

THIS WORK, BUT YOU SHOULD BE WARN !!!!

这项工作,但你应该警告!!!!

@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(); 
}

You can cast from List of Objects to List of Interface in this way. But, if you get this list somewhere in your code and if you try to add something to this list, what would you add? Inteface or Subclass of this interface ? You actually loose information of the type of list, because you let it hold Interface, so you can add anything that implement this interface, but the list is holding the subclasses only, and you could easily get class cast exception if you try to do operations like add or get on this list with some other subclass. The solution is: Change The type of source list to list<Interface>instead of cast, then you are free to go :)

您可以通过这种方式从对象列表转换为接口列表。但是,如果您在代码中的某个地方得到这个列表,并且如果您尝试向这个列表添加一些东西,您会添加什么?此接口的接口或子类?你实际上丢失了列表类型的信息,因为你让它持有接口,所以你可以添加任何实现这个接口的东西,但列表只持有子类,如果你尝试执行操作,你很容易得到类转换异常像添加或获取与其他一些子类的列表一样。解决方案是:将源列表的类型更改为list<Interface>而不是强制转换,然后您就可以自由去了:)

回答by peacey

You can't do that and be safe because List<Interface>and List<SubInterface>are different types in Java. Even though you can add types of SubInterface to a list of Interface, you can't equate the two lists with different interfaces even if they're sub/super interfaces of eachother.

你不能这样做并且是安全的,因为List<Interface>List<SubInterface>在 Java 中是不同的类型。即使您可以将 SubInterface 的类型添加到 Interface 列表中,您也不能将这两个列表等同于不同的接口,即使它们是彼此的子/超级接口。

Why is it that you want to do b = a so bad? Do you just want to store a reference to the SubInterface list?

为什么你想要做 b = a 这么糟糕?您是否只想存储对 SubInterface 列表的引用?

On a side note, I suggest you read this documentation on the oracle site: http://download.oracle.com/javase/tutorial/java/generics/index.htmlIt explains and goes deep into generics very well.

附带说明一下,我建议您在 oracle 站点上阅读此文档:http: //download.oracle.com/javase/tutorial/java/generics/index.html它很好地解释并深入介绍了泛型。

回答by Mike Samuel

There's no way to do it that is type safe.

没有办法做到类型安全。

A List<SubInterface>cannot have arbitrary Interfaces added to it. It is a list of SubInterfaces after all.

AList<SubInterface>不能Interface添加任意的s。SubInterface毕竟是s的列表。

If you are convinced that this is safe to do even though it is not type safe you can do

如果您确信这样做是安全的,即使它不是类型安全的,您也可以这样做

@SuppressWarnings("unchecked")
void yourMethodName() {
  ...
  List<Interface> a = (List<Interface>) b;
  ...
}