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
になったら期待してる通りになりそう。