Notes on Java

Back To Mike's WebToys Page!
This page was created as a summary of what I learned in order to use Java effectively.  Keep in mind that I've several years of C,C++ experience, and so this material tends to focus on differences and new stuff, rather than basic syntax.

Differences between C/C++ and Java

Objects

The keyword null indicates that the reference is invalid.
To copy an object, the object must support the Clonable interface.
To create an object: Variables: Within a method, the variable this refers to the instance itself.  You can declare a field or method to be a 'class variable/method' using the static keyword.  Within the class, you can refer to static variables/methods as if they were regular instance variables, but outside the class, you must prefix the variable/method with the class name, like so:
Thread.sleep( 1000 );
Note that class methods don't have a this variable.
Constructors: Constructors (C'tors) exist, and can be overloaded.  Within a C'tor, you can invoke another constructor via a call to this( <args, if any> ).
Static Initializers:  Just as constructors initialize a given instance, static initializers initialize a class when it's loaded. Note that you can have multiple static initialzer methods in a class, and that at compile-time, all the static variable initializers, and static initializer methods get concatenated together to get one huge static initializer.  Note also that since it gets executed when the class is loaded, it takes no arguments, and returns no values.  It's declare like so:
static { ... }
Destructors: The finalize() method is used as a destructor, kinda.  It's an instance method, takes no arguments, and returns no values. This gets invoked when the object is garbage collected, which may not happen before the JVM exits.  Note that finalize() is invoked once and once only, thereafter the object is rechecked to see if there's a reference to it elsewhere.  Otherwise, it could hand off it's this reference to another object in the finalize method, and then get garbage collected, thus allowing a reference to an invalid object.
Inheritance:
Use the extends keyword to indicate that a class is a subclass of another class.  The parent and child classes can be in different packages.  Classes declared final can't be subclassed.
Constructors: to call a superclass's constructor, use super( <args, if any> ). This can only be called within a constructor, and must be the very first call in the constructor.  If it's not, Java automatically puts a default call ("super()") there for you, ensuring that the highest superclass's constructor is called first, then the next,etc).
Destructors: finalize() methods aren't chained like constructors are, so you have to do this yourself.  It's recommended that you call the super.finalize() method at the end of your finalize().
Shadowed variables: Subclasses can declare variables with the same name as variables in a superclass, which are accessed when no qualification is used, thus 'shadowing' the super variable.  There are three things to note: this.variableName to explicitly refer to the subclass's variable (when variableName is used alone, it does the same thing), super.variableName to access the immediate superclass's variable, or ((SuperClassName)this).variableName to get to any super class's variable.  Note that you cannot refer to overridden methods this way.
Overridden methods:  outside the class, you can't invoke a parent's method, no matter what.  Using a dynamic invocation mechanism, the 'most specific' method is used. final methods (which can't be overridden) use static invocation.  Within a class, you can use super.method() to invoke superclass methods, but only on the immediate parent.
Visibility of fields and methods:
 
Type Accessible To
public everyone
protected the class, subclasses, but no others
private the class, only
package (this is the default, if you don't specify one of the others) the class, any classes in the same package
 
Abstract class/methods: Any method declared abstract doesn't have an implementation, and automatically makes the class an abstract class (and thus can't be instantiated).  Classes can likewise be declared abstract.  A subclass of an abstact class that doesn't implement all of the abstract methods is also, automatically, made abstract.

Arrays

The indeces of arrays are of type int.  Arrays can be allocated like so:
byte arr1[];
Object arr2[1024]; //allocates space for the Objects, not the Objects themselves
can initialize objects using something like:
byte arr3[] = { 1, 2, 3 };
in Java1.1, you can also anonymously initialize arrays, doing something like
O.Method( new String[] = { "yup", "second" } );
You can declare multidimensional arrays, which are actually arrays-of-arrays (or rather, arrays of reference to arrays, since arrays are kind of like objects), like so:
String[10][20][][]; //note that all arrays of specified dimension must come first - String[][10] is erroneous
Nested initializers are fair game, and the multiD arrays don't have to be rectangular

Interfaces

One of the really cool things about Java is the language-level support for Interfaces. And this maps really well into ActiveX, which is cool. Declared using the interface keyword, in the same place that a class keyword would go.  Any methods in the interface are abstract, and any variables must be declared to be static final (ie, constants), which can be accessed outside the class via the Interface.variableName syntax like for a class variable.  Classes that implement an interface can be treated as instances of that interface, just as if the interface was a type or class.  They can also access the interface constants without having to prefix the constant with the interface name.  Interfaces can inherit from on and other, and can inherit from multiple interfaces, if they choose.  They inherit using the extends keyword, just like classes.  Interfaces with no methods or variables can also be used as marker interfaces, in that other classes can see if the class implements an interface, and if so, take an action based on it.  Like the Cloneable and Serializable interfaces.

Exceptions

Exceptions themselves are objects, meaning that they have fields, methods, and can be / are dynamically created.  Exceptions are subclasses of the Throwable class, and fall into three categories. Errors are things like linkage (class couldn't be loaded) and JVM errors (out of memory), and the program can't be expected to actually handle.  Normal Exceptions are stuff the the program should handle, like FileNotFound errors.  RuntimeExceptions (like NullPointerExceptions) could conceivably be handled by the program, but are prevalently possible that we don't have to specify that our methods throw these exceptions.
If a method throws an exception, it must say that using the throws clause of the method name, like so
public void method() throws IOException()
methods throw exceptions using the throw keyword, and giving it an Exception object, like so:
throw new Exception( "Exception Message Here"  );
If a method A invokes another method B, and B throws some exception, method A must either handle the exception, or list the exception in it's throws clause. To handle the exception use the try..catch...finally construct
try { ... }
executes the code, and eventaully returns, either becuase the end of the block was reached, or because of an abnormal exit, which include exceptions being tossed, and break, continue, and return statments.
catch( ExceptionType E ) { ... }
Every try must have 0 or more catch clauses.  if there are 0 catch clauses, then there must be a finally clause.  If there are multiple catch clauses, the first (ie, top-most) clause that matches the thrown exception will be invoked, and none of the others will (but the finally clause,if it exists, will be).  Exception handling code goes in here.
finally { ... }
The finally clause is always executed, regardless of how much of the try statement, or if any of the catch statements are executed. This includes returning from the try clause because of a break, continue, or return.  Useful for clean-up
 

Packages

A package is a collection of classes, for example java.lang. Creating a package yourself is easy, though there are some tricky issues with placing these files in directories that you have to watch out for.

Packages are declared by simply putting the text package pckName at the top of the .java file. Any classes defined in the file are now part of package pckName. You can then compile this into a .class file. Note that subpackages are delimited by periods (e.g., edu.cornell.mwp3.Whatever.*).  The tricky part is figuring out how to setup the directories in relation to your CLASSPATH variable. If you have a package named pckName that contains class Foo.class, Java expects the for some directory in your CLASSPATH variable, there will exist a subdirectory named pckName. Within that directory, there will exist a file named Foo.class. The way you then run that class (assuming it has a main() method, etc) is to invoke the following:
java pckName.Foo
The package stuff can be frustrating since you can cd to the directory pckName, and type java Foo, only to be told that Java "Can't find class Foo", even though it's in your current working directory!
Note that you can abbreviate class names by use of the import keyword.  By saying import java.net.URL, you're telling the compiler that any time you refer to URL, you mean java.net.URL.  Pretty handy.  Also, you can do import java.net.*, meaning grab everything in the java.net package, and allow the abbreviations to be used.  Note that it's a compile-time error for a naming collision to occur because of this (ie, you can't import java.net.URL, mike.net.URL, and then try and instantiate a "URL" object)
 

Inner Classes

Nested classes for Java. Useful for the new Java1.1 AWT event model, because it allows one to create lots of small objects to use as functors without cluttering up a package or namespace.  At this point, I'm not interested.

Keyword summary

abstract: class is abstract (can't be instantiated), or method doesn't have an implementation.  Classes that contain abstrat methods are abstract.
extends: to indicate that a class is a subclass of another class.
catch: catch an exception
final: Once initialized, a variable tagged with "final" isn't allowed to change value. final methods can't be overridden, and final classes can't be subclassed.
import
native: method isn't implemented in Java - use ";" in place of a method body
null
package
synchronized: method will lock class or instance (for class or instance method, respectively) before executing
throw: throw an exception
throws: placed after the method name/args, indicates that the method may throw an exception
transient: in Java1.1, marks a field as being something that won't get serialized
try: exceute the code in the block, which may thrown an exception.
volatile: marks a field as being used by multiple threads, so access the real variable each and every time you use it
 

Class Hierarchy

Using Files

There are (at least) three ways to manipulate files.  The java.io.File class is for manipulating files in a manner similar to command-line ls / dir stuff.  It doesn't allow you to read or write the files, but you can list directories, etc.  If you want to read/write files, you should be looking in the InputStream/OutputStream subclasses (for byte streams), and (in Java 1.1) the Reader/Writer classes (for character streams, which include handy things like readLine/writeLine).  Note that InputStreamReader forms a nice bridge between the two, allowing you to take an InputStream, hand it to the constructor of InputStreamReader, and get something that's a subclass of Reader. One of the tricks to using streams is figuring out when they've finished.  For Reader streams, if the method returns -1, the stream is finished.  If the BufferedReader.readLine() returns null (instead of a String object), then the stream is finished.  Otherwise, there's something left. This is especially important for streams like the one you get back from a URLConnection.

Accessing URLs

java.net.URL, which can either generate the InputStream directly (getInputStream(), which can be wrapped into an InputStreamReader, then into a BufferedReader, to do a readLine-by-readLine access), or through the getConnection() method, which gives you a URLConnection, which can be twiddled for various purposes, and from which you can then get the InputStream.
 

Object Serialization  (Java1.1)

ObjectOutputStream.writeObject( Object o) serializes an object into a stream, ObjectInputStream.readObject() deserializes it.  Pretty cool, sounds like.  The object must
  1. Implement the Serializable or Externalizable interface
  2. fields marked transient aren't serialized
  3. custom (de-)serialization may be done, if you want -- implement a different writeObject()/readObject()

Reflection (Java1.1)

Dynamic invocation, made accessible to the outside world.  java.lang.Class has been extended to return more info - can now get Field, Method, and Constructor objects (and interrogate them)
 

Java Beans  (Java1.1)

Uses the reflection stuff & a naming scheme to expose events, data, etc.  Split into GUI Builder stuff and Bean Dev stuff
GUI Builder: Introspector returns BeanInfo, which enumerates FeatureDescriptors.  Lots more
Bean Dev: auxilliary classes to facillitate interaction with the GUI Builder stuff
 

AWT: Layout managers

It would be nice if we could have a layout manager that simply allows to "put button at x,y", but it's not here yet. I've not clue how one implements a LayoutManager, either. LayoutManagers include:

FlowLayout
The default layout manager for a container, it put things into the container as best they'll fit, left-to-right in first-to-last order
CardLayout
aka property sheet
BorderLayout
Allows for N,E,W,S,Center placement
GridBagLayout
GridLayout