假设我有以下结构:
const recentOrders = Object.keys(data)
.filter(function (key) {
return key.startsWith('L_')
})
.map(function (key) {
const parts = key.match(/^L_([A-Z]+)(\d+)$/);
return {
key: parts[1].toLowerCase(),
value: data[key],
index: parseInt(parts[2])
};
})
.reduce(function (recentOrders, item) {
if (recentOrders[item.index] == null) {
recentOrders[item.index] = {}
}
recentOrders[item.index][item.key] = item.value;
return recentOrders ;
}, []);
console.log(recentOrders);
现在我正在编写一个主要方法来使用它。 我对以下概念很满意:('对象'从超级方法的get方法返回类型)
java.lang.Object
class A extends Object { public boolean mA() {return true;} }
class B extends A { public boolean mB() {return false;} }
因为我可以使用
来调用它public static void m1(List<? super A> l ) {
l.get(0).toString();
}
我对此也很好:(&#39; A&#39;类型从get方法返回以进行扩展)
m1(new ArrayList<A>());
m1(new ArrayList<Object>());
因为我可以使用
来调用它public static void m2(List<? extends A> l ) {
l.get(0).mA();
}
最后我的问题:为什么下面的定义是&#39; super&#39;接收类型&#39; A&#39;作为参数,而不是对象?
m2(new ArrayList<A>());
m2(new ArrayList<B>());
我认为它会变成类似的东西(我知道下面的代码无效......我只是觉得它会与之类似)。
Predicate<? extends A> p1 = a -> a.mA(); // ok
Predicate<? super A> p2 = a -> a.mA(); // why is it of type 'A' too??
我还检查了反编译类,但我没有得到任何新的线索。谁能告诉我引擎盖下发生了什么?我已经阅读了PECS讨论,但它对这个具体问题没有帮助。
提前谢谢! ;)
=====收到答案后用额外代码编辑=====
PredicateImpl<T super A> {
public boolean test(T t);
}
有趣的替代语法(虽然我认为Predicate&lt;?extends Anything&gt;是非常没用的,因为它只接受&#39; null&#39;在测试方法)。无论如何,我发现这样的练习,无论如何我都学会了。
Predicate<? super A> pSuper = a -> a.mA();
Predicate<? extends A> pExtends = a -> a.mA(); // ?? A ??
Predicate<Object> pObject = o -> o.equals(null);
Predicate<A> pA = a -> a.mA();
Predicate<B> pB = b -> b.mB();
pSuper = pObject;
pSuper = pA;
pSuper = pB; // compiler error
pExtends = pObject; // compiler error
pExtends = pA;
pExtends = pB;
答案 0 :(得分:3)
JLS, Section 9.9,讨论了lambda表达式的类型推断。其中一节讨论了存在通配符和边界时的类型推断。
当通用功能接口通过通配符参数化时,有许多不同的实例可以满足通配符并生成不同的函数类型。例如,每个
Predicate<Integer>
(函数类型Integer
- &gt;boolean
),Predicate<Number>
(函数类型Number
- &gt;boolean
) ,Predicate<Object>
(函数类型Object
- &gt;boolean
)是Predicate<? super Integer>
。有时,可以从上下文中了解,例如lambda表达式的参数类型,函数类型是什么(第15.27.3节)。其他时候,有必要选一个;在这些情况下,使用界限。
(大胆强调我的)
此处,目标类型为Predicate<? super A>
,lambda参数a
可能有多种类型:Object
和A
。目标类型绑定为? super A
,因此绑定的A
用作类型。
这对于任何通配符绑定(上限或下限)都是最有意义的。使用上限,绑定类型非常有意义。类型为A
或更低,但它可能只是A
,因此A
方法应该可用。 Predicate<A>
可分配给Predicate<? extends A>
。
使用下限,类型为A
或更高。但为什么不选择Object
?因为A
工作正常。
Predicate<A>
可以分配给Predicate<? super A>
。 Predicate<Object>
也可以分配给Predicate<? super A>
,但这会造成不必要的限制。 lambda表达式仅限于调用Object
方法,因为它可以轻松调用A
方法(方法mA
)。在这里选择最具限制性的类型是有意义的,这样程序员可以调用大多数方法。此外,根据边界限制最多的功能接口类型必须是可分配的。 Predicate<A>
可分配给Predicate<? super A>
。
您甚至可以将lambda表达式a -> a.mA()
分配给Predicate<? extends B>
,Predicate<? super B>
,甚至Predicate<B>
。推断类型为B
,该类型肯定具有方法mA
,从A
继承。
如果您尝试将lambda表达式a -> a.mA()
分配给Predicate<Object>
或Predicate<?>
,则Object
必须是推断类型。在这里,您将得到mA
未定义Object
的编译器错误。