8
Name: mf23781 Date: 10/22/98
*Description:
Here's the situation:
File a\a.java:
=================================================================
package a;
public class a
{
public a()
{
System.out.println("a constructor: " +
foo.class);
}
}
=================================================================
File a\foo.java:
=================================================================
package a;
public class foo
{
}
=================================================================
File b\b.java:
=================================================================
package b;
public class b extends a.a
{
public b()
{
System.out.println("b constructor: " +
a.foo.class);
}
public static void main(String args[])
{
new b();
}
}
=================================================================
Next, compile them with javac in this order (!):
javac a\a.java
javac a\foo.java
javac b\b.java
Now, run them:
java
b.b
a constructor: class a.foo
b constructor: class a.foo
So far, so good, right? Maybe not:
jview b.b
a constructor: class
a.foo
ERROR: java.lang.IllegalAccessError: a/a: field class$a$foo is
inaccessible
OK, then. Time to look at the bytecode:
File a.mocha:
=================================================================
/* Decompiled by Mocha from a.class */
/* Originally compiled from a.java */
package a;
import java.io.PrintStream;
public synchronized class a
{
static Class class$a$foo;
public a()
{
System.out.println((class$a$foo != null) ? class$a$foo :
(class$a$foo = class$("a.foo")));
}
static Class class$(String string)
{
try
{
return Class.forName(string);
}
catch (ClassNotFoundException e)
{
throw new NoClassDefFoundError(e.getMessage());
}
}
}
=================================================================
File b.mocha:
=================================================================
/* Decompiled by Mocha from b.class */
/* Originally compiled from b.java */
package b;
import a.a;
import java.io.PrintStream;
public synchronized class b extends a
{
public b()
{
System.out.println(new StringBuffer("b constructor:
").append((a.class$a$foo != null) ? a.class$a$foo : (a.class$a$foo =
class$("a.foo"))).toString());
}
public static void main(String astring[])
{
new b();
}
static Class class$(String string)
{
try
{
return Class.forName(string);
}
catch (ClassNotFoundException e)
{
throw new NoClassDefFoundError(e.getMessage());
}
}
}
=================================================================
So it looks like javac is trying to be smart, and it doesn't create a local
field to hold foo's Class object -- it just shares the one with its parent
class. The only problem is the access specifier on a.class$a$foo. It's
neither public nor protected, so b.b can't access it. This suggests that
there are two problems here:
javac is generating the wrong code. Either it shouldn't have tried to get
b.b to share the field with a.a, or it should have made a.class$a$foo
protected.
Java.exe doesn't throw an exception when that code executes! Jview rightly
throws an IllegalAccessError.
======================================================================