如何通过Clojure interop访问静态内部Java类?

时间:2011-08-21 20:12:47

标签: java interop clojure

基本上我需要做的就是这个

FileChannel.MapMode.READ_ONLY

我尝试过做明显的

(.. FileChannel MapMode READ_ONLY)

但最终会抛出异常

java.lang.NoSuchFieldException: MapMode

即使为interop documentation中的访问静态字段指定的/表示法也会产生相同的异常

(. (FileChannel/MapMode) READ_ONLY)

2 个答案:

答案 0 :(得分:83)

使用$

访问内部类
java.nio.channels.FileChannel$MapMode/READ_ONLY

答案 1 :(得分:15)

语法(FileChannel/MapMode)是一种简化,仅适用于静态字段和方法(对于字段,您甚至可以省略括号)! ...表单也适用于字段/方法,但不适用于嵌套/内部类!

对于JVM,内部类Outer.Inner只是一个名为Outer$Inner的类(并且编译器为此创建文件Outer$Inner.class)。 Java编译器允许您通过Outer.Inner引用它。您还可以定义一个名为Outer$Inner的非内部类,编译器允许您将其引用为Outer$Inner。但是,您不能同时定义两者,因为两者的类名都为Outer$Inner(和.class文件名为Outer$Inner.class,因此这将是一个重复的类名!)

使用反射时 - 例如使用Class.forName() - (通常是为了引入一些动态性),您不能省略导入类的包名称,并且必须使用带有$符号的真实类名而不是点。

可能由于其动态特性,Clojure采用相同的方法,因此如果类在my.package.Outer$Inner中,您需要使用my.package形式 - 即使您已经导入了外部类!要避免使用软件包名称,可以显式导入内部类my.package.Outer$Inner,然后将其引用为Outer$Inner(它的真实类名!),但不要将其简化为Inner导入它:

Inner对JVM没有意义,只是Java-Compiler在编译时上下文中提供了这个快捷方式(在运行时JVM和Class.forName之类的方法不可用!)。 ..好吧,在Clojure中,你当然可以定义:(def Inner Outer$Inner) ...或(def Tom Outer$Inner)(def Harry Outer$Inner)或其他......如果你更喜欢那样的话。