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: Interface to Filter Applet "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