Java Newsletter by Glen McCluskey - Issue 1
Issue #001
February, 1996
Contents
- Introduction
- The Hello Program in C, C++, and Java
- Java Compilation and Execution
- Comparing C/C++ with Java Part 1 - Garbage Collection
- The Simplest Applet
- Performance
INTRODUCTION
This newsletter will be devoted to the Java programming language, with tutorial information about its features, program and applet examples, comparisons with C and C++, and so on. There will be less emphasis on the HotJava browser and on particular Java tools and environments.
Java is intended to be highly portable, but a mention should be made of the environment used for the examples presented in the newsletter. The Java Development Kit 1.0 from Sun will be used, running on Windows NT 3.51 on a 75 MHz Pentium PC. JDK 1.0 is available for downloading from Sun, and may differ in some respects from the beta versions of the JDK found on CD-ROMs bundled with popular Java books.
Speaking of books, the newsletter will not have regular book reviews, but one excellent book deserving of mention is the Lemay & Perkins one "Teach Yourself Java in 21 Days" (Sams.net/Macmillan, $40). It's got 500 pages of information on Java the language, with many examples and a CD-ROM included. It's a good book for learning Java.
If you have suggestions or comments about the content of the newsletter, please direct them to the address given below.
THE HELLO PROGRAM IN C, C++, AND JAVA
One way to start to understand the different approach that Java takes is to consider the hello program written in three different languages. In C, we have:
#include <stdio.h>
main()
{
printf("Hello, world\n");
return 0;
}
In C++, the equivalent would be:
#include <iostream.h>
main()
{
cout << "Hello, world\n";
return 0;
}
In Java, the program would be:
public class hello {
public static void main(String args[])
{
System.out.println("Hello, world");
System.exit(0);
}
}
The C and C++ versions are similar, but Java is noticeably different. Some of the differences are as follows.
- Java has no header files.
- Java "knows" about certain system features like the String class and the output stream System.out.
- There are no global functions as in C and C++, but instead every function must be a part (a "method") of some class. This includes main().
- main() is a method ("member function" in C++) of the hello class, but it does not operate specifically on object instances of that class, and instead is what is called a "class method" that is part of the class for packaging purposes. In C++ the equivalent would be a static member function.
- The hello class must be defined in a file called hello.java. There is no equivalent requirement in C or C++.
- To pass out an exit status from the program, Java uses System.exit(n). In C and C++, there is the library function exit(), or one can return a value from main().
The Java approach is different from some other popular languages. Whether it is "right" is a somewhat pointless thing to argue about. For example, there are good reasons for not having a programming language "know" about I/O facilities such as stream I/O, but also good reasons on the other side.
Once you have this program in a file, how would you compile and execute it? Using Sun's JDK 1.0, the steps would be:
$ javac hello.java
$ java hello
Running the Java compiler causes a file hello.class to be produced. This file is a compiled form of the original program, consisting of a sequence of what are called bytecodes. The interpreter is then called and given the name of a class to be interpreted.
JAVA COMPILATION AND EXECUTION
The Java compiler takes source code and converts it into an intermediate form known as bytecodes. These codes are independent of any machine language for a given processor such as the Intel 80x86 series or the Sun Sparc or the DEC Alpha. Rather, they are interpreted by the Java interpreter, that is, the interpreter looks at each bytecode and decides what to do with it. The Java interpreter must be ported to each hardware platform, but the bytecodes are portable across platforms.
This means that Java programs are portable across many platforms, and that a compiled program like hello.class can be executed on different hardware than it was compiled on.
The basic technology for generating bytecodes is not new. SmallTalk has used it for some years, and there was a version of Pascal in the 1970s that generated something called P-code that was similar to bytecodes.
We will say more about this approach and its performance characteristics later.
COMPARING C/C++ WITH JAVA - PART 1
In this section we will be discussing some of the differences between C/C++ and Java.
One of the big differences that a C/C++ programmer will notice right away is that Java has no malloc/free operators (C), or delete operator (C++). Instead, it uses a technique known as garbage collection.
The way garbage collection works is simply to clean up after you, by keeping track of all allocated blocks of storage and then reclaiming them when they're no longer needed. For example, with this code fragment:
public class hello {
static void f()
{
int x[] = new int[1000];
/* stuff */
}
static void g()
{
}
public static void main(String args[])
{
f();
g();
}
}
After the call to the f() method returns, the dynamically allocated x[] vector is garbage and is a candidate for reclaiming. Whether it is in fact reclaimed immediately is open to question; typically a garbage collector will start up only when it's needed, that is, when free memory is low. It's also possible to force garbage collection to be done at arbitrary points if desired.
What are the tradeoffs with using garbage collection? The big advantage is that it relieves the programmer of the chore of managing dynamic storage. Problems with memory leaks, freeing an allocated block twice (often resulting in a program crash), and so on are a thing of the past.
On the negative side, garbage collection will be slower than the C/C++ approach to storage management, especially if one takes advantage of the C++ techniques for defining specialized storage managers on a per-class basis. And when the actual garbage collector starts up, there may be a significant time hit as it goes through and reclaims all the storage no longer being used. Also, the runtime support within the Java interpreter will be more complex, because of the need to support the garbage collection facility.
So we might say that the Java memory management facilities are at a higher level than those in C or C++. This is an advantage for nearly all programs, while causing difficulties for a few applications of the real-time and embedded variety.
THE SIMPLEST APPLET
You may have heard the term "applet" in relation to Java and Web programming. What is an applet? Here is a very simple example of one, in a file called "applet.java":
import java.awt.*;
public class applet extends java.applet.Applet {
public void paint(Graphics g)
{
g.drawString("Hello world!", 25, 25);
}
}
This is not a standalone Java program (there is no main() method, for example). Rather, it's a program that must be run in a special context. There is a class called java.applet.Applet in the Java library and the class shown here inherits or derives ("extends") from it.
To execute this program, one needs to write some HTML (Hypertext Markup Language, used in Web programming), in a file called "applet.html":
<html>
<head>
<title>Hello World Example Applet</title>
</head>
<body>
<applet code="applet.class" width=150 height=150></applet>
</body>
</html>
The heart of this HTML is the line reading:
<applet code="applet.class" width=150 height=150></applet>
This line points at the compiled Java program ("applet.class"). A bounding box of 150x150 is established, within which the applet will run when a Web browser executes the HTML code and causes the applet code to be invoked.
Using JDK 1.0, the sequence for running this applet is:
$ javac applet.java
$ appletviewer applet.html
Some of the newer Web browsers can also run applets.
There are a lot of issues around applets that we will discuss at some point. One big one is security. Applets are intended to be downloaded and run by Web browsers, and so their behavior must be constrained to avoid problems with unruly applets causing local problems like wiping the disk clean.
PERFORMANCE
One of the things you may notice fairly quickly is that Java programs can run more slowly than their counterparts in other languages. For example, this Java program:
// sort numbers
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;
}
}
}
}
}
runs about 35-50 times slower than its C++ equivalent (with both JDK on Windows NT and on the Mac with Roaster):
// sort numbers
#include <stdio.h>
const int N = 6500;
short vec[N];
main()
{
int i;
int j;
short t;
// seed with descending order
for (i = 0; i < N; i++)
vec[i] = 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;
}
}
}
return 0;
}
This is due to the interpreted nature of Java and also due to the extra runtime checking that it does (such as for out of bounds vector subscripts). This particular sorting algorithm isn't very efficient (it has N**2 performance), but is illustrative of the point.
Consider another Java program:
// number crunching
class bm2 {
public static void main(String args[])
{
long i = 1200000L;
double d;
while (i > 0) {
d = Math.sqrt((double)i) + Math.log((double)i);
i--;
}
}
}
This program is only about 3 times slower than the equivalent C++:
// number crunching
#include <math.h>
main()
{
long i = 1200000L;
double d;
while (i > 0) {
d = sqrt(double(i)) + log(double(i));
i--;
}
return 0;
}
Why the difference? Well, in this second program, most of the time is taken in executing the math functions sqrt() and log(). These functions are typically implemented in hardware or via low-level software routines ("native" methods). If most of the time is spent in them (math functions are typically quite expensive), then the interpretive overhead required to handle the loop iterations and so on is less important.
In many cases this difference in performance isn't very important. For example, if a Java program or applet is highly interactive or operates across the Internet, then the delays incurred by waiting on humans and networks will be more important than the raw speed of the language.
It remains to be seen just how Java performance will shake out. There are several possibilities for improving it. One is to generate native code, but this works against the portability of Java applets and applications. Another similar technique that has been mentioned is a Java to C translator ("java2c"), but this also works against portability.
There is a technique called "just in time" compilation that is being considered. The technique involves doing dynamic compilation within the bytecode interpreter, so that the next time a bytecode is executed, the actual machine code for a given platform is substituted in its place.
ACKNOWLEDGEMENTS
Thanks to Thierry Ciot 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:
-------------------------
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