Issue #007 July, 1996 Contents: Invoking Subprograms in Java Comparing C/C++ to Java Part 7 - Destructors vs. Finalize Free Java Library Enums and Java Introduction to Applet Programming Part 3 - Events INVOKING SUBPROGRAMS IN JAVA It's often the case that when writing programs, you'd like to invoke another program from within the first and send it input and get output from it. How might this be done in Java? A simple example that runs the UNIX program "ls" to retrieve a listing of files in the current directory looks like this: import java.io.*; public class test1 { public static void main(String args[]) { try { Process cp = Runtime.getRuntime().exec("ls"); DataInputStream d = new DataInputStream(cp.getInputStream()); String line = null; while ((line = d.readLine()) != null) System.out.println(line); } catch (Throwable e) { } } } The call to exec() starts the process running, and returns a Process object. Then we query the Process object to get a buffered input stream that is connected to the output of the child process. We then can simply iterate over this stream, reading lines in turn, that are the output of ls. In a similar way, it's possible to send input to the child process or capture its error output. The Process class has several additional methods available for controlling processes: waitFor() wait for the child process to complete exitValue() return the exit value for the process destroy() kill the process There is also a variant of exec() that supports passing of environment variables to the child process. COMPARING C/C++ TO JAVA PART 7 - DESTRUCTORS VS. FINALIZE In C++ there is the notion of a destructor, a function called when a class object instance goes out of scope. For example: class A { public: A(); ~A(); }; void f() { A a; } When the function f() is entered, the constructor A::A() is called for the local object a, and when f() is exited, the destructor A::~A() is called in turn. Java class objects do not behave in a similar way. They are dynamically allocated, at which point a constructor is run on the object instance, and later garbage collected. Java does not have any notion of a destructor method that is run when an object instance is no longer valid. But it does have a finalize() method: protected void finalize() {} that can be added to any class. finalize() is called for an object instance after that instance has been identified by the garbage collector as no longer a valid object, that is, there are no remaining references to it. For example: public class test1 { public test1() { System.out.println("call ctor"); } protected void finalize() { System.err.println("call finalize"); } public static void f() { test1 p = new test1(); } public static void main(String args[]) { f(); System.gc(); System.runFinalization(); } } After the return from the f() call, there is an object instance that can be garbage collected; there is no reference to the object we created while inside of f(). System.gc() frees up objects and marks them as pending for finalization to be done. Actual finalization processing proceeds asynchronously with the garbage collector, so to force finalization we can call System.runFinalization(). Because of the way that finalize() methods work, you should use caution in assuming that they can be used to reclaim valuable resources such as UNIX file descriptors. Also, you should insert a line like: super.finalize(); at the end of a finalize() method, to call the corresponding method of the superclass. FREE JAVA LIBRARY I have developed a Java library for managing collections of objects, such as lists, stacks, sets, bitmaps, and trees. If you are interested in this library, please see the Web page: http://rmi.net/~glenm/javalib/index.html ENUMS AND JAVA In C++ there is a facility known as enumerations or enumerated types that can be used to represent a set of integral values: enum Color {CO_R = 1, CO_G = 2, CO_B = 3}; After this declaration, Color can be used as a type (including for function overloading purposes), and values like CO_R can be used wherever integral constants would be used. Type checking is done, so that for example: Color c = CO_R; c = 37; is invalid. Java does not have enumerations. One way to simulate them is simply by defining constants in a class: public class Color { public static final byte CO_R = 1; public static final byte CO_G = 2; public static final byte CO_B = 3; }; public means that these values are accessible to all, static means that they're shared across all object instances, final means that they're immutable once set, and byte means that they're represented in bytes in the virtual Java machine. Once a class like this is set up, you can say things like: byte b = Color.CO_G; But notice that this simulation is only a simulation. There's nothing to stop me from saying: byte b = Color.CO_R; b = 29; and thereby introduce an invalid color value. A solution to this problem would be to define Color as a "real" class, that represents the actual current value of an enumeration: public class Color { private byte value = 0; public static final byte CO_R = 1; public static final byte CO_G = 2; public static final byte CO_B = 3; public Color(byte b) { if (b == CO_R || b == CO_G || b == CO_B) value = b; else throw new IllegalArgumentException(); } public byte getvalue() { return value; } } This approach works, but can be cumbersome to use. However, enums, like other language features, add to the total complexity and implementation cost of a language, and leaving them out of Java is a reasonable design tradeoff to make. INTRODUCTION TO APPLET PROGRAMMING PART 3 - EVENTS In previous issues we've talked about the basic protocols underlying an applet and how graphical and text output is done. With this issue we'll start a discussion of input handling, and begin by talking about events just a little bit. Here is an applet that allows a user to do free drawing with the mouse. That is, whenever the mouse button is held down and the mouse moved, a line will be drawn: import java.applet.*; import java.awt.*; public class Draw extends Applet { int prev_x = 0; int prev_y = 0; int color = 0; public boolean mouseDown(Event e, int x, int y) { prev_x = x; prev_y = y; return true; } public boolean mouseDrag(Event e, int x, int y) { Graphics g = getGraphics(); switch (color) { case 0: g.setColor(Color.red); break; case 1: g.setColor(Color.green); break; case 2: g.setColor(Color.blue); break; } if (++color > 2) color = 0; g.drawLine(prev_x, prev_y, x, y); prev_x = x; prev_y = y; return true; } } This applet can be invoked via the HTML code: Interface to Draw Applet using the JDK AppletViewer program. We've alternated the output color of the drawn line, as a means of tying together some of the ideas from the last issue, and to better illustrate what is happening. mouseDown() is an applet method called by the system when the user presses a mouse button. It's passed a description of the event along with an X,Y pair, and returns true if it handled the event, so that the event will not be further processed. In our example we simply record the X,Y location where the event occurred. mouseDrag() is a method called when the user drags the mouse with the button down. When this occurs, we switch colors and then draw a line between the old position and the new one. getGraphics() is a method that returns a java.awt.Graphics object, that is used for line drawing, image painting, and so on. If you run the above applet, the colors will alternate very rapidly if you move the mouse slowly, and alternate more slowly if you move the mouse rapidly. Why is this? It has to do with polling of the mouse. That is, the mouse's status is checked at regular intervals. If the mouse has moved a long ways in the poll interval, then the single-color line segment will be longer than if the mouse had been moved slowly. We will be discussing events and input further in upcoming issues. ACKNOWLEDGEMENTS Thanks to Thierry Ciot, Irv Kanode, Mike Paluka, and Alan Saldanha 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: rmii.com /pub2/glenm/javalett or on the Web at: http://www.rmii.com/~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) 1996 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: rmii.com /pub2/glenm/javalett (for back issues) Web: http://www.rmii.com/~glenm