为什么在Java 6中参数的私有字段可见于泛型方法,而在Java 7中不可见?

13

可能是重复问题:
在升级到Java 7后,泛型类的类型参数化字段变得不可见

public class Test{

    private String _canYouSeeMe = "yes";

    <T extends Test> void genericMethod(T hey){
        String s = hey._canYouSeeMe;
    }

    void method(Test hey){
        String s = hey._canYouSeeMe;
    }   
}

在使用JDK 1.6编译时,这段代码可以正常编译,但是在使用1.7编译时,在genericMethod()方法中会出现编译错误:Test._canYouSeeMe字段不可见。

可以通过将_canYouSeeMe属性从private改为protected来解决此错误,但我想知道从1.6到1.7发生了什么变化。


它不能编译是有道理的:T可能是Test的子类,而这个子类将无法访问Test的私有成员。 - assylias
1
@fmucar 不,它不应该编译通过,你说得对。但是它确实编译通过了。 - Daniel Fischer
2
@assylias:实际上,这并没有太多意义:如果TTest的子类,那么它也是一个Test,我们应该能够访问Test._canYouSeeMe。实际上,在Java 7中将hey转换为Test可以使其工作。 - Joachim Sauer
顺便问一下,如果我将T显式转换为Test,然后再尝试访问私有字段会怎样? - Qnan
6
答案在这里:https://dev59.com/8Wsz5IYBdhLWcg3wsaAN - MicSim
显示剩余7条评论
2个回答

8

一个类(Test)的子类(T)永远不会访问到超类的私有字段。这可能是Java 6编译器中的一个错误,在Java 7中已经被修复。

记住:T extends Test表示TTest的子类,但这并不意味着T的类是Test.class,这是访问私有字段和方法的必要条件。


这部分是正确的,但由于访问私有字段的代码位于超类本身中,我认为它应该具有访问权限。 - Qnan
2
@Matt: 我不太明白。如果那是真的,为什么把“hey”转换成“Test”(这完全合法,甚至不会产生警告),就能让我们访问“_canYouSeeMe”呢? - Joachim Sauer
Java 6中的一些错误直到Java 7才得以修复,以避免引起不兼容性。 - Peter Lawrey
马特,即使它是一个使用泛型的静态方法,编译器也将其视为一个泛型类本身? - Martin Snyder
2
@JoachimSauer 因为在给定的 Test 子类型中添加一个名为 _canYouSeeMe 的字段将会改变字段访问表达式以引用新字段。在这种情况下,如果给定类型是类型变量,则降低类型变量的上限同样可能会改变其含义。这些错误将悄无声息地潜伏着。我个人非常欢迎这扇特定的门被牢牢关闭。 - Ben Schulz

1
回复 @Joachim - 评论太长了。
这与无法编译的事实一致:
void method(SubTest hey) {
    String s = hey._canYouSeeMe;
}

(其中SubTest扩展了Test) 而这将编译

void method(SubTest hey) {
    String s = ((Test) hey)._canYouSeeMe;
}

第二个例子在SubTest是顶级类时无法编译(在Java 6和7中都是如此)。 - Matt Ball
@MattBall:为什么不行?只要SubTest扩展了Test。这对我来说是可以编译的。 - Joachim Sauer
@MattBall 如果 method 是 Test 的成员,即使 SubTest 是一个顶级类,它也可以编译。 - assylias
1
@assylias 是的,它可以编译通过,当且仅当methodTest的成员。Iff - Matt Ball
@MattBall 是的 - 你不能在Test类外部访问它的私有成员(或者如果它本身不是顶级类,则访问其顶级封闭类)。 - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接