Class Loader, Class and Object

T

tuanngda

Class Loader, Class and Object

(http://sgdev-blog.blogspot.sg/2014/01/class-loader-class-and-object.html)

Recently, there are two occasions that make me feel that it is worth talking about the Class Loading mechanism in Java. On the first occasion, my friend asked me how to create new object of the nested class. Simply put, it islike this:

class OuterClass {

private String outerVariable;
private static String outerStaticVariable;

class InnerClass {
public String toString() {
return outerVariable.toString();
}
}

static class StaticInnerClass {
public String toString() {
return outerStaticVariable.toString();
}
}

public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
outerObject.outerVariable = "outerVariable";
outerStaticVariable = "outerStaticVariable";

OuterClass.StaticInnerClass nestedObject = new OuterClass.StaticInnerClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

System.out.println(nestedObject.toString());
System.out.println(innerObject.toString());
}
}

It is very simple to know why if you understand the class loader mechanism in Java well enough. As it is perfectly explained in http://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/

When you create inner class, you need to have an outer class object to bindyour self to before manage to create any object.

The hierarchy of innerObject should be:

Class Loader → OuterClass → outerObject → InnerClass → innerObject.

In constrast, the hierarchy of nestedObject should be:

Class Loader → OuterClass → InnerClass → innerObject

That explain the different among 3 constructors in the above example:

OuterClass outerObject = new OuterClass();
OuterClass.StaticInnerClass nestedObject = new OuterClass.StaticInnerClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();


If you read up to this point, you will wonder when to use inner class, whento use static inner class. For me, static inner class is naturally an independent class that being hide inside another class declaration. It still fully function as a normal class but invisible from IDE autocomplete. It gives you the flexibility of reusing the same name for inner class. Some sampleof using it is the mapper class to be used in JDBC if you find the mapper useful to be reused.

Most of the time, you will just need to use static inner class and it is recommended to do so as JVM will only keep track of one class declaration foryour inner class. If you are still unclear about this benefit, the class itself is also one object in JVM. That why java allow you to access class object using reflection. The only case that you use non-static inner class iswhen you need access to outer class non-static variable.

It is also worth taking note that the class object is not unique in JVM. Tobe more accurate, it is unique per class loader. However, depend on how you create your application, you may have more than one class loader in your JVM. For example, if you run the above code using java OuterClass from terminal, you will only have 1 class loader in your JVM. If you put the class above inside one Java web application then your JVM will have more than one class loader. It is because most of the Java web container use dedicated class loader to load web application for security reason (you do not want theclass from other web application to interfere with your application right?).

In this case, if you deploy 2 web application to the same container that both contain log4j, you actually have 2 log4j class in your JVM. However, only one log4j class is visible to each webapp. Still, it may cause some issues if you have 2 appenders that attempt to write to the same log file. If you choose the other strategy by putting log4j class to web container librarythen you will have unique appender per web container and you force all thewebapps to share log4j configuration. It is highly recommended that you donot put any class that you need access to its static variable to web container library.

Up to this point, I have not mentioned the second occasion yet. Yep, it happened when we deployed two applications with this log4j configuration to Tomcat:

<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.xml</param-value>
</context-param>
<context-param>
<param-name>log4jExposeWebAppRoot</param-name>
<param-value>false</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

Kindly notice the highlighted param above. This is quite tricky and I see many developers suffered from this problem. webAppRoot is a bonus feature that allow you to use webapp root inside log4j config file. However, if you put log4j config file to a share folder in Tomcat, you manage to create conflict here as log4j fail to identify the unique webapp root. Depend of your deployment order, it is likely that the first webapp deployment will pass and the second one will fail. In this case, you got no choice but turn off this feature.
 

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

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,835
Latest member
KetoRushACVBuy

Latest Threads

Top