C# 中var关键字的一种用法是隐式类型声明。var的 Java 等效语法是什么?
15 回答
空无一人。唉,您必须输入完整的类型名称。
编辑:发布 7 年后,var
Java 10 中添加了局部变量的类型推断(带有 )。
编辑:发布 6 年后,从下面收集一些评论:
C# 有
var
关键字的原因是因为在 .NET 中可能有没有名称的类型。例如:var myData = new { a = 1, b = "2" };
在这种情况下,不可能给
myData
. 6 年前,这在 Java 中是不可能的(所有类型都有名称,即使它们非常冗长和笨拙)。我不知道这是否在此期间发生了变化。var
不一样dynamic
。var
iables 仍然是 100% 静态类型的。这不会编译:var myString = "foo"; myString = 3;
var
当类型从上下文中显而易见时也很有用。例如:var currentUser = User.GetCurrent();
我可以说,在我负责的任何代码中,
currentUser
都有一个User
或派生类。显然,如果您的实现User.GetCurrent
返回一个 int,那么这可能对您不利。这与 无关
var
,但是如果您有奇怪的继承层次结构,其中您使用其他方法(例如new public void DoAThing()
)隐藏方法,请不要忘记非虚拟方法受它们被转换为的类型的影响。我无法想象一个现实世界的场景,这表明了良好的设计,但这可能不会像你期望的那样工作:
class Foo { public void Non() {} public virtual void Virt() {} } class Bar : Foo { public new void Non() {} public override void Virt() {} } class Baz { public static Foo GetFoo() { return new Bar(); } } var foo = Baz.GetFoo(); foo.Non(); // <- Foo.Non, not Bar.Non foo.Virt(); // <- Bar.Virt var bar = (Bar)foo; bar.Non(); // <- Bar.Non, not Foo.Non bar.Virt(); // <- Still Bar.Virt
如前所述,虚方法不受此影响。
不,没有一种简单的方法可以在
var
没有实际变量的情况下初始化 a。var foo1 = "bar"; //good var foo2; //bad, what type? var foo3 = null; //bad, null doesn't have a type var foo4 = default(var); //what? var foo5 = (object)null; //legal, but go home, you're drunk
在这种情况下,只需按照老式的方式进行:
object foo6;
如果你将 Lombok 添加到你的项目中,你可以使用它的val关键字。
JEP - JDK 增强-提案
http://openjdk.java.net/jeps/286
JEP 286:局部变量类型推断
作者布莱恩·戈茨
// Goals:
var list = new ArrayList<String>(); // infers ArrayList<String>
var stream = list.stream(); // infers Stream<String>
随着 3 月 20 日 JDK 10 的发布,Java 现在包括JEP 286var
中指定的保留类型名称(不是关键字,见下文)。对于局部变量,以下内容现在在 Java 10 或更高版本中有效:
var map = new HashMap<String, Integer>();
Java 中的var
保留类型名称与 C# 中的关键字几乎相同,var
因为两者都允许隐式类型(重要区别见下文)。var
在 Java 中只能用于以下上下文中的隐式类型推断(如JEP 286:Goals中所列举):
- 带有初始化器的局部变量
- 增强的 for 循环中的索引
- 在传统的 for 循环中声明的本地人
因此var
不能用于字段、返回类型、类名或接口名。它的基本原理是在声明和定义局部变量时消除包含长类型名称的需要,如JEP 286 (由 Brian Goetz 撰写)中所述:
我们试图通过减少与编写 Java 代码相关的仪式来改善开发人员体验,同时保持 Java 对静态类型安全的承诺,允许开发人员省略通常不必要的局部变量类型的清单声明。
var
Java中的作用域
需要注意的var
是,在 Java 中不是关键字,而是保留的类型名称。引用自 JEP 286:
标识符 var 不是关键字;相反,它是一个保留的类型名称。这意味着使用 var 作为变量、方法或包名的代码不会受到影响;使用 var 作为类或接口名称的代码将受到影响(但这些名称在实践中很少见,因为它们违反了通常的命名约定)。
请注意,由于var
是保留类型名称而不是关键字,它仍然可以用于包名称、方法名称和变量名称(以及它的新类型干扰角色)。例如,以下是var
Java 中有效使用 of 的所有示例:
var i = 0;
var var = 1;
for (var i = 0; i < 10; i++) { /* ... */ }
public int var() { return 0; }
package var;
引用自 JEP 286:
这种处理将仅限于具有初始化器的局部变量、增强型 for 循环中的索引以及在传统 for 循环中声明的局部变量;它不适用于方法形式、构造函数形式、方法返回类型、字段、捕获形式或任何其他类型的变量声明。
var
Java和C之间的差异
这是 C# 和 Java 之间的一个显着区别,var
包括以下内容:var
可以用作 C# 中的类型名称,但不能用作 Java 中的类名或接口名称。根据C# 文档(隐式类型局部变量):
如果命名的类型
var
在范围内,则var
关键字将解析为该类型名称,并且不会被视为隐式类型局部变量声明的一部分。
在 C# 中用作类型名称的能力var
会产生一些复杂性并引入一些复杂的解析规则,var
在 Java 中通过禁止var
用作类或接口名称来避免这些规则。有关var
C# 中类型名称复杂性的信息,请参阅适用于隐式类型变量声明的限制。有关 Java 中 `var 的作用域决定背后的基本原理的更多信息,请参阅JEP 286:作用域选择。
我为 IntelliJ 制作了一个插件,在某种程度上,它为你提供var
了 Java。这是一个 hack,所以通常的免责声明适用,但如果您使用 IntelliJ 进行 Java 开发并想尝试一下,它位于https://bitbucket.org/balpha/varsity。
JDK 10 将支持它。甚至可以在早期访问版本中看到它的实际效果。
JEP 286 :
增强 Java 语言以将类型推断扩展到使用初始化程序的局部变量声明。
所以现在不要写:
List<> list = new ArrayList<String>();
Stream<> stream = myStream();
你写:
var list = new ArrayList<String>();
var stream = myStream();
笔记:
var
现在是保留的类型名称- Java仍然致力于静态类型!
- 它只能用于局部变量声明
如果您想在本地系统上不安装 Java 的情况下尝试一下,我创建了一个安装了 JDK 10的Docker 映像:
$ docker run -it marounbassam/ubuntu-java10 bash
root@299d86f1c39a:/# jdk-10/bin/jshell
Mar 30, 2018 9:07:07 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
| Welcome to JShell -- Version 10
| For an introduction type: /help intro
jshell> var list = new ArrayList<String>();
list ==> []
一个简单的解决方案(假设您使用的是体面的 IDE)是在任何地方都键入“int”,然后让它为您设置类型。
我实际上只是添加了一个名为“var”的类,所以我不必输入不同的内容。
代码还是太冗长了,但至少不用打字!
从 Java 10 开始,等价于 ... var
。
你可以看看JetBrains 的Kotlin,但它是 val。不是变种。
Java 10 确实获得了局部变量类型推断,所以现在它var
几乎等同于 C#(据我所知)。
它还可以推断出不可表示的类型(程序员无法在那个地方命名的类型;尽管哪些类型是不可表示的是不同的)。参见例如Tricks with var
and anonymous classes(你不应该在工作中使用)。
我能找到的一个区别是在 C# 中,
在 Java 10var
中不是合法的类型名称。
我知道这是较旧的,但为什么不创建一个 var 类并创建具有不同类型的构造函数,并且根据调用的构造函数,您会得到具有不同类型的 var。您甚至可以构建将一种类型转换为另一种类型的方法。
Lombok
支持 var但它仍被归类为实验性:
import lombok.experimental.var;
var number = 1; // Inferred type: int
number = 2; // Legal reassign since var is not final
number = "Hi"; // Compilation error since a string cannot be assigned to an int variable
System.out.println(number);
尝试在IntelliJ IDEA
. 它似乎按预期工作,但包括自动完成和一切。直到有一个“非 hacky”的解决方案(例如由于JEP 286: Local-Variable Type Inference),这可能是你现在最好的选择。
请注意,val
在Lombok
不修改或创建lombok.config
.
您可以在 Java 10 中,但仅限于局部变量,这意味着,
你可以,
var anum = 10; var aString = "Var";
但是不能,
var anull = null; // Since the type can't be inferred in this case
查看规范以获取更多信息。
一般来说,您可以将 Object 类用于任何类型,但稍后您必须进行类型转换!
例如:-
Object object = 12;
Object object1 = "Aditya";
Object object2 = 12.12;
System.out.println(Integer.parseInt(object.toString()) + 2);
System.out.println(object1.toString() + " Kumar");
System.out.println(Double.parseDouble(object2.toString()) + 2.12);
这个特性现在在 Java SE 10 中可用。静态的、类型安全的 var 终于进入了 java 世界:)
来源:https ://www.oracle.com/corporate/pressrelease/Java-10-032018.html