对于Java 10或+,我们可以使用var
关键字进行声明。在初始化时,编译器将推断类型。
当我实例化的类并分配给用 , 声明的变量var
,是接口的实现时,会发生什么?将推断哪种类型,接口还是实现?
Bar*_*jeu 37
我的2美分来纠正问题和答案:
不是Javavar
关键字。这是一个保留的类型名称。看起来差别不大,但实际上是:
var var = 0;
Run Code Online (Sandbox Code Playgroud)
这里var
也是一个变量名,因此var
可以用作类型名,但没有像常规关键字那样的限制(即我们var
也可以有一个名为的变量)。
变量的实际类型由 Java 编译器在编译时声明变量的行决定,但该类型实际上并不是您在表达式右侧使用的确切实现。看这段代码:
var i = true ? Integer.valueOf(1) : "ABC";
Run Code Online (Sandbox Code Playgroud)
Java 编译器需要为变量选择一个类型i
来满足这两个分支。它可以是 a) Object
、 b) Serializable
、 c)Comparable
或组合,或三者皆有。我们不关心也不知道。
Gio*_*uri 24
当我实例化的类并分配给用 var 声明的变量,是接口的实现时,会发生什么?将推断哪种类型,接口还是实现?
变量的推断类型将正是类,对您分配给用 声明的变量的实例的引用var
。
关于“接口”点:如果它(对象的类,分配给用“var”声明的变量的引用)是某个接口的实现,那么如果该类实现两个或多个接口,您认为会发生什么?您认为 Java 应该如何决定为变量推断哪个超类型(即接口)?即使我们的判断纯粹基于逻辑(与 Java 没有任何关系),这也是不可能的 - 不会有“事实来源”,Java 能够据此做出决定。
请记住,根据语言设计者的说法(自 JDK 10+ 起),使用 的唯一目的var
是美化代码并使其更具可读性(我个人认为,这是没有意义的,因为“ Java 中的 var" 比显式类型更糟糕,而且在很多方面都是如此)。
例如,这段代码:
URL url = new URL("http://www.oracle.com/");
URLConnection conn = url.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
Run Code Online (Sandbox Code Playgroud)
(根据官方JEP 286文档)阅读起来不如:
var url = new URL("http://www.oracle.com/");
var conn = url.openConnection();
var reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Run Code Online (Sandbox Code Playgroud)
var
引入的目的是提供更清晰/更好的可读性,而不是修改 Java 语言的类型系统。这就是为什么,你不能在类级别(静态或实例)字段中使用它,因为字段可能与多态性一起使用(可能接收不同的实现类型,可能由 IoC 注入等)和字节码,不可能针对每种不同的情况动态更改字段类型。
好吧,有几个原因:
到目前为止,其他答案并没有强调一个重要的点,即编译时可推导类型和运行时实例类之间的区别。
假设我们有
var data = Collections.singleton("test");
Run Code Online (Sandbox Code Playgroud)
然后,编译器可以看到Collections.singleton("test")
声明为 return Set<String>
。因此data
实际上被声明为Set<String>
(不是例如nornor Collection<String>
)。是编译器可以找到的最具体的信息。Object
Collections.SingletonSet
Set<String>
运行时,引用的实例data
将是某个实现类(例如Collections.SingletonSet
),由方法决定Collections.singleton()
,这意味着data.getClass()
不会返回该类Set
,而是实现接口的不同对象Set
,即Collections.SingletonSet
。
所以我们必须考虑三种类型:
Collections.SingletonSet
)。这当然总是与(2)和(3)兼容,并且在编译时无法得知。Set<String>
)。var
关键字时,编译器将其视为使用 (2) 中的类型声明(即Set<String>
)。“官方”局部变量类型推断风格指南(https://openjdk.java.net/projects/amber/LVTIstyle.html)提出了这个问题,但说:
“这里必须重申一下,var只能用于局部变量,不能用于推断字段类型、方法参数类型、方法返回类型。“向接口编程”的原则在这些背景。”
和
“如果按照准则 G2 中的建议,局部变量的范围很小,那么具体实现的“泄漏”影响后续代码的风险就会受到限制。”
归档时间: |
|
查看次数: |
39540 次 |
最近记录: |