web-dev-qa-db-ja.com

Javaの保護されたアクセス修飾子とパッケージプライベートアクセス修飾子の違いは?

Protected修飾子とpackage private修飾子の違いに関するさまざまな記事を見てきました。これら2つの投稿の間に矛盾があることがわかりました

  1. 「パッケージプライベート」メンバーアクセスは、デフォルト(修飾子なし)アクセスと同義ではありませんか?

    これで受け入れられた答えは言う

    Protected修飾子は、メンバーが(package-privateのように)自分のパッケージ内でのみアクセスでき、さらに、別のパッケージのクラスのサブクラスからもアクセスできることを指定します。

  2. なぜここでJavaサブクラス?

    これで受け入れられた答えは言う

    保護レベルのアクセスを満たすには、次の2つの条件を満たしている必要があります。

    • クラスは同じパッケージ内にある必要があります。
    • 継承関係が必要です。

彼らは矛盾していませんか?他の記事の私の理解から、最初の投稿は、protected == package-private + subclass in other packageという正しい答えを与えます。

このステートメントが正しい場合、17行目のサブクラスCatで次のエラーメッセージが表示されてこのコードが失敗する理由

The method testInstanceMethod() from the type Animal is not visible 

スーパークラスとサブクラスのコードは次のとおりです。

package inheritance;

public class Animal {

    public static void testClassMethod() {
        System.out.println("The class" + " method in Animal.");
    }
    protected void testInstanceMethod() {
        System.out.println("The instance " + " method in Animal.");
    }
}

package testpackage;

import inheritance.Animal;

public class Cat extends Animal{
        public static void testClassMethod() {
            System.out.println("The class method" + " in Cat.");
        }
        public void testInstanceMethod() {
            System.out.println("The instance method" + " in Cat.");
        }

        public static void main(String[] args) {
            Cat myCat = new Cat();
            Animal myAnimal = myCat;
            myAnimal.testClassMethod();
            myAnimal.testInstanceMethod();
        }
    }

上記のコードが失敗する理由を明確にしてください。それは非常に便利です。ありがとう

31
eagertoLearn

最初の答えは基本的に正しいです-protectedメンバーは次の方法でアクセスできます

  • 同じパッケージのクラス
  • 他のパッケージからの宣言クラスのサブクラス

ただし、ちょっとしたトリックがあります。

6.6.2保護されたアクセスの詳細

オブジェクトの保護されたメンバーまたはコンストラクターは、そのオブジェクトの実装を担当するコードによってのみ宣言されているパッケージの外部からアクセスできます。

つまり、他のパッケージのサブクラスは、スーパークラスの任意のインスタンスのprotectedメンバーにアクセスできず、独自の型のインスタンスでのみアクセスできます(typeはコンパイル時の式です。時間チェック)。

例(このコードがCatにあると仮定):

Dog dog = new Dog();
Animal cat = new Cat();

dog.testInstanceMethod(); // Not allowed, because Cat should not be able to access protected members of Dog
cat.testInstanceMethod(); // Not allowed, because compiler doesn't know that runtime type of cat is Cat

((Cat) cat).testInstanceMethod(); // Allowed

protectedによってDogCatメンバーにアクセスすると、Dogの不変式が壊れる可能性がありますが、Catは独自のprotectedにアクセスできるため、メンバーは、自身の不変式を保証する方法を知っているため、安全に。

詳細なルール:

6.6.2.1保護されたメンバーへのアクセス

保護されたメンバーmが宣言されているクラスをCとします。アクセスはCのサブクラスSの本体内でのみ許可されます。さらに、Idがインスタンスフィールドまたはインスタンスメソッドを示す場合、次のようになります。

  • QがExpressionNameである修飾名Q.Idによるアクセスの場合、式QのタイプがSまたはSのサブクラスである場合にのみアクセスが許可されます。
  • Eがプライマリ式であるフィールドアクセス式E.Idによるアクセス、またはEがプライマリ式であるメソッド呼び出し式E.Id(。。。)によるアクセスの場合、アクセスは次の場合にのみ許可されます。 EのタイプがSまたはSのサブクラスである場合.

6.6.2.2保護されたコンストラクタへの限定アクセス

Cをプロテクトコンストラクターが宣言されているクラスとし、Sをプロテクトコンストラクターの使用が宣言されている最も内側のクラスとします。次に:

  • アクセスがスーパークラスコンストラクター呼び出しsuper(。。。)またはE.super(。。。)の形式の修飾スーパークラスコンストラクター呼び出し(Eはプライマリ式)である場合、アクセスは許可されます。
  • アクセスがフォームnew C(。。。){...}の匿名クラスインスタンス作成式、またはフォームE.new C(。。))...の修飾クラスインスタンス作成式による場合}、ここでEはプライマリ式であり、アクセスは許可されます。
  • それ以外の場合、アクセスがフォームnew C(。。。)の単純なクラスインスタンス作成式、またはフォームE.new C(。。。)の修飾されたクラスインスタンス作成式による場合(Eはプライマリ式) 、アクセスは許可されていません。保護されたコンストラクターは、それが定義されているパッケージ内からのみ、クラスインスタンス作成式(匿名クラスを宣言しない)によってアクセスできます。

以下も参照してください:

25
axtavt

保護されたアクセスでは、メンバーは同じパッケージでアクセスされ、継承されたクラスメンバーの別のパッケージでもアクセスできます。

パッケージアクセスでは、同じパッケージ内のクラスのメンバーにアクセスできます。他のパッケージのクラスメンバーは、パッケージアクセスではアクセスできません。

3
Muhammad kazmi

Catインスタンスを作成し、そのスーパークラスタイプ、つまり動物タイプにキャストしました。 Animalタイプごとに、そのtestInstanceMethodは同じパッケージまたはサブタイプで表示されます。 Animal型にキャストしなかった場合、コードはコンパイルされます。

役立つことを願っています

./Arun

0
Arun