No explicit cast needed for upcasting, but explicit cast needed for downcasting.

Defining your class as implementing an interface marks objects of that class as an instance
of that interface.

An abstract method cannot (obviously) be final.

An abstract method cannot be static because static methods cannot be overridden.

An instance method can be both protected and abstract. A static method can be
protected.

Before Java runtime clones an object, it checks to see if the object’s class implements the
Cloneable interface. If it does, the clone() method returns a clone of the object. If not, the clone()
method throws a CloneNotSupportedException.

The clone method is protected, so an object can only request a clone of another object which
is either in the same package or which it inherits from. (i.e. standard meaning of protected)

The JVM does not call an object’s constructor when you clone the object.

Keywords

Classes can be modified from their default state using any of the three keywords: public,
abstract, and final. So, can’t have a static class, only static methods.

A final variable is a constant, and a final method cannot be overridden.

A synchronised method can belong to an object or to a class.

Only one public class per file.

package statement must come first in file and must be followed by any import statements.

An identifier is an unlimited-length sequence of Java letters and Java digits,
the first of which must be a Java letter. Java letters include _ and $. Digits include 0..9.

Constructors

The JVM does not call an object’s constructor when an object is cloned.

Constructors never return a value. If you do specify a return value, the JVM will interpret
your intended constructor as a method.

If a class contains no constructor declarations, then a default constructor that takes
no arguments is supplied. This default constructor invokes the no-args superclass constructor, i.e. calls super();

If, in a constructor, you do not make a direct call to super or this (with
or without args) [note: must be on the first line] then super(no args) will first be invoked
then any code in the constructor will be executed. See constructors.jpr project.

A call to this in a constructor must also be on the first line. Note: can’t have an explicit
call to super followed by a call to this in a constructor - only one direct call to another constructor
is allowed.

Memory and Garbage Collection

As soon as you lose the reference to an object, that object becomes eligible for garbage collection.

Setting your object reference to null makes it a candidate for garbage collection.

You can directly invoke the garbage collector by getting an object which represents the current
runtime and invoking that object’s gc() method (see p.95 of Exam Guide).

Can’t predict when garbage collection will occur, but it does run whenever memory gets low.

If you want to perform some task when your object is about to be garbage collected, you can
override the java.lang.Object method called finalize(). This method is declared as protected, does not return
a value, and throws a Throwable object, i.e. protected void finalize() throws Throwable.

Always invoke the superclass’s finalize() method if you override finalize().

The JVM only invokes finalize()once per object. Since this is the case, do not
resurrect an object in finalize as when the object is finalized again its finalize() method will not be
called. Instead you should create a clone of the object if you must bring the object back to life.

Remember that Java passes method parameters by value and not by reference. Obviously then, anything
that happens to a primitive data type inside a method does not affect the original value in the calling code. Also,
any reassignment of object references inside a method has no effect on the objects passed in.

Data Types and Values

Ranges for primitive data types are as follows:-

Data Type

Range of Values

byte

-27.. 27-1

signed integer

short

-215.. 215-1

signed integer

int

-231.. 231-1

signed integer

long

-263.. 263-1

signed integer

float

32 bit

signed floating point

double

64 bit

signed floating point

char

16 bit

Unicode character

boolean

either true or false

To specify an octal (base 8) number, put a leading ‘0’ in front of i

To specify a hexadecimal (base 16) number, put a leading ‘0x’ in front of it.

By default, integer values are of type int. However, you can force an integer value to
be a long by placing an ‘L’ after it.

By default, floating point values are of type double. However, you can force a floating-point
value to be a float by placing an ‘F’ after it.

Java sets each element in an array to its default value when it is created. Default object value
is null, default integer value is 0, default boolean value is false, default floating point value
is 0.0, default char value is ‘\u0000’.

Arrays are objects allocated at runtime, so you can use a variable to set their length.

First element in an array is at index 0 and last element is at length-1. length
is a special array variable (not a method, so don’t need round brackets after it).

Can only use curly braces in array initialisation when array is actually declared, i.e. can’t
declare the array on one line then initialise it with curly braces on line below.

ASCII characters are all found in the range ‘\u0000’ to ‘\u00ff’

The default value for any class variable or instance variable declared as a char is ‘\u0000’.

Operators

>> is right shift keep the sign, >>> is right shift don’t keep the sign.

& and | can be used with both integral and boolean types. If used with integers the result
is integral. If used with booleans, both operands are evaluated, even when the result of the operation can
be determined after evaluating only the left operand.

&& and || are used with boolean operands only. The right operand is not evaluated if
the result of the operation can be determined after evaluating only the left operand.

The equals() method (defined at the ‘highest’ level as a method of Object) is used to
test the value of an object. The == operator is used to test the object references themselves.

By default, equals() returns true only if the objects reside in the same memory location,
i.e. if the object references are equal. So, by default, equals() and == do the same things. This will be the
case for all classes that do not override equals().

String, Wrappers (including Integer, Long, Float, Double, Character and Boolean), BitSet, Date
and File classes all override equals() so that the value true is returned if the values are equal.

The + and += operators are overloaded for Strings.

Dividing an integer by 0 is illegal and would cause Java to throw an ArithmeticException.
Floating point numbers have values for infinity and not-a-number, so using arithmetic operators on floating point
numbers never results in an exception.

Control Flow

A loop counter is usually an integer, however it could also be a floating point number - incrementing
by 1.0

Breaking to a label means that the loop at the label is terminated. Any outer loop will keep
iterating.

In contrast, a continue to a label continues execution with the next iteration of the labelled
loop.

The expression for an if and while statement must be a Boolean.

The expression in a switch statement must be an int or a char.

A default statement in a switch is optional.

A case block will fall through to the case block which follows it, unless the last statement
in a case block is a throw, return or break.

As with if statements, for and while loops, it is possible to nest switch statements.

Any line of code can be labelled BUT can only do a labelled continue to a loop, and can
only do a labelled break to a loop or to an enclosing statement.

Exceptions

It is possible to have multiple catch blocks in a try-catch-finally. The finally block is optional.

A catch block must always be associated with a try block, i.e. can’t have a catch block by itself
or with a finally block.

A finally block must always be associated with a try block, i.e. can’t have a finally block
by itself or with a finally block.

With multiple catch blocks, the type of exception caught must progress from the most specific
exception that you wish to catch to the superclasses for these exceptions. (Makes sense!)

Methods must declare any exception which they throw.

Invoking a method which declares it throws exceptions is not possible unless either the code
is placed in a try-catch, or the calling method declares that it throws the exceptions, i.e. checked exceptions
must be caught or rethrown. If the try-catch approach is used, then the try-catch must cope with all of
the exceptions which a method declares it throws.

You can list more than one exception in the throws clause if you separate them with commas.

RuntimeException and its subclasses are unchecked exceptions.

Unchecked exceptions do not have to be caught.

All Errors are unchecked.

You should never throw an unchecked exception in your own code, even though the code will compile.

You cannot use a try block on its own. It must be accompanied by a following catch or finally
(or both).

Code in a finally block will always be executed, whether an exception is thrown or not
and whether any exception thrown is caught or not. Only terminating the program will stop the finally code from
being executed.

A method can only throw those exceptions listed in its throws clause, or subclasses of those
exceptions.

A method can throw any unchecked exception, even if it is not declared in its throws clause.

When you override a method, you must list those exceptions that the override code might throw.
You can list only those exceptions, or subclasses of those exceptions, that are defined in the method definition
you are inheriting from, i.e. you cannot add new exception types to those you inherit. You can choose to throw
a subset of those exceptions listed in the method’s superclass, however, a subclass further down the hierarchy
cannot then re-list the exceptions dropped above it.

Methods

If you define more than one method with the same name in the same class, Java must be able to
determine which method to invoke based on the number and types of parameters defined for that method.

The compiler will complain if you have two methods with identical signatures exception for the
return type and/or the exceptions thrown, i.e. can’t overload based on return type and/or exceptions thrown.

Determining which methods will be invoked with integer params - see p.195 of the Exam Guide.

It is possible to declare an inherited method abstract.

Obviously, it is not possible to override a final method.

A subclass may make an inherited method synchronized, or it may leave off the synchronized
keyword so that its version is not synchronized. If a method in a subclass is not synchronized but the method in
the superclass is, the thread obtains the monitor for the object when it enters the superclass’s method.

It is possible to declare an inherited method as abstract, but then there is no way to
get to the behaviour in the hierarchy above the abstract declaration.

Return types must match the overriden method in the superclass exactly. The parameter types
must match those in the superclass exactly, i.e. in the same order. If this is not the case, then the superclass’s
method is not overridden. Compiler will not complain, however, unless exactly the same signature except
for return type (or exceptions thrown - see earlier).

You cannot make a method in a subclass more private than it is defined in the superclass, ‘though
you can make it more public.

Coercion of arguments only happens with overloading, not overriding.

It is perfectly legal to have two different instance variables with the same name if they are
defined in different classes where one class inherits from the other.

Which variable is accessed depends on the type of object reference which the variable
was declared to hold. Which method gets invoked depends on the underlying object. See p.106 Q1 & p.201
of Exam Guide.

A native method does not have a body, or even a set of braces, e.g. public native void
method();

A native method cannot be abstract.

A native method can throw exceptions.

Math and String Classes

ceil() returns the next highest integer (expressed as a double)

Method call

Returns

ceil(9.01)

9.0

ceil(-0.1)

0.0

ceil(100)

100.0

round() returns the closest integer (expressed as an int if the parameter was a float,
or a long if the parameter was a double)

Method call

Returns

round(9.01)

9

round(9.5)

10

round(-9.5)

-9

round(-0.1)

0

round(100)

100

random() returns a random number, a double, between 0.0 and 1.0

sqrt() takes a double and returns a double. If the argument is NaN or <0, the result
is NaN.

sin(),cos() and tan() all take a double and return a double.

All objects respond to toString(), which you can override to return a String representation
of your object.

There are four versions lastIndexOf() - as above table but, in each method, finding the
last index rather than the first index.

First character in a String is at position 0, last character is at position length()-1

There are two versions of substring()

Arguments

Results

(int startIndex)

Returns a substring starting with startIndex and extending to the end of the String

(int startIndex, int endIndex)

Returns a substring starting with startIndex and extending to (but not including) endIndex

For a StrintoString() returns itself - the same object reference (obviously pointing
to the same object) that was used to invoke the method.

trim() returns a new String object that cuts off any leading and trailing whitespace
for the String for which it was invoked.

Java considers "whitespace" to be any character with a code less than or equal to
‘\u0020’ which is the space character.

Input/Output

InputStream and OutputStream are abstract classes.

FileInputStream and FilterInputStream both inherit directly from InputStream.

FileOutputStream and FilterOutputStream both inherit directly from OutputStream.

DataInputStream inherits directly from FilterInputStream.

DataOutputStream inherits directly from FilterOutputStream.

When you create a Filter stream, you must specify the stream to which it will attach.

A Filter stream processes a stream of bytes in some way. By "chaining" any number
of Filter streams, you can add any amount of processing to a stream of bytes.

DataInputStream, DataOutputStream and RandomAccessFile know how to work with Java data types
because they implement the DataInput and DataOutput interfaces, whereas FileInputStream and FileOutputStream know
only how to work with individual bytes.

RandomAccessFile implements both DataInput and DataOutput methods - RandomAccessFile objects
can read from and write to files.

See p.231 of Exam Guide for subclasses of InputStream and OutputStream. Should know these.

Should also know the subclasses of FilterInputStream and FilterOutputStream - see p.232.

The File class is not used to create files. Can create a file using an instance of class
RandomAccessFile and FileOutputStream.

To test if a File object refers to an existing file, you can invoke exists() which returns
true or false. The File methods canRead() and canWrite() return boolean values that indicate whether
the application can read from or write to the file. (Note: applets can’t write to a file.)

Can use File methods to make a permanent change to the file system. For example, you can call
delete() or rename(). For rename(), need to supply a File object which embodies the new name.

You can create a directory using the File class. The method mkdir() does this.

It is possible to navigate the filing system using the File class. Methods getParent(), getPath()
and getName() are provided, and also getAbsolutePath().

The method getAbsolutePath() returns the name of the current user directory (the full
pathname included) with the file name concatenated. See Practice Exam 1 Q.45

Creating a FileOutputStream object creates the appropriate file. If the file already exists,
FileOutputStream replaces it (unless the FileOutputStream object is created using the constructor which
takes a String and a boolean - see later)

Upon creation of a RandomAccessFile object, need to supply a file object plus a mode. Alternatively,
can supply a filename plus a mode.

Valid modes for RandomAccessFile are "r" and "rw".

Constructors for FileInputStream: one takes a String, one takes a File, one takes a FileDescriptor

Constructors for FileOutputStream: one takes a String, one takes a File, one takes a FileDescriptor,
one takes a String and a boolean (which indicates whether or not to append).

Constructors for FilterInputStream: one only, which takes an InputStream

Constructors for FilterOutputStream: one only, which takes an OutputStream

See Chapter 11 Review Questions for io stuff - very useful.

Threads

A Java program runs until the only threads left running are daemon threads.

You can initiate your own thread of execution by creating a Thread object, invoking its start()
method, and providing the behaviour that tells the thread what to do. The thread will run until its run()
method exists, after which it will come to a halt - thus ending its life cycle.

The Thread class, by default, doesn’t provide any behaviour for run().

There are two ways to provide the behaviour for a thread

Subclass the thread and override the run() method - see p.253 of Exam Guide.

Implement the Runnable interface and indicate an instance of this class will be the thread’s
target.

A thread has a life cycle. Creating a new Thread instance puts the thread into the "new
thread" state. When the start() method is invoked, the thread is then "alive" and "runnable".
A thread at this point will repond to the method isAlive() by returning true.

The thread will continue to return true to isAlive() until it is "dead", no
matter whether it is "runnable" or "not runnable".

If 2 threads are alive, with the same highest priority, the JVM switches between them. The JVM
will switch between any number of threads with the same highest priority.

The priority numbers for threads falls between the range of Thread.MIN_PRIORITY and Thread.MAX_PRIORITY.

The default thread priority is Thread.NORM_PRIORITY.

New threads take on the priority of the thread that spawned them.

You can explicitly set the priority of a thread using setPriority(), and you can get
the priority of a thread using getPriority(). There is no constructor for thread which takes a priority.

The JVM determines the priority of when a thread can run based on its priority ranking, but
this doesn’t mean that a low priority thread will not run.

The currently executing thread can yield control by invoking yield(). If you invoke yield(),
Java will pick a new thread to run. However, it is possible the thread that just yielded might run again immediately
if it is the highest priority thread.

There are 3 types of code that can be synchronized: class methods, instance methods,
any block of code within a method.

Variables cannot take the synchronized keyword.

Synchronization stays in effect if you enter a synchronized method and call out to a non-synchronized
method. The thread only gives up the monitor after the synchronized method returns.

Using a thread’s stop() method will make it die.

There are 3 ways to transition a thread between "runnable" and "not runnable"

put it to sleep and wake it up

(not on the test)

pause it and resume it

(not on the test)

use the methods wait(), notify() and notifyAll()
- these are methods of class Object. wait() throws InterruptedException.

The third method listed above allows communication between the threads, whereas the other 2
methods don’t.

By using the methods wait(), notify() and notifyAll(), any thread can wait for
some condition in an object to change, and any thread can notify all threads waiting on that object’s condition
that the condition has changed and that they should continue.

When a waiting thread pauses, it relinquishes the object’s monitor and waits to be notified
that it should try to reacquire it.

If you know you only have one thread waiting on a condition, you can feel free to use notify(),
otherwise you should use notifyAll(). The notifyAll() method wakes up all threads waiting to reacquire
the monitor for the object.

The reasons why a thread might be "alive" and "not runnable" are as follows:

the thread is not the highest priority thread and so is not able to get CPU time

the thread has been put to sleep using the sleep() method (of class Thread. Throws InterruptedException)

the thread has been suspended using the suspend() method

the thread is waiting on a condition because someone invoked wait() for the thread

the thread has explicitly yielded control by invoking yield()

Graphical User Interfaces

If you want to explicitly repaint a component, you should not call paint() directly.
Instead you should invoke your component’s repaint() method.

The repaint() method is overloaded. The no-args version of repaint() does not
cause your user interface to repaint right away. In fact, when repaint() returns, your component has not
yet been repainted - you’ve only issued a request for a repaint(). There is another version of repaint()
that requests the component to be repainted within a certain number of milliseconds.

The repaint() method will cause AWT to invoke a component’s update() method. AWT passes
a Graphics object to update() - the same one that it passes to paint(). So, repaint() calls
update() which calls paint().

The Graphics object that AWT hands to update() and paint() is different every
time the Component is repainted.

When Java repaints on its own, such as when the user resizes an applet, the AWT does not invoke
update() - it just calls paint() directly.

The update() method does three things in this order:

clears the background of the object by filling it with its background colour

sets the current drawing colour to be its foreground colour

invokes paint(), passing it the Graphics object received

Common graphics methods:

drawString() - takes a String, followed by x then y co-ord of baseline for first char

drawLine() - takes x then y co-ords of starting point, then x then y co-ords of end point

drawRect() / fillRect() - take 4 params - x then y co-ords of top left corner,
then width then height

drawPolygon() / fillPolygon() - (int[] xpoints, int[] ypoints, int npoints) -
array of x co-ords then array of y co-ords followed by the number of points to use

drawArc() / fillArc() - takes 6 params - x then y co-ord of top left corner (of
bounding rectangle of corresponding oval), width then height of arc, then start angle (not really an angle, more
a position on the clock - 0 represents 3 o’clock), then number of degrees to move along the arc. Last parameter
can also be negative, if you want to move in a clockwise direction round the arc.

The Image class does not provide a constructor for specifying where an image will come from.

You can obtain an Image, typically by downloading it from the Internet by specifying a URL.
You can retrieve an image and obtain an Image object by invoking an Applet method named getImage(). This
method takes a URL.

When the getImage() method returns, the data for the image is not necessarily immediately
available. The method returns right away, even if the image resource is located over the Internet on a Web server
and must be downloaded.

When you invoke the Graphics method drawImage() the image download begins. The object
you specify as an ImageObserver keeps the Java graphics system up-to-date on the state of the download. When the
ImageObserver sees that the download is complete, it notifies the graphics system that it can draw the image in
its entirety.

ImageObserver is an interface. The Component class implements this interface, so any component
(such as an Applet itself) can be used as an ImageObserver.

TextArea takes rows then cols in constructor. If you type in more text than can be displayed
all at one, scrollbars appear automatically.

TextField takes only cols. A user may one type one line into a TextField. No scrollbars
appear if the line is too long to be displayed, but can use arrow keys to move to beginning or end of text.

TextArea and TextField both inherit from TextComponent which provides a setEditable()
method.

For a variable width font, TextArea / TextField width is based on average of letter widths.

Can populate a List using addItem() method.

As well as a no-args constructor and a constructor which takes number of rows, List class also
has a constructor which takes number of rows followed by a boolean value which represents whether or not multiple
list item selections are allowed.

enable() / disable() - make a component selectable or not by the user.

size() / resize() - the size() method retrieves the size of the Component
as a Dimension object which has two fields (width and height). The resize() method sets the
size of the Component. The method is overloaded - one version takes a Dimension object and the other takes width
and height directly as int values.

show() / hide() - the show() method makes a Component visible, the hide()
method makes a Component invisible. The show() method is overloaded so that you can supply a boolean parameter
to indicate whether to show the Component (if the parameter is true).

Java provides a Color class which defines many static constants that contain instances of class
Color already initialized to common colours. To use red, for example, you can access Color.red. The Color class
has a constructor which takes three int values of red, green and blue so that you can make up your own colour.

Each container has exactly one layout manager which determines how to arrange the Components
within a Container.

A layout manager is any class that implements the LayoutManager interface. Java’s 5 layout managers
all inherit directly from class Object, but they implement the LayoutManager interface, which defines 5 abstract
methods:

addLayoutComponent()

layoutContainer()

minimumLayoutSize()

preferredLayoutSize()

removeLayoutComponent()

Instead of invoking the layout manager’s methods yourself, Java’s default Container methods
invoke them for you at the appropriate times. These Container methods include add(), getMinimumSize(), getPreferredSize(),
remove() and removeAll() (these are all Java 1.1 methods).

Each type of container comes with a default layout manager. Default for a Frame, Window or Dialog
is BorderLayout. Default for a Panel is FlowLayout().

A FlowLayout object arranges components left to right and top to bottom, centering each line
as it goes. The FlowLayout layout manager is the only layout manager which allows components to be their preferred
size. If a container using a FlowLayout is resized, all of the components inside it might need to be rearranged,
and some might not be completely visible.

A BorderLayout object arranges components according to the directions "North", "South",
"East" and "West". There’s also an area for "Center" which includes any space left
over from other regions.

If nothing is placed in "East" or "West", for example, then the "Center"
stretches all the way from the left edge of the Container to the right edge.

Some components are stretchable and others are not. For example, Button, Label and TextField
are stretchable, whereas Checkbox is not.

GridLayout objects allow you to specify a rectangular grid in which to place the components.
Each cell in the grid is the same height as the other cells, and each width is the same as the other cells. Components
are stretched both horizontally and vertically to fill the cell.

When a GridLayout object is first constructed, you must first specify how many rows and how
many columns the grid will have. Components are added to the grid left to right and top to bottom. If more components
are added than there are columns, the GridLayout keeps the same number of rows but adds the necessary number of
columns.

You can change a Container’s layout manager to be a different one by invoking setLayout().

Event Handling

All of the events dispatched by AWT’s components use event classes that are subclasses of AWTEvent,
which is in java.awt. These subclasses are defined in the java.awt.event package.

The AWT does not notify your event handler of every event that occurs over a component, as in
the old days of 1.0.2. Now, AWT informs your event handler only about the events it is interested in.

Define a class which implements the necessary Listeners and then use the Component addABCListener()
method to register an interest in a certain type of event, e.g. addMouseListener(this).

If you define a class which implements a listener, you must obviously include stubs for those
listener methods not implemented as interfaces are implicitly abstract and failure to implement all
of the methods would result in an abstract subclass.

The Listener methods are as follows: (Note - all are declared as public void and all
take only one parameter which is an Event of the same name as the Listener, i.e. ActionListener methods
take an ActionEvent etc.

Listener

Methods

ActionListener

actionPerformed

AdjustmentListener

adjustmentPerformed

ComponentListener

componentHidden

componentMoved

componentResized

componentShown

ContainerListener

componentAdded

componentRemoved

FocusListener

focusGained

focusLost

ItemListener

itemStateChanged

KeyListener

keyPressed

keyReleased

keyTyped

MouseListener

mouseClicked

mouseEntered

mouseExited

mousePressed

mouseReleased

MouseMotionListener

mouseDragged

mouseMoved

TextListener

textValueChanged

WindowListener

windowClosed

windowClosing

windowDeiconified

windowActivated

windowDeactivated

windowIconified

windowOpened

See pages 360-363 for Event classes.

There’s an Adapter class to match each Listener interface. Each Adapter class defines no-op
stubs for the methods declared in the corresponding interface. So can extend an Adapter rather than implement a
Listener interface (but this only makes sense when the object that will listen for and handle the event has no
other responsibilities).

Passing Arguments to Programs

The main() method must be declared as a public, static method that does not return a
value and takes an array of String objects. The order of public and static, and the way in which the String array
is defined, is not strictly enforced.

When main() ends, that may or may not be the end of the program. The JVM will run until
the only remaining threads are daemon threads. If main() does not spawn any more threads, then the program
will end when main() ends.

If the applet is loaded relative to the page, there are two things that can change the base
location - one of which is if the HTML file itself contains a <base> tag - this tag specifies where to look
for the applet class.

The conventional way to pass a parameter to an applet is to use the <param> tag, using
one <param> tag per parameter. Each <param> tag can take only one parameter.

Each parameter value can be retrieved by the applet as a String, using methods defined in class
Applet.

If you want to pass a different type of value, such as an int or a boolean, you must convert
it from a String, most likely by using a wrapper class.

If you’d like a parameter to contain spaces, you should place this value between quotes. Otherwise
it’s not strictly necessary to pass params in quotes (good style though).

You retrieve the value of a parameter using the getParameter() method defined by the
Applet class. This method returns a String containing the value of the parameter, or null if the parameter
was notdefined at all.

Class Applet inherits from Panel.

When an applet instance is first instantiated, Java invokes the applet’s init() method.

When the Web page containing the applet is about to appear, Java invokes the applet’s start()
method.

When the Web page is about to be replaced with another page, Java invokes the applets stop()
method.

When the Web page is removed from the browser’s cache and the applet instance is about to go
away, Java invokes the applet’s destroy() method.

Inner Classes

In Java 1.1 you can define classes inside classes - these are known as "inner classes".

If you define an inner class at the same level as the enclosing class’ instance variables, the
inner class can access those instance variables - no matter what their access control.

If you define an inner class within a method, the inner class can access the enclosing class’
instance variables and also the local variables and parameter for that method.

If you do reference local variables or parameters from an inner class, those variables or parameters
must be declared as final to help guarantee data integrity.

You can also define an anonymous class - a class without a name. See p.399 Exam Guide for syntax.

If you’d like to refer to the current instance of the enclosing class, you can write EnclosingClassName.this.

If you need to refer to the inner class using a fully qualified name, you can write EnclosingClassName.InnerClassName.

If your inner class is not defined as static you can only create new instances of this
class from a non-static method.

You can also define more than one JAR file in the archive value by listing them all within the
quotes and separating their names with commas.

Serializing Objects

In Java 1.1 it is now possible to read and write objects as well as primitive data types, using
classes that implement ObjectInput and ObjectOutput. These two interfaces extend DataInput and DataOutput to read
or write an object. ObjectInputStream and ObjectOutputStream implement these interfaces.

If a class implements the Serializable interface, then its public and protected
instance variables will be read from and written to the stream automatically when you use ObjectInputStream and
ObjectOutputStream.

If an instance variable refers to another object, it will also be read or written, and this
continues recursively.

If the referenced object does not implement the Serializable interface, Java will throw a NotSerializableException.

The Serializable interface serves only to identify those instances of a particular class that
can be read from and written to a stream. It does not actually define any methods that you must implement.

If you create your own class and want to keep certain data from being read or written, you can
declare that instance variable using the transient keyword. Java skips any variable declared as transient
when it reads and writes the object following the Serializable protocol.

Reflection

Using the Reflection API, a program can determine a class’ accessible fields, methods and constructors
at runtime.