白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

staticなネストクラス

こんばんは。

液晶保護シートが上手に張れないわたしです。
剥がして使ってみたらすごく快適なので、もう張らなくていい気もしてきました。

さて、JavaにもC#にもネストクラスという仕組みがありますが、
ちょっと挙動が違うので整理してみようかと思います。

とりあえずはstaticな方。じゃない方はまた今度。

Java

Javaにおけるstaticなネストクラスは、
staticに、つまり外側のクラスのインスタンスなしにアクセスできるクラスです。
アクセス修飾子をpublicにすれば、トップレベルクラスとしてふるまうことができます。

class Outer {
    
    private static int field1;
    
    private int field2;
    
    public static class Inner {
        
        void notStaticMethod() {
            System.out.println(field1);
            // System.out.println(field2); error!
        }

        static void staticMethod() {
        }
    }
}

class Test {
    void test() {
        Outer.Inner inner = new Outer.Inner();
        Outer.Inner.staticMethod();
    }
}

Outer.Innerという書き方をしていますが、
staticインポートをすれば、Innerだけでアクセスすることも可能です。

ここで注目すべきは、Innerクラス内でOuterクラスのprivateでstaticなメンバにアクセスできることです。
InnerクラスはOuterクラスの内側にあるため、staticなメンバであればアクセス可能です。

一方で、staticではないフィールドにはアクセスできません。
これは、InnerクラスはOuterクラスのインスタンスには属していないからです。

また、Javaではネストしたインタフェースも定義することができますが、
この場合には暗黙的にstaticがついた扱いになります。

C#

一方で、C#におけるstaticなネストクラスは、
staticにアクセスできるクラスではありません。

そもそもJavaでは一番外側のクラスにstaticをつけることはできませんが、
C#ではこれが可能になっています。

ここでのstaticは、staticにしかアクセスしないクラス。
つまりインスタンスの生成が禁止されているクラスという意味です。
もちろんstaticでないメソッドを作ることもできません。

class Outer
{
    private static int field1;

    private int field2;

    public static class Inner
    {
        // error!
        //void notStaticMethod()
        //{
        //}

        static void staticMethod()
        {
            Console.WriteLine(field1);
            // Console.WriteLine(field2); error!
        }
    }
}

class Test {
    void test() {
        // Outer.Inner inner = new Outer.Inner(); error!
        Outer.Inner.staticMethod();
    }
}

C#においてはstaticが付いていなくても、外側のインスタンスなしにネストクラスのインスタンスを生成できます。

つまりどういうことかというと、JavaでいうところのstaticじゃないネストクラスはC#にはありません。
これについては次回詳しく書きます。

どう解釈するか

Javaはネストされたクラスがstaticに定義されている。
C#はstaticかつネストされたクラスが定義されている。

みたいな感じでしょうか。

こういったちょっとした違いは使用する言語が変わると混乱するところですね。
次回はじゃない方のネストクラスについて触れます。