假设您有List
个数字。 List
中的值可以是Integer
,Double
等类型。当您声明这样的List
时,可以使用通配符声明它({{1} })或没有通配符。
?
所以,现在我想final List<Number> numberList = Arrays.asList(1, 2, 3D);
final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);
stream
而List
使用collect
Map
{显然下面的代码只是Collectors.toMap
一个例子来说明问题)。让我们开始流式传输numberList
:
final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D);
numberList.stream().collect(Collectors.toMap(
// Here I can invoke "number.intValue()" - the object ("number") is treated as a Number
number -> Integer.valueOf(number.intValue()),
number -> number));
但是,我不能对wildcardList
:
final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.toMap(
// Why is "number" treated as an Object and not a Number?
number -> Integer.valueOf(number.intValue()),
number -> number));
编译器在调用number.intValue()
时抱怨以下消息:
Test.java:找不到符号
symbol:方法intValue()
location:java.lang.Object类型的变量数
从编译器错误中可以明显看出lambda中的number
被视为Object
而不是Number
。
所以,现在问我的问题:
List
的通配符版本时,为什么它不像List
的非通配符版本那样工作? number
变量被认为是Object
而不是Number
?答案 0 :(得分:34)
它的类型推断没有做到。如果明确提供type参数,它将按预期工作:
List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.<Number, Integer, Number>toMap(
number -> Integer.valueOf(number.intValue()),
number -> number));
这是一个已知的javac错误:Inference should not map capture variables to their upper bounds。据Maurizio Cimadamore说,这个地位,
尝试了一个修复程序然后退出,因为它在8中破坏了案例,所以我们在8中进行了更为保守的修复,同时在9中完成了
显然还没有推出修复程序。 (感谢 Joel Borggrén-Franck指出我正确的方向。)
答案 1 :(得分:3)
表单List<? extends Number> wildcardList
的声明意味着“具有未知类型的列表Number
或子类Number
”。有趣的是,如果未知类型由名称引用,则具有未知类型的相同类型的列表有效:
static <N extends Number> void doTheThingWithoutWildCards(List<N> numberList) {
numberList.stream().collect(Collectors.toMap(
// Here I can invoke "number.intValue()" - the object is treated as a Number
number -> number.intValue(),
number -> number));
}
此处,N
仍然是“Number
的未知类型或Number
的子类”,但您可以按预期处理List<N>
。您可以将List<? extends Number>
分配给List<N>
而不会出现问题,因为未知类型extends Number
兼容的约束。
final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
doTheThingWithoutWildCards(wildCardList); // or:
doTheThingWithoutWildCards(Arrays.asList(1, 2, 3D));
chapter about Type Inference并不容易阅读。我不知道在这方面通配符和其他类型之间是否存在差异,但我认为不应该存在。所以它的要么一个compiler bug ,要么按规范限制,但逻辑上,没有理由说通配符不起作用。
答案 2 :(得分:2)
这是由于type inference,在第一种情况下,您声明List<Number>
,因此编译器在编写number -> Integer.valueOf(number.intValue())
时没有任何反对意见,因为变量number
的类型是{{1} }
但是在第二种情况下,你宣布了java.lang.Number
final List<? extends Number> wildCardList
被翻译为Collectors.toMap
例如
Collectors.<Object, ?, Map<Object, Number>toMap
因此在表达式
中 final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
Collector<Object, ?, Map<Object, Object>> collector = Collectors.toMap(
// Why is number treated as an Object and not a Number?
number -> Integer.valueOf(number.intValue()),
number -> number);
wildCardList.stream().collect(collector);
变量number -> Integer.valueOf(number.intValue()
的类型是对象,并且在类Object中没有定义方法number
。因此,您会收到编译错误。
您需要传递收集器类型参数,以帮助编译器解决intValue()
错误例如。
intValue()
此外,您可以使用方法参考 final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
Collector<Number, ?, Map<Integer, Number>> collector = Collectors.<Number, Integer, Number>toMap(
// Why is number treated as an Object and not a Number?
Number::intValue,
number -> number);
wildCardList.stream().collect(collector);
代替Number::intValue
有关Java 8中类型推断的更多详细信息,请参阅here。
答案 3 :(得分:-1)
你可以这样做:
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.hide();