BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


Java In a Nutshell
Java In a Nutshell, Fourth Edition

By David Flanagan

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction
Welcome to Java. This chapter begins by explaining what Java is and describing some of the features that distinguish it from other programming languages. Then, as a tutorial introduction to the language, it walks you through a simple Java program you can type in, compile, and run.
In discussing Java, it is important to distinguish between the Java programming language, the Java Virtual Machine, and the Java platform. The Java programming language is the language in which Java applications (including applets, servlets, and JavaBeans components) are written. When a Java program is compiled, it is converted to byte codes that are the portable machine language of a CPU architecture known as the Java Virtual Machine (also called the Java VM or JVM). The JVM can be implemented directly in hardware, but it is usually implemented in the form of a software program that interprets and executes byte codes.
The Java platform is distinct from both the Java language and Java VM. The Java platform is the predefined set of Java classes that exist on every Java installation; these classes are available for use by all Java programs. The Java platform is also sometimes referred to as the Java runtime environment or the core Java APIs (application programming interfaces). The Java platform can be extended with optional standard extensions. These extension APIs exist in some Java installations, but are not guaranteed to exist in all installations.
The Java programming language is a state-of-the-art, object-oriented language that has a syntax similar to that of C. The language designers strove to make the Java language powerful, but, at the same time, they tried to avoid the overly complex features that have bogged down other object-oriented languages, such as C++. By keeping the language simple, the designers also made it easier for programmers to write robust, bug-free code. As a result of its elegant design and next-generation features, the Java language has proved popular with programmers, who typically find it a pleasure to work with Java after struggling with more difficult, less powerful languages.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is Java?
In discussing Java, it is important to distinguish between the Java programming language, the Java Virtual Machine, and the Java platform. The Java programming language is the language in which Java applications (including applets, servlets, and JavaBeans components) are written. When a Java program is compiled, it is converted to byte codes that are the portable machine language of a CPU architecture known as the Java Virtual Machine (also called the Java VM or JVM). The JVM can be implemented directly in hardware, but it is usually implemented in the form of a software program that interprets and executes byte codes.
The Java platform is distinct from both the Java language and Java VM. The Java platform is the predefined set of Java classes that exist on every Java installation; these classes are available for use by all Java programs. The Java platform is also sometimes referred to as the Java runtime environment or the core Java APIs (application programming interfaces). The Java platform can be extended with optional standard extensions. These extension APIs exist in some Java installations, but are not guaranteed to exist in all installations.
The Java programming language is a state-of-the-art, object-oriented language that has a syntax similar to that of C. The language designers strove to make the Java language powerful, but, at the same time, they tried to avoid the overly complex features that have bogged down other object-oriented languages, such as C++. By keeping the language simple, the designers also made it easier for programmers to write robust, bug-free code. As a result of its elegant design and next-generation features, the Java language has proved popular with programmers, who typically find it a pleasure to work with Java after struggling with more difficult, less powerful languages.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Key Benefits of Java
Why use Java at all? Is it worth learning a new language and a new platform? This section explores some of the key benefits of Java.
Sun identifies "Write once, run anywhere" as the core value proposition of the Java platform. Translated from business jargon, this means that the most important promise of Java technology is that you only have to write your application once — for the Java platform — and then you'll be able to run it anywhere.
Anywhere, that is, that supports the Java platform. Fortunately, Java support is becoming ubiquitous. It is integrated, or being integrated, into practically all major operating systems. It is built into the popular web browsers, which places it on virtually every Internet-connected PC in the world. It is even being built into consumer electronic devices, such as television set-top boxes, PDAs, and cell phones.
Another key benefit of Java is its security features. Both the language and the platform were designed from the ground up with security in mind. The Java platform allows users to download untrusted code over a network and run it in a secure environment in which it cannot do any harm: untrusted code cannot infect the host system with a virus, cannot read or write files from the hard drive, and so forth. This capability alone makes the Java platform unique.
Java 1.2 took the security model a step further. It made security levels and restrictions highly configurable and extended them beyond applets. As of Java 1.2, any Java code, whether it is an applet, a servlet, a JavaBeans component, or a complete Java application, can be run with restricted permissions that prevent it from doing harm to the host system.
The security features of the Java language and platform have been subjected to intense scrutiny by security experts around the world. In the earlier days of Java, security-related bugs, some of them potentially serious, were found and promptly fixed. Because of the strong security promises Java makes, it is big news when a new security bug is found. No other mainstream platform can make security guarantees nearly as strong as those Java makes. No one can say that Java security holes will not be found in the future, but if Java's security is not yet perfect, it has been proven strong enough for practical day-to-day use and is certainly better than any of the alternatives.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
An Example Program
Example 1-1 shows a Java program to compute factorials. The numbers at the beginning of each line are not part of the program; they are there for ease of reference when we dissect the program line-by-line.
Example 1-1. Factorial.java: a program to compute factorials
 1 /**
 2 * This program computes the factorial of a number
 3 */
 4 public class Factorial {                  // Define a class
 5 public static void main(String[] args) {  // The program starts here
 6 int input = Integer.parseInt(args[0]);    // Get the user's input
 7 double result = factorial(input);         // Compute the factorial
 8 System.out.println(result);               // Print out the result
 9 }                                         // The main() method ends here
10 
11 public static double factorial(int x) {   // This method computes x!
12 if (x < 0)                                // Check for bad input
13 return 0.0;                               // If bad, return 0
14 double fact = 1.0;                        // Begin with an initial value
15 while(x > 1) {                            // Loop until x equals 1
16 fact = fact * x;                          // Multiply by x each time
17 x = x - 1;                                // And then decrement x
18 }                                         // Jump back to start of loop
19 return fact;                              // Return the result
20 }                                         // factorial() ends here
21 }                                         // The class ends here
      
Before we look at how the program works, we must first discuss how to run it. In order to compile and run the program, you need a Java software development kit (SDK) of some sort. Sun Microsystems created the Java language and ships a free Java SDK for its Solaris operating system and also for Linux and Microsoft Windows platforms. At the time of this writing, the current version of Sun's SDK is entitled Java 2 SDK, Standard Edition, Version 1.4 and is available for download from
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Java Syntax from the Ground Up
This chapter is a terse but comprehensive introduction to Java syntax. It is written primarily for readers who are new to the language, but have at least some previous programming experience. Determined novices with no prior programming experience may also find it useful. If you already know Java, you should find it a useful language reference. In previous editions of this book, this chapter was written explicitly for C and C++ programmers making the transition to Java. It has been rewritten for this edition to make it more generally useful, but it still contains comparisons to C and C++ for the benefit of programmers coming from those languages.
This chapter documents the syntax of Java programs by starting at the very lowest level of Java syntax and building from there, covering increasingly higher orders of structure. It covers:
  • The characters used to write Java programs and the encoding of those characters.
  • Data types, literal values, identifiers, and other tokens that comprise a Java program.
  • The operators used in Java to group individual tokens into larger expressions.
  • Statements, which group expressions and other statements to form logical chunks of Java code.
  • Methods (also called functions, procedures, or subroutines), which are named collections of Java statements that can be invoked by other Java code.
  • Classes, which are collections of methods and fields. Classes are the central program element in Java and form the basis for object-oriented programming. Chapter 3 is devoted entirely to a discussion of classes and objects.
  • Packages, which are collections of related classes.
  • Java programs, which consist of one or more interacting classes that may be drawn from one or more packages.
The syntax of most programming languages is complex, and Java is no exception. In general, it is not possible to document all elements of a language without referring to other elements that have not yet been discussed. For example, it is not really possible to explain in a meaningful way the operators and statements supported by Java without referring to objects. But it is also not possible to document objects thoroughly without referring to the operators and statements of the language. The process of learning Java, or any language, is therefore an iterative one. If you are new to Java (or a Java-style programming language), you may find that you benefit greatly from working through this chapter and the next
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Unicode Character Set
Java programs are written using the Unicode character set. Unlike the 7-bit ASCII encoding, which is useful only for English, and the 8-bit ISO Latin-1 encoding, which is useful only for major Western European languages, the 16-bit Unicode encoding can represent virtually every written language in common use on the planet. Very few text editors support Unicode, however, and in practice, most Java programs are written in plain ASCII. 16-bit Unicode characters are typically written to files using an encoding known as UTF-8, which converts the 16-bit characters into a stream of bytes. The format is designed so that plain ASCII and Latin-1 text are valid UTF-8 byte streams. Thus, you can simply write plain ASCII programs, and they will work as valid Unicode.
If you want to embed a Unicode character within a Java program that is written in plain ASCII, use the special Unicode escape sequence \u xxxx. That is, a backslash and a lowercase u, followed by four hexadecimal characters. For example, \u0020 is the space character, and \u03c0 is the character π. You can use Unicode characters anywhere in a Java program, including comments and variable names.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Comments
Java supports three types of comments. The first type is a single-line comment, which begins with the characters // and continues until the end of the current line. For example:
int i = 0;  // Initialize the loop variable
The second kind of comment is a multiline comment. It begins with the characters /* and continues, over any number of lines, until the characters */. Any text between the /* and the */ is ignored by the Java compiler. Although this style of comment is typically used for multiline comments, it can also be used for single- line comments. This type of comment cannot be nested (i.e., one /* */ comment cannot appear within another one). When writing multiline comments, programmers often use extra * characters to make the comments stand out. Here is a typical multiline comment:
/*
 * Step 4: Print static methods, both public and protected,
 * but don't list deprecated ones. 
 */
The third type of comment is a special case of the second. If a comment begins with /**, it is regarded as a special doc comment. Like regular multiline comments, doc comments end with */ and cannot be nested. When you write a Java class you expect other programmers to use, use doc comments to embed documentation about the class and each of its methods directly into the source code. A program named javadoc extracts these comments and processes them to create online documentation for your class. A doc comment can contain HTML tags and can use additional syntax understood by javadoc. For example:
/**
 * Display a list of classes, many to a line. 
 *
 * @param classes The classes to display
 * @return <tt>true</tt> on success,
 * <tt>false</tt> on failure. 
 * @author David Flanagan
 */
See Chapter 7 for more information on the doc-comment syntax and Chapter 8 for more information on the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Identifiers and Reserved Words
An identifier is any symbolic name that refers to something in a Java program. Class, method, parameter, and variable names are all identifiers. An identifier must begin with a letter, an underscore (_), or a Unicode currency symbol (e.g., $, £, ¥). This initial letter can be followed by any number of letters, digits, underscores, or currency symbols. Remember that Java uses the Unicode character set, which contains quite a few letters and digits other than those in the ASCII character set. The following are legal identifiers:
i
engine3
theCurrentTime
the_current_time
θ
               
Identifiers can include numbers, but cannot begin with a number. In addition, they cannot contain any punctuation characters other than underscores and currency characters. By convention, dollar signs and other currency characters are reserved for identifiers automatically generated by a compiler or some kind of code preprocessor. It is best to avoid these characters in your own identifiers.
Another important restriction on identifiers is that you cannot use any of the keywords and literals that are part of the Java language itself. These reserved words are listed in Table 2-1.
Table 2-1: Java reserved words
abstract default if package synchronized
assert do implements private
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Primitive Data Types
Java supports eight basic data types known as primitive types. In addition, it supports classes and arrays as composite data types, or reference types. Classes and arrays are documented later in this chapter. The primitive types are: a boolean type, a character type, four integer types, and two floating-point types. The four integer types and the two floating-point types differ in the number of bits that represent them, and therefore in the range of numbers they can represent. Table 2-2 summarizes these primitive data types.
Table 2-2: Java primitive data types
TypeContainsDefaultSizeRange
boolean true or false false 1 bitNA
char Unicode character \u0000 16 bits \u0000 to \uFFFF
byte Signed integer08 bits-128 to 127
short Signed integer016 bits-32768 to 32767
int Signed integer032 bits-2147483648 to 2147483647
long Signed integer064 bits -9223372036854775808 to 9223372036854775807
float
IEEE 754 floating point
0.032 bits ±1.4E-45 to ±3.4028235E+38
double IEEE 754 floating point 0.064 bits ±4.9E-324 to ±1.7976931348623157E+308
The boolean
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Expressions and Operators
So far in this chapter, we've learned about the primitive types that Java programs can manipulate and seen how to include primitive values as literals in a Java program. We've also used variables as symbolic names that represent, or hold, values. These literals and variables are the tokens out of which Java programs are built.
An expression is the next higher level of structure in a Java program. The Java interpreter evaluates an expression to compute its value. The very simplest expressions are called primary expressions and consist of literals and variables. So, for example, the following are all expressions:
1.7  // A floating-point literal
true  // A boolean literal
sum  // A variable
When the Java interpreter evaluates a literal expression, the resulting value is the literal itself. When the interpreter evaluates a variable expression, the resulting value is the value stored in the variable.
Primary expressions are not very interesting. More complex expressions are made by using operators to combine primary expressions. For example, the following expression uses the assignment operator to combine two primary expressions — a variable and a floating-point literal — into an assignment expression:
sum = 1.7
But operators are used not only with primary expressions; they can also be used with expressions at any level of complexity. Thus, the following are all legal expressions:
sum = 1 + 2 + 3*1.2 + (4 + 8)/3.0
sum/Math.sqrt(3.0 * 1.234)
(int)(sum + 33)
The kinds of expressions you can write in a programming language depend entirely on the set of operators available to you. Table 2-5 summarizes the operators available in Java. The P and A columns of the table specify the precedence and associativity of each group of related operators, respectively.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Statements
A statement is a single command executed b the Java interpreter. By default, the Java interpreter runs one statement after another, in the order they are written. Many of the statements defined by Java, however, are flow-control statements, such as conditionals and loops, that alter this default order of execution in well- defined ways. Table 2-6 summarizes the statements defined by Java.
Table 2-6: Java statements
StatementPurposeSyntax
expression side effects
var = expr ; expr ++; method (); new Type ();
compound group statements { statements }
empty do nothing ;
labeled name a statement label : statement
variable declare a variable
[final] type name [= value ] [, name [=
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Methods
A method is a named sequence of Java statements that can be invoked by other Java code. When a method is invoked, it is passed zero or more values known as arguments. The method performs some computations and, optionally, returns a value. A method invocation is an expression that is evaluated by the Java interpreter. Because method invocations can have side effects, however, they can also be used as expression statements.
You already know how to define the body of a method; it is simply an arbitrary sequence of statements enclosed within curly braces. What is more interesting about a method is its signature. The signature specifies:
  • The name of the method
  • The number, order, type and name of the parameters used by the method
  • The type of the value returned by the method
  • The checked exceptions that the method can throw (the signature may also list unchecked exceptions, but these are not required)
  • Various method modifiers that provide additional information about the method
A method signature defines everything you need to know about a method before calling it. It is the method specification and defines the API for the method. The reference section of this book is essentially a list of method signatures for all publicly accessible methods of all publicly accessible classes of the Java platform. In order to use the reference section of this book, you need to know how to read a method signature. And, in order to write Java programs, you need to know how to define your own methods, each of which begins with a method signature.
A method signature looks like this:
                  modifiers 
                  type 
                  name ( paramlist ) [ throws exceptions ]
The signature (the method specification) is followed by the method body (the method implementation), which is simply a sequence of Java statements enclosed in curly braces. In certain cases (described in Chapter 3), the implementation is omitted, and the method body is replaced with a single semicolon.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Classes and Objects
Now that we have introduced operators, expressions, statements, and methods, we can finally talk about classes. A class is a named collection of fields that hold data values and methods that operate on those values. Some classes also contain nested inner classes. Classes are the most fundamental structural element of all Java programs. You cannot write Java code without defining a class. All Java statements appear within methods, and all methods are defined within classes.
Classes are more than just another structural level of Java syntax. Just as a cell is the smallest unit of life that can survive and reproduce on its own, a class is the smallest unit of Java code that can stand alone. The Java compiler and interpreter do not recognize fragments of Java code that are smaller than a class. A class is the basic unit of execution for Java, which makes classes very important. Java actually defines another construct, called an interface, that is quite similar to a class. The distinction between classes and interfaces will become clear in Chapter 3, but for now I'll use the term "class" to mean either a class or an interface.
Classes are important for another reason: every class defines a new data type. For example, you can define a class named Point to represent a data point in the two-dimensional Cartesian coordinate system. This class can define fields (each of type double) to hold the X and Y coordinates of a point and methods to manipulate and operate on the point. The Point class is a new data type.
When discussing data types, it is important to distinguish between the data type itself and the values the data type represents. char is a data type: it represents Unicode characters. But a char value represents a single specific character. A class is a data type; a class value is called an
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Array Types
Array types are the second kind of reference types in Java. An array is an ordered collection, or numbered list, of values. The values can be primitive values, objects, or even other arrays, but all of the values in an array must be of the same type. The type of the array is the type of the values it holds, followed by the characters []. For example:
byte b;  // byte is a primitive type
byte[] arrayOfBytes;  // byte[] is an array type: array of byte
byte[][] arrayOfArrayOfBytes;  // byte[][] is another type: array of byte[]
Point[] points;  // Point[] is an array of Point objects
For compatibility with C and C++, Java also supports another syntax for declaring variables of array type. In this syntax, one or more pairs of square brackets follow the name of the variable, rather than the name of the type:
byte arrayOfBytes[];  // Same as byte[] arrayOfBytes
byte arrayOfArrayOfBytes[][];  // Same as byte[][] arrayOfArrayOfBytes
byte[] arrayOfArrayOfBytes[];  // Ugh! Same as byte[][] arrayOfArrayOfBytes
This is often a confusing syntax, however, and should be avoided.
With classes and objects, we have separate terms for the type and the values of that type. With arrays, the single word array does double duty as the name of both the type and the value. Thus, we can speak of the array type int[] (a type) and an array of int (a particular array value). In practice, it is usually clear from context whether a type or a value is being discussed.
To create an array value in Java, you use the new keyword, just as you do to create an object. Arrays don't need to be initialized like objects do, however, so you don't pass a list of arguments between parentheses. What you must specify, though, is how big you want the array to be. If you are creating a byte[], for example, you must specify how many byte values you want it to hold. Array values have a fixed size in Java. Once an array is created, it can never grow or shrink. Specify the desired size of your array as a non-negative integer between square brackets:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reference Types
Now that we have discussed the syntax for working with objects and arrays, we can return to the issue of why classes and array types are known as reference types. As we saw in Table 2-2, all the Java primitive types have well-defined standard sizes, so all primitive values can be stored in a fixed amount of memory (between one and eight bytes, depending on the type). But classes and array types are composite types; objects and arrays contain other values, so they do not have a standard size, and they often require quite a bit more memory than eight bytes. For this reason, Java does not manipulate objects and arrays directly. Instead, it manipulates references to objects and arrays. Because Java handles objects and arrays by reference, classes and array types are known as reference types. In contrast, Java handles values of the primitive types directly, or by value.
A reference to an object or an array is simply some fixed-size value that refers to the object or array in some way. When you assign an object or array to a variable, you are actually setting the variable to hold a reference to that object or array. Similarly, when you pass an object or array to a method, what really happens is that the method is given a reference to the object or array through which it can manipulate the object or array.
C and C++ programmers should note that Java does not support the & address-of operator or the * and -> dereference operators. In Java, primitive types are always handled exclusively by value, and objects and arrays are always handled exclusively by reference: the . operator in Java is more like the -> operator in C and C++ than like the . operator of those languages. It is very important to understand that, unlike pointers in C and C++, references in Java are entirely opaque: they cannot be converted to or from integers, and they cannot be incremented or decremented.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Packages and the Java Namespace
A package is a named collection of classes (and possibly subpackages). Packages serve to group related classes and define a namespace for the classes they contain.
The Java platform includes packages with names that begin with java, javax, and org.omg. (Sun also defines standard extensions to the Java platform in packages whose names begin with javax.) The most fundamental classes of the language are in the package java.lang. Various utility classes are in java.util. Classes for input and output are in java.io, and classes for networking are in java.net. Some of these packages contain subpackages. For example, java.lang contains two more specialized packages, named java.lang.reflect and java.lang.ref, and java.util contains a subpackage, java.util.zip, that contains classes for working with compressed ZIP archives.
Every class has both a simple name, which is the name given to it in its definition, and a fully qualified name, which includes the name of the package of which it is a part. The String class, for example, is part of the java.lang package, so its fully qualified name is java.lang.String.
To specify the package a class is to be part of, you use a package directive. The package keyword, if it appears, must be the first token of Java code (i.e., the first thing other than comments and space) in the Java file. The keyword should be followed by the name of the desired package and a semicolon. Consider a file of Java code that begins with this directive:
package com.davidflanagan.jude;  
All classes defined by this file are part of the package named
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Java File Structure
This chapter has taken us from the smallest to the largest elements of Java syntax, from individual characters and tokens to operators, expressions, statements, and methods, and on up to classes and packages. From a practical standpoint, the unit of Java program structure you will be dealing with most often is the Java file. A Java file is the smallest unit of Java code that can be compiled by the Java compiler. A Java file consists of:
  • An optional package directive
  • Zero or more import directives
  • One or more class definitions
These elements can be interspersed with comments, of course, but they must appear in this order. This is all there is to a Java file. All Java statements (except the package and import directives, which are not true statements) must appear within methods, and all methods must appear within a class definition.
There are a couple of other important restrictions on Java files. First, each file can contain at most one class that is declared public. A public class is one that is designed for use by other classes in other packages. We'll talk more about public and related modifiers in Chapter 3. This restriction on public classes only applies to top-level classes; a class can contain any number of nested or inner classes that are declared public, as we'll see in Chapter 3.
The second restriction concerns the filename of a Java file. If a Java file contains a public class, the name of the file must be the same as the name of the class, with the extension .java appended. Thus, if Point is defined as a public class, its source code must appear in a file named Point.java. Regardless of whether your classes are public or not, it is good programming practice to define only one per file and to give the file the same name as the class.
When a Java file is compiled, each of the classes it defines is compiled into a separate
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Defining and Running Java Programs
A Java program consists of a set of interacting class definitions. But not every Java class or Java file defines a program. To create a program, you must define a class that has a special method with the following signature:
public static void main(String[] args)
This main() method is the main entry point for your program. It is where the Java interpreter starts running. This method is passed an array of strings and returns no value. When main() returns, the Java interpreter exits (unless main() has created separate threads, in which case the interpreter waits for all those threads to exit).
To run a Java program, you run the Java interpreter, java, specifying the fully qualified name of the class that contains the main() method. Note that you specify the name of the class, not the name of the class file that contains the class. Any additional arguments you specify on the command line are passed to the main() method as its String[] parameter. You may also need to specify the -classpath option (or -cp) to tell the interpreter where to look for the classes needed by the program. Consider the following command:
% java -classpath /usr/local/Jude com.davidflanagan.jude.Jude datafile.jude
java is the command to run the Java interpreter. -classpath /usr/local/Jude tells the interpreter where to look for .class files. com.davidflanagan.jude.Jude is the name of the program to run (i.e., the name of the class that defines the main() method). Finally, datafile.jude is a string that is passed to that main() method as the single element of an array of String objects.
In Java 1.2, there is an easier way to run programs. If a program and all its auxiliary classes (except those that are part of the Java platform) have been properly bundled in a Java archive (JAR) file, you can run the program simply by specifying the name of the JAR file:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Differences Between C and Java
If you are a C or C++ programmer, you should have found much of the syntax of Java — particularly at the level of operators and statements — to be familiar. Because Java and C are so similar in some ways, it is important for C and C++ programmers to understand where the similarities end. There are a number of important differences between C and Java, which are summarized in the following list:
No preprocessor
Java does not include a preprocessor and does not define any analogs of the #define, #include, and #ifdef directives. Constant definitions are replaced with static final fields in Java. (See the java.lang.Math.PI field for an example.) Macro definitions are not available in Java, but advanced compiler technology and inlining has made them less useful. Java does not require an #include directive because Java has no header files. Java class files contain both the class API and the class implementation, and the compiler reads API information from class files as necessary. Java lacks any form of conditional compilation, but its cross-platform portability means that this feature is rarely needed.
No global variables
Java defines a very clean namespace. Packages contain classes, classes contain fields and methods, and methods contain local variables. But there are no global variables in Java, and, thus, there is no possibility of namespace collisions among those variables.
Well-defined primitive type sizes
All the primitive types in Java have well-defined sizes. In C, the size of short, int, and long types is platform-dependent, which hampers portability.
No pointers
Java classes and arrays are reference types, and references to objects and arrays are akin to pointers in C. Unlike C pointers, however, references in Java are entirely opaque. There is no way to convert a reference to a primitive type, and a reference cannot be incremented or decremented. There is no address-of operator like
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Object-Oriented Programming in Java
Java is an object-oriented programming language. As we discussed in Chapter 2, all Java programs use objects, and every Java program is defined as a class. The previous chapter explained the basic syntax of the Java programming language, including data types, operators, and expressions, and even showed how to define simple classes and work with objects. This chapter continues where that one left off, explaining the details of object-oriented programming in Java.
If you do not have any object-oriented (OO) programming background, don't worry; this chapter does not assume any prior experience. If you do have experience with OO programming, however, be careful. The term "object-oriented" has different meanings in different languages. Don't assume that Java works the same way as your favorite OO language. This is particularly true for C++ programmers. We saw in the last chapter that close analogies can be drawn between Java and C. The same is not true for Java and C++, however. Java uses object-oriented programming concepts that are familiar to C++ programmers and even borrows C++ syntax in a number of places, but the similarities between Java and C++ are not nearly as strong as those between Java and C. Don't let your experience with C++ lull you into a false familiarity with Java.
As we discussed in Chapter 2, a class is a collection of data, stored in named fields, and code, organized into named methods, that operates on that data. The fields and methods are called members of a class. In Java 1.1 and later, classes can also contain other classes. These member classes, or inner classes, are an advanced feature that is discussed later in the chapter. For now, we are going to discuss only fields and methods. The members of a class come in two distinct types: class, or static, members are associated with the class itself, while instance members are associated with individual instances of the class (i.e., with objects). Ignoring member classes for now, this gives us four types of members:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Members of a Class
As we discussed in Chapter 2, a class is a collection of data, stored in named fields, and code, organized into named methods, that operates on that data. The fields and methods are called members of a class. In Java 1.1 and later, classes can also contain other classes. These member classes, or inner classes, are an advanced feature that is discussed later in the chapter. For now, we are going to discuss only fields and methods. The members of a class come in two distinct types: class, or static, members are associated with the class itself, while instance members are associated with individual instances of the class (i.e., with objects). Ignoring member classes for now, this gives us four types of members:
  • Class fields
  • Class methods
  • Instance fields
  • Instance methods
The simple class definition for the class Circle, shown in Example 3-1, contains all four types of members.
Example 3-1. A simple class and its members
public class Circle {
  // A class field
  public static final double PI= 3.14159;  // A useful constant

  // A class method: just compute a value based on the arguments
  public static double radiansToDegrees(double rads) { 
    return rads * 180 / PI; 
  }

  // An instance field
  public double r;  // The radius of the circle

  // Two instance methods: they operate on the instance fields of an object
  public double area() {  // Compute the area of the circle
    return PI * r * r; 
  }
  public double circumference() {  // Compute the circumference of the circle
    return 2 * PI * r; 
  }
}
A class field is associated with the class in which it is defined, rather than with an instance of the class. The following line declares a class field:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating and Initializing Objects
Take another look at how we've been creating Circle objects:
Circle c = new Circle();
What are those parentheses doing there? They make it look like we're calling a method. In fact, that is exactly what we're doing. Every class in Java has at least one constructor, which is a method that has the same name as the class and whose purpose is to perform any necessary initialization for a new object. Since we didn't explicitly define a constructor for our Circle class in Example 3-1, Java gave us a default constructor that takes no arguments and performs no special initialization.
Here's how a constructor works. The new operator creates a new, but uninitialized, instance of the class. The constructor method is then called, with the new object passed implicitly (a this reference, as we saw earlier), and whatever arguments that are specified between parentheses passed explicitly. The constructor can use these arguments to do whatever initialization is necessary.
There is some obvious initialization we could do for our circle objects, so let's define a constructor. Example 3-2 shows a new definition for Circle that contains a constructor that lets us specify the radius of a new Circle object. The constructor also uses the this reference to distinguish between a method parameter and an instance field that have the same name.
Example 3-2. A constructor for the Circle class
public class Circle {
    public static final double PI = 3.14159;  // A constant
    public double r;  // An instance field that holds the radius of the circle

    // The constructor method: initialize the radius field
    public Circle(double r) { this.r = r; }  

    // The instance methods: compute values based on the radius
    public double circumference() { return 2 * PI * r; }
    public double area() { return PI * r*r; }
}
When we relied on the default constructor supplied by the compiler, we had to write code like this to initialize the radius explicitly:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Destroying and Finalizing Objects
Now that we've seen how new objects are created and initialized in Java, we need to study the other end of the object life cycle and examine how objects are finalized and destroyed. Finalization is the opposite of initialization.
As I mentioned in Chapter 2, the memory occupied by an object is automatically reclaimed when the object is no longer needed. This is done through a process known as garbage collection. Garbage collection is not some newfangled technique; it has been around for years in languages such as Lisp. It just takes some getting used to for programmers accustomed to such languages as C and C++, in which you must call the free() function or the delete operator to reclaim memory. The fact that you don't need to remember to destroy every object you create is one of the features that makes Java a pleasant language to work with. It is also one of the features that makes programs written in Java less prone to bugs than those written in languages that don't support automatic garbage collection.
The Java interpreter knows exactly what objects and arrays it has allocated. It can also figure out which local variables refer to which objects and arrays, and which objects and arrays refer to which other objects and arrays. Thus, the interpreter is able to determine when an allocated object is no longer referred to by any other object or variable. When the interpreter finds such an object, it knows it can destroy the object safely and does so. The garbage collector can also detect and destroy cycles of objects that refer to each other, but are not referenced by any other active objects. Any such cycles are also reclaimed.
The Java garbage collector runs as a low-priority thread, so it does most of its work when nothing else is going on, such as during idle time while waiting for user input. The only time the garbage collector must run while something high-priority is going on (i.e., the only time it will actually slow down the system) is when available memory has become dangerously low. This doesn't happen very often because the low-priority thread cleans things up in the background.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Subclasses and Inheritance
The Circle defined earlier is a simple class that distinguishes circle objects only by their radii. Suppose, instead, that we want to represent circles that have both a size and a position. For example, a circle of radius 1.0 centered at point 0,0 in the Cartesian plane is different from the circle of radius 1.0 centered at point 1,2. To do this, we need a new class, which we'll call PlaneCircle. We'd like to add the ability to represent the position of a circle without losing any of the existing functionality of the Circle class. This is done by defining PlaneCircle as a subclass of Circle, so that PlaneCircle inherits the fields and methods of its superclass, Circle. The ability to add functionality to a class by subclassing, or extending, it is central to the object-oriented programming paradigm.
Example 3-3 shows how we can implement PlaneCircle as a subclass of the Circle class.
Example 3-3. Extending the Circle class
public class PlaneCircle extends Circle {
  // We automatically inherit the fields and methods of Circle, 
  // so we only have to put the new stuff here. 
  // New instance fields that store the center point of the circle
  public double cx, cy;

  // A new constructor method to initialize the new fields
  // It uses a special syntax to invoke the Circle() constructor
  public PlaneCircle(double r, double x, double y) {
    super(r);  // Invoke the constructor of the superclass, Circle()
    this.cx = x;  // Initialize the instance field cx
    this.cy = y;  // Initialize the instance field cy
  }

  // The area() and circumference() methods are inherited from Circle
  // A new instance method that checks whether a point is inside the circle
  // Note that it uses the inherited instance field r
  public boolean isInside(double x, double y) {
    double dx = x - cx, dy = y - cy;  // Distance from center
    double distance = Math.sqrt(dx*dx + dy*dy);  // Pythagorean theorem
    return (distance < r);  // Returns true or false
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Data Hiding and Encapsulation
We started this chapter by describing a class as "a collection of data and methods." One of the important object-oriented techniques we haven't discussed so far is hiding the data within the class and making it available only through the methods. This technique is known as encapsulation because it seals the data (and internal methods) safely inside the "capsule" of the class, where it can be accessed only by trusted users (i.e., by the methods of the class).
Why would you want to do this? The most important reason is to hide the internal implementation details of your class. If you prevent programmers from relying on those details, you can safely modify the implementation without worrying that you will break existing code that uses the class.
Another reason for encapsulation is to protect your class against accidental or willful stupidity. A class often contains a number of interdependent fields that must be in a consistent state. If you allow a programmer (including yourself) to manipulate those fields directly, he may change one field without changing important related fields, thus leaving the class in an inconsistent state. If, instead, he has to call a method to change the field, that method can be sure to do everything necessary to keep the state consistent. Similarly, if a class defines certain methods for internal use only, hiding these methods prevents users of the class from calling them.
Here's another way to think about encapsulation: when all the data for a class is hidden, the methods define the only possible operations that can be performed on objects of that class. Once you have carefully tested and debugged your methods, you can be confident that the class will work as expected. On the other hand, if all the fields of the class can be directly manipulated, the number of possibilities you have to test becomes unmanageable.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Abstract Classes and Methods
In Example 3-4, we declared our Circle class to be part of a package named shapes. Suppose we plan to implement a number of shape classes: Rectangle, Square, Ellipse, Triangle, and so on. We can give these shape classes our two basic area() and circumference() methods. Now, to make it easy to work with an array of shapes, it would be helpful if all our shape classes had a common superclass, Shape. If we structure our class hierarchy this way, every shape object, regardless of the actual type of shape it represents, can be assigned to variables, fields, or array elements of type Shape. We want the Shape class to encapsulate whatever features all our shapes have in common (e.g., the area() and circumference() methods). But our generic Shape class doesn't represent any real kind of shape, so it cannot define useful implementations of the methods. Java handles this situation with abstract methods.
Java lets us define a method without implementing it by declaring the method with the abstract modifier. An abstract method has no body; it simply has a signature definition followed by a semicolon. Here are the rules about