Java Break 2
Volume Number: 12
Issue Number: 6
Column Tag: Getting Started
More Java Basics
By Dave Mark
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
Last month, we started exploring Java, Sun’s object-programming language that has
exploded in popularity over the last year. As a reminder, Java is similar to C++, but
with some very important differences. The Java syntax is just like C++, but without
the pointer syntax. The Java environment that runs on your machine is
multi-threaded, with a low-priority thread that does automatic garbage collection.
Your Java source code will reside in a file ending with the .java extension. Your
Java source code will implement a class, or a series of classes. Depending on your
development environment, you will compile the classes into a stream of Java
byte-code, which will get stored in a .class file, in a series of .class files, in a .zip
file, or, in some cases, in a double-clickable application file.
The .class file is designed to hold a single class. If you build a bunch of .class
files, you could pay a severe penalty in wasted hard drive space. For example, my
1-gig hard drive has a minimal file size of 17K. If I build 100 .class files, each of
which is filled with 100 bytes of byte-code, I’ll end up using 1700K of hard drive
space to store 10,000 bytes of byte-code. Not very efficient, eh?
The solution to this problem is the .zip file. The .zip lets you combine a set of
classes into a single file of byte-code. Since the .zip format is based on the .zip
compression format from the PC universe, you can use a zip utility (like UnZip) to
peruse the classes in a .zip file.
To run your byte code, you’ll need a byte-code interpreter. There are several
options for doing this. Your development environment most likely came with some
form of Java virtual machine. It might be called “javai”, “Applet Runner”, “Applet
Viewer”, or something else. The point is, the virtual machine knows how to turn your
generic Java byte-code into the equivalent machine code specific to your platform.
There are Java virtual machines written specifically for the PowerMac, and Java
virtual machines written for 680x0, x86, and Unix platforms as well. The first
virtual machines came from Sun. Other vendors are writing their own. Check with
your development environment for details on your virtual machine.
Java Reference Basics
Our first Java program this month demonstrates an important and potentially
confusing difference between Java and C++. As stated earlier, Java doesn’t support
pointers. When you create an object, the variable you associate with the object
instance is known as a reference. This example should make this clear.
If you are using CodeWarrior or Caffeine, create a new project file using the
appropriate Java stationery. I’m using the CodeWarrior droplet stationery, so my
project was named reference.µ.
The CodeWarrior environment ships with a bunch of stationery, including one for
Java applets and one for Java droplets. The Java applets stationery lets you create an
applet designed to be launched from an HTML file. This is pretty standard stuff and
will be supported by most every Java development environment you run into.
The droplet stationery is both cool and different. It lets you turn your Java code
into a standalone application, complete with 4-byte creator code and its associated
'BNDL' resources. And if you drop a file or set of files onto the droplet, the names of
the files get passed to main() via the argv parameter. I’ll present a small example of
this later in the column.
Once your project file is set up, create a new source code file named
reference.java and type this source code into the file:
public class reference
{
public static void main( String argv[] )
{
String s1 = "Sample String";
String s2 = "Sample String";
String s3 = new String(s1);
if ( s1 == s2 )
System.out.println( "s1 is the same object as s2" );
else
System.out.println("s1 is not the same object as s2");
if ( s1 == s3 )
System.out.println( "s1 is the same object as s3" );
else
System.out.println("s1 is not the same object as s3");
}
}
Compile and run the program. Here’s the results you should see in your stdout
window:
s1 is the same object as s2
s1 is not the same object as s3
Let’s take a walk through the source. These three lines declare references to
String objects:
String s1 = "Sample String";
String s2 = "Sample String";
String s3 = new String(s1);
The first line creates a reference named s1 and also creates a new String object,
initializing it with the literal “Sample String”. The second line also creates a
reference, this one named s2. The question here is, was a new object created? The
answer is no. The compiler checks to see if a literal with the value “Sample String”
already exists. Since such a literal does exist, the compiler doesn’t bother creating a
new one. It just creates the new object reference (s2) and makes it refer to the
original literal. Since there is no way to modify a literal, this strategy is pretty
sure-fire. Since pointers don’t exist in Java, the compiler has more freedom in
allocating memory for objects.
The third line of the set uses new to force the allocation of a new String object.
The String reference s1 is passed as a parameter to the String constructor. So we end
up with three String references: s1 and s2 both refer to the same String object, and
s3 points to a second String object.
To verify this theory, the first if-else statement uses the == operator to test if
s1 is the same as s2. Note that this tests whether s1 and s2 refer to the same object.
As proof, the result of the first if-else is:
s1 is the same object as s2
The second if-else compares s1 to s3. Since we used new to force the allocation of
a new String object, it is no surprise that the second if-else produces this result:
s1 is not the same object as s3
Take a few minutes to review the String methods; you’ll find them in the API
Documentation folder in the file java.lang.String.html. Pay specific attention to
the compareTo(), equals(), and equalsIgnoreCase() methods.
Copying an Object
Before we move on to our second example, let’s talk about copying objects for a
moment. I was reading through my pile of Java books when I noticed an interesting
discrepancy. Several of the books specified that to duplicate an object, you should use
the copy() method, inherited from java.lang.Object. Alternatively, some sources
recommended that you use the clone() method, also inherited from
java.lang.Object.
Being a curious son-of-a-gun, I wheeled over to Netscape and opened up
java.lang.Object.html (in the folder API Documentation) to look for clone() and
copy(). As it turns out, copy() isn’t there and clone() is there, but marked as
protected and couldn’t be called from our main() class above.
So what the heck was going on here? After a few phone calls and emails to my
Java buddies, I found out that copy() was dropped from the Java API between beta 1
and beta 2 of Java. I also found out that the clone() method was changed to protected
and that a new interface (we’ll talk about Java interfaces in a future column) was
created, called the cloneable interface. Basically, if you want your objects to be
cloneable, they need to implement the cloneable interface. To learn more about this,
check out the file CloneNotSupportedException.html and this URL:
http://java.sun.com/JDK-beta2/changes.html
The point of all this isn’t to push the cloneable interface. I was just trying to
save you from going through the head-banging exercise I just went through trying to
figure out why copy() and clone() weren’t working as they were described in the
books. But if you want to learn how to make your objects cloneable, well, go right
ahead...
Figure 1: The Preferences dialog from the Hello droplet
A Quick Droplet
Our second example is a droplet, built using CodeWarrior. Basically, the droplet is an
application that sends the embedded classes to the virtual machine. If any files are
dropped on the droplet, their names are sent to main() in the argv parameter.
To create a droplet, create your project using the droplet stationery. Copy the
resource file from the example “HelloWorld” droplet and edit it to change the creator
signature and signature resource. Next, edit the project preferences to reflect the
application’s file name, the name of your class, and your creator (Figure 1).
Here’s the droplet source code for the Hello droplet (note that the class is called
HelloWorld but the droplet is called Hello):
public class HelloWorld
{
public static void main(String argv[])
{
if (argv.length == 0 )
System.out.println("You launched Hello " +
"without dropping anything on it.");
else
{
System.out.println("You launched Hello " +
"dropping the following things:");
for(int i = 0; i
System.out.println("Arg[" +
i + "]=" + argv[i]);
}
}
}
Basically, this code prints one message if the droplet is launched without any
files dropped on it, or else prints the list of files dropped on the droplet.
Here’s the result of launching the Hello droplet without any files dropped on it:
You launched Hello without dropping anything on it.
Here’s the result when I dropped three files on the droplet:
You launched Hello dropping the following things:
Arg[0]=/Macintosh%20HD/Test%20Files/File1
Arg[1]=/Macintosh%20HD/Test%20Files/File2
Arg[2]=/Macintosh%20HD/Test%20Files/File3
Note that the %20 in the string represents ASCII character 32, which is the space
character. 20 in hex is 32.
Our First Applet
Before we go, here’s a taste of things to come: our first official applet. As mentioned in
last month’s column, a Java applet is a Java class that is derived from the class
java.applet.Applet. The java.applet.Applet class is described in the file
java.applet.Applet.html. Take a few minutes to look this page over.
Our first applet takes advantage of the packages java.awt.Graphics and
java.awt.Font. Take a few minutes to look over the files java.awt.Graphics.html
and java.awt.Font.html. In fact, it is probably a good idea to look through the files
in the API Documentation just to get an idea of what is in there.
Our applet will consist of a single class, called hello, and a single method, called
paint(). Our paint() overrides the standard paint() method that is part of the
standard applet. The default paint() method does nothing. Ours will use a sequence of
AWT (the Java equivalent to the Mac Toolbox) calls to draw the string “Hello, world!”
in a pane or in a window (depending on the browser).
Here’s the source code:
import java.awt.Font;
import java.awt.Graphics;
public class hello extends java.applet.Applet
{
public void paint( Graphics g )
{
Font f = new Font( "Chicago", Font.PLAIN, 36 );
g.setFont( f );
g.drawString( "Hello, world!", 0, 30 );
}
}
Notice that we don’t have a main() in our class. Instead, our class follows the
standard established for applets. The paint() method will be called when it is time to
draw our applet. The Font object will be created using the Chicago font and is set to
plain 36 point. The Font object is passed to the setFont() method, making that font,
style, and size current for the Graphics object g. Next, the string “Hello, world!” is
drawn in g at the coordinates (0, 30) using the method drawString().
To run this applet, you’ll need to first compile the source code into a class file (I
called my class file hello.class) and then build a bit of HTML to launch the applet.
Here’s my HTML code:
My test applet...


Of course, you might want to add more to your HTML, but this should do the trick.
Save the code as hello.html, and be sure hello.html and hello.class are in the
same folder. Now drag hello.html onto your applet runner. Theoretically, you
should see something like the window shown in Figure 2.
Figure 2. Running the applet using CodeWarrior
Till Next Month...
To me, having the advanced windowing toolkit (AWT) is like having a copy of
PowerPlant or the TCL. The framework takes care of all the administrative detail so I
can concentrate on filling in the details. In next month’s column, we’ll do just that.
We’ll poke around the nooks and crannies, exploring the AWT. See you then...