Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Class and interface loading order

Reply
Thread Tools

Class and interface loading order

 
 
Fernando
Guest
Posts: n/a
 
      11-18-2004
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.
 
Reply With Quote
 
 
 
 
bilbo
Guest
Posts: n/a
 
      11-18-2004
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/s...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.

 
Reply With Quote
 
 
 
 
Andrea Desole
Guest
Posts: n/a
 
      11-19-2004
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.

 
Reply With Quote
 
bilbo
Guest
Posts: n/a
 
      11-19-2004
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.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
order of iframe loading with document loading ofir Javascript 0 12-03-2007 12:06 PM
test if obj implemenst interface (provided as interface.class) cyberco Java 8 02-25-2006 12:03 PM
Nested Class, Member Class, Inner Class, Local Class, Anonymous Class E11 Java 1 10-12-2005 03:34 PM
In which order are files looked for when loaded/requierd - and what'sthe order of suffixes? Stephan Kämper Ruby 2 01-18-2004 02:07 PM
Class Files and Class Loading in NT and UNIX matt melton Java 6 09-08-2003 10:09 AM



Advertisments