The basic structure of a Java class

We will next look at the structure of a typical Java class in more detail. More refined class features are left for later discussion.

The overall structure of a Java class is quite similar to a C++ class. A class definition can start with class modifiers that define, e.g. the class accessibility or other high level features. The access modifier of a class can be:

  • public: the class can be referenced from everywhere.

  • Empty (no access modifier given): the class can be referenced from all classes in the same package. We will discuss packages shortly.

The class modifiers are followed by the keyword class and the name of the class, and then comes the class body enclosed in curly brackets that contains class member definitions. In Java each class member is given a separate access modifier (as opposed to C++, where access levels are defined in a blockwise manner). A class member (including, e.g a member class!) may have one of the following access modifiers:

  • public: the member can be referenced from everywhere.

  • protected: the member can be referenced from the same package or from an inheriting/implementing subclass.

    • We discuss inheritance and subclasses later.

  • private: the member can be referenced from the class itself, and if the class is an inner class, also from all enclosing outer classes.

  • Empty (no access modifier given): the member can be referenced from the same package.

A class can contain the following parts:

  • Member variables, falling into two categories:

    • Instance member variables (“ordinary” member variables):

      • Store data in an object (each object/instance of the class has its own independent copy of the variable).

      • Can be accessed only by a member reference via an existing object (which naturally must first have been created).

    • Static member variables (class variables):

      • Defined by giving the modifier static in front of the member type. That is, in the same way as in C++.

      • Store data associated with the class itself (only one copy of each such variable exists).

      • Can be accessed always; static member variables are initialized automatically as soon as the class defining them is first referenced in the program.

      • Used typically for, e.g. defining some useful constant values. For example, all number wrapper classes (Integer, Float, etc.) have public static member variables MIN_VALUE and MAX_VALUE that tell the smallest and largest possible value the variable type can hold.

      • A static member variable should be referenced via its class (e.g. as Integer.MIN_VALUE). It is also legal to refer to a static member via an object, but this is considered to be bad programming style.

  • Constructors:

    • Special functions that have no return type and whose name is equal to the class name.

    • A constructor is executed when a new object is created with the new operator. A constructor cannot be invoked using normal function call syntax.

    • Initializes the new object (e.g. sets some reasonable values to the instance member variables, etc.).

  • Member functions, falling into two categories:

    • Instance member functions (“ordinary” member functions):

      • Can only be invoked by a member reference via an existing object. The function can refer to the object in explicit manner by using the special this reference keyword.

      • Can refer to both instance and class variables of its class.

      • Usually somehow uses the instance member variables of the object (otherwise the function would not need to be an instance member function?).

    • Class member functions (static member functions; class member functions):

      • Defined by giving the modifier static in front of the member function.

      • Can refer to class variables of its class.

      • Is not associated with any object. E.g. cannot use the special this reference keyword nor refer to instance member variables.

      • Used usually when defining general helper functions. For example, the Java library class java.util.Arrays contains practically nothing else but helper functions defined as public static member functions (e.g. the sorting function Arrays.sort).

      • A static member function should be referred to via its class (e.g. as Integer.parseInt).

  • Member classes (inner classes, nested classes):

    • A class definition given inside another class definition. The inner class can be defined in basically the same ways as a top level class, but there are some minor differences regarding, e.g. the access modifiers (e.g. a top level class cannot be private, whereas an inner class can).

    • Usually some kind of helper classes used by their enclosing classes. Inner classes are rarely meant to be used independently from their enclosing classes.

      • Generally useful classes should be defined as separate top level classes.

    • An outer class can refer to all (also private) members of its inner class.

    • What members of an outer class an inner class can access depends on whether the inner class is static (defined using the modifier static) or not.

      • A static inner class has no special rights with respect to the outer class. It has access to only non-private members of an outer class.

      • A non-static inner class can access all (also private) members of its outer class.

  • Member interfaces (inner interfaces, nested interfaces):

    • An interface definition given inside a class definition. The form is quite similar to inner classes.

    • We will discuss interfaces later.

The first example class Point2D shown below is a simple data class that represents a point in two-dimensional space. The class stores the data in private variables and provides a constructor and public getter and setter functions for reading and updating them. Java has a fairly universal convention that the getter and setter functions of a private variable member are named in the manner getMember and setMember, respectively. This example class also contains one static member function that computes the Euclidean distance between two points.

public class Point2D {
  private double x;
  private double y;

  public Point2D(double x, double y) {
    this.x = x;
    this.y = y;
  }

  // A second constructor that does not take parameters. The result is like Point2D(0, 0).
  public Point2D() {
    this(0, 0);  // A constructor can call another constructor by using the this reference.
  }

  public double getX() {
    return x;
  }

  public void setX(double x) {
    this.x = x;
  }

  public double getY() {
    return y;
  }

  public void setY(double y) {
    this.y = y;
  }

  public static double distance(Point2D a, Point2D b) {
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return Math.sqrt(dx*dx + dy*dy);
  }
}

Note how a constructor can call another constructor. If you do this, the another constructor must be called immediately in the beginning of the calling constructor’s body. Java classes often have several constructors (so-called “overloaded” constructors) because Java does not support default parameter values. For example in C++ default parameters would allow us to achieve similar functionality with a single constructor of form Point2D(double x = 0, double y = 0).

The class Point2D could be used, e.g. in the following manner:

Point2D a = new Point2D(1, 2);           // a = coordinate point (1, 2)
Point2D b = new Point2D(2, 1);           // b = coordinate point (2, 1)
Point2D c = new Point2D();               // c = coordinate point (0, 0)
double distAB = Point2D.distance(a, b);  // distAB = 1.4142135623730951
double distAC = Point2D.distance(a, c);  // distAC = 2.23606797749979
a.setY(5);                               // a = coordinate point (1, 5)
b.setX(4);                               // b = coordinate point (4, 1)
distAB = Point2D.distance(a, b);         // distAB = 5.0

The second example class LinkedStack given below implements a simple linked stack. The code demonstrates most of the class features listed above, with the notable exception of interfaces and static members (other than main). A stack is a list data structure whose value read and write operations can only refer to its end (“the top of the stack”). The basic stack operations are (1) adding a new item on top of the stack, (2) reading the value of the top item, and (3) removing the top item from the stack. The example manipulates the items via Object references. As will be discussed later with relation to inheritance, all types of Java objects can be handled using Object references.

// The top level class LinkedStack.
public class LinkedStack {

  // The inner class Node is used for storing individual stack items in nodes.
  public static class Node {
    // The private instance member variables of the Node class. These
    // hold a reference to the next node and the item stored into this node.
    private Node next;
    private Object item;  // An object reference can refer to all types of Java objects!

    // Node constructor that receives "next" and "item" as parameters and
    // initializes the corresponding members of the new Node object with them.
    // Make the constructor private if users are not expected to create nodes.
    private Node(Node next, Object item) {
      this.next = next;
      this.item = item;
    }

    // An instance member function that returns the private member "next".
    // We again omit the access specifier (but could give one).
    Node getNext() {
      return this.next;
    }

    // An instance member function that returns the private member "item".
    // We again omit the access specifier (but could give one).
    Object getItem() {
      return this.item;
    }
  } // The inner Node class definition ends here.

  // The private instance member variables of the class LinkedStack. These hold
  // a reference to the top node of the stack and the current stack size. Java allows
  // to give the initializing values directly in the member variable definition, but
  // these could be initialized also in a constructor.
  private Node top = null;
  private int n = 0;

  // This LinkedStack class does not need a constructor because all necessary member
  // initialization was done directly at the member variable definitions. The class
  // will behave as if it had a constructor of form public LinkedList() {} that does
  // nothing.

  // A public instance member function of LinkedStack that returns the top item.
  public Node peek() {
    return this.top;
  }

  // A public instance member function of LinkedStack that removes
  // and returns the top item. Returns null if the stack was empty.
  public Node pop() {
    Node result = this.top;
    if(this.top != null) { // Remove the top item only if the stack is not empty.
      this.n -= 1;
      this.top = this.top.getNext();
    }
    return result;
  }

  // A public instance member function of LinkedStack
  // that adds the given "item" to the top of the stack.
  public void push(Object item) {
    this.top = new Node(this.top, item);
    this.n += 1;
  }

  // A public instance member function of LinkedStack
  // that returns the size of the stack.
  public int size() {
    return this.n;
  }
} // A note to C++ programmers: no semicolon after the closing bracket of a class definition!
  // Although Java does permit one due to how common this error is among C++ programmers.

Below is a simple test program that uses LinkedStack.

public class StackTest {
  // Tests LinkedStack by first inserting all command line parameters into a stack
  // and then printing and removing the top item until the stack becomes empty.
  public static void main(String[] args) {
    LinkedStack stack = new LinkedStack();
    for(String arg: args) {
      stack.push(arg);  // A String object is ok as a parameter of type Object.
    }
    while(stack.size() > 0) {
      System.out.println("Current stack size: " + stack.size());
      System.out.println("  Top item: " + stack.peek().getItem());
      System.out.println("Now popping the top item.");
      stack.pop();
    }
    System.out.println("Current stack size: " + stack.size());
  }
}

You may place the preceding codes into files named LinkedStack.java and StackTest.java and compile them as javac LinkedStack.java StackTest.java. Then running the program as java StackTest one two three will output:

Current stack size: 3
  Top item: three
Now popping the top item.
Current stack size: 2
  Top item: two
Now popping the top item.
Current stack size: 1
  Top item: one
Now popping the top item.
Current stack size: 0

As mentioned before, the javac compiler produces a separate class file for each different class. This applies also to inner classes. Compiling the single file LinkedStack.java produces two class files LinkedStack.class and LinkedStack$Node.class. Javac names class files of inner classes in the form TopLevelClass$InnerClass.class.

Posting submission...