I have 2 simple classes - com.a.c1 and com.b.c2 as follows:
When I compile both classes and run c2, I get "In c1()". Now, I change the class c1 to be default access as opposed to public and change the print statement in the constructor.
I compiled this class (c1) again and executed c2. This time I get "In c1()...". I was expecting that I will throw some errors because c1 is not accessible outside its package. But now if I compile c2, I am getting the errors that c1 is not accessible. Apparently, before I recompile c2 it is accessing c1 with the old access modifiers but with new constant expressions. Can somebody please explain me what's happening in the JVM? I would appreciate if you could give me some pointers on the internet where this is discussed/described in more detail. TIA -Aj
Access modifiers are understood and implemented by the compiler only, not by the JVM. The two versions of c1.java are both legal on their own, and they compile to exactly the same .class files - no access info is stored in these files. The only way you will get an error is if you recompile the class that is doing the illegal accessing - c2. At that time the compiler will look again at the source for the accessed class, c1, and see that the access is illegal. In general, there are all sorts of confusing effects you can create by recompiling only some of your classes. I have found that when compiling, it's usually best to recompile all files in a project from scratch. It may take a bit longer for a big project (only a little bit though given today's processor speeds), but it's well worth your while to avoid the kind of subtle, confusing bugs you get when some of your class files are out of date.
18.104.22.168 Class and Interface Resolution To resolve an unresolved symbolic reference from D to a class or interface C denoted by N, the following steps are performed: 1.The defining class loader of D is used to create a class or interface denoted by N. This class or interface is C. Any exception that can be thrown as a result of failure of class or interface creation can thus be thrown as a result of failure of class and interface resolution. The details of the process are given in Section 5.3. 2.If C is an array class and its element type is a reference type, then the symbolic reference to the class or interface representing the element type is resolved by invoking the algorithm in Section 22.214.171.124 recursively. 3.Finally, access permissions to C are checked: If C is not accessible (�5.4.4) to D, class or interface resolution throws an IllegalAccessError. This condition can occur, for example, if C is a class that was originally declared to be public but was changed to be non-public after D was compiled. If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, resolution fails, and D is prohibited from accessing C.
"JavaRanch, where the deer and the Certified play" - David O'Meara
Joined: Jan 30, 2000
Good catch, Cindy. I was wrong about the JVM's knowledge of access modifiers - I seem to recall there are cases where the JVM seems to know less about access than the compiler, but details are fuzzy in my memory right now and I don't have time to test. But contrary to me earlier statement, access modifiers are part of the class files, and the JVM is expected to enforce them. But of course, if the class file is out of date, strange things can happen...