Info - Java FAQ
From: elharo@metalab.unc.edu Newsgroups: comp.lang.java.programmer,comp.lang.java.softwaretools,comp.lang.java.gui,comp.lang.java.help,alt.www.hotjava Organization: Cafe au Lait Followup-To: poster Subject: comp.lang.java FAQ Archive-name: computer-lang/java-faq/part1 Posting-Frequency: weekly Last-modified: 1997/10/06 Version: 1.6 URL: http://metalab.unc.edu/javafaq/javafaq.html
abstract?
int to an Integer? a float
to a Float?
for loops
have the same syntax in all four languages); but it is not based on any of those
languages, nor have efforts been made to make it compatible with them.
Java is sometimes referred to as C++ ++ --. The language was originally created because C++ proved inadequate for certain tasks. Since the designers were not burdened with compatibility with existing languages, they were able to learn from the experience and mistakes of previous object-oriented languages. They added a few things C++ doesn't have like garbage collection and multithreading; and they threw away C++ features that had proven to be better in theory than in practice like multiple inheritance and operator overloading. (There's still argument over whether they made the right choices. I tend to think they were correct to throw out operator overloading and probably correct to throw out multiple inheritance. For now let's just say that neither choice is likely to be reviewed soon.)
Even more importantly Java was designed from the ground up to allow for secure execution of code across a network, even when the source of that code was untrusted and possibly malicious. This required the elimination of more features of C and C++. Most notably there are no pointers in Java. Java programs cannot (at least in theory) access arbitrary addresses in memory.
Furthermore Java was designed not only to be cross-platform in source form like C, but also in compiled binary form. Since this is frankly impossible across processor architectures, Java is compiled to an intermediate byte-code which is interpreted on the fly by the Java interpreter. Thus to port Java programs to a new platform all that is needed is a port of the interpreter and a few native code libraries.
Finally Java was designed to make it a lot easier to write bug free code. Shipping C code has, on average, one bug per 55 lines of code. About half of these bugs are related to memory allocation and deallocation. Thus Java has a number of features to make bugs less common:
In 1989 Joy sold his Sun stock, invested heavily in Microsoft and moved out of mainstream Sun to Aspen, Colorado. By the early 90's Bill was getting tired of huge programs. He decided that he wanted to be able to write a 10,000 line program that made a difference. In late 1990 Bill wrote a paper called Further which outlined his pitch to Sun engineers that they should produce an object environment based on C++. Today Joy freely admits that C++ was too complicated and wasn't up to the job.
Around this time James Gosling (of emacs fame) had been working for several months on an SGML editor called "Imagination" using C++. The Oak language (now Java) grew out of Gosling's frustration with C++ on his "Imagination" project.
Patrick Naughton, then of Sun, now vice-president of technology at StarWave, started the Green Project on December 5th, 1990. Naughton defined the project as an effort to "do fewer things better". That December he recruited Gosling and Mike Sheridan to help start the project. Joy showed them his Further paper, and work began on graphics and user interface issues for several months in C.
In April of 1991 the Green Project (Naughton, Gosling and Sheridan) settled on smart consumer electronics as the delivery platform, and Gosling started working in earnest on Oak. Gosling wrote the original compiler in C; and Naughton, Gosling and Sheridan wrote the runtime-interpreter, also in C. Oak was running its first programs in August of 1991. Joy got his first demos of the system that winter, when Gosling and Naughton went skiing at Joy's place in Aspen.
By the fall of 1992 "*7", a cross between a PDA and a remote control, was ready This was demoed to Scott McNealy, Sun's president, in October. He was blown away. Following that the Green Project was set up as First Person Inc., a wholly owned Sun subsidiary.
In early 1993 the Green team heard about a Time-Warner request for proposal for a settop box operating system. First Person quickly shifted focus from smart consumer electronics (which was proving to be more hype than reality) to the set-top box OS market, and placed a bid with Time-Warner.
Fortuitously, Sun lost the bid. The Time-Warner project went nowhere, the same place it probably would have gone if Sun had won the bid. First Person continued work on settop boxes until early 1994, when it concluded that like smart consumer electronics settop boxes were more hype than reality.
Without a market to be seen First Person was rolled back into Sun in 1994. However around this time it was realized that the requirements for smart consumer electronics and settop box software (small, platform independent secure reliable code) were the same requirements for the nascent web.
For a third time the project was redirected, this time at the web. A prototype browser called WebRunner was written by Patrick Naughton in one weekend of inspired hacking. After additional work by Naughton and Jonathan Payne this browser became HotJava. The rest, as they say, is history.
Information in this section is primarily based on the first hand accounts of Bill Joy and Patrick Naughton (which don't always agree). No doubt other people have still different memories of what occurred. If you've got any more first hand information about what went on in the Green project I'd like to hear from you.
At the lowest level the advantage of Java to the web is that it provides a secure, cross-platform way for code to be executed. At a somewhat higher level Java adds several features to existing web sites:
Sun also published a 1.0.2 JDK for MacOS 7.5 on PowerMacs and 68030 (25 MHz and faster) and 68040 Macs. However it's dropped development for Macs in favor of Apple's own Macintosh Runtime for Java (MRJ) which is a better option for Mac users. Currently MRJ supports Java 1.0. Java 1.1 support is promised soon.
SGI's port of Sun's JDK 1.1.x to IRIX 5.3, 6.2, 6.3, and 6.4 is available at http://www.sgi.com/Fun/Free_webtools.html. An IRIX port of JDK 1.0 has mostly been completed by Simon Leinen.
A Linux port is in fairly good shape. See http://java.blackdown.org/java-linux.html.
IBM has ported Java to Windows 3.1, OS/2, and AIX. It is working on ports for MVS and OS/400. See http://ncc.hursley.ibm.com/javainfo/hurindex.html .
The OSF has ported the JDK 1.0.2 to Unixware, the Bull Estrella or other PowerPC running AIX4.1, X86 running DASCOM OSF/1 , the Digital Alpha running Digital UNIX 3.2, the HP700 series running HPUX 10.x, the NCR Globalyst (Pentium) running UNIX SysV, and Sony NEWS (MIPS) running Sony NEWS 6.1.1. See http://www.osf.org/mall/web/JDK/.
Other ports are underway for Nextstep, SunOS 4.1, the Amiga and possibly other platforms.
In the past new versions of Java have most often been made available first for Solaris. If you have to have the latest version as soon as it's released, or if you're developing "Bet your company" applications with Java, you should probably be running Solaris on a SparcStation. Otherwise, if you just want to learn the language, you can get away with an Intel based Windows 95 or NT machine with a lot of RAM.
Netscape 2.0 and later plays Java 1.0 applets on Windows NT, Windows 95, Solaris, SunOS 4.1, Linux and most other Unix platforms. Netscape 3.0 for the Mac also supports Java 1.0. Netscape 4.0 and earlier and Internet Explorer 3.0 and earlier do not support Java 1.1 to any significant extent, only Java 1.0. The only web browser that really supports Java 1.1 is Sun's HotJava.
Netscape 2.0 can even compile Java programs. (Netscape 3.0 cannot).
First download the classes.zip file from the Solaris distribution of the JDK. (You have to download the entire JDK. You can't get just the classes.zip file.) Next set your CLASSPATH environment variable to include the classes.zip file. For example, on Unix, if you put the file in /usr/local/lib/classes.zip, then you would set it like this:
sh: % CLASSPATH=$CLASSPATH:/usr/local/lib/classes.zip csh: % setenv CLASSPATH "$CLASSPATH:/usr/local/lib/classes.zip"You'll probably want to put this line in your .login or .cshrc file. Of course you'll need to adjust this to match where you've installed these files and to add any other classes you use. Finally you compile programs from the command line like this:
% netscape -java sun.tools.javac.Main HelloWorld.javaYou can always alias netscape -java sun.tools.javac.Main to just javac to make this more transparent.
You can also run command-line programs that don't use the AWT in the same way, like this:
% netscape -java HelloWorld.classYou can't use netscape -java to run programs that use the AWT, but you can of course play applets in Netscape..
A little further out in left field, it isn't even necessary to know Java to write Java programs. Intermetrics is beta testing an ADA-95 to Java byte code compiler. Other such cross-compilers are probably possible including ANSI Fortran-77, COBOL, and Basic. However the one most people probably want, a C/C++ to Java byte code compiler, is probably not possible due to Java's lack of pointers.
Java and JavaScript are about as closely related as the Trump Taj Mahal in Atlantic City is to the Taj Mahal in India. In other words Java and JavaScript both have the word Java in their names. JavaScript is a programming language from Netscape which is incorporated in their browsers. It is superficially similar to Java in the same way C is similar to Java but differs in all important respects.
main()
method. An applet is a Java class which extends java.applet.Applet.
A class which extends java.applet.Applet and also has a main()
method is both an application and an applet.
More generally and less technically an application is a stand-alone program, normally launched from the command line, and which has more or less unrestricted access to the host system. An applet is a program which is run in the context of an applet viewer or web browser, and which has strictly limited access to the host system. For instance an applet can normally not read or write files on the host system whereas an application normally can.
The actions of both applets and applications, however, can be controlled by SecurityManager objects. If you can change the SecurityManager that's used you can change what an applet or an application is and is not allowed to do. Thus these are not hard and fast differences, though this is normally how they separate out in practice.
For many more web sites see the Cafe au Lait links page at http://metalab.unc.edu/javafaq/links.html.
The second book I recommend
is Java
in a Nutshell: A Desktop Quick Reference for Java Programmers by
For people with no prior experience in programming I recommend Kris Jamsa's Java Now!, ISBN: 1-884133-30-4, $16.95, Jamsa Press.
None of these books cover Java 1.1. In fact as of this writing, few books truly cover Java 1.1 though several claim to. The best of the lot as of this writing seems to be Rogers Cadenhead's Teach Yourself Java 1.1 Programming in 24 Hours from Sams.net, ISBN 1-57521-270-6. This is a decent book introducing Java 1.1 programming to non-programmers. However it's quite basic, and coverage of the AWT is very limited.
For details about these and many more books see the Cafe au Lait books page at http://metalab.unc.edu/javafaq/books.html
boolean type has been added.)
However the implementation of the data types has been substantially cleaned up
in several ways.
int) Java specifies everything.
Here are the detailed primitive data types:
boolean
true and false only.
true and
false are defined constants of the language and are not the
same as True and False, TRUE and
FALSE, zero and nonzero, 1 and 0 or any other numeric value.
Booleans may not be cast into any other type of variable nor may any other
variable be cast into a boolean.
byte
short
int
long
float
Like all numeric types
floats may be cast into other numeric types (byte, short,
long, int, double). When lossy
casts to integer types are done (e.g. float to short)
the fractional part is truncated and the conversion is done modulo the length
of the smaller type.
double
char
Chars are not the same as bytes, ints, shorts or Strings.
sizeof isn't necessary
in Java because all sizes are precisely defined. i.e. an int is always
4 bytes. This may not seem to be adequate when dealing with objects that aren't
base data types. However even if you did know the size of a particular object,
you couldn't do anything with it anyway. You cannot convert an arbitrary object
into bytes and back again.
Strings are a reference
or object type, that is a instances of the class java.lang.String.
They are not null terminated and are not the same as an array of chars.
Arrays are also objects. Multidimensional arrays are created via arrays of arrays.
if,
else, for, while, do while
and switch statements. The syntax is identical to
C's. However all condition tests must return boolean values. Since non-boolean
assignment statements and arithmetic statements do not return a boolean value,
some of the more obfuscated condition tests in C are prohibited.
argv has become a string array commonly called
args and args[0] is the first command line argument,
not the name of the program. The other arguments are all shifted one to the left
from where they'd be in C or C++.
/*
This is a comment */ comment from C and the // This is a C++ comment However comments that begin
with a /** are special. These comments should only be used before
a method or class declaration. They indicate that the comment should be included
in automatically generated documentation for that declaration.
Superclasses of a class
are indicated with the extends keyword rather than with a :.
Methods must be defined inside the class to which they belong. They may not be declared inside the class and defined outside the class as is common in C++.
Features removed that make
Java easier to read and understand than C++ include #define, typedef,
operator overloading, enum, unions and structs.
The main feature removed to make Java safer and more robust than C++ is pointer arithmetic.
Other features removed include global variables, standalone functions (everything is a method), friend functions (Everything in a package is a friend of everything else in the package.) and non-virtual functions.
A number of features have been added to Java to make it safer including true arrays with bounds checking, garbage collection, concurrency, interfaces (from Objective C) and packages. There is no need to explicitly allocate or free memory in Java.
Vector
class in java.util. It can do anything a linked list can do and a
little more and saves you a lot of coding which, after all, is the point of OOP
and the class library. However it is array based so insertions or deletions from
the middle of a Vector are not as efficient as with a true linked list.
Long answer: Object variables in Java are all references. A reference acts like a pointer in most other languages. (Though they're handles, not pointers, in most Java implementations. The notable exception is Microsoft's.) The main difference is that you can't do pointer arithmetic on references. Therefore wherever you'd use a pointer to an object in C++, in Java you should just use the object itself.
On the other hand the primitive
data types (int, float, double, char, byte, short, long and boolean)
are not references. If you want to get a reference to one of these you need
to wrap it in a class first. Java provides ready-made type-wrapper classes in
the java.lang package for Boolean, Character, Integer,
Double, Float, and Long. Bytes and shorts
can be stored in the Integer class as well. Java 1.1 adds Byte,
Short, and Void classes too.
scanf(), fscanf() and sscanf() functions,
Pascal's read() and readln() function, or Fortran's
READ* function. In particular there's no one method that lets you
get input from the user as a numeric value.
However, roughly equivalent
functionality is scattered across several classes. You first read an input line
into a String using DataInputStream.readline() or
BufferedReader (in Java 1.1)
Next use the StringTokenizer
class in java.util to split the String into tokens.
By default StringTokenizer splits on white space (spaces, tabs,
carriage returns and newlines), but this is user definable.
For example,
import java.util.StringTokenizer;
class STTest {
public static void main(String args[]) {
String s = "9 23 45.4 56.7";
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}
prints the following output:
9 23 45.4 56.7Finally you convert these tokens into numbers using the type wrapper classes as described in the next question.
Integer, Float, Double
and Long type wrapper classes as indicated by the following code
snippet:
class ConvertTest {
public static void main (String args[]) {
String str;
str = "25";
int i = Integer.valueOf(str).intValue();
System.out.println(i);
long l = Long.valueOf(str).longValue();
System.out.println(l);
str = "25.6";
float f = Float.valueOf(str).floatValue();
System.out.println(f);
double d = Double.valueOf(str).doubleValue();
System.out.println(d);
}
}
There are no equivalent Short
and Byte classes in Java 1.0. There are in Java 1.1. For shorts and
bytes use the Integer class but use the byteValue()
or shortValue() methods instead.
Chapter 19 of my book Java Secrets discusses the Java Native Interface in depth. (IDG Books, 1997, ISBN 0-764-58007-8, http://www.amazon.com/exec/obidos/ISBN=0764580078/cafeaulaitA/)
system() call (or your OS's equivalent) to execute the
java interpreter with appropriate command line arguments.
In Java 1.1 the Java Native Method Interface in combination with the Invocation API allows native applications to load and access the Java virtual machine.
In Java 1.1 a serialization
interface has been added to the language. However only objects that explicitly
implement the java.io.Serializable interface can be serialized.
Instead you should declare an interface which declares the function you want to pass; for example
public interface Comparable {
public abstract int compare(Object o1, Object o2);
}
Then declare that your method
takes an object of this type. For example,
public void sort(Object[] o, Comparable c) {
boolean done = false;
while (!done) {
done = true;
for (int i = 0; i < o.length - 1; i++) {
if (c.compare(o[i], o[i+1]) < 0) {
swap(o[i], o[i+1]);
done = false;
}
}
}
Each class you want to compare
then needs its own class which implements Comparable. For example,
public class StringCompare implements Comparable {
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
return s1.compareTo(s2);
}
}
It helps that Object
is a superclass for all object types.
Recently Sun released the $195 payware HotJava HTML Component. This is a Java bean which parses and renders HTML. In requires Java 1.1 or later.
There is at least one semi-free third party solution. Data Technology's Ice Browser (http://www.bgnett.no/datatech/ICEBrowser/index.html) can handle most HTML 3.2 constructs, though I haven't had a chance to test it personally yet. Ice Browser also requires Java 1.1.
import sun.audio.*;
import java.awt.*;
import java.io.*;
public class SoundPlayer extends Frame implements FilenameFilter {
Button openButton = new Button("Open");
Button playButton = new Button("Play");
Button loopButton = new Button("Loop");
Button stopButton = new Button("Stop");
Label filename = new Label(" ");
File theFile = null;
AudioData theData = null;
InputStream nowPlaying = null;
public SoundPlayer() {
super("Sound Player");
resize(300, 200);
Panel north = new Panel();
north.setLayout(new FlowLayout(FlowLayout.LEFT));
north.add(new Label("File: "));
north.add("North", filename);
add("North", north);
Panel south = new Panel();
south.add(openButton);
south.add(playButton);
south.add(loopButton);
south.add(stopButton);
add("South", south);
}
public static void main(String[] args) {
SoundPlayer sp = new SoundPlayer();
sp.show();
}
public void open() {
FileDialog fd = new FileDialog(this, "Please select a .au file:");
fd.setFilenameFilter(this);
fd.show();
try {
theFile = new File(fd.getDirectory() + "/" + fd.getFile());
if (theFile != null) {
filename.setText(theFile.getName());
FileInputStream fis = new FileInputStream(theFile);
AudioStream as = new AudioStream(fis);
theData = as.getData();
}
}
catch (IOException e) {
System.err.println(e);
}
}
public void play() {
stop();
if (theData == null) open();
if (theData != null) {
AudioDataStream ads = new AudioDataStream(theData);
AudioPlayer.player.start(ads);
nowPlaying = ads;
}
}
public void stop() {
if (nowPlaying != null) {
AudioPlayer.player.stop(nowPlaying);
nowPlaying = null;
}
}
public void loop() {
stop();
if (theData == null) open();
if (theData != null) {
ContinuousAudioDataStream cads = new ContinuousAudioDataStream(theData);
AudioPlayer.player.start(cads);
nowPlaying = cads;
}
}
public boolean action(Event e, Object what) {
if (e.target == playButton) {
play();
return true;
}
else if (e.target == openButton) {
open();
return true;
}
else if (e.target == loopButton) {
loop();
return true;
}
else if (e.target == stopButton) {
stop();
return true;
}
return false;
}
public boolean accept(File dir, String name) {
name = name.toLowerCase();
if (name.endsWith(".au")) return true;
if (name.endsWith(".wav")) return true;
return false;
}
}
This example is taken from
Chapter 10 of Java Secrets, available from amazon (http://www.amazon.com/exec/obidos/ISBN=0764580078/cafeaulaitA/)
and various independent bookstores. It's published by IDG Books, ISBN number 0-764-58007-8.
Chapters 8-17 cover various of the sun packages including sun.audio. (Chapters
1-7 cover the internals of Java like byte code and class files. Chapter 19 and
20 cover platform dependent Java including native methods.)
An applet can also get
references to all other applets on the same page using the getApplets()
method of java.applet.AppletContext. Once you've got a reference
to an applet, you can communicate with it by using its public members.
It is conceivable to have applets in different virtual machines that talk to a server somewhere on the Internet and store any data that needs to be serialized there. Then, when another applet needs this data, it could connect to this same server. Implementing this is non-trivial.
A number of organizations have developed special http servers that allow applets or other clients to run Java programs on the server in a secure environment. Most notably Sun's Java Web Server implements a servlet interface for this purpose. The W3C's JigSaw implements a similar idea called resource objects.
final?final class
can no longer be subclassed. Mostly this is done for security reasons with basic
classes like String and Integer. It also allows the
compiler to make some optimizations, and makes thread safety a little easier to
achieve.
Methods may be declared
final as well. This means they may not be overridden in a subclass.
Fields can be declared
final, too. However, this has a completely different meaning. A
final field cannot be changed after it's initialized, and it must include an
initializer statement where it's declared. For example,
public final double
c = 2.998;
It's also possible to make
a static field final to get the effect of C++'s const
statement or some uses of C's #define, e.g.
public static final double c = 2.998;
static variable
in a particular object, the value of that variable changes for all instances of
that class.
Static methods can be referenced
with the name of the class rather than the name of a particular object of the
class (though that works too). That's how library methods like System.out.println()
work. out is a static field in the java.lang.System
class.
abstract?abstract keyword like this:
public abstract class
Container extends Component {
Abstract classes may contain
abstract methods. A method declared abstract is not actually implemented
in the current class. It exists only to be overridden in subclasses. It has
no body. For example,
public abstract
float price();
Abstract methods may only be included in abstract classes. However, an abstract class is not required to have any abstract methods, though most of them do.
Each subclass of an abstract
class must override the abstract methods of its superclasses or itself be declared
abstract.
For more details, see section 8.1.2.1 of the Java Language Specification.
For example suppose you're
writing an inventory database. The inventory may include many different items
of many different types and classes. However each item in the warehouse needs
to be able to tell you its price. Normally you would implement this by having
each class extend a common superclass. However that's not always convenient.
Instead you can declare an interface called Price with a price()
method like this:
public interface Price {
public float price();
}
Any class which implements
the Price interface must contain a method with the signature public
float price(). The code of the price() method is included
separately in each separate class which implements Price, not in
the Price interface itself.
Different classes in your
warehouse can each implement the Price interface like this:
public class Monopoly extends BoardGame implements Price {
// other methods
public float price() {
return 14.95;
}
}
When other code is passed
an object, it can test whether the object implements Price with the
instanceof operator. For example,
if (o instanceof
Price) System.out.println("Subtotal is " + o.price());
In fact, interfaces can
be used to tag objects. The java.rmi.Remote interface declares
no methods. Its sole purpose is to indicate that an object is a remote object.
In general, sub-interfaces of java.rmi.Remote will declare remote
methods, however. For example,
public interface Hello extends java.rmi.Remote {
public String sayHello();
}
public class HelloImpl extends UnicastRemoteServer implements Hello {
public String sayHello() {
return "Hello";
}
}
For more information about
the java.rmi package, see http://chatsubo.javasoft.com/current/rmi/index.html
or Chapter 14 of my book, Java Network Programming, from O'Reilly
& Associates.
Extensions are planned for the class library though. In particular Sun is working on extensions for 3D, multimedia, telephony, and improved graphics.
int to an Integer? a float
to a Float?int or float to an object such as an
Integer or a Float. However the proper way to do this
isn't very hard. Instead do
int x = 5;
myInteger = new Integer(x);
print(). Note that
some of the classes like DataOutputStream have unoverloaded methods like writeInt()
and writeByte().
Java does have references. A reference is an abstract identifier for an object. It is not a pointer. A reference tags a particular object with a name in the Java virtual machine so that the programmer may refer to it. How exactly the virtual machine implements references at the level of machine code is VM-dependent and completely hidden from the programmer in any case. Most VMs including Sun's use handles, not pointers. A handle is a pointer to a pointer. At the level of machine code in the CPU a reference is an address in memory where the address of the object is stored. This way the objects can be moved around in memory and only the master pointer needs to be updated rather than all references to the object. This is completely hidden from the Java programmer, though. Only the implementer of the virtual machine needs to worry about it. Indeed, this is not the only way references can be implemented. Microsoft's VM actually does use pointers rather than handles. Other schemes are possible.
import java.awt.Point;
class changePoint {
public static void main(String args[]) {
Point p1 = new Point(0, 0);
changePoint(p1);
System.out.println(p1);
}
static void changePoint(Point p) {
p.x = 38;
p.y = 97;
}
}
It prints:
java.awt.Point[x=38,y=97]Therefore the point has been changed. However the reference, which is what was really passed, has not been changed. To see that consider the following program.
import java.awt.Point;
class dontChangePoint {
public static void main(String args[]) {
Point p1 = new Point(0, 0);
dontChangePoint(p1);
System.out.println(p1);
}
static void dontChangePoint(Point p) {
p = new Point(38, 97);
}
}
It prints:
java.awt.Point[x=0,y=0]What happened in this example was that a copy of the reference
p1 was passed to the dontChangePoint()
method. A new Point object was then assigned to that copy. However
this did not change the old reference in the main method. In the previous example
the reference p in the changePoint() method and p1
in the main() method both referred to the same object. In this example
p and p1 refer to different objects after the new Point
is assigned to p.
PERFORM or BECOME in Java 1.0. These
would probably open security holes. There are workarounds for some things you
might want to do using interfaces.
In Java 1.1 the Core Reflection
API and the java.lang.reflect package provides most of the
functionality you need. However this API is partially unavailable to applets
due to security issues.
Components are subclasses
of java.awt.Component. Examples of components include buttons,
scrollbars, text fields, frames, windows, dialogs, panels, canvases, and checkboxes.
One subclass of java.awt.Component is java.awt.Container.
A container is a component which can hold other components. Examples of containers
include Frames, Windows, Dialogs, Panels and Applets. An applet is a subclass
of Panel. Panel is a subclass of Container.
Container is a subclass of Component. Therefore an applet is both
a container and a component.
When the user clicks the mouse, types on the keyboard, drags and drops, or does any of a few other things, the operating system produces an event. This event is passed to Java, and the Java runtime tries to figure out which component the event was intended for.
The Java runtime then passes
that event to the handleEvent(Event e) method of some Component.
The Component's handleEvent() method contains a big
if-else statement to look at the type of event and respond appropriately. What
the handleEvent() method does depends on the type of component.
Generally some events are ignored and other events are passed to methods that
know how to respond to those events. For instance a MOUSE_DOWN event is passed
to mouseDown(). The table below shows the events the default handleEvent()
can deal with. When one of these events occurs, handleEvent() passes
it and various other information to the specified method.
Event Method Called -------------------------------------------------------- Event.MOUSE_ENTER: mouseEnter(evt, evt.x, evt.y) Event.MOUSE_EXIT: mouseExit(evt, evt.x, evt.y) Event.MOUSE_MOVE: mouseMove(evt, evt.x, evt.y) Event.MOUSE_DOWN: mouseDown(evt, evt.x, evt.y) Event.MOUSE_DRAG: mouseDrag(evt, evt.x, evt.y) Event.MOUSE_UP: mouseUp(evt, evt.x, evt.y) Event.KEY_PRESS: keyDown(evt, evt.key) Event.KEY_ACTION: keyDown(evt, evt.key) Event.KEY_RELEASE: keyUp(evt, evt.key) Event.KEY_ACTION_RELEASE: keyUp(evt, evt.key) Event.ACTION_EVENT: action(evt, evt.arg) Event.GOT_FOCUS: gotFocus(evt, evt.arg) Event.LOST_FOCUS: lostFocus(evt, evt.arg)By default each of these methods does nothing. Furthermore, by default all other events do nothing. If you want to do something when one of the above events occurs in your component, subclass the component and override the appropriate method. For example, to create a
Canvas
that prints the message "Don't Tread on Me!" every time the user clicks on it,
use the following subclass of Canvas:
public class noTread extends Canvas {
public boolean mouseDown(Event e, int x, int y) {
System.out.println("Don't Tread on Me!");
return true;
}
}
Button, Choice,
TextField, and Checkbox are special because of how they're
implemented as native widgets. They do not see MOUSE_DOWN, MOUSE_UP,
KEY_PRESS, and other such events. Rather they receive one event and
one event only: Event.ACTION_EVENT. When a Button is
pressed, the user hits return in a TextField, the user double clicks
on a List item, clicks a Checkbox, or selects from a
Choice, an ACTION_EVENT is generated. If you haven't
overridden handleEvent(), this is passed to the action()
method of the component's container. These four components are the only things
which generate ACTION_EVENTs. No other component will generate an
ACTION_EVENT. (Menu items, which are not components but are implemented
as native peers, also generate action events.)
Each event handler method,
including handleEvent(), returns true if the event
was completely handled and false if it was not. If false
is returned, then the event is passed to the component's container to see if
the container wants to process the event.
If you want to respond
to a different set of events, you must override handleEvent().
You can either completely replace it or just add the extra events you want to
handle and then return super.handleEvent() for other types of events.
For example to print all the events as they happen in your applet you might
use this handleEvent() method:
public boolean handleEvent(Event e, int x, int y) {
System.out.println(e);
return super.handleEvent(e, x, y);
}
mouseDown(), mouseUp(),
keyDown(), and all the other event methods would still be called
by the superclass. If you don't handle an event in the handleEvent()
method, return super.handleEvent(e) to give your superclass an opportunity
to process the event. In this case, we've handled the event but not completely
so we still let the superclass process it by returning super.handleEvent(e,
int x, int y).
The return value of handleEvent()
is important. If handleEvent() returns true, that means the event
has been fully digested and no further processing is needed. On the other hand
if handleEvent() returns false, then the event is passed to the
component's container to be handled.
Note that this all works
for any component at all. You'll most commonly override these methods in a subclass
of Applet or perhaps Frame. However the same methods
and techniques apply to all subclasses of Component.
The API documentation confuses the issue because of the ambigious use of the word parent. In object-oriented circles the word parent usually refers to the superclass. However in the context of the AWT, the word parent refers to the container that contains a component. Thus in the statement:
returnthe word parent means the component's container, not its superclass.trueif the event has been handled and no further action is necessary;falseif the event is to be given to the component's parent
You must distinguish between
the container/component hierarchy and the inheritance hierarchy. By default,
the way an event travels has nothing to do with the inheritance
hieararchy. If you override an event handling method, then events passed to
that method will not be passed to a component's superclass unless you specifically
ask them to be. However, in most cases your handleEvent() method
will return super.handleEvent() to give the superclass a crack
at handling the event rather than simply returning false.
To sum up, when you write
a subclass of Component, you can either respond to specific events
by overriding the methods that correspond to those events, such as mouseDown();
or you can respond to all events by overriding handleEvent(). Each
of your event handling methods must return a boolean. Return true
when an event has been completely processed, and return false when
you want the component's container to try to handle the event. When overriding
handleEvent(), you also have an option to return super.handleEvent()
to ask the superclass to handle the event and decide whether or not to pass
it along to the component's container.
Instead if you need to
do clipping, create separate offscreen Images
for each clipping region. Each Image should be the size of the
clipping region you desire. Draw into those offscreen images, and then copy
them onto the appropriate section of the of your applet window using java.awt.Graphics.drawImage().
Some coordinate conversion will almost certainly be necessary.
If the background image
isn't a simple color then you'll first need to copy the appropriate part of
that image to your offscreen clipping Image. You can do this by drawing your
background Image into your offscreen region with Graphics.drawImage()
and a suitable shifting of coordinates.
This all works for rectangular
regions only since all Images are rectangular. More complicated
geometries can be faked if all but one section contains only simple colors.
public void paint(Graphics g) {
int x1=5;
int x2=278;
int y1=8;
int y2=93;
// Draw a ten pixel thick line
for (int i = -5; i < 5; i++) {
g.drawLine(x1+i,y1+i,x2+i,y2+i);
}
}
This isn't perfect. The ends
of the line are excessively tapered. You really need to take the slope of the
line into account when incrementing x and y, but this should give you the idea.
If you're doing a lot of this, you can write a class or method to do it for you.
There are other hacks you
can use. For example, a thick line is essentially a filled rectangle. Therefore
you can calculate the endpoints of the rectangle and use fillPolygon()
to draw it.
The real solution is going to have to wait for a more complete graphics API for Java, possibly in Java 1.2.
These names are deprecated in Java 1.1. In Java 1.1 you should use SansSerif, Serif, and Mono instead which will be mapped to an appropriate font like Helvetica, Times, or Courier.
Whether fonts installed
on the client are available to Java is implementation depenedent. You can get
a String array of the names of the available fonts by calling the
getFontList() method from java.awt.Toolkit. For example,
String[] fonts =
Toolkit.getDefaultToolkit().getFontList()
FileInputStream(String) constructor and use one of
the various read() methods to read the data into an array of bytes.
For example the following program reads raw data from a file specified on the
command line. It then writes the same data to the standard output.
import java.io.*;
class ReadRawData {
public static void main (String args[]) {
boolean done = false;
byte b[] = new byte[1024];
int num_bytes = 0;
FileInputStream fin = null;
try {
fin = new FileInputStream(args[0]);
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("You have to give me the name of a file to open.");
System.exit(0);
}
catch (FileNotFoundException e) {
System.out.println("Could not open input file " + args[0]);
System.exit(0);
}
catch(IOException e) {
System.out.println("Error while opening input file" + args[0]);
System.exit(0);
}
catch (Exception e) {
System.out.println("Unexpected exception: " + e);
System.exit(0);
}
try {
num_bytes = fin.read(b);
}
catch(IOException e) {
System.out.println("Finished Reading: " + e);
done = true;
}
catch (Exception e) {
System.out.println("Unexpected exception: " + e);
System.exit(0);
}
while(!done) {
System.out.write(b, 0, num_bytes);
try {
num_bytes = fin.read(b);
}
catch(IOException e) {
System.out.println("Finished Reading: " + e);
done = true;
}
catch (Exception e) {
System.out.println("Unexpected exception: " + e);
System.exit(0);
}
if (num_bytes == -1) done = true;
} // end while
} // end main
} // end ReadRawData
On the other hand if you're
reading a text file in Java 1.0 you'll probably want to use a DataInputStream
which gives you a readLine() method that returns successive lines
of the file as Java Strings. You can then process each String
as you see fit.
// Implement the Unix cat utility in java
import java.io.*;
class cat {
public static void main (String args[]) {
String thisLine;
//Loop across the arguments
for (int i=0; i < args.length; i++) {
//Open the file for reading
try {
FileInputStream fin = new FileInputStream(args[i]);
try {
DataInputStream myInput = new DataInputStream(fin);
try {
while ((thisLine = myInput.readLine()) != null) { // while loop begins here
System.out.println(thisLine);
} // while loop ends here
}
catch (Exception e) {
System.out.println("Error: " + e);
}
} // end try
catch (Exception e) {
System.out.println("Error: " + e);
}
} // end try
catch (Exception e) {
System.out.println("failed to open file " + args[i]);
System.out.println("Error: " + e);
}
} // for ends here
} // main ends here
}
This code emulates the Unix
"cat" command. Given a series of filenames on the command line it concatenates
the files onto the standard output.
In Java 1.1 DataInputStream.readLine()
is deprecated. You should use a BufferedReader instead as in this
class:
// Implement the Unix cat utility in java
import java.io.*;
class cat {
public static void main (String args[]) {
String thisLine;
//Loop across the arguments
for (int i=0; i < args.length; i++) {
//Open the file for reading
try {
FileReader fr = new FileReader(args[i]);
BufferedReader myInput = new BufferedReader(fr);
while ((thisLine = myInput.readLine()) != null) { // while loop begins here
System.out.println(thisLine);
} // while loop ends here
} // end try
catch (IOException e) {
System.out.println("Error: " + e);
}
} // for ends here
} // main ends here
}
Within an application, however, file access is straight-forward. There are several ways but here is a simple example using formatted output streams:
import java.io.*;
class PrintToAFile {
public static void main (String args[]) {
//First open the file you want to write into
try {
FileOutputStream fout = new FileOutputStream("test.out");
// now convert the FileOutputStream into a PrintStream
PrintStream myOutput = new PrintStream(fout);
// Now you're able to use println statements just as if you were using System.out.println
// to write to the terminal
myOutput.println("Hello There!");
myOutput.println(1 + " + " + 1 + " = " + (1+1));
}
catch (IOException e) {
System.out.println("Error opening file: " + e);
System.exit(1);
}
} // main ends here
}
There are a number of other
things to note about writing data to a file. This program creates or opens a file
called "test.out" in the same directory as the running program. However
you could pass it a full pathname to a file in a different directory instead.
You should also learn about
the DataOutputStream class and the write() method
when you get a chance. DataOutputStreams and DataInputStreams
are used for moving data between Java programs in a portable way. The various
incarnations of the write() method are used for writing and reading
arbitrary byte streams. What I've demonstrated here is more suitable for human
consumption.
In Java 1.1 you should
probably use a PrintWriter instead of a PrintStream.
FileOutputStream constructor
to indicate that you want to append data to the file:
public FileOutputStream(String name, boolean append)
throws IOException
In Java 1.0, however, you
must use the java.io.RandomAccessFile class that lets you read and
write bytes from arbitrary locations in a file. This class implements DataInput
and DataOutput so you have all the methods of DataInputStream
and DataOutputStream available to you.
To create a new random
access file pass the name of the file and the mode to the constructor. The mode
is either "r" (read-only) or "rw" (read and write). The length() method returns
a long that tells you how many bytes there are in a file and the seek(long
p) method lets you position the file pointer at a particular point in
the file. Thus to start writing at the end of a RandomAccessFile raf,
you first raf.seek(raf.length()). The following example demonstrates
by appending the string "Kilroy was here!" to every file specified on the command
line.
import java.io.*;
class AppendToAFile {
public static void main (String args[]) {
for (int i = 0; i < args.length; i++) {
//First open the file you want to append to
try {
RandomAccessFile raf = new RandomAccessFile(args[i], "rw");
// Position yourself at the end of the file
raf.seek(raf.length());
// Write the String into the file. Note that you must
// explicitly handle line breaks.
raf.writeBytes("\nKilroy was here!\n");
}
catch (IOException e) {
System.out.println("Error opening file: " + e);
}
}
}
}
In Java 1.1, the java.text
package contains classes that format numbers according to particular needs.
In particular it's worth getting to know the java.text.NumberFormat
and java.text.DecimalFormat classes, though these can't handle
exponential notation. I've begun work on my own formatting class that does handle
exponential and other notations available through printf(). It
can be found at http://metalab.unc.edu/javafaq/formatter/.
Gary Cornell and Cay Horstmann's popular book Core
Java also includes such a class. You can probably find more at Gamelan.
Manning Publications has also recently published a book titled Java Network Programming. It's not a bad book, and is surprisingly orthogonal to mine. About 2/3 of that book is streams and encryption which I only touch on. My book covers servlets, applets, RMI, multicast sockets, and Java 1.1 which that book doesn't discuss. The matching titles appear to be just unlucky choices. Both publishers went with the most obvious title they could think of. However the cover of the Manning book has a big fish, and looks suspiciously like an O'Reilly book. Don't be fooled. The real O'Reilly book has a gyroscope on the cover.
You can buy Java Network Programming at any bookstore that stocks computer books, or you can order it from amazon.com or Computer Literacy.
String hostname =
InetAddress.getByName("199.1.32.90").getHostName()
The first thing to know is that there are two ways a CGI program can accept data from a web browser, GET and POST. CGIs that use GET take their arguments from the URL. Programs that use POST read their arguments from standard input.
The second thing to know is that when you submit data to a form through a web browser, the web browser encodes the data for you. In an applet, however, you need to encode the data yourself. The data is encoded like this: Each form entry is a name-value pair. Names and values are separated from each other by equals signs (=). Pairs are separated from each other by ampersands (&). For example, consider this form:
<Form method=GET action="http://metalab.unc.edu/javafaq/cgi-bin/getform.pl"> Email: <Input NAME="email" size=40> Name: <Input NAME="realname" size=40> <Input TYPE="submit" VALUE="Subscribe"> </Form>You see that this uses the GET method to communicate with a cgi-bin program at http://metalab.unc.edu/javafaq/cgi-bin/getform.pl. It sends two fields to the CGI program, email and realname. Let's say you want to send the string "elharo@metalab.unc.edu" for the email address, and the string "Elliotte Harold" for the real name. Then the query string would look like this:
String qs = "email=elharo%40metalab.unc.edu&realname=Elliotte%20Harold";
The spaces in "Elliotte Harold" and the @ in "elharo@metalab.unc.edu" have been converted into percent escapes. All non-alphanumeric characters in the values must be replaced with a % followed by their ASCII value. Thus a space becomes %20 and the @ becomes %40.
To send this data to the server, append a question mark (?) and the query string to the URL of the CGI program, and request that URL from the server. Thus the URL you want is:
http://metalab.unc.edu/javafaq/cgi-bin/getform.pl?email=elharo%40metalab.unc.edu;realname=Elliotte%20Harold";
In Java terms this requires
constructing a URL object from this string, and opening that URL's InputStream
to read the response. The following code fragment demonstrates:
try {
String thisLine;
String qs = "email=elharo%40metalab.unc.edu&realname=Elliotte%20Harold";
URL u = new URL("http://metalab.unc.edu/javafaq/cgi-bin/getform.pl?" + qs);
DataInputStream theHTML = new DataInputStream(u.openStream());
while ((thisLine = theHTML.readLine()) != null) {
System.out.println(thisLine);
}
}
catch (Exception e) {
System.err.println(e);
}
Communicating with CGI programs
that use POST is somewhat more complex, and it doesn't work very well in Java
1.0.2. It may be improved in Java 1.1. When POSTing to a CGI, you encode the query
string exactly as you do for GET requests. However instead of merely requesting
a URL's InputStream, you open a URLConnection to the CGI program.
Do not append the query
string to the URL as you did with GET. Instead set the URLConnection's
doOutput and doInput fields to true and set AllowUserInteraction
to false. Chain the URLConnection's OutputStream to
a DataOutputStream and use the DataOutputStream's
writeBytes() method to send the query string to the server.
If you want to read the
response, then chain the URLConnection's InputStream
to a DataInputStream, and use the DataInputStream's
readLine() method to read the response in a while
loop. The following code fragment demonstrates:
String query = "email=elharo%40metalab.unc.edu;realname=Elliotte%20Harold";
try {
// open the connection and prepare it to POST
URL u = new URL("http://metalab.unc.edu/javafaq/cgi-bin/postform.pl");
URLConnection uc = u.openConnection();
uc.setDoOutput(true);
uc.setDoInput(true);
uc.setAllowUserInteraction(false);
DataOutputStream dos = new DataOutputStream(uc.getOutputStream());
// Send the data
dos.writeBytes(query);
dos.close();
// Read the response
DataInputStream dis = new DataInputStream(uc.getInputStream());
String nextline;
while((nextline = dis.readLine()) != null) {
System.out.println(nextline);
}
dis.close();
}
catch (Exception e) {
System.err.println(e);
}
As you see, posting forms
is considerably more complex than using the GET method. However on some platforms,
GET has an annoying habit of failing once the query string grows past 200 characters.
The exact point where GET fails varies depending on the operating system and the
web server.