Issue #006 June, 1996 Contents: JavaDoc Comparing C/C++ to Java Part 6 - Method Overloading Introduction to Applet Programming Part 2 - Drawing Performance - Primitive Types vs. Wrappers JAVADOC You may have heard of the term "JavaDoc" in relation to Java. What is this? JavaDoc is a tool that comes with the Java Development Kit. It's used for preparing HTML (the language of the Web) documentation for Java classes. That is, it generates HTML code that documents a class or package (set of related classes), including their methods, interfaces, exceptions, class hierarchy, and so on. JavaDoc extracts structured comments from a Java source file. For example: /** * Create a hash table. * * @param sz initial table size in hash slots (>= 1) * @param load_factor (average elements per slot) * (0.25 - 10.0) * @param growth_factor (how much to grow the table * when load factor is exceeded) (1.1 - 2.0) * @exception IllegalArgumentException for invalid arguments */ public Hash(int sz, float load_factor, float growth_factor) { // stuff } This is documentation for a constructor for a hash table class. JavaDoc keys off of "/**" and tags like "@param". Page 182 of David Flanagan's "Java in a Nutshell" (O'Reilly) describes the tags that can be used. You can run JavaDoc on individual Java source files, or on whole packages. It generates a set of HTML files that can be used on a Web page or with a Web browser whether connected to the Web or not. The files have hyperlinks between related classes and methods, so that a user can navigate easily through the documentation. COMPARING C/C++ TO JAVA PART 6 - METHOD OVERLOADING In both C++ and Java it's possible to have functions/methods with the same name as other functions. For example, in C++ you can say: class A { public: void f(int i) {} void f(char* s) {} }; and the compiler will choose the right function based on the type of the argument given to f(). Java has a similar facility. One question that naturally arises is how to choose the proper function or method to call. For example, with this C++ code: void f(short s) {} void f(long l) {} and a call: char c = 0; f(c); it's not clear which of these functions to call, because a char could be promoted to either a short or a long (this particular call is in fact ambiguous in C++). Java uses what is known as a "most specific" algorithm to figure out which method to call. Before we explain what is meant by this, we need to talk a bit about assignment, namely, what sorts of types can be assigned to other types in Java. Here is an example to illustrate this point: public class test1 { public static void main(String args[]) { short s = 0; int i = 0; float f = 0.0f; i = s; // OK f = i; s = i; // error i = f; s = (short)i; // OK but have to be careful i = (int)f; } } We can assign shorter primitive types to longer ones, for example short (16 bits) to int (32 bits). We can assign an int to a float. We cannot assign a longer type to a shorter or a float to an int, unless we use a cast. With casting one has to be careful, because of potential loss of precision, for example, in stuffing 32 bits into 16. Similarly, we can assign class object references to references to a base class, but not the other way around without casting. Given this notion of assignment, and an actual method call, how does Java decide which method to call? First of all, it finds all methods that have the correct name, the correct number of parameters, and parameters that are of types that can be assigned the values of the arguments. If only one method matches, then that is the method that is invoked. If there's more than one method in the set under consideration, then the compiler goes through and finds methods for which all the parameter types are assignable to another method's parameter types in the set, and removes that other method from the set of methods being considered. The method removed is considered "less specific". If the result of this process is a single method, then that method is invoked. If there's more than one method left, the call is ambiguous. To illustrate these ideas, consider another example: public class test2 { public static void f1(int i, int j) {} public static void f1(int i, short j) {} public static void f2(long i, long j) {} public static void f2(int i, int j) {} public static void f3(short i, short j) {} public static void f4(double i, float j) {} public static void f4(float i, double j) {} public static void main(String args[]) { int i = 0; short s = 0; f1(i, s); f2(i, s); f3(i, s); f4(i, s); } } The f1() call invokes f1(int, short) and is an exact match. The f2() call invokes f2(int, int) because f2(int, int) has parameter types that are assignable to f2(long, long) and f2(long, long) is therefore removed from the set. The f3() call is an error because an int for the first parameter cannot be assigned to a short. The f4() call is ambiguous because both methods can be called and neither can be removed from the set of possible methods to call because neither has parameter types assignable to the other. Coming back to C++ for a moment, it's fair to say that the equivalent argument matching rules in that language are significantly more complicated, reflecting a more complex language in general. For example, consider a case like: class String { public: String(char); }; where a constructor is defined to create a String from a character. In C++, usage like: String s(37); is valid, with the integer constant 37 being demoted to a char and then the constructor invoked. Whether a user intended this or not is not clear, given that usage such as: String s(12345); is a problem when chars are 8 bits. There's no magic formula for avoiding problems with method overloading, except perhaps to follow the general rule of avoiding cleverness. If a reader of your code can't quickly tell which method is invoked in a given case, then it might be worth reworking the code or at least adding a comment about its operation. INTRODUCTION TO APPLET PROGRAMMING PART 2 - DRAWING In previous issues we gave a simple example of an applet, and talked about the handshaking that goes on between an applet and the applet viewer or Web browser. As you recall, an applet is not a standalone Java program of the sort we've presented examples of here, but instead is a program that runs in a particular context, invoked via a Web browser or applet viewer program. We will continue our discussion by talking about drawing in an applet, things like lines and boxes and colors and fonts. To illustrate these ideas, let's look at an actual applet: import java.applet.*; import java.awt.*; public class test1 extends Applet { public void paint(Graphics g) { g.setColor(Color.red); g.fillOval(20, 20, 350, 200); g.setColor(Color.green); g.setFont(new Font("Helvetica", Font.ITALIC, 36)); g.drawString("This is a test", 80, 120); //g.setColor(Color.blue); g.setColor(new Color(0, 0, 223)); g.drawRect(20, 20, 350, 200); } } that is invoked via a browser or applet viewer using the HTML code: The parameters passed in to the applet set the bounding box (400 x 400 in this example) within which the applet will function. As we've discussed previously, an applet has no main() method, and the paint() method is part of the handshaking protocol for an applet. paint() is called when the applet needs to be drawn. The first thing that paint() does is to set a color for drawing. A color like "red" is a static data member of the Color class found in the Abstract Windowing Toolkit (AWT) in Java. It's also possible to specify your own color, as we illustrate later in the example: g.setColor(new Color(0, 0, 223)); where (0, 0, 223) are red/green/blue values 0-255. This particular color is a dark shade of blue. After setting the color, we draw a filled oval, starting at position (20, 20) relative to the bounding box we've established. The oval has a width of 350 and a height of 200. We now have a red oval on the screen, and we change the drawing color to green and draw some text. In this example, the Helvetica font is used and the text is drawn in italics using 36-point letters. The string originates at (80, 120) in the bounding box. Finally, we draw a box around the oval, using the color we've created from RGB values. The Graphics class in java.awt has a variety of methods for drawing lines, rectangles, ovals, polygons, and strings, with or without filling. There are also various methods for getting and setting colors and fonts. The Color class has a set of standard colors defined, and methods for creating your own colors or querying properties of existing colors. The Font class has similar methods for fonts, and there is also a FontMetrics class for determining the metrics of a specified font, such as might be used to compute the width of a string displayed in a given font. PERFORMANCE - PRIMITIVE TYPES VS. WRAPPERS In Java all class types are derived from the base class Object. Primitive types such as int or double are not class types and do not have this property. But they do have class type wrappers, that can be used to represent the primitive type and hence plug in to the Object hierarchy. For example, the wrapper for int is Integer: Integer x = new Integer(37); Object p = x; In this example we've taken an integer constant (37) and created a class object instance to represent this value. The object instance can be assigned to an Object reference and manipulated in various ways. Wrappers have some overhead associated with them. They offer generality at the cost of inconvenience in digging out the value: int i = ((Integer)p).intValue(); and there are some space costs as well. To more closely examine this latter point, we can write a program that allocates a vector of ints or int wrappers, and compute the size of each vector element: public class test1 { public static final int N = 25000; public static long freemem() { System.gc(); return Runtime.getRuntime().freeMemory(); } // ints without wrappers public static void test01() { long start_mem = freemem(); int vec[] = new int[N]; for (int i = 0; i < N; i++) vec[i] = i; long end_mem = freemem(); long n = (start_mem - end_mem) / N; System.out.println("bytes per element = " + n); } // ints with wrappers public static void test02() { long start_mem = freemem(); Integer vec[] = new Integer[N]; for (int i = 0; i < N; i++) vec[i] = new Integer(i); long end_mem = freemem(); long n = (start_mem - end_mem) / N; System.out.println("bytes per element = " + n); } // driver public static void main(String args[]) { test01(); test02(); } } This program uses a system method freeMemory() that returns the amount of memory currently free. We force a garbage collection via System.gc() to make the figure more reliable. As we mentioned in issue #004, this technique for determining memory use per element should be used cautiously. When we run this program, it reports 4 bytes used per element without wrappers, and 16 per element with a wrapper. A wrapped double reports as 24 bytes per element, with the actual double value as 64 bits (8 bytes). The space overhead of wrappers goes to support things like garbage collection. Wrappers have considerable advantages in that primitive types can be treated in a way similar to class types. See for example the discussion on page 243 of Arnold & Gosling's book "The Java Programming Language" (Addison-Wesley). But they do take extra space and time, which may be an issue in some circumstances. 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