読者です 読者をやめる 読者になる 読者になる

白猫のメモ帳

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

Java使いがC#を勉強する その⑦ アクセス修飾子

こんばんは。

本棚がいっぱいになって困っています。わたしです。
今回はアクセス修飾子について見ていきます。

基本


アクセス修飾子は型および型のメンバーにつけることができます。
アクセス修飾子の種類は以下の通りです。
  

修飾子 Java C#
public どこからでもアクセス可能 どこからでもアクセス可能
protected 同一パッケージまたは派生クラスから
アクセス可能
派生クラスからアクセス可能
protected internal - 現在のアセンブリまたは派生クラスから
アクセス可能
internal - 現在のアセンブリからアクセス可能
なし 同一パッケージからアクセス可能(default) クラスはinternal、メンバーはprivateと同じ扱い
private 自クラスからのみアクセス可能 自クラスからのみアクセス可能

※現在のアセンブリコンパイルされたコードライブラリのこと(具体的にはEXEとDLL)
※privateはインタフェースとか列挙型ももちろん可

 
挙動が同じなのはpublicとprivateのみですね。

Javaの場合には「何もつけない」修飾子(defaul修飾子)が存在しているのに対して、
C#の場合には何もついていないときはinternalまたはprivate扱いということになっているので注意。

また、Javaがパッケージ単位でアクセス制限をしているのに対して、
C#アセンブリ単位でアクセス制限をしているのもポイントです。

 

クラスのアクセス修飾子


アクセス修飾子を付ける対象によって、選択肢が異なることには注意が必要です。

ネストしていない(一番外側の)クラス

修飾子 Java C#
public どこからでもアクセス可能 どこからでもアクセス可能
internal - 現在のアセンブリからアクセス可能
なし 同一パッケージからアクセス可能(default) internalと同じ扱い

Javaでは一番外側のpublicなクラスは一つの.javaファイルに一つしか定義できません。
また、ファイル名とpublicなクラスの名前は一致している必要があります。(インタフェースも同じ)

クラスのメンバー(変数とかメソッドとか)

修飾子 Java C#
public どこからでもアクセス可能 どこからでもアクセス可能
protected 同一パッケージまたは派生クラスから
アクセス可能
派生クラスからアクセス可能
protected internal - 現在のアセンブリまたは派生クラスから
アクセス可能
internal - 現在のアセンブリからアクセス可能
なし 同一パッケージからアクセス可能(default) privateと同じ扱い
private 属するクラスまたは属するクラスの
ネストクラスからのみアクセス可能
属するクラスまたは属するクラスの
ネストクラスからのみアクセス可能

注意としてはネストクラスで外側のクラスの方が可視性が低い場合、外側のクラスの可視性に引っ張られます。
例えば、外側のクラスが修飾子なしでネストクラスがpublicだとすると、
外側のクラスが見えない場合にはネストクラスも見えません。当然といえば当然。

ネストしているクラス、インタフェース

メンバーと同じです。

インタフェースのアクセス修飾子

 

ネストしていない(一番外側の)インタフェース

修飾子 Java C#
public どこからでもアクセス可能 どこからでもアクセス可能
internal - 現在のアセンブリからアクセス可能
なし 同一パッケージからアクセス可能(default) internalと同じ扱い

 

インタフェースのメンバー(メソッドとか)

修飾子 Java C#
public どこからでもアクセス可能 書けない(public扱い)
なし publicと同じ扱い publicと同じ扱い

どちらもpublicしかないのですが、Javaでは書いても書かなくても同じなのに対して、
C#では書くとコンパイルエラーになってしまいます。
ちなみにアクセス修飾子ではないですが、abstractも同じ扱いです。

また、Javaでは定数(public static finalな変数)を定義できますが、C#では定義できません。
定数クラスをインタフェースで作る派の方はご注意。

 

ネストしているクラス、インタフェース

Javaの場合、メンバーと同じです。
C#ではインタフェースには型を宣言できません。
個人的にはネストインタフェースとか結構好きなんですけど、ダメなんですね。

継承とかなんとか


クラスの継承の際に可視性を変更することができます。
Javaでは上げることも下げることもできます。

class Test {

    class A {}
    
    public class C extends A {}
    
    private class D extends A {}
}

C#では上げることはできません。

class Test 
{

    class A {}

    // ダメ
    //public class C : A {}

    private class D : A {}
}


また、Javaではメソッドをオーバーライドする際に可視性を変更することもできます。
上げることはできますが、下げることはできません。

class Test {

    abstract class A {
        protected abstract void method();
    }

    // OK
    class B extends A {
        @Override
        public void method() {}
    }

    // ダメ
//    class C extends A {
//        @Override
//        private void method() {}
//    }
}

C#では可視性の変更はできません。

class Test 
{

    abstract class A 
    {
        protected abstract void method();
    }

    // ダメ
    //class B : A 
    //{
    //    public override void method() { }
    //}

    // ダメ
    //class C : A
    //{
    //    private override void method() { }
    //}
}


少し余計な話をすると、Javaの場合は外側のクラスを継承して可視性を上げるとメンバを外から見ることができます。
ので、修飾子なしクラスにpublicなネストクラスを作ることに全く意味がないわけでもないことも・・・ない?

class A {
    public class B {
    }
}
public class C extends A {
}

とした上で、

// A.B c = new A().new B(); Aが見つからないのでダメ
C.B c = new C().new B(); // OK

みたいに参照できるわけですね。
まぁそんなことしないけど。

 

なんでもpublicにすればいいってもんじゃないんだぞ


ちゃんと考えると結構難しいアクセス修飾子ですが、
publicかprivateしかないプロジェクトなんて言うのも結構あったりしますよね。

かつて私のいたプロジェクトもprotectedやdefaultを使っているのが自分だけだったりしました。
フィールドは全部private、クラスは全部publicなんていうのはちょっとどうかと思います。