"private access" - Fehler mit Generika
Ich hatte ein problem konnte ich tatsächlich lösen mich, aber ich verstehe immer noch nicht, warum meine ursprüngliche code nicht funktioniert, oder wenn es eine elegantere Lösung als die, die ich gefunden. Ich präsentiere eine vereinfachte version meines Codes hier.
Betrachten Sie die folgende abstrakte Oberklasse X:
public abstract class X{
private int i;
public void m1(X x){
x.i = 1;
m2(x);
}
public abstract void m2(X x);
}
Wenn m1 heißt, wir Bearbeiten ein privates Feld X der Instanz übergeben, und dann nennen wir m2 mit dieser Instanz.
Ich habe mehrere Unterklassen von X, Sie sind alle gleich in dem Sinne, dass Sie auch erklären, private Mitglieder, die Sie manipulieren. Um zu erreichen, dass Sie immer brauchen, um eine Besetzung zu Beginn von m2. Hier ist einer von Ihnen:
public class Y extends X{
private int j;
public void m2(X x){
Y y = (Y) x;
y.j = 0;
}
}
Aber ich kann garantieren, dass jeder Aufruf von m1 in einer Instanz einer Unterklasse von X haben immer einen parameter des gleichen Typs, z.B. wenn ich eine Instanz von Y, die parameter der Methode m1 wird immer wieder eine Instanz von Y.
Wegen der Garantie, ich wollte die cast unnötig, durch die Einführung von Generika. Dies ist, wie ich möchte, dass meine Unterklassen Aussehen:
public class Y extends X<Y>{
private int j;
public void m2(Y y){
y.j = 0;
}
}
Wie funktioniert der Superklasse X muss schauen wie jetzt? Mein Erster Versuch war, dass:
public abstract class X<T extends X<T>>{
private int i;
public void m1(T x){
x.i = 1;
m2(x);
}
public abstract void m2(T x);
}
Aber - das klappt nicht, wenn ich kompilieren, bekomme ich die folgende Fehlermeldung:
X.java:6: error: i has private access in X
Das ist in der Regel, was Sie bekommen, Sie versuchen, Zugriff auf die privaten member einer anderen Klasse. Offensichtlich Java nicht erkennen, dass T ist immer eine Instanz von X als gut, obwohl ich "T extends X" in der Erklärung.
Ich Feste X so:
public abstract class X<T extends X<T>>{
private int i;
public void m1(T x){
X<?> y = x;
y.i = 1;
m2(x);
}
public abstract void m2(T x);
}
Wenigstens bin ich nicht über CASTET - aber warum ist diese zusätzliche Zuweisung notwendig? Und warum nicht der original code funktioniert? Auch fand ich es seltsam, ich musste X<?>
und konnten nicht X<T>
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube, wir können reduzieren Sie Ihre Frage unten zu: Warum funktioniert das folgende Beispiel nicht kompilieren?
Es ist eine gute Frage, und es nahm mich durch überraschung. Aber wir können tatsächlich entfernen Sie Generika aus der Gleichung mit der Feststellung, dass dies nicht funktioniert entweder:
In anderen Worten, das Problem ist, dass man sich mit einer Unterklasse von
Foo
, nichtFoo
selbst. Im Fall vonT
wissen wir nicht die Unterklasse, aber wir wissen, dass es eine Unterklasse, oderFoo
.Da hast du schon herausgefunden, die Lösung (überraschend, zumindest für mich) ist die Verallgemeinerung:
Oder für den Allgemeinen Fall:
Ist die Besetzung so schlecht? Nicht wirklich. Es ist sicherlich genauso gut oder besser als die Vermeidung der Besetzung mit einer Zwischengröße. Wie bei jeder Verallgemeinerung, ich nehme an, es wäre vom compiler entfernt. Es ist nur als einen Hinweis an den compiler. Wir sicherlich don ' T haben sorgen über die Sicherheit der Besetzung, weil die Löschung der
T
ist schonFoo
.Kann ich nur annehmen, dass diese Einschränkung erforderlich ist, um klar zu werden über den Zugriff...da
SubFoo
könnte redeclarebar
selbst, könnte es zu zweideutig, diebar
bezeichnet wird, und also der cast ist notwendig. Dies zeigt sich auch in diesem komplizierten Beispiel:In diesem Zusammenhang, es dient mehr als einem qualifier als eine Besetzung.
private
ist der falsche access-modifier für jedes Feld, das Sie wollen, zugänglich zu Unterklassen? Warum nicht bei der Benutzung des geschützten Modifikator statt, oder eine getter-Methode?