Class and interface loading order

Discussion in 'Java' started by Fernando, Nov 18, 2004.

  1. Fernando

    Fernando Guest

    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.
    Fernando, Nov 18, 2004
    #1
    1. Advertising

  2. Fernando

    bilbo Guest

    Fernando wrote:
    > 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.
    bilbo, Nov 18, 2004
    #2
    1. Advertising

  3. 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?


    Fernando wrote:
    > 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.
    Andrea Desole, Nov 19, 2004
    #3
  4. Fernando

    bilbo Guest

    Andrea Desole wrote:
    > 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.
    bilbo, Nov 19, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. matt melton
    Replies:
    6
    Views:
    516
    Gordon Beaton
    Sep 8, 2003
  2. E11
    Replies:
    1
    Views:
    4,717
    Thomas Weidenfeller
    Oct 12, 2005
  3. cyberco
    Replies:
    8
    Views:
    480
    cyberco
    Feb 25, 2006
  4. Stephan Kämper
    Replies:
    2
    Views:
    229
    Stephan Kämper
    Jan 18, 2004
  5. ofir
    Replies:
    0
    Views:
    178
Loading...

Share This Page