Java 泛型方法,用于强制参数类型和返回类型之间的类型不变性



我已经尝试了下面代码的多种不同变体,但找不到任何不依赖于不安全强制转换或导致其他编译器警告的解决方案。我相信这个目标是可能的,但也许不是?

简单地说,目标是我有彼此相关并具有不变关系的派生类型,这可以通过泛型方法强制执行。

AlphaTask总是返回AlphaTaskResultAlphaTaskITask<T>的具体实现,其中TStringAlphaTaskResult扩展了TaskResult<T>的基类,其中T再次String

一切都会检查出来,直到编写一个泛型方法,该方法接受任何Task并返回相应的TaskResult类型。

错误是:

Required type: List<U>
Provided:      List<TaskResult<T>>
no instance(s) of type variable(s) exist so that TaskResult<T> conforms to U inference variable T has incompatible bounds: equality constraints: U lower bounds: TaskResult<T>
package com.adobe.panpipe;
import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;

interface ITask<T>{
TaskResult<T> make();
}
class TaskResult<T>{
T value;
}
class AlphaTaskResult extends TaskResult<String> {
AlphaTaskResult(String value){
this.value = value;
}
}
class BetaTaskResult extends TaskResult<Integer> {
BetaTaskResult(Integer value){
this.value = value;
}
}
class AlphaTask implements ITask<String> {
public AlphaTaskResult make(){
return new AlphaTaskResult("alphaTask");
}
}
class BetaTask implements ITask<Integer> {
public BetaTaskResult make(){
return new BetaTaskResult(9001);
}
}
public class Main <T>{
public static <T, U extends TaskResult<T>, V extends ITask<T>> List<U> run(List<V> tasks){
List<U> results =  tasks
.stream()
.map(ITask::make)
.collect(Collectors.toList());
return results;
}
public static void main(String[] args) {
List<AlphaTaskResult> alphaResults = run(Arrays.asList(new AlphaTask(), new AlphaTask()));
List<BetaTaskResult> betaResults = run(Arrays.asList(new BetaTask(), new BetaTask()));
}
}

ITaskTaskResult之间没有联系。当然,任务实现会使用其各自的返回类型覆盖make,但此信息不能用于run方法的声明。

您可以通过向ITask添加其他类型参数来建立连接:

interface ITask<T, TResult extends TaskResult<T>>{
TResult make();
}
class TaskResult<T>{
T value;
}

相应地更改任务实现和run

class AlphaTask implements ITask<String, AlphaTaskResult> {
public AlphaTaskResult make(){
return new AlphaTaskResult("alphaTask");
}
}
class BetaTask implements ITask<Integer, BetaTaskResult> {
public BetaTaskResult make(){
return new BetaTaskResult(9001);
}
}
public class Main { // Main doesn't need a type parameter
public static <T, U extends TaskResult<T>, V extends ITask<T, U>> List<U> run(List<V> tasks){
List<U> results =  tasks
.stream()
.map(ITask::make)
.collect(Collectors.toList());
return results;
}
public static void main(String[] args) {
List<AlphaTaskResult> alphaResults = run(Arrays.asList(new AlphaTask(), new AlphaTask()));
List<BetaTaskResult> betaResults = run(Arrays.asList(new BetaTask(), new BetaTask()));
}
}

只需将结果的类型R extends TaskResult<T>添加到任务的类型ITask即可。以下编译就可以了:

import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;

interface ITask<T, R extends TaskResult<T>>{
R make();
}
class TaskResult<T>{
T value;
}
class AlphaTaskResult extends TaskResult<String> {
AlphaTaskResult(String value){
this.value = value;
}
}
class BetaTaskResult extends TaskResult<Integer> {
BetaTaskResult(Integer value){
this.value = value;
}
}
class AlphaTask implements ITask<String, AlphaTaskResult> {
public AlphaTaskResult make(){
return new AlphaTaskResult("alphaTask");
}
}
class BetaTask implements ITask<Integer, BetaTaskResult> {
public BetaTaskResult make(){
return new BetaTaskResult(9001);
}
}
public class Main <T>{
public static <T, R extends TaskResult<T>> List<R> run(List<ITask<T, R>> tasks){
List<R> results =  tasks
.stream()
.map(ITask::make)
.collect(Collectors.toList());
return results;
}
public static void main(String[] args) {
List<AlphaTaskResult> alphaResults = run(Arrays.asList(new AlphaTask(), new AlphaTask()));
List<BetaTaskResult> betaResults = run(Arrays.asList(new BetaTask(), new BetaTask()));
}
}

您的版本无法编译的原因是结果的确切类型不包含在任务类型中,并且由于 Java 中没有类型优化,因此无法推断出U类型。

最新更新