使用var和字面量一起,会产生一个原始类型还是一个原始类型包装类?

36

阅读并讨论了Java 10的新保留类型名称var (JEP 286:局部变量类型推断)后,讨论中出现了一个问题。

当与字面值一起使用时:

var number = 42;

现在的number是一个int还是一个Integer?如果你只是将其与比较运算符一起使用或作为参数使用,由于自动装箱和拆箱,通常不太重要。

但由于Integer的成员函数,这可能会有影响。

那么var创建的是原始类型的int还是类Integer


3
然而,有一种方法可以确保尝试它,您可以尝试查看number instanceof Integer对于您的情况是否有效(因为instanceof不能用于原始类型)。然而,如果数字被强制转换为(Integer) 42,那么就会奏效。 - Naman
4个回答

35

var 会让编译器从变量的初始化器中推断出变量的类型,而 42 的自然类型是 int。因此,number 将是一个 int 类型。这就是JLS示例中所说的内容

var a = 1;  // a has type 'int' 

如果我写出这样的东西,而不期望原始数据类型,那我会感到惊讶。

如果你需要作为包装好的原始数据类型的 var,你可以这样做:

var x = (Integer) 10;  // x is now an Integer

2
@BackSlash 你可以通过 `var x = new Object() { int y; int z; }; int test = x.y;` 进行类似的操作。这只有在编译器推断类型的情况下才可能实现,还可参考此链接 https://dev59.com/4qnka4cB1Zd3GeqPW_00。 - Eugene
1
@BackSlash,我刚刚阅读了这篇文章,它主要是为了减少冗长。我开始理解这在哪些情况下会有用,这只限于局部变量,所以不会像JS(和其他语言)一样混乱。 - AxelH
15
你所说的是动态类型,而这个问题涉及的是隐式类型。它们是完全不同的事情。 - Jörg W Mittag
2
@Eugene,您错误地使用了“语法糖”的术语。这不是纯粹的语法转换。 - Brian Goetz
6
好的,"var x = (Integer) 10;" 比 "Integer x = 10;" 更长,所以我可能会选择后者。我会选择后者。 - mid
显示剩余3条评论

13
根据14.4.1 局部变量声明符和类型拟议的规范更改:

如果LocalVariableTypevar,那么当初始化表达式被视为独立表达式(15.2)且不出现在赋值上下文中时,则让T成为初始化表达式的类型。该局部变量的类型是对于T提及的所有合成类型变量而言的向上投影 (4.10.5)。

换句话说,局部变量的推断类型就是初始化表达式作为独立表达式所具有的类型。以42作为独立表达式的类型为int,因此,变量number的类型为int向上投影是规范更改中定义的一个术语,不适用于这种简单情况。

我不确定它是否需要在答案本身中提及,但我很好奇“向上投影”到底是什么,因为这个答案只告诉你它不是什么。在链接规范变更中关于向上投影的一个句子总结:“使用‘向上投影’将初始化程序的类型映射到超类型,消除任何捕获变量或匿名类。” - M. Justin

8

让我们进行测试。使用jshell:

jshell> Integer boxed1 = 42000;
boxed1 ==> 42000

jshell> Integer boxed2 = 42000;
boxed2 ==> 42000

jshell> System.out.println(boxed1 == boxed2);
false

jshell> var infered1 = 42000;
infered1 ==> 42000

jshell> var infered2 = 42000;
infered2 ==> 42000

jshell> System.out.println(infered1 == infered2);
true

在第一个比较中,这两个变量不相同;它们是不同的实例。第二个比较是正确的,因此这里必须推断出一个整数。
注:要在家里试用,请使用范围外的值 <-128, 128)。该范围内的整数实例已经被缓存。

16
这是一个非常迂回的证明。而且你依赖于整数缓存的实现细节......一个更好的证明方法是简单地使用var i = 10,然后跟着使用i instanceof Integer。你会得到ERROR: unexpected type,因为它是一个int而不是引用。 - Michael
4
顺便提一下,您不需要使用 System.out.println。只需单独评估 infered1 == infered2 即可。 - Michael
Michael,对啊,我想了一下 instanceof,但没试试。我应该试试 :) - david a.
总的来说,我喜欢通过代码来“证明”,但从更普遍的角度来看,JLS仍然更好。一个实现可以被更改,除非这在JLS中已经写明。但是由于我从未想过何时使用Jshell,所以我很喜欢这个答案! - AxelH
1
@AxelH 同意。如果答案基于经验主义,我会说您应该始终说明您正在测试的版本。 - Michael

1
编译器将 var number = 42; 同样视为 int number = 42;
public void method(Integer i) {
    System.out.print("Integer method");
}
public void method(int i) {
    System.out.print("int method");
}

var n = 42; // n has type 'int' 
method(n); // => "int method"

自动装箱发生的情况:
public void method(Integer i) {
    System.out.print("Integer method");
}

var n = 42; // a has type 'int'
method(n); // => "Integer method"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接