Name: laC46010 Date: 05/20/97
JDK1.1.2E compiler allows to read private field of one inner class from
another (sibling) inner class while JDK1.1 prohibits that.
In the example "Test1" below, method testAccess() of inner class Test1.A
prints out the private field 'p' of other sibling inner class Test1.B
JDK1.1 reports the following compile-time error:
Test1.java:9: Access across scopes to the private member p in inner class Test. B is not implemented. The reference will succeed if the member is given package scope.
System.out.println("b.p="+b.p);
^
1 error
At the same time both JDK1.1.1 and JDK1.1.2E compile and execute Test1
and print out correct value of that private field 'p' (153).
Note that all considered compiler versions don't allow to write into private field
in the same conditions - see "Test2" below for which JDK1.1.2E compiler reports:
Test2.java:8: Invalid left hand side of assignment.
b.p = 7;
^
1 error
It seems to be inconsistent that compiler allows reading but denies writing.
"Inner Classes in Java 1.1" specification says:
"Access protection never prevents a class from using any member
of another class, as long as one encloses the other, or they
are enclosed by a third class."
There are ambiguities in this statement.
First, it is not clear what is "one" and what is "other" in
"as long as one encloses the other" phrase. We assume the following
sense:
"Access protection never prevents a class A from using any member
of another class B, as long as B encloses A, or they are enclosed
by a third class."
Second, it is unclear, whether words "they are enclosed by a third class"
mean C{A{B{}}} or C{A{}B{}} :
-- if C{A{B{}}} assumed then the bug is that we can read private field
of sibling inner class in C{A{}B{}} case;
-- if C{A{}B{}} assumed then the bug is that we can't use it as a left
hand side of assignment.
--------------------Test1.java----------------------
public class Test1 {
public static void main(String argv[]) {
new Test1().new A().testAccess();
}
class A {
void testAccess() {
B b = new B();
System.out.println("b.p="+b.p);
}
}
class B {
private int p=153;
}
}
--------------------Test2.java----------------------
public class Test2 {
public static void main(String argv[]) {
new Test2().new A().testAccess();
}
class A {
void testAccess() {
B b = new B();
b.p = 7;
System.out.println("b.p="+b.p);
}
}
class B {
private int p=153;
}
}
--------------------Test3.java----------------------
public class Test3 {
public static void main(String argv[]) {
new Test3().new A().testAccess();
}
class B {
class A {
void testAccess() {
}
}
}
}
---------------------------------------------------------
======================================================================
[chamness 5/21/97] Another user reports the same problem:
From: Roly Perera
Synopsis: Access across sibling scopes is read-only!
Description: javac claims that the following field access expression is
not a valid assignment target. However it is, because its value is a
reference to a non-final field:
class A {
class B {
private int x;
}
class C {
{ new B().x = 5; } // javac doesn't allow this
}
}
======================================================================
[chamness 6/20/97] And another user reports the same problem:
Name: Lee Hasiuk
Synopsis: Anonymous Inner Class Compilation Bug in JDK 1.1.1
Description:
(Resubmitted since I never received an automated reply.)
The code included in this message, below, will not compile with JDK 1.1.1 as long as exit() is declared private. The following compilation (bogus) errors are reported:
AnonBug.java:18: Can't reference this before the superclass constructor has been
called.
addWindowListener(
^
AnonBug.java:23: Can't reference this before the superclass constructor has been
called.
exit();
^
AnonBug.java:27: Can't reference this before the superclass constructor has been
called.
setVisible(true);
^
3 errors
This appears to be a compiler bug, since inner classes are supposed to be able to call private methods of enclosing instances. I can make the adapter into a named inner class and it compiles just fine. I can also get it to compile by changing the access of exit() to package or public.
Here's the code:
import java.awt.*;
import java.awt.event.*;
public class AnonBug extends Frame
{
public static void main(String args[])
{
new AnonBug().init();
}
public AnonBug()
{
super("Anon Bug");
}
public void init()
{
addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
exit();
}
}
);
setVisible(true);
}
private void exit()
{
System.exit(0);
}
}
- duplicates
-
JDK-4059046 Setting private data member of an inner class doesn't work
- Closed