Showing posts with label JavaSpecialists. Show all posts
Showing posts with label JavaSpecialists. Show all posts

Friday, October 26, 2007

JavaSpecialists Notes - II

Issue 18: Class names don't identify a 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:18)
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.

Monday, October 22, 2007

JavaSpecialists Notes - I

This is the first part of a series of blogs that I would write in order to keep the crux of all the JavaSpecialists Newsletters at one place for a quick reference. It would include the links and excerpts from the original newsletter.

Issue 1: Deadlocks

In Swing, all GUI components have to be changed from within the Swing thread.
This means that you cannot execute jLabel1.setText("blabla") from within any thread
besides the Swing thread.
If you have change any GUI from another thread you should rather say:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jLabel1.setText("blabla");
}
}

Issue 2: Anonymous Inner Classes

If you wanted to pass in a Collection instead of an array it would look as follows:

Collection temp_names = new Vector(3);
temp_names.add("Heinz");
temp_names.add("John");
temp_names.add("Anton");
universityRegistration.addNames(temp_names);

The ability to avoid local temporary variables with arrays was always a strong
deciding factor in defining interfaces to my classes because I could get away with
one line of code instead of five, and the less lines of code the better. I would
therefore rather define addNames(String[] names) than addNames(Collection names) even
if it meant I would have to convert backwards and forwards between arrays and
collections. However, with anonymous inner classes we can get the same effect seen
above but with collections:

universityRegistration.addNames(new Vector(3)
{{ add("Heinz"); add("John"); add("Anton"); }});

Issue 8: boolean comparisons

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu == true) {
/* work out incorrect salary using double */
}

This will compile fine in Java, but so will the following, which assigns true to
pentiumTMcpu and will always work out the salary using the Pentium bug (younger
readers would not remember):

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu = true) {
/* this code will always be executed */
}

Instead, it would be a lot safer to write

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu) {
/* work out incorrect salary using double */
}
.........
.........
.........
There is a technique used alot in Microsoft's C++ libraries in which they would have
written the comparison as:

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (true == pentiumTMcpu) {
/* work out incorrect salary using double */
}

More would follow as and when I would read other issues. :)