给定`T`和`U`,其中`T延伸U`如何返回'U`

时间:2016-09-01 17:14:38

标签: java generics optional

给出如下的API:

class Bar { ... }
class Foo extends Bar { ... }

在Java的Optional类型中,我们可以说:

Optional<Foo> fooOption = ...
fooOption.orElse(aFoo) // returns something of type Foo

但是,由于FooBar,我希望能够说:

Optional<Foo> fooOption = ...
fooOption.orElse(aBar) // returns something of type Bar

作为练习,我想用另一种类型来完成这个:

public abstract class Option<T> {
    // this doesn't compile
    public abstract <U super T> U orElse(U other);
}

我如何重写这个以进行编译,还支持同时在需要时扩展类型的能力?

4 个答案:

答案 0 :(得分:6)

  

但是,由于FooBar

Bar不是Foo。我的意思是你可以这样做:

Optional<Bar> fooOpt = Optional.of(new Foo());
Bar bar = fooOpt.orElse(new Bar());

但你不能对Optional<Foo>做同样的事情,因为它违反了Optional.orElse方法的类型限制。

Option<T>的假设实施中,您应明确将U定义为T

的超类型
public class Option<U, T extends U> {
    T value;

    public U orElse(U other) {
        if (value != null) {
            return value;
        }
        return other;
    }
}

在这种情况下,您可以编写像这样的代码

Option<Foo, Bar> fooOpt = Option.of(new Foo());
Bar bar = fooOpt.orElse(new Bar());

答案 1 :(得分:3)

由于U应该是T的超类型,您可以这样做:

public abstract class Option<U, T extends U> {

    public abstract of(T value);

    public abstract U orElse(U other);

}

答案 2 :(得分:3)

您可以使用map定义自己的方法来扩展类型:

public static <U, T extends U> U orElse(Optional<T> tOpt, U u) {
    return tOpt.<U>map(Function.identity()).orElse(u);
}

答案 3 :(得分:2)

在你的问题中有一个基本前提是有缺陷的:

  

在Java的Optional类型中,我们可以说:

     

可选fooOption = ...   fooOption.orElse(aFoo)//返回类型为Foo的东西   但是,既然Foo是一个酒吧,我想能够说:

     

可选fooOption = ...   fooOption.orElse(aBar)//返回类型为Bar

的东西

A Foo是一个酒吧,但酒吧不是Foo。如果你的Generic被定义为:

Optional<Foo> fooOption = ...

然后您可以返回Foo类型的任何内容。 Bar类型为Foo

如果您有其他对象:

class FooBar extends Foo{}

然后你可以在你的例子中将它转换为foo:

  

可选fooOption = ...

     

fooOption.orElse(aFooBar)//返回类型为Foo的东西

或者,或者,如果您已将Optional定义为Optional<Bar>,则可以使用FooBarFooBar个对象,因为它们是全部或继承自Bar类型。

关于问题的第二部分:

public abstract class Option<T> {
    // this doesn't compile
    public abstract <U super T> U orElse(U other);
}

只需用常用的超类型写一下:

public abstract class Option<T> {
    // this now compiles.
    public abstract T orElse(T other);
}

您说的是 继承自类型T的任何内容都是可以接受的。