java – “具有私有访问”错误与泛型
我有一个问题我可以解决自己,但我仍然不明白为什么我的原始代码不起作用,或者如果有一个比我发现的更优雅的解决方案.我在这里提供我的代码的简化版本.
考虑以下抽象超类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的子类,它们都是一样的,他们也声明他们操纵的私有成员.为了达到这个目标,他们总是需要在m2的开始时做一个演员.这是其中之一: public class Y extends X{ private int j; public void m2(X x){ Y y = (Y) x; y.j = 0; } } 但是 – 我可以保证X的子类的实例的每个m1的调用将始终具有相同类型的参数,例如当我有一个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. 解决方法
我相信我们可以减少你的问题:为什么下面的例子无法编译?
public class Foo { private final String bar = "bar"; public <T extends Foo> void printFoo(T baz) { System.out.println(baz.bar); //bar is not visible } } 这是一个很好的问题,它确实令我惊喜.但是我们实际上可以从方程式中删除泛型,注意到这也不行: public class Foo { private final String bar = "bar"; public void printFoo(SubFoo baz) { System.out.println(baz.bar); //bar is not visible } } class SubFoo extends Foo { } 换句话说,问题是你正在处理Foo的子类,而不是Foo本身.在T的情况下,我们不知道哪个子类,但是我们知道它是一个子类,或者是Foo. 如你已经想到的那样,解决方案(令人惊讶的是,至少对我来说)是upcast: System.out.println(((Foo)baz).bar); 或对于通用情况: public <T extends Foo> void printFoo(T baz) { System.out.println(((Foo)baz).bar); } 演员是不是很糟糕?不是真的.它绝对与避免使用中间变量的转换一样好或更好.和任何upcast一样,我会假设它将被编译器删除.它仅作为编译器的提示存在.我们当然不必担心演员的安全,因为T的擦除已经是Foo. 我只能假设这个限制是必需的,以便清楚访问…因为SubFoo可以重新声明条的本身,它可能会变得模糊,哪个栏被引用,所以演员是必要的.这在这个复杂的例子中得到证明: public class Foo { private final String bar = "hello"; static class SubFoo extends Foo { private final String bar = "world"; } public <T extends SubFoo> void printFoo(T baz) { // System.out.println(baz.bar); // doesn't compile System.out.println(((Foo)baz).bar); //hello System.out.println(((SubFoo)baz).bar); //world } public static void main(String[] args) { new Foo().printFoo(new SubFoo()); //prints "hellonworld" } } 在这方面,它作为一个限定词,而不是作为一个演员. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |