Java中是否有自动类型推断?

165

Java中是否有像C++中的auto变量类型?

一个例子:

for ( auto var : object_array)
    std::cout << var << std::endl;

for( auto var : object_array)
    var.do_something_that_only_this_particular_obj_can_do();

我知道Java中有增强型for循环,但是是否有自动的呢?如果没有,是否有什么方法可以实现这个功能?我指的是C++11中的新特性。


1
除了基本类型之外,任何东西都可以分配给类型为“Object”的变量,因此对于某些操作,您可以在想要“auto”的地方使用“Object”。 - Zyx 2000
1
Java 中不存在这样的变量。 - Aliaksei Bulhak
@Zyx2000:那么,它将使用对象的 to_string 函数,而不是实际的对象本身,不是吗? - Games Brainiac
2
@GamesBrainiac:不,它将使用重写版本(如果存在)。 - Keppil
2
你要找的术语不是“auto”,而是“类型推断”。关于Java中的类型推断有很多问题,尽管它们大多涉及泛型,所以我不确定如何找到重复项... - user395760
6个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
119

也许 Java 10 可以通过 var 关键字满足你(和我)的需求。

var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>

来自JDK Enhancement Proposals 286


更新: 是的,该功能已经被纳入Java 10版本!


9
是的,这是一种改进,但该关键字仅适用于局部变量。不像C++的自动类型推断那样强大。 - SwiftMango
10
细微之处:var 不是关键字!来自JLS的解释:“var不是关键字,而是作为局部变量声明类型的具有特殊含义的标识符”。因此,与关键字不同,没有任何阻止您将变量或方法命名为“var”。 - Klitos Kyriacou
2
很好的观点@KlitosKyriacou。然而,如果我想象用“标识符”甚至是“具有特殊含义的标识符,如本地变量声明的类型”来替换“关键字”,那么答案可能就不那么清晰了。但是,是的,var确实不在关键字列表中。 - sorrymissjackson
1
它不仅仅是为了向后兼容而存在的关键字。除了你可以使用这个名称作为标识符之外,var还扮演着关键字的角色。 - facetus
最后,很遗憾这花了这么长时间。那么我们可以期待在另外20年左右实现类型别名吗? - David Bradley

70
Java 10引入了一个类似于C++的autovar标识符;请参见sorrymissjackson的回答。 在Java 10之前,没有与auto关键字相当的东西。可以通过以下方式实现相同的循环:
for ( Object var : object_array)
  System.out.println(var);
Java有局部变量,其作用范围限于定义它们的代码块内。与C和C++类似,但没有auto或register关键字。然而,Java编译器不允许使用未显式初始化的局部变量,并会给出编译错误(与C和C++不同,编译器通常只会给出警告)。来源:Wikipedia。 Java没有像C++那样的主流类型推断。有一个RFE(请求功能增强),但被关闭为“不会修复”。给出的理由是: 人类从类型声明的冗余中受益。首先,冗余的类型作为有价值的文档 - 读者不必搜索getMap()的声明以找出它返回的类型。其次,冗余允许程序员声明预期的类型,并从编译器执行的交叉检查中受益。

10
在Java中,方法调用始终具有多态性。但是,许多其他操作(例如重载解析或任何未在“Object”上定义的操作)无法像这样执行。这不是一个好答案,它之所以有效只是因为问题中的示例比较弱。 - user395760
10
这个问题是关于C++11中的类型推导,而不是关于C和C++11之前旧用法中的auto。你的编辑与主题不相关。 - user395760
4
不是这个意思,一旦你将其类型转换为对象,它会给你对象的to_string。这是错误的,绝对100%错误。 - Louis Wasserman
159
人类从冗余中获益。这是事实。每天早上我都会想“如何使我的代码更加冗余?” 因为它有好处。 - ahoffer
3
最荒谬的拒绝实现这种方便功能的理由,现在我明白为什么我的非开发人员朋友称呼我为打字员了。 - Saleh
显示剩余9条评论

28

Java 7引入了菱形语法

Box<Integer> integerBox = new Box<>(); // Java 7

与旧版Java相比

Box<Integer> integerBox = new Box<Integer>(); // Before Java 7

仔细阅读的读者会注意到,这种新的语法并不能解决原问题中for循环的编写。这似乎是正确且完全故意的。请参阅引用了Oracle错误数据库的其他答案。



5
没错,但他(和我)想要的是类似于这样的东西:auto integerBox = new Box<Integer>();,通常用于从函数中获取返回值,有时可能很复杂,比如HashMap<String, LinkedList<Operation, Set<Integer>>> - Roee Gavirel
1
那个问题就是我在代码示例之后解决的。结论是Java并不会这样做,这也是有意为之的。 - Tarrasch
1
当我了解这个加法时,它完全让我困惑。它完全与你所期望的相反,并且提供了适度的好处。 - David Bradley

20

在Java 8中,您可以使用lambda类型推断来避免声明类型。与提问者示例的类比如下:

在Java 8中,您可以使用Lambda类型推断来避免声明类型。类比于提问者示例的做法如下:
object_array.forEach(obj -> System.out.println(obj)); 
object_array.forEach(obj -> obj.do_something_that_only_this_particular_obj_can_do());

这两种方法也可以使用方法引用来简化:

object_array.forEach(System.out::println); 
object_array.forEach(ObjectType::do_something_that_only_this_particular_obj_can_do);

8

这不是一个纯Java解决方案,但是添加一个叫做 lombok 的库将使下面的代码编译并且工作得非常类似于C++中的auto关键字。

List<String> strList = Arrays.asList("foo", "bar", "baz");
for (val s: strList){
    System.out.println(s.length());
}

8
简而言之,没有自动类型。如果你只是打印值,你可以将该值称为“Object”。

或者计算哈希码,或者收集类名,你懂的 ;) 列表很短。请参阅Object类文档(这条注释是为初学者准备的,我相信你知道,SimonC)。 - Alexander Malakhov

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