1. 概要

Javaプログラミング言語では、フィールド、コンストラクター、メソッド、およびクラスをアクセス修飾子でマークできます。 このチュートリアルでは、保護されたアクセスについて説明します。

2. 保護されたキーワード

privateとして宣言された要素には、宣言されたクラスからのみアクセスできますが、 protected キーワードは、同じパッケージのサブクラスとメンバーからのアクセスを許可します。

protected キーワードを使用して、パッケージまたはクラス階層の内部と見なす必要があるメソッドとフィールド、および外部コードに公開するメソッドとフィールドを決定します。

3. 保護されたフィールド、メソッド、およびコンストラクターの宣言

まず、 protected フィールド、メソッド、およびコンストラクターを含むFirstClassという名前のクラスを作成しましょう。

public class FirstClass {

    protected String name;

    protected FirstClass(String name) {
        this.name = name;
    }

    protected String getName() {
        return name;
    }
}

この例では、 protected キーワードを使用して、FirstClassと同じパッケージ内のクラスおよびFirstClassのサブクラスへのこれらのフィールドへのアクセスを許可しています。 ]。

4. 保護されたフィールド、メソッド、およびコンストラクターへのアクセス

4.1. 同じパッケージから

次に、FirstClassと同じパッケージで宣言された新しいGenericClassを作成して、protectedフィールドにアクセスする方法を見てみましょう。

public class GenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is " + first.getName());
        first.name = "new name";
    }
}

この呼び出しクラスはFirstClass、と同じパッケージに含まれているため、すべての保護されたフィールド、メソッド、およびコンストラクターを表示および操作できます。

4.2. 別のパッケージから

次に、FirstClassとは異なるパッケージで宣言されたクラスのこれらのフィールドを操作してみましょう。

public class SecondGenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is "+ first.getName());
        first.name = "new name";
    }
}

ご覧のとおり、コンパイルエラーが発生します

The constructor FirstClass(String) is not visible
The method getName() from the type FirstClass is not visible
The field FirstClass.name is not visible

これは、protectedキーワードを使用して期待していたこととまったく同じです。  これは、SecondGenericClassFirstClassと同じパッケージに含まれておらず、サブクラス化されていないためです。

4.3. サブクラスから

ここで、 FirstClassを拡張するクラスを宣言したが、別のパッケージで宣言した場合に何が起こるかを見てみましょう。

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        super(name);
        System.out.println("SecondClass name is " + this.getName());
        this.name = "new name";
    } 
}

予想どおり、すべての保護されたフィールド、メソッド、およびコンストラクターにアクセスできます。 これは、SecondClassFirstClassのサブクラスであるためです。

5. 保護されたインナークラス

前の例では、 protected フィールド、メソッド、およびコンストラクターが動作しているのを見ました。 もう1つの特定のケースがあります—保護された内部クラスです。

FirstClass内にこの空の内部クラスを作成しましょう。

package com.baeldung.core.modifiers;

public class FirstClass {

    // ...

    protected static class InnerClass {

    }
}

ご覧のとおり、これは静的な内部クラスであるため、FirstClassのインスタンスの外部から構築できます。 ただし、保護されているであるため、インスタンス化できるのはFirstClassと同じパッケージのコードからのみです。

5.1. 同じパッケージから

これをテストするために、GenericClassを編集してみましょう。

public class GenericClass {

    public static void main(String[] args) {
        // ...
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

ご覧のとおり、GenericClassFirstClassと同じパッケージに含まれているため、InnerClassを問題なくインスタンス化できます。

5.2. 別のパッケージから

SecondGenericClassからInnerClassをインスタンス化してみましょう。これは、覚えているように、FirstClass’パッケージの外部にあります。

public class SecondGenericClass {

    public static void main(String[] args) {
        // ...

        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

予想どおり、コンパイルエラーが発生します

The type FirstClass.InnerClass is not visible

5.3. サブクラスから

SecondClassから同じことを試してみましょう。

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        // ...
 
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }     
}

InnerClassを簡単にインスタンス化することを期待していました。 ただし、ここでもコンパイルエラーが発生しています。

The constructor FirstClass.InnerClass() is not visible

InnerClass宣言を見てみましょう。

protected static class InnerClass {
}

このエラーが発生する主な理由は、 保護されたクラスのデフォルトのコンストラクターは暗黙的に保護されています。 加えて、 SecondClass FirstClassのサブクラスですが、InnerClassのサブクラスではありません 。  最後に、FirstClassのパッケージの外でSecondClassも宣言しました。

これらすべての理由により、SecondClassprotected InnerClassコンストラクターにアクセスできません。

でこの問題を解決し、SecondClassInnerClassオブジェクトをインスタンス化できるようにする場合、パブリックコンストラクターを明示的に宣言できます。

protected static class InnerClass {
    public InnerClass() {
    }
}

これにより、コンパイルエラーが発生しなくなり、SecondClassからInnerClassをインスタンス化できるようになりました。

6. 結論

このクイックチュートリアルでは、Javaのprotectedアクセス修飾子について説明しました。 これにより、必要なデータとメソッドのみを同じパッケージ内のサブクラスとクラスに確実に公開できます。

いつものように、サンプルコードはGitHubから入手できます。