白猫のメモ帳

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

staticでないネストクラス

こんばんは。

昔は海の日から夏休みが始まった気がするのですが、
最近はハッピーマンデーの関係でそうでもないんですよね。

さて、前回のつづきです。
前回はstaticなネストクラスについて書きましたが、
今回は「でない」方です。

Java

Javaにおけるstaticでないネストクラスは、
外側のクラスのインスタンスなしにはアクセスできないクラスです。

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

このネストクラスにはstaticアクセスできないため、当然staticメソッドを定義することはできません。

外側のクラスのインスタンスを「エンクロージングインスタンス」といい、
ネストクラスはstaticでないフィールドにもアクセスすることができます。
(「エンクロージング」は「囲い込む」みたいな意味)

this修飾する場合には「Outer.this.field2」というちょっと不思議な文法を使います。
「this.Outer.field2」ではないことに注意です。

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

newキーワードによってインスタンスを生成する場合には、エンクロージングインスタンスが必要です。
「outer.new Inner()」という書き方は慣れないと少し変な感じがしますね。

C#

C#のstaticでないネストクラスは前回の記事で触れたとおり、
Javaでのstaticなネストクラスと全く同じ挙動になります。

class Outer
{
    private static int field1;

    private int field2;

    public class Inner
    {
        public void notStaticMethod()
        {
            Console.WriteLine(field1);
            // Console.WriteLine(field2); error!
        }

        public static void staticMethod()
        {
        }
    }
}

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

C#にはエンクロージングインスタンスという概念はありません。

じゃあ外側のインスタンスのメンバには絶対にアクセスできないかというと、
当然そんなことはなくて、単純に外側のクラスのインスタンスを内部に保持してしまえば良いのです。

class Outer
{
    private int field;

    public class Inner
    {
        private readonly Outer outer;
            
        public Inner(Outer outer)
        {
            this.outer = outer;
        }

        public void notStaticMethod()
        {
            Console.WriteLine(this.outer.field);
        }
    }
}

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

こんな感じ。
自分で作るの意外と面倒・・・。

Javaのインナークラスはいろいろあるよ

Javaのインナークラスには今回紹介した「staticネストクラス」「非staticネストクラス」の他に、
「無名クラス」と「ローカルクラス」というものもあります。
せっかくなのでちょっと見てみましょうか。

「無名クラス」はインタフェースのインスタンスを直接生成したり、
派生クラスをインスタンス生成時に作成する仕組みです。
Java8でラムダ構文ができたので、今は使うことはあまりないですね。

interface Runnable {
    void run();
}

void test() {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {}
    };
}

「ローカルクラス」はメソッド内で定義するクラスです。
いやほんとこれいつ使うの?

void test() {

    class Local {
    }

    Local local = new Local();
}

上手に使い分けるべし

えーと、みんな違ってみんないいってことでいいですかね?

わざわざ一生懸命使う必要はないですが、
こんな選択肢もあるんだなくらいに心の片隅に置いておくといいことがあるかもしれませんね。

それでは。

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かつネストされたクラスが定義されている。

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

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

62分の1のサラダ記念日

こんばんは。

熱い日が続きますね。
早くも夏バテしそうです。

さて、今日は7月6日。
みんな大好きサラダ記念日です。

意外と多い?

「この味がいいね」と君が言ったから七月六日はサラダ記念日

うんうん。
でもこれ別に七月六日じゃなくてもはまりそうだよねとか無粋なことを言ってみたりします。

三文字の月は

・にがつ
・しがつ
・ごがつ
・くがつ

の4つ。

四文字の月は

・いちがつ
・さんがつ
・ろくがつ
・しちがつ
・はちがつ
・じゅうがつ

の6つです。

で、

三文字の日は

・ふつか
・みっか
・よっか
・いつか
・むいか
・なのか
・ようか
・とおか
・はつか

の9つ。

四文字の日は

・ついたち
・ここのか

の2つです。

ということは4×2+6×9=62
62分の1の確率を見事に獲得したのが七月六日というわけです。

※「ゅ」は数えなくて「っ」を数えてるのは完全な主観です。

いやむしろ

しかし、よく考えてみると君が言ってくれる日は調整できません。
ということはむしろ、うまくはまる日でなければ歌自体が誕生しなかった可能性もあります。

365分の62、その確率は約17%。
おぉ、案外シビアな確率だったのですね。

いやいやでもでも

三月三日はひなまつり。
七月七日は七夕です。

そう考えるとほかの行事の日とかとかぶっている場合には、
サラダ記念日にはならなかったかもしれません。

衝撃の事実

ここまで書いていて気付いたのですが、

七月六日

最初から字余りしてる…。
ここまでの考察はいったいなんだったんだろう。(最初から意味わからないけど)

ところで

下の句の話しかしていないので、上の句に合う記念日がないか探してみると、

十二月二十五日はクリスマス

おぉ、ぴったし!

合わせると、

十二月二十五日はクリスマス七月六日はサラダ記念日

うん…そうだねって感じです。

そもそもフィクション

あったことをそのままでは短歌にはならないということで、実際は鳥のから揚げをいつもと違う味付けにしたら『美味しい』と言われたので、『これで今日は記念日だな』と思ったのがきっかけであったということと、爽やかな感じを出すためにメインではなくサイドのものが記念日になるということが表現したかったことや、サラダのSや7月のSが響き合うことや、7月7日では七夕であるので1日前にずらしたことを自身が語っている。

おあとがよろしいようで。