Why is a parameter's private field visible to a generic method in Java 6 but not in Java 7? [duplicate]
Asked Answered
B

2

13

Possible Duplicate:
Type-parameterized field of a generic class becomes invisible after upgrading to 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;
    }   
}

When building against JDK 1.6 this compiles just fine but against 1.7 there is a compiler error in genericMethod(): The field Test._canYouSeeMe is not visible

The error can be resolved by making _canYouSeeMe protected rather than private, but I'm just wondering what has changed from 1.6 to 1.7

Brazilin answered 1/8, 2012 at 14:23 Comment(12)
why not? this is a method of the same class, isn't it? and non-static, too.Hayton
@fmucar Compiled fine here with openjdk 1.6.0_24.Polysepalous
error, and just in 1.7. It compiles and just fine in 1.6 so is it a resolved bug or is just that 1.7 is more strict?Brazilin
It makes sense that it does not compile: T could be a subclass of Test, which would not have access to a private member of Test.Selfconfessed
@fmucar No, it shouldn't have compiled, you were right with that. It did, however.Polysepalous
@assylias: actually, it doesn't make a lot of sense: If T is a subclass of Test then it's also a Test and we should be able to access Test._canYouSeeMe. Actually: casting hey to Test makes it work in Java 7.Catchment
BTW, what if I explicitly cast T to Test and then try to access the private field?Hayton
The answer is here: https://mcmap.net/q/369099/-type-parameterized-field-of-a-generic-class-becomes-invisible-after-upgrading-to-java-7Camelopardalis
For simplicities sake you can reduce the problem to using a subclass of Test as the argument type and avoid generics.Catchment
Yes, very interesting finding. Now I wonder why as well but i still think that it should not compile on 1.6 as well although it compilesMalherbe
@MicSim: great find, that's indeed the reason. And a very interesting change as well!Catchment
@JoachimSauer See my non answer ;-)Selfconfessed
W
8

Subclasses (T) of a class (Test) never have access to the superclass' private fields. This was likely a bug in the Java 6 compiler that was fixed in Java 7.

Remember: T extends Test means that T is a subclass of Test. It does not mean that T's class is Test.class, which is the necessary condition for having private field & method access.

Wernerwernerite answered 1/8, 2012 at 14:31 Comment(5)
this is partly true, but since the code accessing the private field is in the superclass itself, I would say it should have the accessHayton
@Matt: I don't get it. If that were true, then why does casting hey to Test (which is entirely legitimate and doesn't even produce a warning) let's us access _canYouSeeMe?Catchment
+1 A number of bugs in Java 6 were not fixed until Java 7 to avoid causing an incompatibility.Crowson
Matt, so even though it's a static method (that uses generics), the compiler treats that as a generic class itself?Lucania
@JoachimSauer Because adding a field named _canYouSeeMe to the given subtype of Test would change the field access expression to refer to the new field. In this case, where the given type is a type variable, lowering the upper bound on the type variable could similarly change the meaning. Those bugs would creep up on us in utter silence. I for one welcome that particular door being firmly shut.Catha
S
1

In reply to @Joachim - too long for a comment.

It is consistent with the fact that this would not compile:

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

(where SubTest extends Test) whereas this would compile

void method(SubTest hey) {
    String s = ((Test) hey)._canYouSeeMe;
}
Selfconfessed answered 1/8, 2012 at 14:42 Comment(5)
The second example does not compile (in both Java 6 & 7) when SubTest is a top-level class.Wernerwernerite
@MattBall: why not? as long as SubTest extends Test. It compiles for me.Catchment
@MattBall if method is a member of Test, it does compile, even if SubTest is a top level class.Selfconfessed
@Selfconfessed yes, it compiles iff method is a member of Test.Wernerwernerite
@MattBall Yes - you can't access a private member of Test outside of Test (or its top level enclosing class if it is not a top level class itself).Selfconfessed

© 2022 - 2024 — McMap. All rights reserved.