简体   繁体   English

如何将泛型类型转换为 Object?

[英]How to cast generic type to Object?

The code below won't compile because it can't add Task<T> to List<Task<Object>> how to fix it?下面的代码无法编译,因为它无法将Task<T>添加到List<Task<Object>>如何解决?

import java.util.ArrayList;
import java.util.List;

public class Tasks {

  private final List<Task<Object>> queue = new ArrayList<>();

  public static abstract class Task<T> {}

  public <T> List<T> process(List<Task<T>> tasks) {
    for (Task<T> task : tasks) queue.add(task); // <== problem here
  }

}

Imagine Task was exactly like List : It has an add(T item) method.想象一下 Task 就像List一样:它有一个add(T item)方法。

If you allowed adding a Task<T> to a List of Task<Object> , then other code could then grab an item from the list, which would have type Task<Object> , which would let you thus call the add(Object o) method, letting you add anything you want, as anything is an object.如果您允许将Task<T>添加到Task<Object>列表中,那么其他代码可以从列表中获取一个项目,该项目的类型为Task<Object> ,这样您就可以调用add(Object o)方法,让你添加任何你想要的东西,因为任何东西都是 object。

So if you added a Task<String> , your task now has non-strings in it.因此,如果您添加了Task<String> ,您的任务现在包含非字符串。

That's why this isn't allowed.这就是为什么这是不允许的。

Now, presumably, your task has absolutely no opportunities to 'add' things;现在,大概,您的任务绝对没有机会“添加”东西; none of the methods have a T as parameter, the T occurs solely in a 'get' position, in academicese, as a covariant option: For example, it only shows up in return types of methods in the Task class.这些方法都没有 T 作为参数,T 仅出现在“get”position 中,在学术上,作为协变选项:例如,它仅显示在Task class 中的方法的返回类型中。

Java unfortunately does not have the kind of use-site variance declaration model that makes this easy.不幸的是,Java 没有那种使用站点差异声明 model 使这变得容易。

You have two general solutions:您有两个通用解决方案:

  1. 'uglycasting': Cast things, using the 3rd form of the cast construct, where you cast to a type that has generics, or perhaps, a raw type: 'uglycasting':使用第三种形式的 cast 构造进行转换,您可以在其中转换为具有 generics 的类型,或者可能是原始类型:
Task /* raw */ temp = task;
queue.add(temp); // this will work, but generates a warning.

then use @SuppressWarnings .然后使用@SuppressWarnings Note that this does mean you're 'opting out' of the compiler checking your work, and if Task either has a method like add(T) or gets one later, you get no protections, and the end result will likely be that you end up seeing ClassCastException errors in places with zero casts in them.请注意,这确实意味着您正在“选择退出”编译器检查您的工作,并且如果 Task 有类似add(T)的方法或稍后获得一个方法,您将得不到任何保护,最终结果可能是您最终看到ClassCastException错误的地方有零演员表。

  1. Redefine queue .重新定义queue

Alternatively, redefinine queue to accept covariance.或者,重新定义队列以接受协方差。 In that sense, Task<Object> is rather useless;从这个意义上说, Task<Object>是相当无用的。 few to no task types you'll ever make are actually assignable to this type.您将创建的几乎没有任务类型实际上可以分配给这种类型。 Try Task<? extends Object>试试Task<? extends Object> Task<? extends Object> , which can be shortened to just Task<?> . Task<? extends Object> ,可以简称为Task<?> Just like with a List<? extends Whatever>就像List<? extends Whatever> List<? extends Whatever> , you cannot invoke add() style methods at all on such a thing; List<? extends Whatever> ,你根本不能在这样的事情上调用add()风格的方法; any method Task has that takes as parameter a T are now not invokable*. Task具有的任何将 a T作为参数的方法现在都不可调用*。 That's a good thing;这是好事; it frees you up to assign any Task<T> regardless of what T might be to it, then.然后,它使您可以分配任何Task<T> ,而不管 T 可能是什么。

List<Task<?>> queue = new ArrayList<>();

*) Unless you pass literally null , which is every type, and thus also fits for an unknown bound, but that's rather useless, of course. *) 除非您按字面意思传递null ,它是每种类型,因此也适合未知范围,但这当然没用。

If you are storing mixed task types, you need to use ?如果要存储混合任务类型,则需要使用? , since your list does not know what kind of Task is going to be passed into it. ,因为您的列表不知道将传递什么样的Task

private final List<Task<?>> queue = new ArrayList<>();

import java.util.*;
import java.util.stream.Collectors;

public class Tasks {
    // Static classes, methods and fields

    public static abstract class Task<T> {
        private T value;
        public T getValue() { return value; }
        protected Task(T value) { this.value = value; }
        public String toString() { return String.format("Task[value=%s]", this.value);  }
    }

    // Instance fields

    private final List<Task<?>> queue = new ArrayList<>();

    // Class methods

    public List<?> process(List<Task<?>> tasks) {
        for (Task<?> task : tasks) queue.add(task);
        return queue.stream().map(Task::getValue).collect(Collectors.toList());
    }

    // Implementation

    private static class StringTask extends Task<String> {
        protected StringTask(String value) {
            super(value);
        }
    }

    private static class IntTask extends Task<Integer> {
        protected IntTask(Integer value) {
            super(value);
        }
    }

    public static void main(String[] args) {
        Tasks tasks = new Tasks();

        List<Task<?>> taskList = Arrays.asList(
            new StringTask("Hello World"),
            new IntTask(42)
        );

        tasks.process(taskList).stream().forEach(System.out::println);
    }
}

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

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