Class Loader, Class and Object
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 talkin=
g about the Class Loading mechanism in Java. On the first occasion, my frie=
nd asked me how to create new object of the nested class. Simply put, it is=
like 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.StaticInnerCl=
ass();
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 bind=
your self to before manage to create any object.
The hierarchy of innerObject should be:
Class Loader =E2=86' OuterClass =E2=86' outerObject =E2=86' InnerCla=
ss =E2=86' innerObject.
In constrast, the hierarchy of nestedObject should be:
Class Loader =E2=86' OuterClass =E2=86' InnerClass =E2=86' innerObjec=
t
That explain the different among 3 constructors in the above example:
OuterClass outerObject = new OuterClass();
OuterClass.StaticInnerClass nestedObject = new OuterClass.StaticInnerCla=
ss();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
If you read up to this point, you will wonder when to use inner class, when=
to use static inner class. For me, static inner class is naturally an inde=
pendent class that being hide inside another class declaration. It still fu=
lly function as a normal class but invisible from IDE autocomplete. It give=
s you the flexibility of reusing the same name for inner class. Some sample=
of 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 re=
commended to do so as JVM will only keep track of one class declaration for=
your inner class. If you are still unclear about this benefit, the class i=
tself is also one object in JVM. That why java allow you to access class ob=
ject using reflection. The only case that you use non-static inner class is=
when you need access to outer class non-static variable.
It is also worth taking note that the class object is not unique in JVM. To=
be more accurate, it is unique per class loader. However, depend on how yo=
u 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 term=
inal, you will only have 1 class loader in your JVM. If you put the class a=
bove 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 cl=
ass loader to load web application for security reason (you do not want the=
class from other web application to interfere with your application right?=
).
In this case, if you deploy 2 web application to the same container that bo=
th contain log4j, you actually have 2 log4j class in your JVM. However, onl=
y one log4j class is visible to each webapp. Still, it may cause some issue=
s if you have 2 appenders that attempt to write to the same log file. If yo=
u choose the other strategy by putting log4j class to web container library=
then you will have unique appender per web container and you force all the=
webapps to share log4j configuration. It is highly recommended that you do=
not put any class that you need access to its static variable to web conta=
iner library.
Up to this point, I have not mentioned the second occasion yet. Yep, it hap=
pened when we deployed two applications with this log4j configuration to To=
mcat:
<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 m=
any developers suffered from this problem. webAppRoot is a bonus feature th=
at allow you to use webapp root inside log4j config file. However, if you p=
ut log4j config file to a share folder in Tomcat, you manage to create conf=
lict 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 a=
nd the second one will fail. In this case, you got no choice but turn off t=
his feature.