Kapselung protected aber in einer Kindklasse nicht zugänglich

HansD

Mitglied
Java:
package p1;

public class Acc {
    int p;
    private int q;
    protected int r;
    public int s;
}
Folgender Code ergibt eine Compile-Time-Error, weil die Variable r protected deklariert ist.
Java:
package p2;
import p1.Acc;

public class Test extends Acc
{
    public static void main (String[] args)
    {
        Acc obj = new Test();

     // obj.p = 12;
     // obj.q = 13;
        obj.r = 14;  // Test.java:12: error: r has protected access in Acc
        obj.s = 15;
    }
}

Test ist ja ein Erbe von Acc und überall lese ich, dass eine protected deklarierte Variable im selben Package, und darüber hinaus in auch allen Kindklassen zugänglich sei. Trotzdem die Fehlermeldung des Compilers.

Ändere ich den Quelltext wie folgt, wird ohne Beanstandung kompiliert.

Java:
package p2;
import p1.Acc;

public class Test extends Acc
{
    public static void main (String[] args)
    {
        Test obj = new Test();

        obj.r = 14;
        obj.s = 15;
    }
}

Ich verstehe bisher nicht, warum.

Während ich das schreibe, denke ich es ist vielleicht so zu verstehen:
  1. Durch Acc obj = new Test(); wird kein Objekt von Test erstellt, sondern eines von Acc, deswegen greift die Regel, das Kindklassen auf die protected-Variable zugreifen können nicht, denn ein Acc-Objekt ist nie ein Kind seiner eigenen Klasse.
  2. Als Acc-Objekt kann obj auch nicht auf die Variable r zugreifen, da Acc in diesem Fall im Package p2 erzeugt und daher nicht im selben Package ist.
Irgendwie verwirrend.
 
  • If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.
In E.id muss der compilezeit-Typ von E also die abgeleitete Klasse sein, in deinem Fall Test
 
Zuletzt bearbeitet:

In E.id muss der compilezeit-Typ von E also die abgeleitete Klasse sein, in deinem Fall Test

Danke für den Hinweis!

Ich habe mir das wie folgt zu dem Beispiel notiert:

Zugriff auf ein geschütztes Feld (Access to a protected Member)

Sei C die Klasse, in der ein Feld (Member) als protected deklariert ist. Der Zugriff ist nur in einer Unterklasse S von C erlaubt.

Wenn Id darüber hinaus ein Instanzfeld oder eine Instanzmethode bezeichnet, dann:

Wenn der Zugriff über einen qualifizierten Namen Q.Id erfolgt, wobei Q ein Ausdrucksname ("an ExpressionName") ist, dann ist der Zugriff nur dann erlaubt, wenn der Typ des Ausdrucks Q S oder eine Unterklasse von S ist.

Erfolgt der Zugriff über einen Feldzugriffsausdruck ("field access expression") E.Id, wobei E ein primärer Ausdruck ("primary expression") ist, oder über einen Methodenaufrufsausdruck ("method invocation expression") E.Id(...), wobei E ein primärer Ausdruck ist, so ist der Zugriff nur dann zulässig, wenn der Typ von E S oder eine Unterklasse von S ist.

Weitere Informationen über den Zugriff auf geschützte Mitglieder finden Sie in Checking Access to Protected Members in the Java Virtual Machine von Alessandro Coglio, im Journal of Object Technology, Oktober 2005.

(Quelle: James Gosling e. al.: "The Java® Language Specification Java SE 7 Edition", "Chapter 6 Names", Oracle, 28. Februar 2013, https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.1, abgerufen am 14. Juni 2022)
 
Protected :
Heißt für mich zugriff in einer erbenden Klasse und im selben Package.

Die Klasse Acc und Test sind aber nicht im gleichen Package.
Also ist von "Test" auf "Acc protected int r" nicht möglich.

Würdest du das Package von Test auf p1 ädern würde es gehen.


Test ist ja ein Erbe von Acc und überall lese ich, dass eine protected deklarierte Variable im selben Package, und darüber hinaus in auch allen Kindklassen zugänglich sei.
Du hast es eigentlich schon selbst beantwortet. Du bist nicht im selben Package.
 
Zuletzt bearbeitet:
Ich glaube, die Verwirrung kam eher, weil der Code, der auf Acc.r zugreifen möchte, ja "in der Subklasse" ist.
Also der Code befindet sich ja in Test.main() und Test ist eine Subklasse von Acc.
Sein Punkt war eher der Teil ".... und darüber hinaus in auch allen Kindklassen zugänglich sei."
Ausschlaggebend ist aber nicht die Klasse, in der sich der Code befindet, der versucht, auf Acc.r zuzugreifen, sondern der statische compilezeit-Typ des Ausdrucks E in E.r. Dieser muss ein Subtyp von Acc sein, wenn Acc und die Subklasse nicht imselben Package sind.

Oh cool! Hab gerade gesehen, dass Backticks wie in Markdown hier jetzt auch einen inline Codeblock bedeuten. Sehr cool!
 

Neue Themen


Zurück
Oben