如何在单个约束中使用方法和类类型参数?

eas*_*825 11 java generics

我将尝试在以下简化示例中说明我的问题:

public class DataHolder<T> {
  private final T myValue;

  public DataHolder(T value) {
    myValue = value;
  }

  public T get() {
    return myValue;
  }

  // Won't compile
  public <R> DataHolder<R super T> firstNotNull(DataHolder<? extends R> other) {
    return new DataHolder<R>(myValue != null ? myValue : other.myValue);      }

  public static <R> DataHolder<R> selectFirstNotNull(DataHolder<? extends R> first,
                                                     DataHolder<? extends R> second) {
    return new DataHolder<R>(first.myValue != null ? first.myValue : second.myValue);
  }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我想写泛型方法firstNotNull返回DataHolder的类型参数的共同参数化父Tthisother论证,所以后来我能写如

DataHolder<Number> r = new DataHolder<>(3).firstNotNull(new DataHolder<>(2.0));
Run Code Online (Sandbox Code Playgroud)

要么

DataHolder<Object> r = new DataHolder<>("foo").firstNotNull(new DataHolder<>(42));
Run Code Online (Sandbox Code Playgroud)

问题是这个定义firstNotNull被编译器拒绝,消息表明super T类型约束的一部分是非法的(语法上).然而,没有这个约束定义也是错误的(显然),因为在这种情况下T并且R彼此无关.

有趣的是,类似静态方法的定义selectFirstNotNull是正确的,后者按预期工作.是否有可能在Java类型系统中使用非静态方法实现相同的灵活性?

Pau*_*ora 6

这是不可能的.Guava的作者遇到了同样的问题Optional.or.从该方法的文档:

关于泛型的注意事项:签名public T or(T defaultValue)过于严格.但是,理想的签名,public <S super T> S or(S)不是合法的Java.因此,涉及子类型的一些合理操作是编译错误:

Optional<Integer> optionalInt = getSomeOptionalInt();
Number value = optionalInt.or(0.5); // error

FluentIterable<? extends Number> numbers = getSomeNumbers();   
Optional<? extends Number> first = numbers.first();
Number value = first.or(0.5); // error
Run Code Online (Sandbox Code Playgroud)

作为一种解决方法,施放一个总是安全的 Optional<? extends T> to Optional<T>.将上述任一示例Optional实例转换为Optional<Number>(Number所需的输出类型)解决了问题:

Optional<Number> optionalInt = (Optional) getSomeOptionalInt();   
Number value = optionalInt.or(0.5); // fine

FluentIterable<? extends Number> numbers = getSomeNumbers();   
Optional<Number> first = (Optional) numbers.first();
Number value = first.or(0.5); // fine
Run Code Online (Sandbox Code Playgroud)

既然DataHolder是不可变的Optional,上面的解决方法也适用于你.

另请参阅:Rotsor使用'super'关键字对Bounding泛型的回答