У меня была проблема, которую я мог бы решить самостоятельно, но я до сих пор не понимаю, почему мой исходный код не работает, или если есть более элегантное решение, чем тот, который я нашел. Я представляю упрощенную версию моего кода здесь.
Рассмотрим следующий абстрактный суперкласс X:
public abstract class X{
private int i;
public void m1(X x){
x.i = 1;
m2(x);
}
public abstract void m2(X x);
}
Когда вызывается m1, мы управляем частным полем X переданного экземпляра, а затем мы вызываем m2 с этим экземпляром.
У меня есть несколько подклассов X, они все одинаковы в том смысле, что они также объявляют частных членов, которыми они манипулируют. Чтобы достичь этого, им всегда нужно сделать бросок в начале м2. Вот один из них:
public class Y extends X{
private int j;
public void m2(X x){
Y y = (Y) x;
y.j = 0;
}
}
Но - я могу гарантировать, что каждый вызов m1 экземпляра подкласса X всегда будет иметь параметр того же типа, например. когда у меня есть экземпляр Y, параметр метода m1 всегда будет другим экземпляром Y.
Из-за этой гарантии я хотел сделать ненужным бросок, введя дженерики. Вот как я хочу, чтобы мои подклассы выглядели следующим образом:
public class Y extends X<Y>{
private int j;
public void m2(Y y){
y.j = 0;
}
}
Как выглядит суперкласс X теперь? Моя первая попытка заключалась в том, что:
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);
}
Но - это не работает, когда я скомпилирую это, я получаю следующую ошибку:
X.java:6: error: i has private access in X
Обычно вы пытаетесь получить доступ к закрытым членам другого класса. Очевидно, что Java не признает, что T всегда является экземпляром X, хотя я использовал "T extends X" в объявлении.
Я зафиксировал X следующим образом:
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);
}
По крайней мере, я больше не использую роли, но почему это дополнительное назначение необходимо? И почему исходный код не работал? Кроме того, мне показалось странным, что я должен был использовать X<?>
и не мог использовать X<T>
.