Внутренние классы в Java являются просто синтаксическим сахаром для классов, которые передают ссылку на внешний класс в своем (синтаксическом) конструкторе.
Я не знаю ни одного синтаксического сахара для вызова таких конструкторов в Clojure. Но мы можем проверить, как этот синтаксический сахар языка Java преобразуется в сгенерированный байт-код JVM.
Давайте рассмотрим этот пример:
package test;
public class Outer {
public String oName;
public Outer(String name) {
this.oName = name;
}
public class Inner {
public String iName;
public Inner(String name) {
this.iName = name;
}
}
}
Когда мы скомпилируем этот код и проверим сгенерированный байт-код, мы увидим, что следующий синтаксический конструктор был сгенерирован в классе test.Outer.Inner
(команда javap -verbose Outer\$Inner.class
):
public test.Outer$Inner(test.Outer, java.lang.String);
descriptor: (Ltest/Outer;Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Ltest/Outer;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: aload_0
10: aload_2
11: putfield #3 // Field iName:Ljava/lang/String;
14: return
LineNumberTable:
line 12: 0
line 13: 9
line 14: 14
В Java мы не используем этот конструктор напрямую, но вызов к нему генерируется компилятором Java.
Итак, этот код в Java:
Outer outer = new Outer("outer");
Outer.Inner inner = outer.new Inner("inner");
компилируется во что-то подобное в байт-коде JVM:
Outer outer = new Outer("outer");
Outer.Inner inner = new Outer.Inner(outer, "inner");
Мы можем перевести это в Clojure и перевести версию байт-кода JVM в код Clojure:
(import '[test Outer Outer$Inner])
(let [outer (Outer. "outer")
inner (Outer$Inner. outer "inner")]
(println "Outer" (.-name outer))
(println "Inner" (.-name inner)))