63

Basically what I need to do is this

FileChannel.MapMode.READ_ONLY

I tried doing the obvious

(.. FileChannel MapMode READ_ONLY)

but that ends up throwing an exception

java.lang.NoSuchFieldException: MapMode

even the / notation specified as for access static fields in the interop documentation produces the same exception

(. (FileChannel/MapMode) READ_ONLY)
Jakub Arnold
  • 85,596
  • 89
  • 230
  • 327

2 Answers2

102

You access inner classes with $

java.nio.channels.FileChannel$MapMode/READ_ONLY

Mind that if you are importing FileChannel you should also import FileChannel$MapMode.

Bartosz
  • 3,318
  • 21
  • 31
Hamza Yerlikaya
  • 49,047
  • 44
  • 147
  • 241
  • 39
    Don't forget that if you are importing FileChannel with the `import` function or with the `:import` keyword, you must also specify that you are importing `FileChannel$MapMode` – Terje Dahl Jan 13 '12 at 15:14
  • 1
    Thank you @TerjeDahl. I think you should edit your question to include this, Hamza Yerlikaya. – Joe Dec 10 '13 at 16:51
  • 1
    This is a very old question, but just in case this comment saves someone a few minutes: when importing those nested classes, you have to make sure the nested class is defined in the class that you are importing from. If the nested class is inherited, you have to import it from the parent class. – mkhanoyan Oct 24 '18 at 16:47
16

The syntax (FileChannel/MapMode) is a simplification and intended only for static fields and methods (for fields, you may even omit the parentheses)! Also the . and .. forms are for fields/methods but NOT for nested/inner classes!

For the JVM, an inner class Outer.Inner is just a class named Outer$Inner (and the compiler creates a file Outer$Inner.class for this). The Java compiler lets you refer to it by Outer.Inner. You can also define a not-inner class named Outer$Inner to which the compiler lets you refer as Outer$Inner. You cannot define both at the same time, however, since both would have class names of Outer$Inner (and .class files named Outer$Inner.class, so this would be a duplicate class name!)

When using reflection - e.g. with Class.forName() - (usually to introduce some dynamicity) you cannot omit the package name of an imported class and you must use the real class name with the $ sign instead of a dot.

Probably for its dynamic nature, Clojure takes the same approach, so you need to use the form my.package.Outer$Inner if the class is in my.package - even if you imported the outer class already! To avoid the package name, you can explicitly import the inner class my.package.Outer$Inner and then refer to it as Outer$Inner (its real class name!) but you will not reduce this to Inner by just importing it:

Inner has no meaning to the JVM, just the Java-Compiler offers you this shortcut from the compile time context (which is NOT available to the JVM and methods like Class.forName at runtime!) ... OK, in Clojure you could, of course, always define: (def Inner Outer$Inner) ... or (def Tom Outer$Inner) or (def Harry Outer$Inner) or whatever ... if you like that better.

Cactus
  • 27,075
  • 9
  • 69
  • 149
Martin Valjavec
  • 161
  • 1
  • 2
  • `(def Inner Outer$Inner)` does not work for static fields of `Inner`. The following would not work: `Inner/staticField` – Jason Feb 08 '22 at 17:01