No unmet needs exist and...current unmet needs that are being met will continue to be met.
-- Transportation Commission on Unmet Transit Needs, California
A newer version of Java has arrived since the original publication of this book. Called the Java 1.1 Platform (hereafter simply "Java 1.1"), it adds some language features, a few packages, and many classes to existing packages. The goals of Java 1.1 are to support internationalization better, fix the incongruities of the original abstract window toolkit package (
java.awt
, or just "AWT" for short), complete functionality that was missing or impoverished, and add several useful packages. This book does not cover AWT, so we do not cover it in this appendix.This appendix does summarizes the other changes. For extensive changes, especially those having to do with new classes and packages, you will have to use the reference documentation shipped with your Java 1.1 system to supplement this appendix. The section titles in this appendix correspond to the chapters of this book where the new features would appear.
SortMetrics
class on page 75 is to return multiple values from the metrics
method of the SortDouble
class. It is a good candidate to be an inner class:
abstract class SortDouble { static final class SortMetrics implements Cloneable { // ... the rest of SortMetrics (see page 75) } // ... the rest of SortDouble (see page 73) }
An inner class name is qualified by its enclosing class. In this case, the proper name of SortMetrics
is SortDouble.SortMetrics
, and so its declaration in SimpleSortDouble
on page 76 would be
SortDouble.SortMetrics metrics = bsort.sort(testData);Inner classes and interfaces can use the same access modifiers as other members of a class. A class that was used only in internal data structures might be marked
private
; one intended only for use by subclasses would be protected
. Inner classes can also be public
or package accessible.The example above declares
SortMetrics
as static
. An inner class that is not static has an implicit reference to its enclosing object, which is the object that created the inner class object. This reference is useful because many inner classes are strongly tied to particular objects, and need to access their fields. For example, the class EnumerateWhichChars
on page 222 is used to implement the Enumeration
interface for the WhichChars
class, and could be nicely rewritten to look like this:
public class WhichChars { private BitSet used = new BitSet(); // in original private class Enumerate implements Enumeration { private int pos = 0; private int setSize = used.size(); public boolean hasMoreElements() { while (pos < setSize && !used.get(pos)) pos++; return (pos < setSize); } public Object nextElement() throws NoSuchElementException { if (hasMoreElements()) return new Character((char)pos++); else throw new NoSuchElementException(); } } public Enumeration characters() { // from page 223 return new Enumerate(); } }
We use the shorter class name Enumerate
because the class is already nested inside WhichChars
, so EnumerateWhichChars
would be redundant. The class is private
so that even other classes in the package can't use the type directly-it is purely an implementation detail of the WhichChars
class.
In the original code on page 222,
used
was passed as a parameter to the class's constructor, which stored the reference in a field of its own called bits
. Here the code for Enumerate
directly accesses the field used
of its enclosing object. When resolving identifiers, the inner class's enclosing object (also called its enclosing instance) is searched for fields and methods after the class's own this
. Because Enumerate
does not have a field named used
, the identifier used
in the inner class refers to the enclosing object's field of that name. The enclosing object for an inner class is the this
reference of the method that created the inner class object. In our example above, when an Enumerate
object is created inside a particular WhichChar
object, the Enumerate
object's enclosing object is set to be the this
reference of the WhichChar
method that created it. This means you cannot create an instance of a non-static inner class in a static context (inside a static method, a static block, or as an initializer for a static field).You can get a reference to an enclosing object using its class name. For example, code in an
Enumerator
object could get a reference to its enclosing object using WhichChar.this
.
final
. If you do not expect to change the value of a parameter or variable inside the method, you can declare it final
to let the compiler enforce that. The compiler can also optimize uses of a final
parameter or variable since it knows the value will never change.The
final
-ness of a parameter is not part of the method signature-it is simply a detail of the implementation. A subclass can override a method and add or drop any final
parameter modifiers you wish. You can also add or drop final
modifiers in a method's parameters without causing any harm to existing compiled code that uses that method. The final
declaration does not show up in the documentation generated from doc comments.You can defer initialization of a
final
field or variable, as long as you initialize it before it is used and assign a value to it exactly once. The compiler will check for proper assignment, as will the verifier before code is executed. Deferred initialization can be useful when the proper value can only be calculated by a loop or other code that is hard or impossible to encode in a variable initializer, such as code that throws exceptions that must be caught and handled.
static
blocks described on page 44, except the keyword static
is left off.
new
. Suppose you want to create a simple Observer
object (see page 233) that keeps a history of the events stored in a field of your object. The following would do this directly and simply:
private Vector history = new Vector(); public void watch(Observable o) { o.addObserver(new Observer() { public void update(Observable o, Object arg) { history.addElement(arg); } }); }
The addObserver
has an embedded new
of an anonymous class that implements the Observer
interface, implicitly extending Object
. This anonymous class implements update
by adding an element to the enclosing object's history
vector. The compiler creates an unnamed (hence "anonymous") class that overrides update
as specified. The end of the anonymous class declaration is the end of the allocation expression started by the new
. Here we simply close off the call to addObserver
with a closing parenthesis.
An anonymous class can extend a class instead of implementing an interface, in which case it is an unnamed subtype of that class. Such a
new
can invoke any superclass constructor. Anonymous classes cannot have their own constructors.Anonymous classes are a quick, terse subclassing tool that is useful in certain situations, such as creating several types of AWT buttons, each with its own small action, or creating simple
Runnable
objects. Unfortunately, they share a common failing of many terseness features-it is trivial to write code that is torture to read. You should use of anonymous classes only for tiny classes that override one, or at most two, methods, with a total of four lines of code or fewer. Otherwise people who read your code can become confused trying to keep track of what piece of which class's method's code they are reading, and what the outer context is. Use this tool sparingly. When it's good, it's very, very good. When it's not, it's awful.
Object.hashCode
is to return keys that are likely to be different for different objects. As described on page 64, many classes override both hashCode
and equals
to provide different notions of equality. However, sometimes you need the original notion of equality, in which all objects are different, even for an object that usually is used with a broader notion. You can use ==
to test if two objects are the same, but you will need to use System.identityHashCode
to hash the objects, since it preserves the default implementation of hashCode
in which all objects are considered different.
@
tags (such as @author
and @see
) that are not documented in this book. The new @deprecated
tag has particular meaning-it marks a class, interface, field, or method as not recommended for continued use. Existing code that uses the deprecated entity will still compile and run, but the compiler will generate a warning, suggesting that you update your code to avoid that entity. You should follow that recommendation.To have this effect on a type or a member of a type, the
@deprecated
tag must be at the beginning of a doc comment line (ignoring white space and any *
character). This is the only place in the entire Java language where the contents of a comment affect the generated code. The @deprecated
tag should always refer readers to the preferred replacement(s). For example
/** * @deprecated This call has been replaced with dwishm * @see dwishm */ public void dwim() { /*...*/ }The
transient
keyword, marked as "unused" on page 93, now has defined meaning; see Section D.5.2.
You can initialize the contents of an array when you
new
it. For example, the following would be a flexible way to create an array of strings:
String[] martians = new String[] {
"Gidney", "Cloyd"
};
D.4 Threads
The interruption mechanism briefly described on pages 173-174 as future functionality has been implemented in Java 1.1. See those pages for more details.D.5 I/O
D.5.1 Internationalization
Many new I/O classes have been added to handle full internationalized character issues. The original classes really worked only with ISO-Latin-1 8-bit characters (notice that InputStream.read
, for example, returned eight bits, not sixteen, in its int
). The most specific change is that PrintStream
is now a deprecated class, since it thinks only in terms of ISO-Latin-1. The new class is called PrintWriter
, and provides all the methods of PrintStream
except those for writing raw bytes. Existing code that uses the print
and println
methods of PrintStream
will have the output translated to the local character set. (To prevent a massive outpouring of deprecation warnings, only the constructors of PrintStream
are deprecated.)PrintStream
described on page 199 has been cleaned up. If autoflush is turned on, any newline anywhere in the output causes a flush, as does any write
of a byte array. If autoflush is off, no automatic flushing is done.PrintWriter
is a subclass of the abstract Writer
class, which is the parallel to OutputStream
for classes that understand internationalization. The Reader
abstract class is the parallel to InputStream
. There are several new Reader
and Writer
classes for internationalized I/O.System.in
, System.out
, and System.err
are final in Java 1.1 for security reasons, so code that modifies these fields (like that shown on page 197) will not work.java.text
includes many classes useful for parsing and producing internationalized text. It includes classes for date and number formatting, comparing and sorting strings in a locale-sensitive way, splitting up native language text, and other locale-related I/O.D.5.2 Object Serialization
The streams ObjectInputStream
and ObjectOutputStream
help you read and write entire objects and object graphs. Objects written to an ObjectOutputStream
using writeObject
generate a stream of bytes that, when read by an ObjectInputStream
with readObject
, create a full copy of the original objects. The process of creating such a stream of bytes is called serialization. Serialized copies are deep-you can serialize an entire graph of objects, and when you deserialize the generated bytes, you will get a full copy of the original graph. If two or more objects refer to a particular object in the original graph, a deserialized copy will have copies of those two or more objects that refer to a copy of that same particular object.private
fields as secret, and would not be pleased to have values exposed in this way. For this reason, objects are not serializable unless they implement the Serializable
interface. Serializable
is an empty interface that simply marks the object as one that can be serialized. The default serialization mechanism just writes the non-static, non-transient fields of an object. You can override this by providing readObject
and writeObject
methods.Externalizable
-a subinterface of Serializable
-is serializable but must provide custom readExternal
and writeExternal
methods; the default serialization will not be used.D.6 Utilities
D.6.1 Resource Localization
Several new utilities have been added for localization. A new Locale
class describes particular locales to define a user's preferred language and other properties. A ResourceBundle
superclass is provided to customize a set of resources (such as messages that might be displayed to the user) based on the user's preferred locale. Some subtypes of ResourceBundle
are provided: ListResourceBundle
, an abstract class that provides a simple implementation of ResourceBundle
to which you must simply provide the list of resources and keys for each resource, and PropertyResourceBundle
, which uses files that contain the keyed resources.D.6.2 Dates and Times
The functionality of the Date
class has been split up into a richer system that can cope with varying reckonings of time. A Date
object now only represents a particular moment in time with millisecond granularity. Its other constructors and methods previously performed two other duties: formatting strings and viewing a moment in time as year, month, day, hour, minute, and second values. All these methods are deprecated in favor of:
Calendar
class for handling various ways of marking time
TimeZone
class that represents time zone offsets and other adjustments, such as daylight savings time
java.text.DateFormat
class that defines how one can parse and format date strings
These abstract classes allow flexibility, but almost everyone will need to work with Gregorian dates that are used in most of the world and in international commerce, so Java 1.1 also provides:
GregorianCalendar
class
SimpleTimeZone
class for use with GregorianCalendar
java.text.SimpleDateFormat
class that parses and formats Gregorian dates
GregorianCalendar
to print out the current year:
class CurrentYear { public static void main(String[] args) { GregorianCalendar now = new GregorianCalendar(); int year = now.get(Calendar.YEAR); System.out.println("The year is " + year); } }
java.lang.reflect
provides a reflection mechanism for Java. This is a tool for examining classes fully. A Class
object can now return a list of all the public methods and fields of the related class. You can use the Method
objects returned to invoke methods, and the Field
objects to get and set field values. A Class
object can also return a list of all members, including non-public ones, but security restrictions usually prevent doing this.You should avoid the temptation to use reflection when other tools more natural to the language would suffice. If you are accustomed to using function pointers in another language, for example, you might think that using
Method
objects are a natural replacement, but usually an object-oriented tool-such as an interface that is implemented by objects that perform the needed action-is better. Reflection is intended for use by language tools such as debuggers and class browsers.
Short
and Byte
. These are subtypes of Number
. A new Void
class has also been added for completeness, and is used by the reflection methods to represent void
return types.
Class
object for a given type with a new use of the class
keyword:
Class threadClass = Thread.class; Class intClass = int.class; Class voidClass = void.class;
java.beans
-Java Beans are software components that allow unrelated developers to write and ship Java components that can be composed together by end-user tools.
java.math
-This package provides tools for mathematical manipulations. Currently a BigInteger
class provides arbitrary-precision integer arithmetic, and BigDecimal
provides arbitrary-precision decimal arithmetic.
java.rmi
-Remote Method Invocation (RMI) allows you to create objects whose methods can be invoked by objects running in other Virtual Machines, including Virtual Machines running on other hosts. Because Java code can be downloaded and run securely, RMI lets you pass subtypes of the declared method parameters, and return subtypes of the declared type of the remote method. This allows you to pass object behavior as well as simple values. RMI provides remote procedure calls with a Java flavor and benefits.
java.security
-This package and its subpackages provide some basic interfaces and classes for security-related operations, such as authentication, authorization, signed data, and encryption.
java.sql
-This package provides tools for using relational databases.
java.text
-This package provides text internationalization tools, such as date parsing and number formatting.
java.util.zip
-You can use these classes for handling ZIP files.