简体   繁体   English

为什么Java不能将ArrayList <TreeSet <Integer >>转换为List <Set <Object >>?

[英]Why can't Java convert an ArrayList<TreeSet<Integer>> into a List<Set<Object>>?

I'm attempting to do something that seems rather simple: sum the sizes of a list of sets. 我试图做一些看似相当简单的事情:总结一组列表的大小。 Netbeans gives the following warning/error: Netbeans给出以下警告/错误:

actual argument java.util.ArrayList<java.util.TreeSet<java.lang.Integer>> cannot be    converted to java.util.List<java.util.Set<java.lang.Object>> by method invocation conversion

for the following two pieces of code: 对于以下两段代码:

/**
 * Sums the sizes of all sets in a list.  Note that while there will be
 * no duplicate elements in a single set, "sister" sets may contain
 * elements, so the value returned is **not** equal to the number of unique
 * elements in all sets.
 * @param list, a List of Sets
 * @return the number of elements contained in all sets
 */
public static int sizeOfListOfSets(List<Set<Object>> list) {
    int size = 0;

    for (Set<Object> set : list) {
        size += set.size();
    }

    return size;
}

and then calling it with the following: 然后使用以下内容调用它:

    ArrayList<TreeSet<Integer>> testList = new ArrayList<TreeSet<Integer>>();
    TreeSet<Integer>            testSet;
    int                         size = 0;

    testSet = new TreeSet<Integer>();
    testSet.add(new Integer(++size));
    testSet.add(new Integer(++size));
    testList.add(testSet);
    testSet = new TreeSet<Integer>();
    testSet.add(new Integer(++size));
    testList.add(testSet);

    int expResult = size;
    int result    = Helpers.sizeOfListOfSets(testList);

the last line gives the compilation error: 最后一行给出了编译错误:

error: method sizeOfListOfSets in class Helpers cannot be applied to given types;
1 error

So, why can't java.lang.Integer be converted to java.lang.Object? 那么,为什么java.lang.Integer不能转换为java.lang.Object?

A List<Integer> is not a List<Object> . List<Integer>不是List<Object> If Java allowed that, then you could call the method with List<String> and you will be broken. 如果Java允许,那么您可以使用List<String>调用该方法,您将被破坏。 As Jeremy Heiler pointed out you can use List<? extends Object> 正如Jeremy Heiler指出你可以使用List<? extends Object> List<? extends Object> and you will be fine. List<? extends Object>你会没事的。 This means every type which extends Object is allowed. 这意味着允许扩展Object每个类型。 ? is called a wildcard in generic jargon. 在通用术语中称为wildcard

Anything you declare as a generic type must be the exact same generic type always. 您声明为泛型类型的任何内容都必须始终是完全相同的泛型类型。 The only think that can vary is the base type ie: 可以改变的唯一想法是基本类型,即:

List<MyObject> myList = new ArrayList<MyObject>;

This is because for example if you had a parameter declared as List<Object> , and you could pass it a List<Integer> , then you would be able to add ANY kind of object to that list, which would break the type safety. 这是因为,例如,如果您有一个声明为List<Object>的参数,并且您可以将它传递给List<Integer> ,那么您将能够向该列表添加任何类型的对象,这将破坏类型安全性。

Although there is a workaround using the wildcard ? 虽然使用通配符有解决方法? , you still will NOT be able to add elements unless you do it like this <? super MyObject> ,你仍然无法添加元素,除非你这样做<? super MyObject> <? super MyObject> , because anything higher on the inheritance tree would be ok to add to the list. <? super MyObject> ,因为继承树上任何更高的内容都可以添加到列表中。

The issue is not converting from an Integer to an Object, but from a list of Integer to a list of Object which fails because List<Integer> is not a List<Object> . 问题不是从Integer转换为Object,而是从Integer列表转换为Object列表失败,因为List<Integer>不是List<Object> Java compiler does not try to automatically cast generic types. Java编译器不会尝试自动转换泛型类型。

You might change your method declaration to something like this to get away with the error: 您可以将方法声明更改为类似的内容以避免错误:

public static int sizeOfListOfSets(List<Set<? extends Object>> list)

Because that would enable you to put any object in that list. 因为这样可以将任何对象放入该列表中。 When you access elements later from your original list reference, it will contain non-Integer objects, although the list is still declared as a List<Integer> - which means that you can't rely on what the type says anymore. 当您稍后从原始列表引用访问元素时,它将包含非Integer对象,尽管列表仍然被声明为List<Integer> - 这意味着您不能再依赖于类型所说的内容。 Example: 例:

List<Integer> intList = new ArrayList<Integer>();
doSomething(intList);
for (Integer i : intList) {
    // i must be an Integer, so doSomething must not
    // be able to put non-Integers into that list.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM