A Brief Introduction to Java

by P. Chew

These notes are meant for someone who is already familiar with programming who wants a brief introduction to the Java programming language.  This is not meant to be a comprehensive Java reference.  More complete information on Java can be found in The Java Tutorial, an online tutorial by the developers of Java.

You should also look at the CS410 handout Pascal/Java/C Comparisons, a table indicating and discussing some of the differences between Pascal, Java, and C; look here to get a quick idea of the proper syntax for some common kinds of Java statements.  More complete syntax information is available in The Java Language Specification.   Some example Java programs are in Queue.java and QTest.java.  QTest.java can be run as either an applet or an application and contains lots of comments.

Please email us with mistakes, places where we've been unclear, or additional topics that should be included.

Object Oriented Programming

Object Oriented Programming is a style of programming based on objects, classes, and inheritance.  An object is a software bundle of data and related operations.  A class is a template that defines objects of a certain kind.  Using a class, one can create several objects where each is an instance of this class.  Classes can be defined in terms of other classes.  A class inherits from its superclass

Classes, Fields, and Methods

A Java program consists of a number of interacting classes.  Predefined classes in Java include String, Vector, Stack, Hashtable, and many others.  A Stack is a subclass of Vector which is a subclass of Object.  All classes in Java are subclasses of the class Object. 

Java classes have fields (these are the variables) and methods.   To refer to the field field within the instance instance, the syntax is instance.field.  A method call looks like instance.methodName(args); this calls the version of methodName that "resides within" the given instance.  Methods always have parentheses; a method call with no arguments looks like instance.methodName().

Methods can be overloaded (i.e., the same method name can be used to refer to several different methods).  If x.methodName(y,z) is used then the system looks for a method methodName that belongs to instance x.  Note that x, y, and z are not treated symmetrically in Java: the method actually chosen during a call is based on the true class of the data stored in x, while for y and z we use types based on the declarations of y and z.

All fields and all methods are part of some class.  For instance, mathematical constants, such as pi and e, and standard mathematical functions, such as the trigonometric functions, reside in the class java.lang.Math.

How a Java Program Runs

For an application, you have to tell the runtime system which class is to be run.   The runtime system looks for a method within this class that looks like public static void main (String[] args) and runs this method.

For an applet, the web page tells the runtime system which class is to be run.   The necessary code is downloaded and the runtime system looks for the following methods within the class:

These methods are automatically run by the system at the appropriate times.

A single class can include the methods for running applets as well as the main-method used for running as an application.  When doing a large program, consisting of many interacting classes, it can often be useful to have main-methods, containing debugging code, in several classes.

The Special Names this and super

The name this when used within a method (one that is not static) refers to the current object.  Note that without the use of this, there is no way to access the current object from within a method.  The name super also refers to the current object, but it is treated as a member of the superclass of the current object.  For instance:

class Thing extends SuperThing {
    int x, y;
    ...
    public void reset (int x) {
        this.x = x;    // this.x is Thing's x
                       // while x is the parameter x.
    }
}

Note that in the above example, if the parameter was called z then x and this.x would both refer to Thing's x.

Within another of Thing's methods, this.reset(5) would call the reset method shown above while super.reset(5) would call a different method that presumably exists in class SuperThing.

Constructors and the Keyword new

Constructors handle initialization when a new object is created.  A constructor is like a method, but it has a different syntax:

A constructor can only be called with a special syntax using the keyword new.

Vector v = new Vector();
Queue q = new Queue();

The first action of a constructor is to create an instance of its class; this is done automatically and requires no explicit code.  In general, the remainder of a constructor is then used to properly prepare the instance's fields.  Within the constructor's code, the newly created instance can be referred to by using the keyword this.

Packages and Java's API

Java allows related classes to be grouped into packages.  To use a class that is part of a package you have to import that class.  This is done with an import statement, usually placed near the beginning of the file in which the class is used.  For instance, to use Vector we would place the following statement at the beginning of our file.

import java.util.Vector;

Much of Java's functionality resides within the packages that are part of Java.   The Java API (Applications Programming Interface) describes the packages that are part of Java.  Documentation on the API is accessible from within J++ and you should take a look at it.  In particular you should check out

java.lang which contains Integer, Float, Double, Math, Object, String, StringBuffer, and System among other classes.  The entire java.lang package is always imported automatically.

java.util which contains Vector, Stack, BitSet, Hashtable, and Enumeration.

java.io which contains classes useful for file I/O.

java.awt, the Abstract Windowing Toolkit.

Standard Output

In Java, printing to the standard output is handled by the method System.out.println; this is a method that takes a single argument of type String.  System is a class that is part of the java.lang package.  The java.lang package is always imported automatically so the class System is always available.  The class System is basically a standard place to hold various items related to the system.  In particular, System.out represents the standard output and println is a method of the file System.out.

int x = 42;
System.out.println("The answer is " + x);

will print:

The answer is 42

Objects that appear with the string concatenation operator (+) are, in general, automatically converted into Strings.  This works for primitive types and also for user-defined objects as long as the user-defined object has a toString() method.

Modifiers for Fields (Variables) and Methods

For fields and methods, access is controlled by modifiers.  Here are possible access modifiers:

Modifier Access
private accessible only from within the class itself
no modifier (= "friendly") accessible from within the same package
protected accessible from within the same package and from subclasses
public accessible from everywhere

Additional modifiers include final and static.  A final variable is constant; its value can't be changed.  A final method can't be overridden by a method of the same name declared in a subclass.  Static implies just one copy for the entire class.  A static variable is associated with the class itself rather than any specific instance of that class.  A static method is also associated with the class itself rather than an instance.  In practice, this means that "this" can't be used within a static method.  Constants associated with a class are usually declared as both static and final (i.e., there is just one copy and it can't be changed).

Modifiers for Classes

The access modifiers for a class are "friendly" (= no modifier) and public.   These have roughly the same meanings as above: a friendly class is accessible from within the same package and a public class is accessible everywhere.

Additional modifiers include abstract and final.  For an abstract class, you don't have to specify code for all of its methods.  An abstract class cannot be instantiated.  For a final class, no subclasses are allowed.   Many of the standard Java classes are declared to be final.

File Names versus Class Names

Java is tied into the file system more intimately than most programming languages.   For instance, the code for a public class named MyClass must reside in a file called MyClass.java.  The code for a class that is not public (a "friendly" class) can reside within a file with other classes.

Java packages are also closely tied into the file system.  A public class called MyClass in package myPackage must reside in a file called MyClass.java that is within a folder called myPackage.

Primitive Types versus Objects

In Java, primitive types (int, float, char, etc.) are weird. 

Why are primitive types so different from Objects?  It has to do with the way they are stored.  Objects use references (pointers) while primitive types are stored directly. 

For a method-call, every argument is copied to the corresponding local parameter for the method.   For primitive types, we copy the value.  For Objects, we copy the value of the pointer.  Here's an example method:

void change (int j, Vector v) {
    j = 4;
    v.addElement("hello");
}

What happens when this method is called in the following piece of code?

int i = 10;
Vector vv = new Vector();
change(i,vv);

After this code runs, i has the value 10 and vv is a Vector that contains "hello".  The variable i is unchanged because its value is copied to j, then j is changed, but the changed value is never copied back into i.  The variable vv still points at the same Vector, but a new element has been added to the Vector.   Think about what would happen if the line v=null were added to the end of the change method.

Note that there is no equivalent to Pascal's var parameters.  Thus, in Java it's impossible to write a method swap(i,j) that swaps the value of two ints.

Wrapper Classes

What do you do if you need to store, say, an int within a Vector?  An int is not an Object so it can't be placed directly into a Vector.  The solution is to create a wrapper that is an Object.  Here's the code for such a wrapper class:

class MyInteger {
    private int value;
    public MyInteger (int iValue) {
        value = iValue;
    }
    public int getValue () {
        return value;
    }
}

If we wished to place, say, 5 into an existing Vector v, it could be done this way:

v.addElement(new MyInteger(5));

This creates an Object of type MyInteger that holds the int value 5 and places into the next position in the Vector.

You don't actually have to create wrapper classes for the primitive types.  Java provides a full set of them, including java.lang.Integer, java.lang.Float, java.lang.Double, etc.  These classes also include some handy code for converting to and from Strings and converting between numeric types.

Declaring, Instantiating, and Initializing

In Java, there is a distinction made between declaring an Object, instantiating an Object, and initializing an Object.  For example,

String [] alpha;

declares alpha to be an array of Strings, but allocates no space for this array.   At this point, alpha has the value null.

alpha = new String[5];

allocates space for alpha.  Alpha can now hold 5 Strings, but the Strings themselves are not initialized.  Alpha[3], for example, is now null.

alpha[3] = "abc";

initializes alpha[3] to be the String "abc".  Note that alpha[3] is not a valid reference to a String until all three of these steps are complete.

For another example, consider

Vector v;
v = new Vector();

The first statement declares the variable v to be of type Vector, but does nothing else.  At this point, the value of v is null.  The second statement calls the Vector constructor which allocates space and initializes a Vector.  At this point, v holds a newly initialized Vector.  These two statements can be combined.  The code

Vector v = new Vector();

will declare the variable v and cause it to hold a newly initialized Vector.

Type Conversions

There are often occasions when you wish to convert a value from one type into another one.  The syntax for this is simple: just put the new type name (in parentheses) in front of whatever it is that you want to convert.

Widening numeric conversions are automatic.  Narrowing numeric conversions must be explicit.  For example

float x = 5;

is OK, while

float pi = 3.1415926;
int p = pi;    // illegal

is illegal.  To convert pi into an appropriate integer, we should use:

int p = (int) pi;    // rounds toward 0.

Some conversions are done without complaint even though information is being lost:

long g = 123456789;
int m = g;    // Silently drops higher bits.

It is often necessary to convert the types of Objects.  Note that runtime checking is done to ensure that the conversion is legal (i.e., you can only convert an Object into a String if that Object was actually created as a String).  Here is an example using type conversion for an Object.

Vector v = new Vector();
v.addElement(new Integer(4));
if (v.elementAt(0).intValue() == 4)    // This is an error.
    ...

The problem in the if-statement is that v.elementAt(0) returns an Object (even though it was an Integer when it was placed in the Vector).  We need to convert it back into an Integer.  Here's one way to do this.

if ( ( (Integer)v.elementAt(0) ).intValue() == 4)

Coding Conventions

There are a number of Java coding conventions that are followed in the Java-code produced by Sun.  I suggest that you follow these same conventions. 

Java Pitfalls

Some of these are well-known C pitfalls.  Java's syntax is largely based on C so some of the same pitfalls are available.

Email us if you have additional pitfalls to suggest.  We'll add them to the list.