gpt4 book ai didi

java - "has private access"泛型错误

转载 作者:搜寻专家 更新时间:2023-10-30 21:31:05 25 4
gpt4 key购买 nike

我遇到了一个实际上可以自己解决的问题,但我仍然不明白为什么我的原始代码不起作用,或者是否有比我找到的解决方案更优雅的解决方案。我在这里展示了我的代码的简化版本。

考虑以下抽象父类(super class) 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 的私有(private)字段,然后我们用该实例调用 m2。

我有几个 X 的子类,它们在某种意义上都是相似的,因为它们也声明了它们操纵的私有(private)成员。为了实现这一点,他们总是需要在 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;
}

}

父类(super class) 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

这通常是您尝试访问另一个类的私有(private)成员时得到的结果。显然,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

正如您已经想到的那样,解决方案(令人惊讶的是,至少对我而言)是向上转型:

System.out.println(((Foo)baz).bar);

或者对于一般情况:

public <T extends Foo> void printFoo(T baz) {
System.out.println(((Foo)baz).bar);
}

Actor 有那么差吗?并不真地。它肯定比避免使用中间变量进行强制转换更好或更好。与任何向上转换一样,我假设它会被编译器删除。它仅作为对编译器的提示而存在。我们当然不必担心转换的安全性,因为 T 的删除已经是 Foo

我只能假设此限制是必需的,以便清楚访问...因为 SubFoo 可以重新声明 bar 本身,它可能变得模棱两可 bar 被引用,因此强制转换是必要的。这个复杂的例子证明了这一点:

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 "hello\nworld"
}
}

在这方面,它更像是一个限定符而不是一个 Actor 。

关于java - "has private access"泛型错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20672840/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com