record Outer(int a) { record Nest(int b) { } }
こんなことしたらどうなるんだろうと気になりまして。
record が単にクラスのシンタックスシュガーであれば、NestはインナークラスになるのでOuterのインスタンス変数、ここでは a にアクセスできるんですが、単なるネストクラスであればアクセスできません。
結論としてはNestからaにはアクセスできず、NestはOuterのインスタンスを持たない、staticが省略されていると言うことになります。
ネストだのインナーだのは 匿名クラスとかローカルクラスとか を参照ください。
確認はNestの方にメソッド生やしてOuterのインスタンスメンバにアクセスしてみようとすればいいんですが、他にもNestをjavapかリフレクションでコンストラクタやフィールドを見て、Outerがあるかどうかを見ればわかります。
そいや他でもどうなるんだろ?とこんなの書いて確認。
class OuterClass { class NestClass { } interface NestInterface { } enum NestEnum { } record NestRecord() { } static class StaticNestClass { } static interface StaticNestInterface { } static record StaticNestRecord() { } static enum StaticNestEnum { } } enum OuterEnum { CONSTANT; class NestClass { } interface NestInterface { } enum NestEnum { } record NestRecord() { } static class StaticNestClass { } static interface StaticNestInterface { } static record StaticNestRecord() { } static enum StaticNestEnum { } } public interface OuterInterface { class NestClass { } interface NestInterface { } enum NestEnum { } record NestRecord() { } static class StaticNestClass { } static interface StaticNestInterface { } static record StaticNestRecord() { } static enum StaticNestEnum { } } record OuterRecord(String s) { class NestClass { } interface NestInterface { } enum NestEnum { } record NestRecord() { } static class StaticNestClass { } static interface StaticNestInterface { } static record StaticNestRecord() { } static enum StaticNestEnum { } }
で、全部のコンストラクタ舐めて出力。インタフェースはコンストラクタ無いから出ないけどね。
String[] targets = {"Class", "Interface", "Enum", "Record"};
record OuterAndNest(String outer, String nest) {
Class<?> nestClass() {
try {
return Class.forName(nest);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
Arrays.stream(targets)
.map(outer -> "Outer" + outer)
.peek(System.out::println)
.flatMap(outer -> Stream.concat(
Arrays.stream(targets).map(nest -> new OuterAndNest(outer, outer + "$Nest" + nest)),
Arrays.stream(targets).map(nest -> new OuterAndNest(outer, outer + "$StaticNest" + nest))
))
.forEach(e -> {
Class<?> nestClass = e.nestClass();
System.out.println(" " + nestClass);
Arrays.stream(nestClass.getDeclaredConstructors())
.forEach(constructor -> {
System.out.println(" " + constructor);
});
});
結果。
OuterClass
class OuterClass$NestClass
OuterClass$NestClass(OuterClass)
interface OuterClass$NestInterface
class OuterClass$NestEnum
private OuterClass$NestEnum(java.lang.String,int)
class OuterClass$NestRecord
OuterClass$NestRecord()
class OuterClass$StaticNestClass
OuterClass$StaticNestClass()
interface OuterClass$StaticNestInterface
class OuterClass$StaticNestEnum
private OuterClass$StaticNestEnum(java.lang.String,int)
class OuterClass$StaticNestRecord
OuterClass$StaticNestRecord()
OuterInterface
class OuterInterface$NestClass
public OuterInterface$NestClass()
interface OuterInterface$NestInterface
class OuterInterface$NestEnum
private OuterInterface$NestEnum(java.lang.String,int)
class OuterInterface$NestRecord
public OuterInterface$NestRecord()
class OuterInterface$StaticNestClass
public OuterInterface$StaticNestClass()
interface OuterInterface$StaticNestInterface
class OuterInterface$StaticNestEnum
private OuterInterface$StaticNestEnum(java.lang.String,int)
class OuterInterface$StaticNestRecord
public OuterInterface$StaticNestRecord()
OuterEnum
class OuterEnum$NestClass
OuterEnum$NestClass(OuterEnum)
interface OuterEnum$NestInterface
class OuterEnum$NestEnum
private OuterEnum$NestEnum(java.lang.String,int)
class OuterEnum$NestRecord
OuterEnum$NestRecord()
class OuterEnum$StaticNestClass
OuterEnum$StaticNestClass()
interface OuterEnum$StaticNestInterface
class OuterEnum$StaticNestEnum
private OuterEnum$StaticNestEnum(java.lang.String,int)
class OuterEnum$StaticNestRecord
OuterEnum$StaticNestRecord()
OuterRecord
class OuterRecord$NestClass
OuterRecord$NestClass(OuterRecord)
interface OuterRecord$NestInterface
class OuterRecord$NestEnum
private OuterRecord$NestEnum(java.lang.String,int)
class OuterRecord$NestRecord
OuterRecord$NestRecord()
class OuterRecord$StaticNestClass
OuterRecord$StaticNestClass()
interface OuterRecord$StaticNestInterface
class OuterRecord$StaticNestEnum
private OuterRecord$StaticNestEnum(java.lang.String,int)
class OuterRecord$StaticNestRecord
OuterRecord$StaticNestRecord()
わかりづらいから flatMap の後で適当に filter しとく。
.filter(e -> Arrays.stream(e.nestClass().getDeclaredConstructors())
.anyMatch(constructor -> Arrays.stream(constructor.getParameterTypes())
.anyMatch(parameterType -> parameterType.getName().equals(e.outer()))))
結果。
OuterClass
class OuterClass$NestClass
OuterClass$NestClass(OuterClass)
OuterInterface
OuterEnum
class OuterEnum$NestClass
OuterEnum$NestClass(OuterEnum)
OuterRecord
class OuterRecord$NestClass
OuterRecord$NestClass(OuterRecord)
エンクロージングクラスのインスタンスを受けるようにコンストラクタが弄られるのは class の時だけ、と言うことで。
きっかけ
- IntelliJ IDEA 2021.2.3

IntelliJ IDEAさんが警告してくれなかったのよね。StaticNestInterfaceやStaticNestEnumはstatic要らないって灰色で、NestClassはstaticにできるよって黄色で。
「あってもなくても意味ないのなら灰色になるんじゃないかなぁ、出ないってことは違いあるのかなぁ」って思ったのだけど、黄色にもなってないので。

ああ、一律あってもなくても意味ないのに灰色にしてるわけじゃなく、「enumの不要な修飾子」みたいな括りなのか。なるほど。

なおinterfaceにネストした場合は全部のstaticが灰色になってくれます。これはinterfaceのメンバに対する不要な修飾子で引っかかってる模様。
満足。(言語仕様とか見に行く気力は残ってない)
IntelliJ IDEAさんは IDEA-266665 でfix済だった。 2021.3 になったら期待してる通りになりそう。