问题 Scala无法访问Java内部类?


我有一个看起来像这样的java类:

public class Constants {
    public class Commands {
        public static final String CreateOrder = "CreateOrder";
    }
}

我想访问“CreateOrder”常量,在java中我可以像这样轻松访问它:

String co = Constants.Commands.CreateOrder

但在Scala这不起作用为什么??? 如何从Scala访问“CreateOrder”,我无法改变Java代码。

谢谢。


2997
2017-10-13 13:29


起源

你能试一下吗 Constants$Command$CreateOrder ? - Peter Lawrey
常量$ Command $ CreateOrder不起作用 - Mustafa
为什么是 Commands 非静态? - Chris Martin
我正在使用其他java银行库,我没有编写java代码,也无法更改它。 - Mustafa
这种不相容现在让我烦恼。有没有人找到除反射之外的替代方法? - tuxdna


答案:


据我所知,没有办法在Scala中做你想做的事。

但是如果你绝对无法改变Java代码,那么你可以采用一些反思技巧。

val value = classOf[Constants#Commands].getDeclaredField("CreateOrder").get(null)

6
2017-10-13 13:45



我花了几个小时寻找这个问题的解决方案。我正在使用具有以这种方式定义的常量的第三方库。这是唯一有效的方法。下面由@Travis Brown建议实例化一个对象然后访问它对我来说不起作用。 - Tim Ryan


来自 Java语言规范

内部类可能不会声明静态成员,除非它们是常量变量(第4.12.4节),否则会发生编译时错误。

在常量变量的情况下,您可以使用 Constants.Commands.CreateOrder 语法,即使通常是任何引用 Constants.Commands 必须与一个实例相关联 Constants因为它不是一个静态的内部类。

这可以被认为是Java中一个疯狂的一次性语法特殊情况,而Scala语言设计者并没有费心去融入Scala的Java互操作性。

你最好的选择(如果真正的Java类看起来完全像这样)是创建一个实例 Constants,此时您可以以完全自然的方式访问内部类的静态字段:

scala> (new Constants).Commands.CreateOrder
res0: String = CreateOrder

如果由于某种原因这不是一个选项,你不得不在另一个答案中采用基于反射的方法,不幸的是。


5
2017-10-13 14:06





我认为反射和实例化的第三种替代方法是编写一小段Java粘合代码。喜欢

public class Glue {
    public static String createOrder() { return Constants.Commands.CreateOrder; }
}

然后从Scala你应该能够写 Glue.createOrder


4
2017-10-13 15:37



这是我基于反思的答案的一个很好的替代方案。如果您能够/允许将新Java代码添加到应用程序,这是一个更好的选择。 - monkjack
作为旁注:当使用sbt构建时,将.java文件放入混合中是开箱即用的。这通常是Java和Scala视角不匹配的快速工作(我认为可见性是另一种情况) - 0__