275

C# 中var关键字的一种用法是隐式类型声明。var的 Java 等效语法是什么?

4

15 回答 15

261

空无一人。唉,您必须输入完整的类型名称。

编辑:发布 7 年后,varJava 10 中添加了局部变量的类型推断(带有 )。

编辑:发布 6 年后,从下面收集一些评论:

  • C# 有var关键字的原因是因为在 .NET 中可能有没有名称的类型。例如:

    var myData = new { a = 1, b = "2" };
    

    在这种情况下,不可能给myData. 6 年前,这在 Java 中是不可能的(所有类型都有名称,即使它们非常冗长和笨拙)。我不知道这是否在此期间发生了变化。

  • var不一样dynamicvariables 仍然是 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;
    
于 2010-08-09T20:23:25.120 回答
46

如果你将 Lombok 添加到你的项目中,你可以使用它的val关键字。

http://projectlombok.org/features/val.html

于 2010-12-14T19:25:47.917 回答
27

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>
于 2017-07-24T15:36:44.630 回答
21

随着 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 对静态类型安全的承诺,允许开发人员省略通常不必要的局部变量类型的清单声明。

varJava中的作用域

需要注意的var是,在 Java 中不是关键字,而是保留的类型名称。引用自 JEP 286:

标识符 var 不是关键字;相反,它是一个保留的类型名称。这意味着使用 var 作为变量、方法或包名的代码不会受到影响;使用 var 作为类或接口名称的代码将受到影响(但这些名称在实践中很少见,因为它们违反了通常的命名约定)。

请注意,由于var是保留类型名称而不是关键字,它仍然可以用于包名称、方法名称和变量名称(以及它的新类型干扰角色)。例如,以下是varJava 中有效使用 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 循环中声明的局部变量;它不适用于方法形式、构造函数形式、方法返回类型、字段、捕获形式或任何其他类型的变量声明。

varJava和C之间的差异

这是 C# 和 Java 之间的一个显着区别,var包括以下内容:var可以用作 C# 中的类型名称,但不能用作 Java 中的类名或接口名称。根据C# 文档(隐式类型局部变量)

如果命名的类型var在范围内,则var关键字将解析为该类型名称,并且不会被视为隐式类型局部变量声明的一部分。

在 C# 中用作类型名称的能力var会产生一些复杂性并引入一些复杂的解析规则,var在 Java 中通过禁止var用作类或接口名称来避免这些规则。有关varC# 中类型名称复杂性的信息,请参阅适用于隐式类型变量声明的限制。有关 Java 中 `var 的作用域决定背后的基本原理的更多信息,请参阅JEP 286:作用域选择

于 2018-04-01T12:40:14.350 回答
20

我为 IntelliJ 制作了一个插件,在某种程度上,它为你提供var了 Java。这是一个 hack,所以通常的免责声明适用,但如果您使用 IntelliJ 进行 Java 开发并想尝试一下,它位于https://bitbucket.org/balpha/varsity

于 2013-04-14T18:10:11.023 回答
11

JDK 10 将支持它。甚至可以在早期访问版本中看到它的实际效果。

JEP 286 :

增强 Java 语言以将类型推断扩展到使用初始化程序的局部变量声明。

所以现在不要写:

List<> list = new ArrayList<String>();
Stream<> stream = myStream();

你写:

var list = new ArrayList<String>();
var stream = myStream();

笔记:


如果您想在本地系统上不安装 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 ==> []
于 2018-02-22T16:51:52.350 回答
8

一个简单的解决方案(假设您使用的是体面的 IDE)是在任何地方都键入“int”,然后让它为您设置类型。

我实际上只是添加了一个名为“var”的类,所以我不必输入不同的内容。

代码还是太冗长了,但至少不用打字!

于 2014-05-09T15:57:42.760 回答
6

从 Java 10 开始,等价于 ... var

于 2018-04-02T12:17:42.250 回答
5

你可以看看JetBrains 的Kotlin,但它是 val。不是变种。

于 2015-08-16T05:34:09.367 回答
5

Java 10 确实获得了局部变量类型推断,所以现在它var几乎等同于 C#(据我所知)。

它还可以推断出不可表示的类型(程序员无法在那个地方命名的类型;尽管哪些类型是不可表示的是不同的)。参见例如Tricks with varand anonymous classes(你不应该在工作中使用)

我能找到的一个区别是在 C# 中,

如果名为 var 的类型在作用域内,则 var 关键字将解析为该类型名称,并且不会被视为隐式类型局部变量声明的一部分。

在 Java 10var中不是合法的类型名称。

于 2018-03-29T14:00:56.630 回答
3

我知道这是较旧的,但为什么不创建一个 var 类并创建具有不同类型的构造函数,并且根据调用的构造函数,您会得到具有不同类型的 var。您甚至可以构建将一种类型转换为另一种类型的方法。

于 2014-11-09T06:02:56.727 回答
3

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),这可能是你现在最好的选择。

请注意,valLombok不修改或创建lombok.config.

于 2017-11-06T12:25:41.130 回答
2

您可以在 Java 10 中,但仅限于局部变量,这意味着,

你可以,

var anum = 10; var aString = "Var";

但是不能,

var anull = null; // Since the type can't be inferred in this case

查看规范以获取更多信息。

于 2018-04-26T10:10:15.937 回答
0

一般来说,您可以将 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);
于 2018-04-01T12:45:37.180 回答
-1

这个特性现在在 Java SE 10 中可用。静态的、类型安全的 var 终于进入了 java 世界:)

来源:https ://www.oracle.com/corporate/pressrelease/Java-10-032018.html

于 2018-04-12T06:18:15.503 回答