The Race Moves up a notch

   Print.Print
Email.Email weblog link
Blog this.Blog this
Ted Neward

Ted Neward
Nov. 05, 2002 04:09 PM
Permalink

Atom feed for this author. RSS 1.0 feed for this author. RSS 2.0 feed for this author.

Sun released another early-access version of the JSR 14 "Generics for Java" implementation recently, and can be found at http://developer.java.sun.com/developer/earlyAccess/adding_generics/. (The main JDC page claims that the last release was 1.2, on March 21; that's incorrect. If you click through the link to the URL above, it reads as 1.3, released on October 30.)

Using the 1.3 release is a bit awkward, since the release itself ships as two .jar files, one for the compiler and another for the java.util Collection classes (properly genericized). This means, unfortunately, that you'll need to put the javac.jar compiler code somewhere in the bootclasspath of the javac.exe tool when you run it, and reference the collect.jar as part of the bootclasspath when you compile and run the resulting code. The 1.3 release ships with some UNIX and Win32 script/batch files to help ease this pain, but if you're planning to do any serious work with the release, I'd suggest just writing your own quick-and-dirty JNI Invocation launcher to get all the options in the right place; details on how to do so can be found in a variety of different JNI books, as well as my own (now horribly outdated) Server-Based Java Programming. If I get around to it, I'll write one myself and post it here.

One nice thing about the JSR EA implementation is that once you get past the compilation phase (and if you don't use any of the generic collection classes in collect.jar), you can run the compiled code on preexisting VMs--there's no structural changes to the code made when compiling generics into standard Java classes. So, for example, taking this code:

class Generic
{
  T data;

  public Generic(T d) { data = d; }
}

public class GenTest
{
  public static void main(String[] args)
  {
    Generic gs = new Generic("Hello, world");
    System.out.println(gs.data);
  }
}
and compiling it in the genericized Javac (which I'll call gjavac from here on out) yields "Generic.class" and "GenTest.class".

One of the goals for the JSR 14 was "designed to be fully backwards compatible with the current language, making the transition from non-generic to generic programming very easy." Part of this means that there can be no structural changes to the underlying JVM that will be used to execute the code. (This is in direct contrast to the Gyro release from Microsoft--it patches the CLR to recognize generic types within the runtime. This pretty accurately reflects the differences in philosophy between Sun and Microsoft--Sun believes in "one language", and Microsoft believes in "multiple languages".) Sure enough, if we disassemble the compiled Generic class, we see

Compiled from GenTest.java
class Generic extends java.lang.Object {
    java.lang.Object data;
    public Generic(java.lang.Object);
}

Method Generic(java.lang.Object)
   0 aload_0
   1 invokespecial #1 <Method java.lang.Object()>
   4 aload_0
   5 aload_1
   6 putfield #2 <Field java.lang.Object data>
   9 return
As you can see, the underlying data type for "data", which was represented in the source as the type variable "T", is a java.lang.Object reference. Similarly, using the parameterized Generic behaves much as you'd expect (once again, consulting javap for a bytecode disassembly):
Compiled from GenTest.java
public class GenTest extends java.lang.Object {
    public GenTest();
    public static void main(java.lang.String[]);
}

Method GenTest()
   0 aload_0
   1 invokespecial #1 <Method java.lang.Object()>
   4 return

Method void main(java.lang.String[])
   0 new #2 <Class Generic>
   3 dup
   4 ldc #3 <String "Hello, world">
   6 invokespecial #4 <Method Generic(java.lang.Object)>
   9 astore_1
  10 getstatic #5 <Field java.io.PrintStream out>
  13 aload_1
  14 getfield #6 <Field java.lang.Object data>
  17 checkcast #7 <Class java.lang.String>
  20 invokevirtual #8 <Method void println(java.lang.String)>
  23 return
The "smoking gun", as it were, is on disassembly lines 14 and 17: the runtime will retrieve the data as an Object, then cast it down to a String (the parameterized type) at runtime. In short, the code is no different than if you'd written it "the long way" yourself--all the type-safety is being checked at compile-time, much as C++ does.

The key thing is to realize that, despite what my earlier post about JSR 14 may have implied, the generics-in-Java effort is not stalled or dead, and with any luck we'll see a release before JDK 1.5 goes out the door. In the meantime, I encourage you to play with the early access release, and offer feedback to the JSR 14 team about what you think of it.

Ted Neward is an independent software development architect and mentor in the Sacramento, California area.