Как получить доступ к статическому внутреннему классу Java через взаимодействие Clojure? - PullRequest
53 голосов
/ 22 августа 2011

В основном, что мне нужно сделать, это

FileChannel.MapMode.READ_ONLY

Я пытался сделать очевидное

(.. FileChannel MapMode READ_ONLY)

, но в итоге выдается исключение

java.lang.NoSuchFieldException: MapMode

даже нотация /, указанная для статических полей доступа в документации взаимодействия , выдает то же исключение

(. (FileChannel/MapMode) READ_ONLY)

Ответы [ 2 ]

84 голосов
/ 22 августа 2011

Вы получаете доступ к внутренним классам с $

java.nio.channels.FileChannel$MapMode/READ_ONLY
15 голосов
/ 04 июня 2012

Синтаксис (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-компилятор предлагает вам этот ярлык из контекста времени компиляции (который не доступен для JVM и таких методов, как Class.forName во время выполнения!) ... Хорошо, в Clojure вы, конечно, всегда можете определить: (def Inner Outer$Inner) ... или (def Tom Outer$Inner) или (def Harry Outer$Inner) или что-то еще ... если вам это нравится больше.

...