|
JavaFAQ Home » Story by Dr. Kabutz

2001-05-03 The Java Specialists' Newsletter [Issue 018] - Class names don't identify a class
2001-05-03 The Java Specialists' Newsletter [Issue 018] -
Class names don't identify a class
Author:
Dr. Heinz M. KabutzJDK version: Category: Language
You can subscribe from our home page:
http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge
Welcome to the 18th issue of "The Java(tm) Specialists'
Newsletter", now sent to 38 countries on all continents of our
globe. Please remember to forward the newsletter to others who
might be interested.
BEFORE YOU FILE THIS NEWSLETTER ...
I have a question for you:
South Africa is a beautiful country with a relatively stable
economy, compared to other developing countries. The South-
Western part of South Africa, called the Western Cape, is an
especially great place to live, mainly because of the stunning
environment, weather, etc. For some strange reason, we are
losing a lot of programmers to the land of mist and the land of
abundance. There are those in the private sector willing to
invest significant money to realise their dream of the Western
Cape becoming another success story in the computer world.
Now the question: If you used to live in South Africa, what
would entice you to come back to the Western Cape? If you are
already living in South Africa, what would prevent you from
leaving? Lastly, if you are an IT professional living outside
of South Africa, what "things" would attact you to move to the
Western Cape?
I'm very interested to hear your opinions on this question, so
don't delay, answer today
Class names don't identify a class
This week I want to introduce the concepts of having Class
objects in the VM with the exact same name, but being completely
different. I had the opportunity to question Dr. Jung, who has
been using this for a while now, and at long last, my small brain
has made "click" and I understand (I think). In two weeks time,
he is going to write the newsletter (he wrote the piece on
dynamic proxies) and he will demonstrate how you can build up a
sibling hierarchy of class loaders which you can use to
automatically redeploy classes and find dependencies, etc. I
didn't quite follow all of his explanations, so I'm looking
forward to read what he has to say about this topic. In the
meantime, to prepare us all, I've written a simple example to
demonstrate how it works.
In JDK 1.2, SUN added a new approach to class loading which
allows you to identify classes not only by the class name, but
also by the context in which it was loaded. We can set the
ClassLoader for a Thread, which we can then use to load classes.
By having a different classloader, you are effectively
constructing a new instance of Class, which is then completely
different from other instances of Class. This was, I think, also
possible in JDK 1.1, but it is much easier to make an instance of
a ClassLoader in JDK 1.2 as there is now a URLClassLoader which
you can point to a directory where it will load the classes from.
For example, say we have two directories, a1 and a2. In each of
these directories we have a class A:
//: a1/A.java
public class A {
public String toString() { return "This is the first class"; }
}
//: a2/A.java
public class A {
public String toString() { return "This is the second class"; }
}
As you will agree, the two classes are completely different.
They can have different method definitions, data members or
access control. The normal way of using these two classes is to
choose at compile/run time which one you wish to use. For
example, we may have a class NormalTest below:
//: NormalTest.java
public class NormalTest {
public static void main(String[] args) {
System.out.println(new A());
}
}
To compile this class, we have to specify the directory where A
resides, either a1 or a2. Since the signature is the same, we
can compile with one class and run with the other class if we
want.
javac -classpath .;a1 NormalTest.java
java -classpath .;a2 NormalTest
would result in "This is the second class" being displayed on the
console.
What happens if we want to have instances of both A classes in
use at the same time? Normally we cannot do that, but if we use
ClassLoaders we can.
//: Loader.java
import java.net.*;
public class Loader {
public static void main(String[] args) throws Exception {
ClassLoader a1 = new URLClassLoader(
new URL[] {new URL("file:a1/")}, null);
ClassLoader a2 = new URLClassLoader(
new URL[] {new URL("file:a2/")}, null);
Class c1 = a1.loadClass("A");
Class c2 = a2.loadClass("A");
System.out.println("c1.toString(): " + c1);
System.out.println("c2.toString(): " + c2);
System.out.println("c1.equals(c2): " + c1.equals(c2));
System.out.println("c1.newInstance(): " + c1.newInstance());
System.out.println("c2.newInstance(): " + c2.newInstance());
}
}
The two classes, both called "A", are loaded with different
ClassLoader objects, and are thus, as far as the VM is concerned,
different classes altogether. We can print the names of the
classes, compare the two classes (even though their names are the
same, the classes are not equal, you should therefore never
compare just the class names if you want to compare classes,
rather use the Class.equals() method), and make instances of them
by calling the newInstance() method.
The output if we run Loader is:
c1.toString(): class A
c2.toString(): class A
c1.equals(c2): false
c1.newInstance(): This is the first class
c2.newInstance(): This is the second class
We can also let these two "A" classes have a common superclass.
For example, say we have a superclass called Parent.java located
in the root directory:
//: Parent.java
public class Parent {
public String toString() {
return "Thanks for caring... but what do you want??? ";
}
}
And our A.java classes are now written as:
//: a1/A.java
public class A extends Parent {
public String toString() {
return super.toString() + "This is the first class";
}
}
//: a2/A.java
public class A extends Parent {
public String toString() {
return super.toString() + "This is the second class";
}
}
We then need to have a common parent ClassLoader which we use to
load the Parent.class file. We have to specify the location
to start looking for Parent.class, and the locations are searched
in a hierarchical fasion. Note that the compile-time Parent
class is loaded with a different ClassLoader to the one loaded
with the URLClassLoader called "parent" so they refer to a
different class altogether, which means we cannot type-cast an
instance of "A" to a Parent. Also, if we load the class "Parent"
without using the classloader, we will see that it is not equal
to the superclass of "c1".
//: Loader.java
import java.net.*;
public class Loader {
public static void main(String[] args) throws Exception {
ClassLoader parent = new URLClassLoader(
new URL[] {new URL("file:./")}, null);
ClassLoader a1 = new URLClassLoader(
new URL[] {new URL("file:a1/")}, parent);
ClassLoader a2 = new URLClassLoader(
new URL[] {new URL("file:a2/")}, parent);
Class c1 = a1.loadClass("A");
Class c2 = a2.loadClass("A");
System.out.println(c1.newInstance());
System.out.println(c2.newInstance());
System.out.println(
c1.getSuperclass().equals(c2.getSuperclass()));
System.out.println(
Class.forName("Parent").equals(c1.getSuperclass()));
try {
Parent p = (Parent)c1.newInstance();
} catch(ClassCastException ex) {
ex.printStackTrace();
}
System.out.println("We expected to get ClassCastException");
}
}
Thanks for caring... but what do you want??? This is the first class
Thanks for caring... but what do you want??? This is the second class
true
false
java.lang.ClassCastException: A
at Loader.main(Loader.java:1
We expected to get ClassCastException
Note that the super classes of both "A" classes are equal.
Where is this all this useful? It is very useful when you have
an application server into which you want to deploy business
objects written by different people. It is entirely feasible
that you have two developers with different versions of classes
deploying their applications onto the same server. You don't
necessarily want to start a new VM for each deployment, and so
with ClassLoaders it is possible to have lots of classes with the
same name running in the same memory space but not conflicting
with one another. They would also share the common JDK classes
with one another, so we would not have to have a
java.util.ArrayList class loaded for each of the ClassLoaders.
Until next week, and please remember to forward this newsletter
in its entirety to as many Java users as you know who would be
interested.
Heinz
Copyright 2000-2004 Maximum Solutions, South Africa
Reprint Rights. Copyright subsists in all the material
included in this email, but you may freely share the entire
email with anyone you feel may be interested, and you may
reprint excerpts both online and offline provided that you
acknowledge the source as follows: This material from The
Java(tm) Specialists' Newsletter by Maximum Solutions (South
Africa). Please contact Maximum Solutions
for more information.
Java and Sun are trademarks or registered trademarks of Sun Microsystems,
Inc. in the United States and other countries. Maximum
Solutions is independent of Sun Microsystems, Inc.
Printer Friendly Page
Send to a Friend
..
Search here again if you need more info!
|