3

我正在将其他人的 java 代码转换为 scala(出于好奇,这是这里的示例),并且在以下内容上遇到了编译器错误(稍微简化了):

var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);

这是我收到的错误消息:

[error]   (java.util.Locale,java.lang.String,<repeated...>
[java.lang.Object])java.util.Formatter <and>
[error]   (java.lang.String,<repeated...>[java.lang.Object])java.util.Formatter
[error]  cannot be applied to (java.lang.String, java.lang.Object, Int)
...
[error] one error found

如果我将第二行更改为:

out.format("%s-%d ", someObject, someInteger.asInstanceOf[Object]);

有人可以解释这是为什么吗?

这是否意味着在 java 中可以传递需要对象参数但在 scala 中不行的整数?

4

4 回答 4

4

其他答案都添加了一些东西,但我不确定他们是否解释了问题所在。

这一切都归结为Int在 Scala 中是一个类,而int在 Java 中是一个原语。因此,在 Java 中,当您编写一个方法需要一个Object并且您传递一个int时,Java 会自动将其装箱在一个java.lang.Integer.

现在,Java 在 Scala 中的等价java.lang.ObjectAnyRef,但Int不是. 有一个合适的类型:. An既可以包含 Java 的子类,也可以包含Java 中的原语。如果您说一个方法期望并传递一个,那么它将被自动装箱,但不是 for 。AnyRefAnyAnyjava.lang.ObjectAnyIntAnyRef

因此,每当您与 Java 交互并且方法希望您传递装箱的原语时,您必须自己强制装箱。您可以在 Scala 中创建一个期待的方法Any,然后将其转换为AnyRef并调用 Java 等价物,以便在您要经常调用该方法时使事情变得更容易。

于 2012-08-20T14:31:03.653 回答
2

您没有指定如何someInteger定义,但我假设您正在尝试执行以下操作:

val someObject: Object = "this"
val someInteger = 3

var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);

问题是当你someInteger = 3在 Scala 中说变量时,变量是 Scala 的Int而不是 Java 的int,而 JavaFormatter不知道如何处理它。

如果您将声明更改为使用 Java 可以理解的整数类型,那么它就可以正常工作。例如:

import java.lang.Integer

val someInteger = new Integer(3)

至于为什么丑陋的asInstanceOf版本有效?快速检查 REPL 会告诉你发生了什么:

scala> 3.asInstanceOf[java.lang.Object].getClass
res0: java.lang.Class[_ <: java.lang.Object] = class java.lang.Integer

因此,当您调用.asInstanceOf[java.lang.Object]一个时Int,Scala 会返回一个java.lang.Integer.

但实际上,您应该以更类似于 Scala 的方式重写代码。如果你这样做了,安德鲁·麦卡勒姆会更开心。

于 2012-08-20T06:29:36.940 回答
2

java和scala中的类层次结构不一样。 java.lang.Object在java中位于层次结构的根部。在 scala 中,Any类型位于根目录。因此,任何东西都可以传递给带有 type 参数的函数Any。但是,只能java.lang.Object将 的子类型传递给接受类型参数的函数java.lang.Object

更糟糕的是,有两种类型的整数。有 scala 的 Int 类型和 java.lang.Integer。前者是在 scala 中将某些内容设置为数字文字时通常会得到的。后者是你得到的new Integer(3)or 3.asInstanceOf[Integer]。事实证明,scala Int 不是从 java.lang.Object 继承的,而是 java.lang.Integer 继承的。因此,您不能将 scala Int 作为期望 java.lang.Object 的参数传递。这就是为什么这在scala中不起作用的原因。

Java 的故事有点奇怪。过去,javaint无法传递到预期对象的位置;您需要将它们显式转换为java.lang.Integer. 但是,最近的一项更改(版本 5)会自动为您执行此操作。这称为自动装箱或拆箱,具体取决于转换的方式。所以这就是它在java中工作的原因。

于 2012-08-20T06:43:05.750 回答
1

正如 dhg 所说,scala 编译器将 Scala int 类型视为与 Java int 类型不同。您可以尝试导入JavaConversions隐式,看看是否有帮助。我不太了解确切的区别(我原以为它会对它们一视同仁)。

或者,您可以使用 Scala 格式化工具:

val someObject: Object = "this"
val someInteger = 3
val out = "%s-%d ".format(someObject, someInteger)
于 2012-08-20T06:40:58.447 回答