具有无意义类型通配符的方法的Java API类

时间:2017-08-15 15:16:58

标签: java generics

在Java 8中,类java.util.Optionaljavadoc)类提供"Maybe" MonadOption Type的功能。

更直接:

  

公共最终类java.util.Optional< T> extends Object

     

容器对象,可能包含也可能不包含非null值。如果一个   值存在,isPresent()将返回true,get()将返回   价值。

One of the methods是:

  

< U>可选< U> map(函数<?super T,?extends U> mapper)

     

如果存在值,请将提供的映射函数应用于它,如果存在   结果为非null,返回描述结果的Optional。

问题在于map()为什么在U类型上使用类型通配符。

我对类型通配符的理解很简单:

enter image description here

? super T指定从ObjectT(包括ObjectT的子类路径)给出的类集合中的某些类型。在任何子接口路径上找到的接口集"作为一个侧面的"通过implements

? extends U只是从扩展U(包含U)的类集合中指定某种类型。

所以可以写一下:

  

< U>可选< U> map(函数<?super T,U> mapper)

不丢失信息。

或不?

1 个答案:

答案 0 :(得分:7)

不完全。

Function<? super T, U>Function<? super T, ? extends U>不同。

例如,即使我将Optional<CharSequence>传递给该方法,我仍然可以获得Function<Object, String>。如果该方法被定义为<U> Optional<U> map(Function<? super T, U> mapper),那么这是不可能的。

这是因为泛型不变:<T><? extends T>不同。这是用Java语言实现的设计决策。

让我们看看Jon Skeet explains what would happen如果泛型不会是不变的:

class Animal { }

class Dog extends Animal { }

class Cat extends Animal { }
public void ouch() {
    List<Dog> dogs = Arrays.asList(new Dog(), new Dog());
    List<Animal> animals;
    // This would be legal, right? Because a list of dogs is a list of animals.
    List<Animal> animals = dogs;
    // This would be legal, right? Because a cat could be added to a
    // list of animals, because a cat is an animal.
    animals.add(new Cat());
    // Unfortunately, we have a confused cat.
}

虽然我不完全确定你在评论中的意思,但我会尝试详细说明。

如果您可以完全控制自己提供的Function,那么该方法的签名是Function<? super T, U>还是Function<? super T, ? extends U>并不重要。我会相应调整你的Function。但是该方法的作者可能希望该方法尽可能灵活,允许提供Function的第二个参数也是U的子类,而不只是U本身。实际上,您将其下限从U扩展到U的某个子类型。

  

因此该函数应该真正读取<U> Optional<? the-most-general-but-fixed-supertype-of U> map(Function<? super T, U> mapper),但以这种方式表达会很尴尬。

我确实很尴尬。此外,您提出的符号与map()的实际方法签名之间存在差异,其中涉及下限上限的含义。

了解更多: