- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我无法理解以下有关两个 Predicate
对象的代码。第一个使用下界通配符,第二个使用上限。
Predicate<? super String> p1 = s -> s.startsWith("a"); // why can I call startsWith()?
Predicate<? extends String> p2 = s -> s.startsWith("a");
p1.test("a"); // works
p2.test("a"); // doesn't work (why?)
关于 p1
我不明白的是,为什么可以调用 String
类的方法,例如startsWith()
?为什么我只能将 String
对象传递给 p1.test()
,我希望能够为 Number
和 Object 调用它
对象也是如此。
作为 p1
的行为,我认为 p2
会,但事实并非如此。我什至无法将 String
对象传递给 p2.test()
。这对我来说没有意义,因为我们期望一个对象继承自 String
(包括 String
)。
我认为这可能与我们指定引用类型而不是对象本身的类型这一事实有关。但是对象使用什么类型呢?
最佳答案
您调用startsWith
是合法的对于 p1
, 即使 p1
用下界键入 ? super String
,因为类型参数被推断为 String
. lambda 表达式 s -> s.startsWith("a");
被推断为 Predicate<String>
, 分配给 Predicate<? super String>
类型的变量是合法的.
编译:
Predicate<String> ps = s -> s.startsWith("a");
Predicate<? super String> p1 = ps;
这不是:
// no "startsWith" on Object
Predicate<? super String> p1 = (Object s) -> s.startsWith("a");
JLS 引用在 Section 15.27.3 中, “Lambda 表达式的类型”。
If T is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization (§9.9) of T.
这里,ground target type 是 lambda 表达式的类型,T
是目标类型,这是您的下限变量数据类型。这允许编译器分配 Predicate<String>
作为地面目标类型,成为 lambda 表达式的类型。
另请注意,您不能将父类(super class)对象传递给 p1.test
,因为您可以(并且已经)分配了一个 Predicate<String>
至 p1
,它需要一个 String
.
p1.test(new Object()); // Error: can't pass something higher than String
至于为什么不能传一个String
至 p2.test
, 当你有一个上限通配符时,例如 ? extends String
,这意味着类型参数可以是任何类 String
或子类型。 (编译器忽略 String
在这里是 final
并且不能有任何 String
的子类。)谓词 p2
可以分配一个 Predicate<SillyString>
,假设 SillyString
是 String
的子类.但是你不能传递 String
到一个可以期待 SillyString
的方法.
关于java - 引用类型中的有界通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58294604/
我是一名优秀的程序员,十分优秀!