Class and interface loading order

F

Fernando

In resume, I have a factory class that creates/instantiates a family
of classes, like in this example:

public class Test{
public static void main(String args[]){
TestInterface t = Factory.getInstance(0);
t.f();
}
}

class Factory{
public static TestInterface getInstance(int type){
System.out.println("Executed Factory.getInstance()");
switch(type){
case 0: return new TestInterfaceImpl0();
case 1: return new TestInterfaceImpl1();
default: return new TestInterfaceImpl2();
}
}
}

abstract class TestInterface{
public abstract void f();
}

class TestInterfaceImpl0 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl0.f()"); }
}

class TestInterfaceImpl1 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl1.f()"); }
}

class TestInterfaceImpl2 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl2.f()"); }
}

When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
[Loaded TestInterfaceImpl0]
[Loaded TestInterfaceImpl1]
[Loaded TestInterfaceImpl2]
Executed Factory.getInstance()
Executed TestInterfaceImpl0.f()

So, what we see here is that JVM loads ALL classes referenced from
Factory.getInstance() (TestInterfaceImpl0, TestInterfaceImpl1 and
TestInterfaceImpl2) before it is executed.

Now, my question. If I change the abstract class TestInterface into an
interface, the loading order is completely different. See:


public class Test{
public static void main(String args[]){
TestInterface t = Factory.getInstance(0);
t.f();
}
}

class Factory{
public static TestInterface getInstance(int type){
System.out.println("Executed Factory.getInstance()");
switch(type){
case 0: return new TestInterfaceImpl0();
case 1: return new TestInterfaceImpl1();
default: return new TestInterfaceImpl2();
}
}
}

interface TestInterface{
public void f();
}

class TestInterfaceImpl0 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl0.f()"); }
}

class TestInterfaceImpl1 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl1.f()"); }
}

class TestInterfaceImpl2 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl2.f()"); }
}


When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
Executed Factory.getInstance()
[Loaded TestInterfaceImpl0]
Executed TestInterfaceImpl0.f()

This time, ONLY TestInterfaceImpl0 is loaded and its loading is
postponed until it is needed (Factory.getInstance() before the
loading).

Does anyone now why this happens?

Thanks a lot.

Regards,
Fernando.
 
B

bilbo

Fernando said:
In resume, I have a factory class that creates/instantiates a family
of classes, like in this example:

[snipped code where TestInterface is an abstract class]
When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
[Loaded TestInterfaceImpl0]
[Loaded TestInterfaceImpl1]
[Loaded TestInterfaceImpl2]
Executed Factory.getInstance()
Executed TestInterfaceImpl0.f()

So, what we see here is that JVM loads ALL classes referenced from
Factory.getInstance() (TestInterfaceImpl0, TestInterfaceImpl1 and
TestInterfaceImpl2) before it is executed.

Now, my question. If I change the abstract class TestInterface into an
interface, the loading order is completely different. See:

[snipped code where TestInterface is an interface]
When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
Executed Factory.getInstance()
[Loaded TestInterfaceImpl0]
Executed TestInterfaceImpl0.f()

This time, ONLY TestInterfaceImpl0 is loaded and its loading is
postponed until it is needed (Factory.getInstance() before the
loading).

Does anyone now why this happens?

Thanks a lot.
From my understanding of JLS
(http://java.sun.com/docs/books/jls/index.html) chapter 12, both the
behaviors you noticed above are allowed, so it's really just
implementation dependent. I have no idea why the implementation does
different things for your two examples, but they both exhibit standards
compliant behavior.

Specifially, check out JLS section 12.1.2:

http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44459

It specifically explains that an implementation is free to be lazy and
only load classes the first time they're actually used, or at the other
extreme, recursively resolve all references as soon as a class is
loaded, and specifically mentions that this may cause errors to occur
at different times, or not at all, depending on the ClassLoader
implementation. In your example the first program will die with an
error if the TestInterfaceImpl1.class is not found at runtime, whereas
the second example runs fine. Unfortunately both behaviors are allowed
by the JLS.

On the related issue of class initialization, the spec, section 12.4.1,
is much more strict about when initialization occurs, and basically
says a class can't be initialized until it is about to be used in some
way. So in your example, if TestInterfaceImpl1 contained a static
block, it would never be called since you never used TestInterfaceImpl1
in your program.
 
A

Andrea Desole

Classes should be loaded when they are needed. From the JVM spec:

Creation of a class or interface C denoted by the name N consists of the
construction in the method area of the Java virtual machine (§3.5.4) of
an implementation-specific internal representation of C. Class or
interface creation is triggered by another class or interface D, which
references C through its runtime constant pool. Class or interface
creation may also be triggered by D invoking methods in certain Java
class libraries (§3.12) such as reflection.

So my guess is that the second case is correct, and the first is not.
Maybe a bug?

In resume, I have a factory class that creates/instantiates a family
of classes, like in this example:

public class Test{
public static void main(String args[]){
TestInterface t = Factory.getInstance(0);
t.f();
}
}

class Factory{
public static TestInterface getInstance(int type){
System.out.println("Executed Factory.getInstance()");
switch(type){
case 0: return new TestInterfaceImpl0();
case 1: return new TestInterfaceImpl1();
default: return new TestInterfaceImpl2();
}
}
}

abstract class TestInterface{
public abstract void f();
}

class TestInterfaceImpl0 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl0.f()"); }
}

class TestInterfaceImpl1 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl1.f()"); }
}

class TestInterfaceImpl2 extends TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl2.f()"); }
}

When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
[Loaded TestInterfaceImpl0]
[Loaded TestInterfaceImpl1]
[Loaded TestInterfaceImpl2]
Executed Factory.getInstance()
Executed TestInterfaceImpl0.f()

So, what we see here is that JVM loads ALL classes referenced from
Factory.getInstance() (TestInterfaceImpl0, TestInterfaceImpl1 and
TestInterfaceImpl2) before it is executed.

Now, my question. If I change the abstract class TestInterface into an
interface, the loading order is completely different. See:


public class Test{
public static void main(String args[]){
TestInterface t = Factory.getInstance(0);
t.f();
}
}

class Factory{
public static TestInterface getInstance(int type){
System.out.println("Executed Factory.getInstance()");
switch(type){
case 0: return new TestInterfaceImpl0();
case 1: return new TestInterfaceImpl1();
default: return new TestInterfaceImpl2();
}
}
}

interface TestInterface{
public void f();
}

class TestInterfaceImpl0 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl0.f()"); }
}

class TestInterfaceImpl1 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl1.f()"); }
}

class TestInterfaceImpl2 implements TestInterface{
public void f(){ System.out.println("Executed
TestInterfaceImpl2.f()"); }
}


When I run Test class using -verbose:class option I got this output:

[Loaded Test]
[Loaded Factory]
[Loaded TestInterface]
Executed Factory.getInstance()
[Loaded TestInterfaceImpl0]
Executed TestInterfaceImpl0.f()

This time, ONLY TestInterfaceImpl0 is loaded and its loading is
postponed until it is needed (Factory.getInstance() before the
loading).

Does anyone now why this happens?

Thanks a lot.

Regards,
Fernando.
 
B

bilbo

Andrea said:
Classes should be loaded when they are needed. From the JVM spec:

Creation of a class or interface C denoted by the name N consists of the
construction in the method area of the Java virtual machine (§3.5.4) of
an implementation-specific internal representation of C. Class or
interface creation is triggered by another class or interface D, which
references C through its runtime constant pool. Class or interface
creation may also be triggered by D invoking methods in certain Java
class libraries (§3.12) such as reflection.

So my guess is that the second case is correct, and the first is not.
Maybe a bug?


See my other post though. The paragraph you're citing just says that a
reference to a class C can trigger C being loaded. Both of the OPs
classes had references to to all the classes, so the above paragraph
doesn't preclude them being loaded. Specifically, look at JLS 12.2.1,
which spells out more clearly when a class can actually be loaded, and
pretty explicitly allows both behaviors that the OP noted.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top