Issue #013
January, 1997


Contents:

JDK 1.1
Reflection
1.1 Performance
Indexing Program
Comparing C/C++ and Java Part 13 - Arrays
Conditional Compilation
Introduction to Applet Programming Part 9 - Image Loading and Filtering


JDK 1.1

A major upgrade to Java has been released by Sun in beta form, Java
Development Kit 1.1.  It's available via FTP from Sun at:

        http://java.sun.com/products/JDK/1.1

We will be using JDK 1.1 in subsequent newsletter discussions and
examples.

There are many new features in 1.1, including Remote Method
Invocation, SQL support, security features, text processing,
reflection, and so on.


REFLECTION

One of the interesting 1.1 features is something known as reflection,
where it is possible to query a class at run time to determine its
properties.  For example, with this code:

        import java.lang.reflect.*;

        public class Dump {
                public static void main(String args[])
                {
                        try {
                                String s = "java.lang." + args[0];
                                Class c = Class.forName(s);
                                Method m[] = c.getMethods();
                                for (int i = 0; i < m.length; i++)
                                        System.out.println(m[i].toString());
                        }
                        catch (Throwable e) {
                        }
                }
        }

one can query a class for the names and properties of its public
methods, using the new package "java.lang.reflect".  There is also
support for accessing private and package level methods.
Additionally, you can dynamically invoke methods on a given object.

Running this program by saying:

        $ java Dump Object

results in:

        public final native java.lang.Class java.lang.Object.getClass()
        public native int java.lang.Object.hashCode()
        public boolean java.lang.Object.equals(java.lang.Object)
        public java.lang.String java.lang.Object.toString()
        public final native void java.lang.Object.notify()
        public final native void java.lang.Object.notifyAll()
        public final native void java.lang.Object.wait(long)
        public final void java.lang.Object.wait(long,int)
        public final void java.lang.Object.wait()

This type of feature simply doesn't exist in a language like C or
C++.  Certain programming environments or debuggers may offer an
equivalent, but not as part of the language or its core libraries.


1.1 PERFORMANCE

In issue #001, we presented a crude benchmark for assessing run time
performance:

        // sort numbers

        public class bm1 {
                static final int N = 6500;
                public static void main(String args[])
                {
                        int i;
                        int j;
                        short t;

                        short vec[] = new short[N];

                        // seed with descending order

                        for (i = 0; i < N; i++)
                                vec[i] = (short)(N - i);

                        // sort into ascending order

                        for (i = 0; i < N - 1; i++) {
                                for (j = i + 1; j < N; j++) {
                                        if (vec[i] > vec[j]) {
                                                t = vec[i];
                                                vec[i] = vec[j];
                                                vec[j] = t;
                                        }
                                }
                        }
                }
        }

With JDK 1.0 and Borland C++ 5.0, running on Windows NT 3.51, and
compiled with optimization on, the Java version of this program runs
about 43 times slower than the C++ version.

With JDK 1.1 beta, as mentioned above, the difference is about 17
times, or a speedup of around 2.5 for the Java interpreter.  This is
presumably due to rewriting the main interpreter loop in assembly
language.

There are further speedups possible, such as use of Just In Time
compilation technology.  And this benchmark is worst-case in some
ways, in that it does no I/O, network access, or number crunching
using functions like log() and sin().  For example, low-level Java I/O
appears to be around 3X slower than its C counterpart, and a program
heavily dependent on I/O will not have the performance difference
observed with this sorting example (although higher-level Java I/O has
some significant differences from its C counterpart as far as
performance goes).

Also, the Java language is aimed at a slightly different sort of
application than C, and comparisons of this sort are never perfect.


INDEXING PROGRAM

As an example of using Java to write conventional applications, as
compared to applets or networking, I have written a Java program that
will go through all the files in a specified directory structure and
extract words in them and insert these into an index.  You can then
later specify words and be told which files contain those words.  This
is something like what Web search engines do.

The program indexes at around 10 MB/minute on a slow Pentium, and
lookup is nearly instantaneous.  The indexes are about 3-5% of the
size of the input files across a mixture of file types.

If you're interested in trying an early version of this program,
please let me know.  You need Java, preferably a faster version like
JDK 1.1.


COMPARING C/C++ AND JAVA PART 13 - ARRAYS

Java has arrays that in actual use look like conventional arrays in C
or C++.  For example, if you want to sum the first ten elements of an
array, you might say:

        int sum = 0;
        for (int i = 0; i < 10; i++)
                sum += a[i];

But there are some major differences in Java's treatment of arrays.
One big one is that Java checks array subscripts, and if instead of
the above I'd said:

        int sum = 0;
        for (int i = 0; i < 11; i++)
                sum += a[i];

an exception would be thrown, assuming that "a" is in fact an array of
ten elements.

Another difference is that a Java array may be of zero length, for
example:

        int x[] = new int[0];

C++ supports this but C does not.

The length of the array is available at any time by saying:

        int len = x.length;

".length" is not a function call or anything, just a specifier that
allows the length to be retrieved at will.  This is the actual length
of the array.  If, for example, you have an array of integers, of
length 20, and you've only inserted values into the first ten slots,
then there's no general way of knowing that except by a convention you
yourself adopt (such as ending the list with -1).

Array names are references, and thus it's possible to "assign" to an
array like so:

        int x[] = new int[10];
        int y[] = null;

        y = x;

In C/C++, actual arrays may not be assigned to:

        int x[10];
        int y[10];

        y = x;  // invalid

though pointers representing arrays certainly may be.

In C++, code like:

        class A {
        public:
                A();
        };

        A* p = new A[10];

will result in ten constructor calls, one for each array slot, whereas
in Java, code of the form:

        public class A {
                A() {}
                A p[] = new A[10];
        }

will not.  Rather, an array of ten references to A class instances
will be created, each initialized to the null value.  In other words,
the new call in C++ will allocate the space and then arrange for A's
constructor to be called on each array slot, whereas with Java, you
must initialize the array by saying:

        for (int i = 0; i < 10; i++)
                p[i] = new A();

Finally, it's possible to assign array objects to Object references,
as in:

        Object p = null;
        int x[] = new int[10];

        p = x;

and manipulate the array through an Object reference.  An array type
is a special type of class, and an actual instance of an array is
considered to be a class object.

Whether all of these properties of Java arrays are "good", for
example, the forced subscript checking, is of course a matter of
personal philosophy.  There are tradeoffs to be made in getting down
to the bare metal, like C does, vs. a higher-level approach where the
programming system is doing more for you.
        

CONDITIONAL COMPILATION

In issue #011 we talked about Java's lack of a preprocessor, such as
used in C and C++.  This lack is both a blessing and a curse.  One
common idiom in C is to use conditional compilation, for example, the
use of DEBUG to control program execution and possibly take different
action such as dumping out more information to the user:

        #ifdef DEBUG

        debugging stuff ...

        #endif

The preprocessor runs before the compiler proper and so the use of
#ifdef results in different subsets of the program actually being
compiled based on which constants (such as DEBUG) are set.

In Java, we could achieve a similar end by saying something like:

        public class test1 {

                public static final boolean DEBUG = false;

                public static void main(String args[])
                {
                        for (int i = 1; i <= 10; i++) {
                                if (DEBUG)
                                        System.out.println("i = " + i);
                        }
                }

        }

which will dump out the loop index at each loop iteration, if DEBUG is
true.

There is a quirk with this worth noting.  A program like:

        public class test2 {

                void f()
                {
                        int x = 0;

                        while (false)
                                x = -37;
                }

        }

is invalid, even thought it's superficially like the one above, in
that in one case we have:

        if (false)
                statement;

and in the other:

        while (false)
                statement;

In both cases the statement is unreachable, but Java special cases the
"if" case, in order to support conditional compilation.  See 14.19 in
the "Java Language Specification" for a more detailed discussion of
this point.

This approach to "conditional compilation" still requires that the
code be valid.  That is, with use of the C/C++ preprocessor
conditional compilation is textually based, in that excluded code is
never presented to the actual compiler, whereas the scheme above is
logically based -- the code is simply never executed.


INTRODUCTION TO APPLET PROGRAMMING PART 9 - IMAGE LOADING AND FILTERING

An interesting aspect of applet programming that we've not talked
much about is the use of images.  In this issue we'll present a simple
example of how images are loaded and manipulated.

Let's first look at some actual applet code:

        // Filter.java
        
        import java.applet.*;
        import java.awt.*;
        import java.awt.image.*;
        
        public class Filter extends Applet {
        
                Image img;
                Image black;
                boolean flag = true;
        
                public void init()
                {
                        img = getImage(getDocumentBase(), "image.gif");
                        ImageFilter f = new BlackFilter();
                        ImageProducer ip = new FilteredImageSource(
                            img.getSource(), f);
                        black = createImage(ip);
                        repaint();
                }
        
                public void update(Graphics g)
                {
                        g.clearRect(0, 0, size().width, size().height);
                        g.drawImage(flag ? img : black, 10, 10, this);
                        flag = !flag;
                }
        
                public boolean mouseUp(Event e, int x, int y)
                {
                        repaint();
                        return true;
                }
        }
        
        class BlackFilter extends RGBImageFilter {
        
                public BlackFilter()
                {
                        canFilterIndexColorModel = true;
                }
        
                public int filterRGB(int x, int y, int rgb)
                {
                        int a = rgb & 0xff000000;
                        int r = ((rgb & 0xff0000) + 0xff0000) / 2;
                        int g = ((rgb & 0xff00) + 0xff00) / 2;
                        int b = ((rgb & 0xff) + 0xff) / 2;
                        //return a | r | g | b;
                        return a | 0 | 0 | 0;
                }
        }

which is driven by HTML code:

        <html>

        <head>
        <title>Interface to Filter Applet</title>
        </head>

        <body>

        <applet code="Filter.class" width=300 height=300></applet>

        </body>

        </html>

"image.gif" is not supplied in this newsletter and you'll need to find
your own image if you want to try this example.

This particular applet draws an image, and then toggles the image to
black and back to its original color at each mouse click.  The
commented-out line of code at the bottom of the applet would instead
"gray out" the image by averaging its RGB (red/green/blue) color
values with white.

The applet is conventional in structure save for the image filtering
and the color manipulation.

The image is retrieved using getImage(), specifying a name
("image.gif") and a URL document base.  We then create a black filter
and filter the loaded image through it.  With image filtering, an
ImageProducer is a source of an image.  A filter can be applied to the
ImageProducer, resulting in another ImageProducer from which an actual
image can be created using createImage().  This is a bit of
simplification of what the java.awt.image package is really about, but
it's sufficient for our purposes.

The RGB transformation averages each color with white, if graying out
is desired, or else simply returns 0 | 0 | 0 (black in the RGB color
scheme).  The high 8 bits (mask 0xff000000) represent the "alpha"
value, used to represent transparency.

An example of another type of transformation on images would be
CropImageFilter(), that crops an image to a specified rectangle.


ACKNOWLEDGEMENTS

Thanks to Jay Burgess, Thierry Ciot, Irv Kanode, Mike McCann, Mike
Paluka, Srihari Sampathkumar, and Bob Shore for help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com
with this line as its message body:

subscribe java_letter

Back issues are available via FTP from:

        rmi.net /pub2/glenm/javalett

or on the Web at:

        http://rainbow.rmi.net/~glenm

There is also a C++ newsletter.  To subscribe to it, say:

subscribe c_plus_plus

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1997 Glen McCluskey.  All Rights Reserved.

This newsletter may be further distributed provided that it is copied
in its entirety, including the newsletter number at the top and the
copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional Computer Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmi.net /pub2/glenm/javalett (for back issues)
Web: http://rainbow.rmi.net/~glenm
