Object Oriented Programming - Lecture Notes

Mehmet Gençer
Istanbul Bilgi University
Department of Computer Science

[1]

1 Preface

These lecture notes are unfinished work that is a collection of materials used in Object Oriented Programming (OOP) undergraduate courses given to second year students at Istanbul Bilgi University’s Department of Computer Science. Target audience were students who have learned essential functional programming principles and practice using Scheme language. The OOP course aims to teach these students various aspects and practices of OOP using the Java language. Due to such positioning the course aims to first introduce students to writing programs in an imperative and strictly typed language like java, then proceeds to object oriented paradigm. Through the way we introducing them to tools and practices usable in industrial applications, and underline relative strength and weaknesses of imperative/OOP for different fields of applications.

The course syllabus for the actual courses these lecture notes are used for can be found at which provides information on detailed objectives and administrative matter. These notes are provided as a standalone introductory level document on object oriented programming for anyone interested.

2 Introduction

The programming language, Java, which will be used for practicing concepts taught in this course shares some common features with other industrial grade programming technologies that are very popular today such as C/C++. The key features that distinguish these programming languages from those such as Scheme and Lisp are that (1) they are typed or strictly typed languages, (2) they are object oriented, (3) they are mostly used in imperative style programming, and (4) they are compiled rather than interpreted. Before we start off with full blown examples of Java programs we must explore these features.

2.1 Functional/declarative vs imperative programming

Introducing computer science to programming using a functional programming language like Scheme is gaining popularity among instructors, and well justified considering my experience with performance of those students in later subjects during their education.

Functional programming falls under a generic category of approach which is called the declarative approach in programming. In this style of programming, it is more natural for the programmer to code a computation into a program, once it is mathematically well established. Consider, for example, the problem of computing Fibonacci numbers. The series of Fibonacci numbers can be expressed as follows:
$F_n = \left\{ \begin{array}{ll} n & \textrm{if $n=0$ or $n=1$}\\ F_{n-1} + F_{n-2} & \textrm{if $n>1$} \end{array} \right.$
With the above mathematical definition in hand, it is quite straightforward to express the computation as a Scheme program as follows:

Fibonacci numbers in Scheme

(define (fibo n)
      (cond [(<= n 1) n]
            [else (+ (fibo (- n 1)) (fibo (- n 2)))]))

This approach is labeled as declarative programming since the programmer expresses what needs to be computed (usually in a recursive manner as in the above example), rather than how to compute it (the imperative way). As a result functional/declarative programs are easier to check for correctness.

While ease of code expression is and important advantage, especially in early stages of programming education, there are certain motivations to seek other approaches. First is the fact that achieving computational efficiency may not be possible with the most natural formulation of a computation when expressed as a declarative program. The Fibonacci numbers example above is one example of inefficient code (see Exercise [exer:fibo]). While it is possible to write an efficient program using declarative style and recursive algorithms (see Exercise [exer:fibotailrec]), the mathematical formulation of this new program will no longer be trivial as the first one, hence undermining the advantage of declarative programming in cases like this.

A second motivation for imperative programming is the fact that it is how computer hardware actually works. CPUs (Central Processing Units) simply follow a series of instructions. Languages such as C offer the advantage of resembling more closely the underlying system they intend to control.

Programming languages like Java and C/C++ are not imperative themselves. However, the programming practice of using these languages have been mostly in imperative style and the languages themselves has many facilities that are targeted for such use, such as statements for iterations.

2.2 Strictly typed languages

In the above example of Fibonacci program there’s no indication that the function parameter must be an integer, nor is its return value. Therefore the correct functioning of the system relies on passing of correct values to the function. Many other languages are more sensitive to types of function arguments and return values, and called ’strictly typed’ languages for this reason1. The following function definition is an example implementation of recursive -and inefficient- Fibonacci program in a strictly typed language:

Fibonacci numbers in Java/C

  int fibo(int n) {
    if (n<=1)
      return 1;
    else
      return fibo(n-1)+fibo(n-2);
  }

The above code can pass as a function definition in both C and Java languages (as the latter was inspired by from the former heavily and uses similar syntax). There are several differences compared to Scheme program:

Despite the syntactic differences the function outline resembles that of the Scheme version.

2.3 Object orientation

Traditional computer programs look much like the computer itself. They are composed of ’functions’, which take some inputs and produce an output; much like basic circuit elements like AND,OR gates. The larger software system is an interconnection of inputs and outputs of such elements.

While this aproach works for smaller systems, it caused many problems as the applications of computer programs grow in variety and scale (See (Brooks 1995) for a good reading on these issues). Just like circuits, failure of one element has rendered the whole system malfunction. OOP came out as a practical solution to these problems. OOP is based on the concept of ’object’ , which correspond to an actual entity in the problem one tries to program for. The object in OOP encapsulates all data of a certain type of object and functions applied to that data in programming units called ’classes’. Such way of conceptually collecting data and functions related to that data is found to reduce programming errors in large software systems, in addition to being easier to design as things correspond to real entities.

Therefore in order to apply OOP, one needs programming languages that support such mechanisms. Most modern programming languages today support objects in one way or another. Various software tools are referred to in the incremental treatment of the matter in this document.

2.4 Compiled vs interpreted languages

Some popular programming languages like Scheme, Lisp, Python, PHP, and Perl are all interpreted languages. One needs a special program called interpreter which runs the program written by the programmer. This has the advantage that if one has an interpreter for different systems (e.g. Linux, Python, a cell phone) the same program can be used without any changes.

On the other hand this approach has some disadvantages. The interpreter program must spend a certain time parsing the program before it can be run (hence the word interpret). This brings a certain overhead to the system and interpreted programming languages are generally slower than compiled languages. In compiled languages the program is first passed through a special program called the compiler which translates it to machine code which can be directly executed by the hardware (i.e. the CPU). For example we cannot use an interpreted language to write an OS(operating system), because the OS is the first program to run on the hardware, hence there cannot be an interpreter already available there. Furthermore, compilers can have certain advantages in terms of optimizing the outcome with respect to specific features of the target hardware. Finally, compiled languages are preferred for commercial programs since the original program cannot be recovered by looking at the machine code which is delivered to the customers. Therefore an organization or person who seeks profit from a computer program can keep the original code hidden as a private asset.

Java is somewhat distinct in the sense that it is both compiled and interpreted. The Java compiler produces machine code for execution on not a specific hardware but something called Java Virtual Machine (JVM). Different JVMs of varying capabilities are available for regular PCs, larger computers, cell phones, or chips used in credit cards. In this way Java retains the dual advantages of portability and performance.

2.5 Resources

There are various Java programming and object oriented programming books around. However, this lecture notes are intended to go with a general purpose Java reference (such as (Zakhour et al.)) in addition to other material referenced in the text.

2.6 Exercises

  1. [exer:fibo] Find the complexity, O(), of the Fibonacci program.

  2. [exer:fibotailrec] Write a Scheme program to compute Fibonacci numbers efficiently.

3 Introduction to imperative and strictly typed programming in Java with Processing

Before we attempt writing Java programs for inductrial grade Java programming environments, in this chapter we will start by using Processing (see htt://www.processing.org) to write simple programs that produce visual output. You can install Processing by downloading it from its website. When it is run you will see a screen where you can type your program, much similar to the way DrScheme works. Processing programs are Java programs, but Processing allow us to postpone some cumbersome aspects of industrial grade java environments and instead focus on imperative style programming in a strictly typed language. The Processing environment also have the advantage of having good quality reference and tutorial documentation in addition to examples.

In the screen of Processing system enter your first program as follows:

A first Processing program

/*Program to draw two lines of different thichnesses*/
void draw() {
   strokeWeight(1); //set line thickness
   line(0,0,50,100);// draw a line, eg. line(x1,y1,x2,y2)
   strokeWeight(5);
   line(50,100,100,50);
}

The special function name draw is used by the entry point to drawing by the Processing system. Note that the return type of this function is void, ie. it does not return anything! This is typical of imperative style programming that the function is intended for its side effect, not its return value. What is drawn by the function remains on the screen (and memory of the Processing system) but no return value is meaningful in this case. The remainder of lines starting with a //, in addition to all text between /* and */ are comments in the Java program.

It is possible to write Processing/Java programs using recursion. The following example draws a simple fractal shape:

Recursive pattern

void draw() {
   drawRecursive(0,0,0,90);
}
void drawRecursive(float x, float y, float angle, float length) {
  if (length<=5) //stop drawing
      return; //return from function, with nothing since return type is void
  else{
    float x2;
    float y2;
    x2=x+length*cos(angle);
    y2=y+length*sin(angle);
    line(x,y,x2,y2);
    drawRecursive(x2,y2,angle+PI/2,length*0.9);
  }
}

The above example demonstrates declaration of variables (e.g. float x2) and assignment of values to variables (using = operator), in addition to using some trigonometric functions available in Processing. It also demonstrates use of conditional execution (the if .. else statement). In this program the sequence of statements in the drawRecursive() function is executed one after the other. This is why such programs are called imperative because they impose how and through which steps a task must be executed, contrary to the Scheme Fibonacci program before.

3.1 Iteration

The contrast between declarative and imperative programming becomes more striking if one uses iteration facilities to replace recursive calls. Following is a program to draw a similar fractal:

Using iteration

void draw() {
   drawIterative(0,0,0,90);
}

void drawIterative(float x, float y, float angle, float length) {
  float x1=x;
  float y1=y;
  float currentAngle=angle;
  float currentLength=length;
  while (currentLength>=5) {
    float x2=x1+currentLength*cos(currentAngle);
    float y2=y1+currentLength*sin(currentAngle);
    line(x1,y1,x2,y2);
    currentAngle=currentAngle+PI/2;
    currentLength=currentLength*0.9;
    x1=x2;
    y1=y2;
  }
}

The program uses the while statement which keeps executing the code (i.e. loops) in its brackets as far as the condition in the parenthesis is satisfied. In this example the importance of side effects for the working of the program are more apparent. The program relies on the fact that previous drawing point, angle and line segment length are stored in certain variables.

3.2 A note about data types

So far we have used two data types in Java: void and float. There are various other data types such as double, long, boolean, String, etc. You are recommended to consult a reference documentation whenever necessary. In the future chapters we will have a closer look into data types.

3.3 Variable scopes

Note that among several variables declared in our iterative program some are inside the brackets that belong to the while statement. In Java variables continue to exists and keep whatever value you store in them until their scope vanishes/exits, and the scope is essentially determined by the enclosing brackets. For example if there were any other statements after the while statement, it would not be possible to use x2 or y2 in those statements because their scope has been exited and they have been sent to trash by the Java system. On the other hand variables x1 and x2 can be used in the scope of the while loop in addition to the drawIterative() function, because their scope (the brackets of the function) contains the scope of while loop.

3.4 Exercises

  1. [exer:koch] Write a Processing program to draw a Koch snowflake (search Google for this simple pattern).

  2. [exer:tree] Write a Processing program to draw a tree using a fractal approximation.

3.5 Creating animations with Processing

What Processing system actually does is calling the draw() function you write repetitively. Processing first calls a function named setup(), if available, and then calls the draw() function at a certain frequency. Let us write a Processing program which declares a setup() function to setup screen size and animation rate, in addition to using global scope variables:

Animated random lines

float x=0;
float y=0;

void setup() {
  size(500,700);
  frameRate(5);
}

void draw() {
   //background(255);
   float tmpx=x+random(10);
   float tmpy=y+random(10);
   line(x,y,tmpx,tmpy);
   x=tmpx;
   y=tmpy;
}

In the above program the variables, x and y, are at the global scope, wheras tmpx and tmpy are within the scope of draw() function.

3.6 Exercises

  1. Write a Processing program which animates a growing circle.

  2. [exer:clock] Write a Processing program to draw an analog clock on the screen. You can use hour(), minute(), and second() functions in Processing to learn the time.

  3. [exer:randomtree] Write a Processing program to draw a fractal tree with random variations for more realistic results.

4 Data types, variables, expressions and arithmetic, arrays, and iteration

[ch:data] As Java is a typed language, one needs to make informed use of data types and know related operations, as different from programming in a language like Scheme where types are not explicit (although they exist). In this chapter we will discover essential data types first, then learn how to create and use lists (so called arrays). An important technique in using arrays is iteration, which is a common and practical replacement for recursion when the number of repetitions are known beforehand.

WE have already defined and used some variables. Java uses two kinds of variables where the difference is somewhat hidden from the programmer: primitive and reference type variables. WE will also explore the difference, which is an important topic you may encounter when using other programming languages.

4.1 Data types

An important motivation behind the use of types (in addition to type checking for programming errors) is to use memory efficiently. For this reason Java has several data types that are used when creating variables or declaring function parameters and return types. We will first list the data types which are called primitive data types in Java. :

Please note that all primitive data type names start with a small case letter. This is an important convenience you need to remember to deal with the issues of reference type which we will cover later.

Declaring and using a primitive data type is quite straightforward. For example:

  int n1;
  int n_2;
  n1 = 1;
  n_2 = 25;

A variable name must start with a letter and can contain letters, digits, and the underscore in its name. Other than these syntactic rules there are certain conventions in programming profession you should consider following. These are covered in Appendix [app:codingconventions].

4.2 Operators, expressions, and arithmetic

It is possible to declare multiple variables of the same type on a single line or assign a value during declaration as follows:

  int n1=5;
  float x1,x2=6,x3=7;

A variable can be assigned to the value of another variable or to result of an arithmetic expression:

  int n1=5;
  int n2=n1/2;
  float x1=5.1;
  float x2=(x1/2+1)/5;

In the above example note that the value 5/2 is not an integer. In such cases the result is trucated. In certain cases you may want to cast type of a value to something else using the new type in parenthesis. For example:

  float x=5.1;
  int n= (int)x/2;

In addition to arithmetic operator (+-/*), there is also a modulo operator (%) which evaluates to remainder.

Apart from numeric expressions, logical expressions can be constructed (for example in if statements) as in the following example:

  if ( (x>5) && (x<=10) ) //true if x is greater than 5 AND less than or equal to 10
  if ( (x<5) || !(x>10) )  // true if x is greater than 5 OR not greater than 10
  if ( x%2 == 0) //true if x is even
  if ( x%3 != 0) //true if x module 3 is not equal to zero

4.3 Arrays and iteration

A consequence of the fact that Java is strictly typed and tries to optimize memory usage is that lists in Java are also restricted in their size. If we want to use a storage for many numbers (or other type of things) we must define it to be of certain size. Such immutable, fized size lists are called ’arrays’ in Java (and in other strictly typed languages). Following syntax demonstrates how an array to contain ten integer values is created and accessed:

  int[] array;
  array=new int[10];
  array[0]=1;
  ..
  array[9]=10;

As seen in the example, arrays are indexed started from 0, i.e the first element of the array is at position 0. An array’s length can be learned by appending .length to its name, e.g. array.length evaluates to 10 in the above example.

Arrays of more than one dimension can be defined to store matrices as follows:

  int[][] matrix=new int[5][10];
  matrix[0][0]=1;
  ...
  matrix[4][9]=50;

The size of such arrays are referenced similarly: e.g. matrix[0].length is 10, whereas matrix.length is 5. In other words each of matrix[i] is actually an array of length 10. As a result following assignment is valid:

  int[] row=matrix[0];

When using Scheme, you are accustomed to using recursive functions to span a list of values. For example by recursing into tail of a list to find the maximum value in a list. Although the same is possible in Java, a convenient mechanism, called iteration, is commonly used to span a list whose size is know (which is commonly the case). This is particularly true for arrays.

Following is an example function which returns the maximum of numbers in an integer array (note: array.length returns the size of array):

  /*
   * A function to find maximum of integers in an array
   */
  int max(int[] array) {
    int max=array[0];
    for(int i=1; i<array.length; i=i+1) {
      if (array[i]>max)
          max=array[i];
    }
    return max;
  }

The so called ’for’ loop syntax is as follows:

  for (initialization; control; increment)
    BODY

The initialization is done first. Then if the control expression is validated the BODY is executed. At the end increment part is done and control expression is checked again. This loop continues until control expression is not valid anymore. The BODY part of a for loop can be a single command as in the above example, or a group of commands enclosed within brackets { and }. Although brackets are unnecessary for a single command, it nevertheless increases readability of your programs and hence recommended.

4.4 Variables and reference types

A second group of types in Java are so called Reference types. These are closely related to classes and object as we will explore in the further chapters. A common reference type is String, which is used for storing pieces of text:

  String message = "Hello Ömer!";
  System.out.println(message); //prints the string to terminal output

The important difference between reference and primitive data types relates to assignment and comparison operations. The key to understanding the difference is that reference type variables are addresses (or so called references) of the actual value stored in memory, whereas primitive type variables store the actual value. For example:

int n1,n2;
n1=1;
n2=n1;
n1=2;

When the second statement above is executed the value of n1 is copied into n2. After the third statement the value of n1 is set to 2, however the value of n2 remains the same and not affected. However when a similar thing is done with a reference type like String:

String s1="abcdef";
String s2=s1;
s1="fedcba";

After the above statements are executed you will find that the values of both s1 and s2 are the same (e.g. try printing them as above). The reason is that s1 and s2 are just two different names for the same variable in the memory. The assignment operator in the second statement above copies the address/reference of the first one to the second, not its value. You will find a similar result for all reference type variables in Java (such types all start with a capital letter). For the same reason the following comparison will not yield to a true value:

String s1="abc";
String s2="abc";
if (s1=s2) // evaluates to false, because what is
           // compared is the references, not values

We will learn how to compare strings after exploring classes, objects, and their methods.

4.5 Exercises

  1. [exer:growingcircles] Write a Processing program which animates 10 filled circles of different color, each of which are centered on a random position, starts from a diameter of 10, grows into diameter of 100 as they are drawn repetitively, then returns to diameter 10 again.

  2. [exer:functiondraw] Write a Processing program to draw the plot of a function, for example f(x) = 20 + 2x − x2 / 10 + x3 / 100.

  3. [exer:fibospiral] Write a Processing program to draw a Fibonacci spiral or Fibonacci tiling.

  4. Write a Processing program which animates a growing fractal tree.

5 Classes and Objects

Consider an example problem to solve in Processing: We want to animate a group of moving colored balls (i.e. circles in two dimensions for simplicity). Each ball has a different color, starting position and speed. In order to solve this problem one will need to store colors, positions, and speeds of balls in three different lists (in the same order so that information about a ball can be reliably identified). After drawing balls in their current position in each animation frame, we will need to modify their positions according to their speed.

Following is a solution of the problem using techniques we have learned so far:

Growing balls problem

int numberOfCircles=10;
int sizeX=500, sizeY=700;
color[] colors=new color[numberOfCircles];
float[] posx=new float[numberOfCircles];
float[] posy=new float[numberOfCircles];
float[] radius=new float[numberOfCircles];

void setup() {
  size(sizeX,sizeY);
  for(int i=0;i<numberOfCircles;i=i+1) {
    colors[i]=color(random(255));
    posx[i]=random(sizeX);
    posy[i]=random(sizeY);
    radius[i]=10;
  }
}

void draw() {
  background(255); //white
  for(int i=0;i<numberOfCircles;i=i+1) {
    fill(colors[i]);
    ellipse(posx[i], posy[i], radius[i]*2, radius[i]*2);
    radius[i]=radius[i]+1;
    if (radius[i]>100)
      radius[i]=10;
  }
}

The solution looks fine and works, although it is not very easy to read, since the data for balls and operations on the data are defined is different places. If one wants to make the circles start from a different radius, or change the growth threashold, one can see how the above approach becames less readable (and writeable!).

5.1 Creating classes: types, objects, instances, and references

In OOP terminology objects are concrete examples of the class of things they belong. The motivation for using classes and object oriented programming has been to keep the data about an object and operations on that data close to one another. A class consists of (1) state variables that define a particular object (instance of the class), and (2) the behavior of the object expressed as methods (functions in a class) next to state variables.

Now we will start progressively defining our first class to represent a growing ball in our problem. First we define t he class with state variables only:

 class Ball {
  float positionX;
  float positionY;
  float radius;
  color ballColor;
 }

The class definition collects properties of a ball (its position in two dimensional display, its radius, and color). You must remember that having a class does not mean that we have any objects. Defining a class in our programs means creating a new variable type (which is similar to int, or float). Creating objects mean that we need to create instances of the class. An instance is a particular ball, not the general concept of ball, which has its particular values of the state variables.

Creating objects (which is also called as instantiating a class) is somewhat different from creating variables of type int or float. Following is an example of defining an object of a particular class type, and instantiating it:

  Ball ball;
  ball=new Ball();

The first line above defines a new variable of type Ball. However it is different from defining a variable of type int. For int and other primitive types we can start using the variable (e.g. assigning a value to it) immediately after defining the variable. On the contrary, for objects one needs to create an instance of the class using new ClassName() as we have seen in the above example. This is due to the fact that objects are reference variables (like Strings) and are different from primitive types. For example consider the Java statements below below:

 Ball ball1,ball2;
 ball1 = new Ball();
 ball2= ball1;

In this example we have defined two variables of type Ball (in the first line), but we have created only one object (in the second line). The second variable is assigned to the value of first one (in the third line), but this assignment does not create a copy of the object, as it does for int or float (or all primitive types). Instead it copies the reference to the object. As a consequence ball1 and ball2 are just two names for the same object in Java’s memory. You must remember this distinction between primitive and reference types when programming in Java.

As with primitive types, one can create arrays to store multiple objects. With our growing balls problem we can create the ten balls we need as in the following Processing program:

class Ball {
  ...
}

Ball[] balls=new Ball[10];

void setup() {
  for (int i=0; i<balls.length; i=i+1) {
     balls[i] = new Ball();
  }
}

5.1.1 Accessing state variables of an object: the . notation

Note in the above example that the state variables of the Ball object, ball1, has not been assigned any values. Variables of an object can be accessed using a special notation as in the following example:

  Ball ball;
  ball=new Ball();
  ball.positionX=120;
  ball.positionY=ball.positionX;

In our particualar example of the growing balls problem, we will need to assign initial values to each ball as follows:

class Ball {
  ...
}

Ball[] balls=new Ball[10];

void setup() {
  for (int i=0; i<balls.length; i=i+1) {
     balls[i] = new Ball();
     balls[i].positionX = random(500);
     balls[i].positionY = random(700);
     ...
  }
}

5.1.2 Using constructors

As we have mentioned earlier, the key advantage of using classes and objects is to keep object’s state variables and actions that pertain to these variables close to one another. Therefore the above example of initializing a Ball’s state variables is inadequate. In all object oriented languages it is possible to define a special method called ’constructor’ which is used for initializing state variables. Constructor method must have the same name with the class, and is different from other Java functions in one sense that they do not have a return type. If a class has a constructor then the cosntructor method is executed automatically when an instance of the class is created using a statement like new ClassName().

In our particular example our constructor will need to know the size of the display so that ball position can be selected randomly within the screen. The modified class definition will look like the following:

 class Ball {
  float positionX;
  float positionY;
  float radius;
  color ballColor;

  Ball(int screenSizeX, int screenSizeY) {
     positionX=random(screenSizeX);
     positionY=random(screenSizeY);
     radius=10;
     ballColor=color(random(255),random(255),random(255));
  }
 }

Now if we want to create objects of this class, we will need to provide the required parameters during its instantiation, as follows:

  Ball ball=new Ball(500,700);

]

With the latest version of our class, it is possible to write parts of the Processing program in a more simple and understandable way:

class Ball {
  ...
}

Ball[] balls=new Ball[10];

void setup() {
  for (int i=0; i<balls.length; i=i+1) {
     balls[i] = new Ball(sizeX, sizeY);
  }
}

5.1.3 Using instance methods

We are only halfway through our definition of the Ball class. Unless the class have methods to control its behavior (ie. growing), it is incomplete.

Class methods are function defined inside the scope of the class. They are like any other function in the sense that they have a return type and a parameter list. The only difference is that since they are in the same scope with state variables of the object, these variables are accessible from the instance methods. Similarly the methods can access one another as they are in the same scope. Following is a complete version of our Ball class:

 class Ball {
  float positionX;
  float positionY;
  float radius;
  color ballColor;

  Ball(int screenSizeX, int screenSizeY) {
     positionX=random(screenSizeX);
     positionY=random(screenSizeY);
     radius=10;
     ballColor=color(random(255),random(255),random(255));
  }

  void growAndPaint() {
     radius=radius+1;
     if (radius>100)
         radius=10;
     fill(ballColor);
     ellipse(positionX, positionY, radius*2, radius*2);
  }

  float area() {
     return PI*radius*radius;
  }
 }

Note that we have added a class method to compute area of the Ball as an example of methods with return type, although it was not necessary for our particualr problem in hand.

With this class definition in hand, our Processing program becomes much simpler and understandable:

class Ball {
  ...
}

Ball[] balls=new Ball[10];

void setup() {
  size(sizeX, sizeY);
  for (int i=0; i<balls.length; i=i+1) {
     balls[i] = new Ball(sizeX, sizeY);
  }
}

void draw() {
  background(255);
  for (int i=0; i<balls.length; i=i+1) {
     balls[i].growAndPaint();
  }
}

5.1.4 Exercises

  1. Write a Processing program which animates several rectangles (their number is random between 5 and 15), of random position and color, which grow/shrink in width/height alternatively.

  2. Write a Processing program which animates moving balls, which start with random positions, radius, and speed, then move around the screen and bounce from the sides.

  3. [ex:complexnumbers] Write a class to represent a complex number. The class must have a constructor method, and a method to compute magnitude (or so called absolute value) of the complex number. Assume that a method named ’sqrt()’ is available for taking square root of a number.

5.2 Using class diagrams in class design

The real potential of using objects in large scale software applications comes from the fact that objects in OOP correspond to real objects, and their interaction resemble actual interaction of entities in the system, rather than a clockwork modeling of reality that functional programming dictates (which is actually useful in small scale).

This potential can be turned to actual advantage if OOP mechanisms are used within object oriented design (OOD) principles. The key element in design is deciding what properties and behavior of objects in a system will be like before actually writing the code for them. This practice provides what ’contracts’ do in PLT style Scheme programming.

A common practice in object oriented design is starting off with so called class diagrams. Following is an example class diagram for what is expected to be a representation of Complex numbers:

  ----------------------------------------
  | Complex                              |
  ----------------------------------------
  | float real                           |
  | float imaginary                      |
  |---------------------------------------
  | Complex(float real, float imaginary) |
  | float magnitude()                    |
  | float getReal()                      |
  | float getImag()                      |
  ----------------------------------------

The class diagram is a very concise summary of properties and methods of the class. Now if we want to write a method to multiply two complex numbers we know how to access its properties, before even the class is actually coded! This is an important advantage in industrial software development, because once it is decided how several classes will allow access to their methods and properties to create a useful system, different programmers can take each class and implement them. The collection of class diagrams provide a conceptual guide for those involved in creating the software system.

5.3 Using DrScheme/ProfessorJ for non-graphical exercises

Processing system is useful for graphical exercises, but is limiting for other types of programming. DrScheme program, to which students may be familiar from Scheme programming, has recently released with facilities to use it for Java programming. This extension called ProfessorJ takes us one step closer to using industrial grade Java environments.

After running DrScheme, choose Java+dynamic as the language of study. Then in the DrScheme’s main area you can enter your class definition. The console below the main area can be used to create instances of your class, and then to invoke its methods for testing. For the purposes of this course, we will not cover the testing facilities for Java programs.

Try using DrScheme for solving the Complex number implementation exercise above.

5.4 Garbage collection and object destructors

Notice that we have not done anything to destroy objects we have created. When there is no reference available for an object or when its scope is destroyed, the Java garbage collector takes care of cleaning them. For example the code below:

  Circle c1=new Circle(100);
  c1=new Circle(200);

leaves the first circle inaccessible. Java keeps track of the references to objects, and takes care of cleaning the memory for objects which there’s no way of referencing them again. In general we have no control over when or how often the garbage collection takes place. This have some consequences for real time programming using Java, but in general it is of no concern to programmers except such cases where instantenous performance is critical.

When an object is destroyed by the garbage collector, the instance method called finalize(), if available, is called. This method is called the destructor, as it is the opposite of constructor.

5.5 Creating three dimensional animations in Processing

3D animation is an advanced topic in Processing. Nevertheless we provide a small example of it below, which uses a modified version of the Ball class and setup() function. Pleas enote that a library is necessary to use 3d drawing (see following chapters for importing libraries). Furthermore one needs to turn on the lights and use trandformations for 3D drawing. Please refer to Processing reference documentation to explore the 3D drawing facilities further.

The key elements of drawing can be simplified as follows:

Following program draws growing spheres at random locations in the 3D space, uses default ambient lighting.

import processing.opengl.*;

class Ball {
  float positionX;
  float positionY;
  float positionZ;
  float radius;
  color ballColor;

  Ball(int screenSizeX, int screenSizeY, int screenSizeZ) {
     positionX=random(screenSizeX);
     positionY=random(screenSizeY);
     positionZ=random(screenSizeZ);
     radius=10;
     ballColor=color(random(255),random(255),random(255));
  }

  void growAndPaint() {
     radius=radius+1;
     if (radius>100)
         radius=10;
     fill(ballColor);
     pushMatrix();
     translate(positionX, positionY,positionZ);
     //ellipse(positionX, positionY, radius*2, radius*2);
     sphere(radius*2);
     popMatrix();
  }

  float area() {
     return PI*radius*radius;
  }
 }
 int sizeX=500, sizeY=700, sizeZ=500;
 Ball[] balls=new Ball[10];

void setup() {
  size(sizeX, sizeY,P3D);
  for (int i=0; i<balls.length; i=i+1) {
     balls[i] = new Ball(sizeX, sizeY,sizeZ);
  }
}

void draw() {
  background(255);
  lights();
  for (int i=0; i<balls.length; i=i+1) {
     balls[i].growAndPaint();
  }
}

6 Classes, types, and objects

You may have already noticed that variables which are objects (class instances) are defined similar to primitive type variables. For example:

int x=2;
Ball b=new Ball();

Also remember that the two variables are different: the first is a primitive type variable which holds the value we assign to it, whereas the second is a reference type variable which holds the reference of the class instance.

Despite these differences the declaration syntax demonstrates that the new class we have defined, Ball, becomes a data type in Java. The new variable, b, in the above example is of this new type. Therefore, creating classes in Java means adding new data types to the language.

The types are important in a strictly typed language like Java, because a variable of certain type can be assigned a value of the same type only. For example the following statement will cause an error in Java:

 Ball b=3;
 if ("abc">4) ...

Because we are trying to assign an integer value to a variable of type Ball, or compare a string to a number! Java is quite strict about matching types in assignment or comparison operations. Nevertheless, it will allow automatic conversion between numeric types (e.g. from float to int) in most cases.

What is more interesting when using classes is that a class itself is a variable, of type class! Remember that a class definition starts as class Ball .... This has important consequences when programming in Java, because one must learn the difference between a class (which is an entity of type class), and its instances (which are of type the class itself). Therefore a class is an entity of type class, but it is special in the sense that it creates a new type in Java.

More important in this matter is that one must learn to differentiate things which belong to a class, and things which belong to instances. This is perhaps one of the most stumbling points for students learning Java.

6.1 Class members versus object members

So far we have only used instances of classes. Therefore classes provided as a template for creating objects. However Java provides certain mechanisms for classes to have variables of methods of their own. This is done to save memory or speed up method invocation.

For example consider a class to represent Circles, and to provide methods to compute its area and circumference.

  class Circle {
    double radius;
    double PI=3.14;
    Circle(double radius) {
      this.radius=radius;
    }
    double area() {
      return PI*radius*radius;
    }
  }

With the above code, a copy of PI constant will be stored in computer memory for each instance of the class. Instead of doing so, we can define the PI variable as a class variable using ’static’ keyword : public static double PI=3.14; This reduces the amount of memory to store variables by 50%! The static members of a class can be accessed without creating an object instance from class: eg. just Circle.PI.

In some cases, the static mechanism can be used for methods also. For example if we want to implement a group of functions to operate on natural numbers:

  class NaturalNumberMethods {
    static int factorial(int n) {
      if (n<=1)
        return 1;
      else
        return n*factorial(n-1);
    }
    static int fibonacci(int n) {...}
  }

Note that the class has no constructor, because it will neve be instantiated! It is just used as a container of methods and has no object specific state. Therefore the methods are accessed directly via classes: eg. NaturalNumberMethods.factorial(5).

You must keep in mind that although static and non-static members are mixed in the class code, they are worlds apart. Static methods cannot reference object variables or use this keyword. For example if we opt to make area() method of the Circle class above as static, it would not work, since it references the object variable ’radius’.

Mixing static and non-static methods is rather counter-intuitive in object orientation (unlike rare cases as in the example above with static PI variable), although it is syntactically possible.

6.1.1 Exercises

  1. [ex:complexmethods] Create a class which has collection of methods for complex number arithmetic, in addition to being able to represent a complex number. The class must have methods for addition, substraction, and multiplication of complex numbers. Note that each of these methods consume two arguments of type Complex (e.g. you class in part (i)), and returns a new instance of Complex.

  2. Improve the Complex class in DrScheme/ProfessorJ, so that it keeps track of how many instances of the Complex is created, and how many instances are alive. Use a static counter to count instances, and use the destructor to detect how many instances are alive.

6.2 Reflection

Since a class is like any other object in Java it is possible to inspect its members, such as class methods. This is called reflection in Java. Since it is an advanced topic we do not cover reflection in this course. The curious readers are recomended to consult Reference documentation of the Class class, and consult relevant tutorial lessons at java.sun.com website.

Classes and methods can be passed around and inspected as other Java entities. It is possible to inspect classes and objects using a group of reflection tools in Sun JDK. Following is a demonstration of these mechanisms. Please refer to http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html for an extensive review.

  class A{
    A() {}
    String summary() {
        return String.format("This is an instance of %s",
          this.getClass().getName());
    }
  }
  class B{
    B() {}
    String summary() {
        return String.format("This is an instance of %s\n And it has a different summary.",
          this.getClass().getName());
    }
  }

  class CFN {
    static void main(String[] args) {
      String input=System.console().readLine("Enter class name : ");
      try {
        Class c=Class.forName(input);
        I x=(I)(c.getConstructors()[0].newInstance());
        System.out.println(x.summary());
      } catch (Exception e) { System.out.println(e);}
    }
  }

7 Using Industrial Grade Java Environments

Among descriptions of programming languages you will hear the terms compiled and interpreted. Compiled languages are those such as C and assembler, which take the program code you write and run it through a program called the compiler to produce the so called ’executable’ which can be directly understood (i.e. interpreted) by the computer’s CPU. On the other hand interpreted languages has no such intermediate conversion, but instead the program code is interpreted by the program called interpreter.

Each system has its advantages. In compiled languages the end user will need the executable suitable for the hardware architecture(type of CPU and operating system) they have, in order to run your program. However with the advantage that the executable is optimized for the CPU. In the case of interpreted languages, on the other hand, end users need an interpreter for their architecture, but besides that can run the same program code on any architecture. Interpreted languages are somewhat more convenient, but compiled languages usually result in faster running programs2.

Java was designed to have best of both worlds. It is both a compiled and an interpreted language. To run a Java program one must first run it through the Java compiler to produce the Java bytecode (the equivalent of executable). However, unlike C executable, Java bytecode is not intended to be interpreted directly by the CPU+operating system, but rather by an interpreter called the Java Virtual Machine (JVM). Although this may seem unnecessarily complicated, this design of Java resulted in excellent portability3 which Java owes its success. The JVM isolates Java software from the specifics of hardware and operating system. Because of this isolation Java is extremely safe. For example a JVM that works inside your web browser provides the system for programs called Java applets. Since this JVM isolates the applet from the rest of your computer, they are safe to run and does not carry any risks. Also it has been possible to create JVMs -with reduced capabilities- for very small devices such as cell phones or credit card chips so that they can run Java programs.

One of the most commonly used Java systems comes from Sun Microsystems, the designers of Java language. It is free to download Sun Java SDK(system development kit) which includes the compiler, the JVM, and many libraries you can use when writing programs. Many other systems are available such as commercial systems from Borland and IBM, or public licensed ones from GNU. If you are using a GNU/Linux system such as Ubuntu, you should be able to install Sun Java SDK on your system by running the following commands to install necessary packages:

  aptitude install sun-java6-jdk
  aptitude install sun-java6-jre
  aptitude install sun-java6-plugin

First package installs Java compiler and libraries. The second installs the JVM. And the third enables your web browser to run Java applets.

A simple type of Java program that we create using such systems is console based applications which does not have a graphical user interface. The industrial grade Java systems mentioned above use the same template to create such an application. Following is a piece of code that resembles Java Hello World applcation you will see in the first pages of many Java books and online tutorials:

 /**
 * A simple Java console based application
 * @author Mehmet Gencer
 */
 public class HelloWorld {
    public static void main (String[] arguments) {
      System.out.println("Hello user!");
      if (arguments.length>0) {
          System.out.println("You have run this program with the following arguments:");
          for(int i=0; i< arguments.length; i=i+1)
              System.out.println(arguments[i]);
      }
     }
  }

Save the code above in a file named HelloWorld.java. The file and the class must have the same name! Then compile as below:

  javac HelloWorld.java
If you see no error messages, you must have a new file named HelloWorld.class. That is the file containing compiled bytecode. You can now run it as follows:
  java HelloWorld
If you give command line arguments\mymark{command line arguments}, you will see the program reporting them back:
  java HelloWorld a1 a2 a3
  Hello user!
  You have run this program with the following arguments:
  a1
  a2
  a3

In summary, the requirements for having a console based Java application is therefore having a public class which has the same name with the file, and having a public and static method named main within that class. This is very much like setup() and draw() methods in Processing, the main() method is where Java will start executing your program. Please note that we have not created an instance of the HelloWorld class! Instead JVM invokes its static method to execute our application. The command line arguments we give to the program are passed by the JVM as an array of strings to the main() method.

The statement which starts with System.out demonstrates an example of interacting with the user, which we will explore further in the following sections.

7.0.1 Why the static main() method?

When a Java program first starts, all it knows are the classes imported from libraries (the next section) and classes defined by the user. There are no objects (except some everpresent obejcts, see the next section below). For this reason it is imperative that the entry method for the Java programs must be a static method! It is just a common convenience that all JVM implementations look for a class method (i.e. static method) named main as the starting point of the programs. This is much like the convenience of having setup() and draw() methods in PRocessing system.

7.1 Using Java libraries

Sun Java SDK comes in with a rich set of libraries you can use in your proograms. These range from mathematical facilities, to libraries for processing image or sound files. A reference documentation of all Sun JDK libraries (generated using javadoc) can be found at http://java.sun.com/javase/6/docs/api/.

In order to use a library in your program, you must first tell Java to ’import’ the library. To demonstrate these mechanisms we will now try to create a program which ask the user to enter numbers and finds their squareroot. For this application we will need the Math library to compute squareroots. Following is the program code:

  import java.lang.Math;

  public class RootFinder {
    public static void main(String[] arguments) {
        String input;
        do {
            input=System.console().readLine("Enter a number : ");
            if (input.length()>0) {
                double number=Double.parseDouble(input);
                double numberRoot=Math.sqrt(number);
                System.out.println(numberRoot);
            }
        } while (input.length()>0);
        System.out.println("Goodbye!");
    }
  }

The first line imports the Math library. After that we can use the methods in the library with a syntax such as Math.sqrt(). You can imagine that this library is like the complex number class we have created, which is composed of static methods. For getting input from user we call System.console() which returns an object suitable for reading from the console by its readLine() method. But this method returns a string type value, so we must convert it to a real number using Double.parseDouble() method.

Some classes we have used in the above program such as Double are built-in, we did not need to import anything to use them. However for the Math class we needed to import it.

The import mechanism is necessary in Java to control capabilities of the system and bytecode size. For example in Java Mobile, which is a JVM that works on cellular phones, or Java Micro, which works on much smaller devices such as credit card chips, some (most!) libraries wouldn’t be available.

java.sun.com provides the reference documentation for all essential objects in Java SDK, and for those that come in its standard libraries. When writing programs you will often need to consult the reference documentation. Make sure you use the appropriate version of the documentation. You can learn the version of the Java SDK you are using by invoking the javac command with -version option.

7.2 Everpresent objects in JVM

One special object, named System, exists when a Java program is started execution in tje JVM. The System object represents the operating system environment surrounding the JVM and allows one to access system properties or interact with the user using the system console in which the program runs.

You are advised to read Java reference documentation of the System class to learn full features it provides.

7.3 Interacting with the user

One of the uses of System object is to print messages to the user console, or read input from it. The programs above have already demonstrated some uses such as System.out.println(...) statement. The in and out members of the System object are rather crude channels representing input from and output to user console. A more convenient way of interacting with user through the console is to obtain and use the Console object from the System, which has more convenient methods to do these things. The console can be used as in the following examples:

import java.io.Console;
...
String s=System.console().readLine("Enter some string please:");
...
String name="Mehmet";
int grade=50;
System.console().format("Hello Mr. %s, your grade is %d", name, grade);

7.4 Exercises

  1. Write a Java program which prints all System properties on the console output.

  2. [ex:jcafactorial] Write a Java console application which takes an integer number as command line argument and reports its factorial. (Hint: use Integer.parseInt(some string) to convert a command line argument to an integer number.)

  3. [ex:reverstring] Write a Java console application reads strings from the user and prints them in reversed form. (Hint: read the Java reference documentation of the String class)

  4. Write a Java program which computes Fibonacci number for large n, using BigInteger class from java.util library.

7.5 Handling errors in Java programs

Many unexpected errors may occur, especially when your program uses unchecked input from user of files. In many cases where an error (exception in Java parlance) is possible, Java compiler will warn you. But proper error handling, still relies on programmer skills. Following program demonstrates how exception handling mechanisms can be used in a program which expects a number from the user and reports its factorial. If the number cannot be properly converted to integer, program will report the error.

  public class Exceptions {
    static int factorial (int n)  {
        if (n==1)
            return 1;
        else
            return n*factorial(n-1);
    }
    public static void main(String[] args) {
        String input=System.console().readLine("Enter a number : ");
        int n;
        try {
            n=Integer.parseInt(input);
            System.out.println(factorial(n));
        } catch (NumberFormatException e) {
            System.out.println("You have mistyped the number.");
        }

    }
  }

The new mechanism in the program is the try .. catch.. block. Which will try to execute the command block and if an exception occurs, it will take prescribed steps in the catch block corresponding to the exception type. There are several predefined exceptions in Java, and ’NumberFormatException’ is one of them. For a list of Java predefined exceptions, and a detailed review of exception mechanisms see http://java.sun.com/docs/books/tutorial/essential/exceptions/index.html.

Try running the above program, first provide a valid positive integer, then type something dummy to see NumberFormatException. And finally give it a negative number, which will cause a runtime problem which cannot be captured by any catch block. To prevent this last problem, we have to redefine our factorial method so that it will deny carrying out the calculation for an invalid value:

  public class Exceptions {
    static int factorial  (int n) throws Exception {
        if (n<=0)
            throw new Exception("Negative value given!");
        if (n==1)
            return 1;
        else
            return n*factorial(n-1);
    }
    public static void main(String[] args) {
        String input=System.console().readLine("Enter a number : ");
        int n;
        try {
            n=Integer.parseInt(input);
            System.out.println(factorial(n));
        } catch (NumberFormatException e) {
            System.out.println("You have mistyped the number");
        } catch (Exception e) {
            System.out.println("Unexpected error:");
            System.out.println(e);
            e.printStackTrace();
        }

    }
  }

In this version, the function definition declares that it potentially causes(throws) an exception of a certain type. The generic ’Exception’ type is the root of all exceptions. Also in this version we have used more than one catch block, which are chosen by Java according to the type of exception that occurs. The second catch block will catch any exception which is not catched by the previous one, and also uses the exception instance to print out detailed information about the error.

7.6 Self documenting programs

Java SDK comes with several useful tools. One of them, javadoc, is used for creating HTML documentation from your code comments. Try the following command:

  javadoc HelloWorld.java

It will produce a file named index.html. Open the file in a web browser and see how it allows you to browse your classes and methods. For each class, method, or class variable, javadoc uses your comments which immediately precede the definition of class or method, or variable.

7.6.1 Exercises

  1. Explore the javadoc manual page and find out how to include author information in the generated documentation.

7.7 Profiling Java processes

Even if one is very careful, certain programming mistakes can lead to programs which suffer from bad performance. In such situations use of a profiling tool can prove very useful. Recent versions of the Sun Java SDK comes with one such tool called jvisualvm. Using this tool, one can examine properties of live Java processes and JVMs, such as their memory usage, or where (which methods) the program spends its time. You are recommended to use this or similar tools to solve performance problems which you cannot figure out the reason by looking at your -potentially large- program code.

8 Sub-classing and Inheritence

So far all the classes we have created stand on their own (except for mutual references). In many cases, however, we need mechanisms to avoid code repetition, and facilitate class access. A typical such case is when multiple sub-classes are needed to represent classes of objects that have many similar aspects, yet have their own peculiarities.

Consider the case of different type of resources in the library. Different information needs to be kept for books and journals, yet some other information such as whether the resource is in the library or borrowed, its call number, etc., are common to two types. For such cases, Java (and other object oriented languages) offers the inheritence mechanism to solve the problem, so that all class members (variables and methods) can be inherited and extended by sub-classes. In the library example we first define the Resource class to represent aspects common to all resource types:

 |--------------------------------------|
 |   Resource                           |
 |--------------------------------------|
 | String callID                        |
 | String title                         |
 | boolean isBorrowed                   |
 |--------------------------------------|
 | Resource(String callID, String title)|
 | String summary()                     |
 | void borrowed()                      |
 | void returned()                      |
 |--------------------------------------|

We have included a summary() method in our class so that it can report the item to users, and two other methods to use when the resource is borrowed and returned. Following is a Java console program which implements the class and creates a few instances to experiment with it:

  class Resource {
    String callID;
    String title;
    boolean isBorrowed;
    Resource(String callID, String title) {
        this.callID=callID;
        this.title=title;
        isBorrowed=false;
    }
    String summary() {
        String summary;
        if (isBorrowed)
            summary=String.format("Call ID: %s \nTitle: %s\n not in library.",callID,title);
        else
            summary=String.format("Call ID: %s \nTitle: %s\n in library.",callID,title);
        return summary;
    }
    void borrowed() { isBorrowed=true;}
    void returned() { isBorrowed=false;}
  }

  public class Library {
    public static void main(String[] arguments) {
        Resource[] resources=new Resource[3];
        resources[0]=new Resource("QA76.1","Euclid's geometry");
        resources[1]=new Resource("QA73.2","Literate programming");
        resources[2]=new Resource("QA73.3","Origin of the species");
        resources[0].borrowed();
        for (int i=0; i<resources.length; i=i+1)
            System.out.println(resources[i].summary());
    }
  }

When we want specific types of resources such as books and journals, a difficulty arises. For books we need the author information in addition to variables of the Resource class. For the journals on the other hand we don’t have author information, but instead we need the issue number. At this point we will use the sub-classing mechanism. The Book and Journal classes will be sub-classes of the Resource class. They inherit all variables and methods, and extend it instead of re-implementing everything. Following is a Java console program using this method:

  class Resource {
    String callID;
    String title;
    boolean isBorrowed;
    Resource(String callID, String title) {
        this.callID=callID;
        this.title=title;
        isBorrowed=false;
    }
    String summary() {
        String summary;
        if (isBorrowed)
            summary=String.format("Call ID: %s \n  Title: %s\n  not in library.",callID,title);
        else
            summary=String.format("Call ID: %s \n  Title: %s\n  in library.",callID,title);
        return summary;
    }
    void borrowed() { isBorrowed=true;}
    void returned() { isBorrowed=false;}
  }

  class Book extends Resource {
    String author;
    Book(String callID, String title, String author) {
        super(callID,title);
        this.author=author;
    }
    String summary() {
        return super.summary()+String.format("\n  Author: %s",author);
    }
  }

  class Journal extends Resource {
    String issue;
    Journal(String callID, String title, String issue) {
        super(callID,title);
        this.issue=issue;
    }
    String summary() {
        return super.summary()+String.format("\n  Issue: %s",issue);
    }
  }

 public class Library {
    public static void main(String[] arguments) {
        Resource[] resources=new Resource[3];
        resources[0]=new Resource("QA76.1","Euclid's geometry");
        resources[1]=new Journal("QA73.2","ACM Transactions","March 2007");
        resources[2]=new Book("QA73.3","Origin of the species","Charles Darwin");
        resources[0].borrowed();
        for (int i=0; i<resources.length; i=i+1)
            System.out.println(resources[i].summary());
    }
  }

Let’s go over the new mechanisms in this program one by one:

8.0.1 A note about the types

Note that the array in the example program above is an array of Resource type, although its contents are instances of different classes (Journal, Book, etc.). In Java (and most object oriented languages), an instance of a sub-class passes as an instance of its super-class. THis is because the sub-class has everything the super-class has. We will see a similar type compatibility when we use interfaces in the following chapters.

8.1 Scopes, disambiguation, and overloading

As we have mentioned in Chapter [ch:data] each variable or method defined has a scope within which it can be used. In Processing it was possible to use variables at the global scope (i.e. not inside any brackets). However when using industrial grade java environments, each variable or method must be inside a class, or its methods.

When a variable is defined at the class level, it is accessible from every member method of the class. However you must remember that static members of a class are different fron those that are not. Since non-stati members belong to objects (class instances) and not to the class itself, you cannot, for example, use non-static variables or methods from within static methods. For example paarts of the the following code will cause an error:

class C {
  int n=0;
  static int s=0;
  void getn() {
    return n; //OK
  }
  void gets() {
    return s; //OK
  }
  static void get2n() {
    return n; //ERROR!!
  }
}

Remember that although it is syntactically correct to access static variables from non-static methods, one must be very careful when doing so, because what is changed is the single copy of variable that is inside the class, not some variable that is peculiar to the instance.

In certain situations a variable can become unreachable although it is in the scope. Consider the following example:

class C {
   int n;
   C(int n) {
      n=n; // ??? WHICH n WE ARE TALKING ABOUT ?
   }
}

Since the method parameter is in an inner scope, it shadows the variable in the higher scope. In the above situation, one can use the special variable, this, to refer to the class instance (ie. disambiguate the reference) as follows:

class C {
   int n;
   C(int n) {
      this.n=n; // ??? WHICH n WE ARE TALKING ABOUT ?
   }
}

A similar problem is possible when a sub-class defines a variable or method which shadows the member of super-class in a similar manner. This is also the same problem when one needs to call the constructor of a super-class. One can use the special variable super to refer to the super-class in such situations. For example.

class C {
   int n;
   ...
}
class C2 extends C {
   int n; //SHADOWS THE SUPER-CLASS VARIABLE
   void f() {
     n=super.n;
  }
  C2() {
    super(); //CALLS SUPER-CLASS' CONSTRUCTOR
    ...
  }
}

8.1.1 Overloading and overriding methods, method signatures

In the example above the meaning of having a constructor for a sub-class is actually overriding the construtor of the super-class. Because when the class is instantiated, the constuctor method invoked will be that of the sub-class, hence the constuctor of the super-class is overridden. Similar would be the case if a sub-class re-defines any of the super-class methods.

In some cases it is necessary to allow different types of constuctors for a class. For example consider that we want to create a class to represent a circle. We may want to allow the user to choose the coordinates and/or size of the circle, or if he/shee chooses they will be randomly assigned. The following class which defines multiple constructors does this:

 -----------------------------------------|
 |  Circle                                |
 -----------------------------------------|
 | float r, x, y;                         |
 -----------------------------------------|
 | Circle();                              |
 | Circle(float radius);                  |
 | Circle(float radius, float x, float y);|
 |----------------------------------------

class Circle {
  float r, x, y;
  Circle() {
     r=random(100);
     x=random(300);
     y=random(400);
  }
  Circle(float radius) {
     r=radius;
     x=random(300);
     y=random(400);
  }
  ...
}

Although the three constructor methods all have the same name, Java will have no problem in choosing which one to invoke, because the given parameters to constuctor can help choosing which method to invoke. This is said as that the methods have different signatures (i.e. different parameter lists). This method of defining multiple methods with the same name but different parameter lists is called method overloading. It is particularly useful for class constructors, but nevertheless can be used for any class method.

8.2 Abstract classes and methods

A mechanism that can be used when implementing a group of related classes is the abstract classes and abstract methods. For example consider that we want to implement uni-dimensional shapes such as circles, squares, and equilateral triangles. We know that all have a single dimension to be specified when constructed, but methods for drawing them or computing their circumferences are different. In such a case we can use a semi-implemented class which has some abstract methods as follows:

   abstract class Shape {
     float size;
     Shape(float size) { this.size=size;}
     abstract float circumference();
   }

Since some methods are abstract (and thus the class is incomplete), it is not allowed to create instances of this class. Instead we have to create classes which extend it and implement these methods:

   class Circle extends Shape {
     float circumference() { return PI*size*size;}
   }
   class Square extends Shape {
     float circumference() { return 4*size;}
   }

Note that we had to implement only the abstract methods in our sub-classes

8.2.1 Exercises

  1. Consider that we want to implement different types of shapes in Processing. Use the abstract class mechanism to implement circles and squares in the program.

8.3 An example of extending JDK classes: Graphical user interfaces

Java’s original popularity was largely due to graphical capabilities of Java Applets, which are Java programs that can run within a web page. Sun Java SDK not only have tools for creating applets but also provides libraries to create industrial grade graphical user interfaces. This section provides only a short peek into these capabilities. Please visit http://java.sun.com/applets/ for extensive tutorials.

An applet is designed to be displayed within an HTML page. Following is a simple applet and the HTML page to display it:

import javax.swing.JApplet;
import java.awt.*;
import java.util.*;
public class SimpleApplet extends JApplet {
    Date timestamp;
    public void init() {
      timestamp=new Date(); //current time
    }
    public void paint(Graphics g) {
        g.drawLine(0,0,this.getSize().width,this.getSize().height);
        g.drawString(timestamp.toString(), 5, 15);
        g.drawString(new Date().toString(), 5, 35);
    }
}

The class in the applet program extends the Applet class of JDK. The HTML page for displaying the applet is as follows:

 <html>
  <body>
    <p> My little applet:</p>
    <applet code="SimpleApplet" width=400 height=400>
  </body>
</html>

If you first compile the Java program and then display the HTML page in a browser you will see the applet simply drawing a diagonal line. note that the HTML page and the Java class file must be in the same directory since the HTML applet tag indicates the code resides in the same directory.

Applets have a limited use these days, but GUI applications are commonplace. Following is a standalone Java application which demonstrates how similar GUI libraries is used in standalone applications. It dows exactly what the applet above does, but this time in a window of its own:

import javax.swing.*;
import java.awt.*;
class BasicApplication {
    static GUI gui;
    static JFrame mywindow;
    public static void main(String[] args) {
        gui=new GUI();
        mywindow = new JFrame("My window");
        mywindow.setSize(200, 300);
        mywindow.add(gui);
        mywindow.setVisible(true);
    }
}

class GUI extends JPanel {
    JButton button;
    GUI () {
        button=new JButton("Click here");
        add(button);
    }
    public void paintComponent(Graphics g) {
        g.drawLine(0,0,100,100);
    }
}

You can run the above application like any other JDk application, with the difference that it will display a GUI window. The application uses library classes from Java Advanced Windowing Toolkit (AWT) and its newer, and richer cousing Swing. A Java GUI application has a JFrame as its window. A window frame may include a Panel (the main area), toolbars, and menus. Our little application uses only a panel, and places a clickable button on the panel. The panel itself is a drawable area much like the applet window. Our class, GUI, which extends the JPanel class has a method names paintComponent() which is called at the beginning to populate the content of the application window.

8.3.1 Exercises

  1. [ex:juliafractal] Interesting fractal shapes can be produced using quadratic Julia sets on the complex numbers plane. A quadratic function is one which is iterated as zn + 1 = zn2 + c, where c is a complex constant. The Julia set corresponding to c is the set of points z0 which when the iteration does not approach infinity. Write a JDK application which can read c from the user and draws the Julia set on the screen (e.g. by visualizing which points around the center of the complex plane belong to Julia set). Usually choosing a color based on how fast the function converges at a given point gives nicer looking results than monochromatic visualizations.

9 Interfaces

A different type of problem arises when several classes are only similar in terms of behavior. For example consider shapes such as circles and rectangles in a drawing. All shapes will need to have methods to draw them, or compute their area. But other than this commonality, they share nothing. Drawing a circle or computing its area is not similar to doing the same for a rectangle. Therefore having a basic Shape class and extending it will not help us at all. On the other hand we certainly need to convenience of treating all shapes in the drawing similarly, as we have done in the main() method of our libaray application above. Books and Journals could both be treated as resources, and stored in the same array. In this chapter we will learn a mechanism which is a better alternative to abstract classes and methods we have learned before.

A new mechanism, based on interfaces, is used for solving problems like the one in the shapes example. What we need to do is to design an interface which declares what methods an abiding class must have. Afterwards when we create different classes, we declare them as implementing the interface, so that they can be treated similarly (i.e. they are compatible types).

We will implement this example in Processing. Following is our program:

    Shape[] shapes=new Shape[3];

    void setup() {
      size(500,500);
      shapes[0]=new Circle(50,100,100);
      shapes[1]=new Rectangle(50,70,200,300);
      shapes[2]=new Rectangle(100,70,300,400);
    }

    void draw() {
      for (int i=0; i<shapes.length; i=i+1)
        shapes[i].draw();
    }

    interface Shape{
      void draw();
      float area();
    }

    class Circle implements Shape {
      float radius;
      float posX,posY;
      Circle(float radius, float posX, float posY) {
        this.radius=radius;
        this.posX=posX;
        this.posY=posY;
      }
      void draw() {
          ellipse(posX,posY,radius*2,radius*2);
      }
      float area() { return PI*radius*radius;}
    }

    class Rectangle implements Shape {
      float a,b;
      float posX,posY;
      Rectangle(float a, float b, float posX, float posY) {
        this.a=a;
        this.b=b;
        this.posX=posX;
        this.posY=posY;
      }
      void draw(){
        rect(posX,posY,a,b);
      }
      float area() { return a*b;}
    }

Note that similar to the sub-classing method, classes that implement Shape interface are accepted as instances of Shape. Thus we are able to store shapes that are instances of different classes in an array of type Shape.

9.1 Multiple interfaces (or why interfaces are better than abstract classes)

A shortcoming -or rather a design preference- in Java is lack of polymorphism, i.e. a class can not be a sub-class of more than one class. However, intrfaces does not have this limitation. A class can extend only one claass but can implement as many interfaces as desired.

For example consider in the shapes example above that there are shapes that can move. We can represent the behavioral blueprint of moving shapes in the following interface:

  interface MovingShape {
    void moveTo(float newX, float newY);
  }
Now we can redefine our Circle class to implement both interfaces:
  class Circle implements Shape, MovingShape {
  ...
    void moveTo(float newX, float newY) {
      this.posX=newX;
      this.posY=newY;
    }
  }

This new class can pass as an instance of both Shape and MovingShape.

9.2 Mixing the mechanisms

It is perfectly possible to use a mix of sub-classing, interfaces and abstract classes to implement a problem. Consider that we want to implement some uni-dimensional shapes which can also be moved in a coordinate system. Following is one possible solution to the problem:

  interface MovingShape {
    void moveTo(float newX, float newY);
  }
  abstract class UnidimensionalMovingShape implements MovingShape {
     float size, posX, posY;
     UnidimensionalMovingShape(float size, float posX, float posX) {
       this.size=size;
       this.posX=posX;
       this.posY=posY;
     }
     void moveTo(float newX, float newY) {
      this.posX=newX;
      this.posY=newY;
     }
     abstract float circumference();
  }
  class Circle extends UnidimensionalMovingShape {
     float circumference() {
       return PI*size*size;
     }
  }

9.2.1 Exercises

  1. Consider the different types of resources in a University library. Write an interface to represent the behavior of these resources.

  2. Consider a size limited buffer to store integers. Write an interface to represent operations on such a buffer. Make two implementations for first-in-first-out and last-in-last-out buffers.

9.3 Example: Responsive GUI application

Note that the button in our previous GUI application application was not responsive, nor it was shut down when the window is closed. To add this capability we need to use several additional libraries. Following is an application which does a more complex work and also can sense button clicks and mouse location. The application will keep drawing a connnected series of lines as you click on its screen:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.event.*;

class BasicApplicationReactive {
    static GUI gui;
    static JFrame mywindow;
    public static void main(String[] args) {
      gui=new GUI();
      mywindow = new JFrame("My Application");
      mywindow.setSize(200, 300);
      mywindow.add(gui);
      mywindow.setVisible(true);
      mywindow.addWindowListener(new MyWindowAdapter());
    }
}

class GUI extends JPanel {
    JButton button;
    int x,y;
    LinkedList<Line2D.Double> lines;
    GUI () {
        x=0;
        y=0;
        lines=new LinkedList();
        button=new JButton("Click here to reset");
        button.setActionCommand("click");
        button.addActionListener(new MyActionListener(this));
        add(button);
        addMouseListener(new MyMouseListener(this));
    }
    public void paintComponent(Graphics g) {
        g.clearRect(0,0,getSize().width,getSize().height);
        for (int i=0;i<lines.size();i+=1)
            ((Graphics2D)g).draw(lines.get(i));
    }
    void moveTo(int newx, int newy) {
        lines.add(new Line2D.Double(this.x,this.y,newx,newy));
        this.x=newx;
        this.y=newy;
        this.repaint();
    }
    void reset(){
        lines=new LinkedList();
        getGraphics().clearRect(0,0,getSize().width,getSize().height);
    }
}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent event) {
        System.exit(0);
    }
}

class MyActionListener implements ActionListener {
    GUI gui;
    MyActionListener(GUI gui) {
        this.gui=gui;
    }
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("click"))
            gui.reset();
    }
}
class MyMouseListener extends MouseInputAdapter {
    GUI gui;
    MyMouseListener(GUI gui) {
        this.gui=gui;
    }
    public void mouseClicked(MouseEvent e) {
        int newx=e.getX();
        int newy=e.getY();
        gui.moveTo(newx,newy);
    }
}

The application introduces several additions to handle different kinds of events:

Window events

Events caused by user actions such as minimizing, maximizing, or closing the window (JFrame).

Actions

Events caused by clicking buttons, menu or toolbar items.

Mouse events

Any other mouse click inside the application window (panel).

In this modified version, the GUI class implements ActionListener interface (from java.awt.event library) itself, so that it can respond to button click. On the other hand, seperate classes are used for the other two event types. The MyWindowAdapter is needed by the window (Frame) level only, thus it is added to the main window by addWindowListener() method of JFrame. On the other hand mouse clicks in the drawing area are captured by MyMouseListener class, which is attached to the Panel as its mouse event listener, by addMouseListener() method of JPanel. The button click is identified by first setting the action command at the beginning after JButton instance is created, then looking for the identification string as action events arrive.

This version of the application maintains a list of lines (Line2d.Double class instances) and adds new lines extending to the point where user clicks the mouse. The button click will reset the lines list. Use of Line2d.Double class imposed the necessity to type cast Graphics to Graphics2D which can manage instances of this class. The mix of these classes is a result of historical development of JDK GUI libraries. At some point AWT development was ceased, and new classed were started to be developed as a part of Swing library.

There are -seemingly- less painful ways of designing Java GUIs. The NetBeans IDE (Integrated Development Environment) from Sun Microsystems is one free software which can be used for designing GUIs by dragging and dropping visual elements to application window.

10 Encapsulation and data safety in classes

You have probably noticed that the classes in the previous section contained variable and method modifiers such as public. This access modifier is one of several that allows us to control how a class member can be accessed.

Let’s first see the motivations for access control in classes. Consider a class as follows to represent a circle:

  class Circle{
    float radius;
    Circle(float radius) {
      this.radius=radius;
    }
  }

Now we can create a circle and later set its radius:

  Circle c=new Circle(5);
  c.radius=-5;

The assignment above is a mistake, but not a syntax error. The program will work and it is upon us to figure out something is wrong with the circle which has a negative radius! We must take control of how radius is set and does not allow invalid values. This requirement is an essential motivation for so called Model-View-Control (MVC) concept in many programming tasks.

Java provides a mechanism to disallow access to class variables (and actually methods, as we will see later). The private and public modifiers allow us to describe the level of access. By default everything is non-private, but it is a good exercise to make things explicit. The new class is as follows:

  class Circle{
    private float radius;
    public Circle(float radius) {
      this.radius=radius;
    }
    public getRadius() { return radius; }
    public setRadius(float newRadius) {
      if (newRadius>0)
       radius=newRadius;
    }
  }

With the definition above, any attempt to access radius of a circle directly is prohibited. The following line will produce an error:

  c.radius=5; //ERROR at compilation

Following is a summary of the consequences of using access modifiers on accessibility of elements:

Modifier Class Package Subclass World
public Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N

NOTE: Where making encapsulation explicit whereever possible is the recommended practice, we omit doing so in most examples below to make them easier to read.

10.0.1 Exercises

  1. [ex:bankaccount] Write a class to represent a bank account. The account should have variables to store account holder’s name, access password, and amount of money in the account, and have methods to withdraw money if the correct password is given.

10.1 Nested and anonymous classes

Not all classes need to be at the global scope, it is possible to define a class within anothre class, for example to avoid its use beyond that:

class Outer {
  ...
  private class Inner {
    ...
  }
  Inner i;

In a different way, one may wish to use a class which is not used anywhere except one point in the program. In such cases it is possible to define an anoynymous class as follows:

class C {
  void someMethod(java.util.Enumeration) {
    ...
  }
  ...
  someMethod(new java.util.Enumeration() {
      public boolean hasMoreElements() {  ... }
      public Object nextElement() { ... }
    });

Note that an anonymous class has not name and it can only be defined as extending a class or implementing an interface.

11 Implementing data structures

11.1 Self-references, mutual-references

We have seen that classes have variables to keep data about objects. There is no limitation that prevents us having a variable whose type is a class we create, or even the class it is defined within. For example consider the problem of representing the sales in a shop. There will be many sales during the day and we don’t know how many. Thus using a fixed size array is not a suitable solution. A way of overcoming the problem is to store a chain of sales (a linked list), in which each sale points to the next, and the last one points to nothing:

  class Sale{
    float amount;
    Sale next;
    Sale(float amount) {
      this.amount=amount;
      next=null;
    }
  }

What we have done is called ’self-referencing’ since on of class variables is of the type class itself. We left the variable having a value of null since we do not know its value before another sale is created. However we can have a second constructor for cases we want to support values for both variables:

  class Sale{
    float amount;
    Sale next;
    Sale(float amount) {
      this.amount=amount;
      next=null;
    }
    Sale(float amount, Sale next) {
      this.amount=amount;
      this.next=next;
    }
  }

What we have done is called method overloading, as we have multiple definitions for the same method. Since two definitions have different argument lists, Java can choose one depending on how we instantiate the class.

Following is an example piece of code to enter a few sale operations into a system using the class above:

   Sale lastSale=null;
   lastSale=new Sale(100);
   lastSale=new Sale(200,lastSale);

In other situations we may have more than one class in our programs which are somehow related. For example consider that we want to store who sold what when we keep sale records in the above example. It is apparent that we will have a class to represent salesman. Let’s first draw

the class diagram for this system:
   |-----------------------------|   |---------------------------|
   | Sale                        |   |Salesman                   |
   |-----------------------------|   |---------------------------|
   |float amount                 |<--|Sale saleChain             |
   |Sale next                    |   |String name                |
   |Salesman sm                  |-->|---------------------------|
   |-----------------------------|   |Salesman(String name)      |
   |Sale(float amount)           |   |void addSale(float amount) |
   |Sale(float amount,Salesman sm)   |---------------------------|
   |Sale(float amount,Salesman sm,
   |         Sale next)          |
   |-----------------------------|

Note how we used arrows to indicate mutual referencing between the two classes. The class diagrams present a complete view which allows manipulating the system. Now we can proceed to write the two classes.

  class Sale{
    float amount;
    Sale next;
    Salesman sm;
    Sale(float amount) {
      this.amount=amount;
      next=null;
      sm=null;
    }
    Sale(float amount, Salesman sm) {
      this.amount=amount;
      this.sm=sm;
      next=null;
    }
    Sale(float amount, Sale next, Salesman sm) {
      this.amount=amount;
      this.sm=sm;
      this.next=next;
    }
  }
   class Salesman {
     Sale saleChain;
     String name;
     Salesman(String name) {
       this.name=name;
     }
     void addSale(float amount){
       saleChain=new Sale(amount,saleChain,this);
     }
   }

Now we can enter sales for different salesperson:

   Salesman sp1=new Salesman("ali");
   Salesman sp2=new Salesman("ayse");
   sp1.addSale(100);
   sp2.addSale(200);

(See (Felleisen 2004) for a more detailed discussion on self and mutual references)

11.1.1 Exercises

  1. [ex:totalsales] Add a method to Salesman class which finds total amount of sales by the salesperson.

  2. [ex:booksauthors] We want to represent books in the library and their authors using Java classes. For books we want to store book title and author of the book. For authors we want to store their name. Create class diagrams for both classes.

  3. [ex:stack] Implement a stack of integers which provide methods for pushing and popping values from the stack, and returning the size of stack. If the stack is empty, simply return 0 when one attempts to pop a value.

11.2 Variable size data: implementing mutable lists

When the amount of entities to be stored are not known in advance, immutable lists (Java arrays) are not much useful. A common remedy is using a linked list, in which each item knows the reference of the next item, thus forming a chain. Such a self-referential class for storing integers would be as follows:

  class IntegerList {
    int n;
    IntegerList next;
  ...
  }

Obviously one would need methods to add, remove, or access elements of the list. Linked lists vary according to how elements are added and removed (e.g. stacks, queues, sorted lists, etc.). Following program demonstrates how a stack can be implemented:

    class ListItem {
        int n;
        ListItem next;
        ListItem(int n) {
            this.n=n;
            next=null;
        }
        ListItem(int n, ListItem next) {
            this.n=n;
            this.next=next;
        }
    }
    class IntegerStack {
        ListItem header;
        IntegerStack() {
            header=null;
        }
        void push(int n) {
            header=new ListItem(n, header);
        }
        int pop() {
            ListItem retval=header;
            header=header.next;
            return retval.n;
        }
        boolean isEmpty() {
            if (header==null)
                return true;
            else
                return false;
        }
    }
    public class Stack {
        public static void main (String[] args) {
            IntegerStack stack=new IntegerStack();
            stack.push(1);
            stack.push(2);
            while (!stack.isEmpty())
                System.out.println(stack.pop());
        }
    }

Linked lists are very commonly used and Java SDK provides libraries to avoid implementing the above functionality each time a mutable list is needed. Following program has the same functionality with the above one using LinkedList class from java.util library:

    import java.util.*;

    public class JavaList {
        public static void main(String[] args) {
            LinkedList stack=new LinkedList();
            stack.push(1);
            stack.push(2);
            while (!stack.isEmpty())
                System.out.println(stack.pop());
        }
    }

The LinkedList implementation aditionally offers exporting the data as an array, which comes handy in some cases.

Since the LinkedList stored the generic Object type, its use may involve typecasting in most cases beyond our simple integer list. To avoid this LinkedList variables can be declared to hold a specific type as in the following example: LinkedList<String> list;

11.2.0.0.1 Example: Books and authors

Consider an application to store information about books in a library and their authors. Each book will have more than author, and each author is releated to several books. Also the amount of books in the library is subject to change. Following is a solution to the problem:

    import java.util.*;
    class Author {
        String name;
        LinkedList<Book> books;
        Author(String name) {
            this.name=name;
            books=new LinkedList();
        }
        void addBook(Book book) {
            books.add(book);
        }
        void printSummary() {
            System.out.println(name);
            for (int i=0; i<books.size();i=i+1)
                System.out.println(String.format("  %s",books.get(i).title));
        }
    }
    class Book {
        String title;
        LinkedList<Author> authors;
        Book(String title) {
            this.title=title;
            authors=new LinkedList();
        }
        void addAuthor(Author author) {
            authors.add(author);
        }
        void printSummary() {
            System.out.println(title);
            for (int i=0; i<authors.size();i=i+1)
                System.out.println(
                String.format("  author: %s",authors.get(i).name));
        }
    }
    public class Library {
        /**
          * Find author in the authors list and return. Return null if
          * author is not in the list.
          */
        static Author findAuthor(LinkedList<Author> authors, String name) {
            for (int i=0; i<authors.size(); i=i+1)
                //Note that string comparison is different from primitive types
                if (authors.get(i).name.equals(name))
                    return authors.get(i);
            return null;
        }
        public static void main(String[] args) {
            LinkedList<Author> authors=new LinkedList();
            LinkedList<Book> books=new LinkedList();
            String title;
            do { //loop to enter books
                title=System.console().readLine(
                 "Enter the book title (or empty to finish) : ");
                if (!title.equals("")) {
                    Book book=new Book(title);
                    String authorName;
                    do { // loop to enter authors of a book
                        authorName=System.console().readLine(
                         "Enter the author name (or empty to finish) : ");
                        if (!authorName.equals("")) {
                            //first check if author already exists
                            Author author=findAuthor(authors, authorName);
                            if (author==null){  //author does not exist, create it
                                author=new Author(authorName);
                                authors.add(author);
                            }
                            book.addAuthor(author);
                            author.addBook(book);
                        }
                    }while(!authorName.equals(""));
                    books.add(book);
                }
            } while (!title.equals(""));
            System.out.println("BOOKS IN THE LIBRARY");
            for(int i=0; i<books.size();i=i+1)
                books.get(i).printSummary();
            System.out.println("AUTHORS IN THE LIBRARY");
            for(int i=0; i<authors.size();i=i+1)
                authors.get(i).printSummary();
        }
    }

12 Object serialization and persistence

An object that resides in the memory of JVM can be serialized, i.e. turned into a sequence of bytes from which the object can be recovered in its state at the time of serialization. The possibility of serializing objects have many advantages such as the ability to store them in a file to be later recovered, or transferring them over the Internet to another JVM in another computer (e.g. in e-business). The only requirement for a Java class to be serializable is to implement the interface called Serializable, which requires no methods to be implemented. Any object which is an instance of a class implementing Serializable interface can be given to an ObjectOutputStream instance (from java.io library) to be written out. The following example demonstrates how the serialization can be invoked on a LinkedList which already implements Serializable interface:

    import java.io.*;
    import java.util.*;
    class Serialize {
        public static void main(String[] args) {
            LinkedList list=new LinkedList();
            list.add(1);
            list.add(2);
            try {
                ObjectOutputStream so = new ObjectOutputStream(System.out);
                so.writeObject(list);
            } catch (IOException e) {
                System.out.println("Problem writing object");
                System.out.println(e);
            }
        }
    }

The serialized form printed on the screen by the above program is not readable. However it is only intented to be read by Java de-serialization.

The following demonstrates how to persist serialized objects which are instances of our classes into a file. When the program is first run, it will store an object in the file myobj, and in later runs of the program it will recover the object instead of creating a new one. Try running the program more than once.

    import java.io.*;

    class TimeChecker implements Serializable{
        long time;
        TimeChecker () {
            this.time=System.currentTimeMillis();
        }
        long getTime() {
            return this.time;
        }
    }

    class PersistenceExample {
        public static void main(String[] args) {
            TimeChecker tc;

            //de-serialize object if the file exists, create new one otherwise
            try {
                FileInputStream file = new FileInputStream("myobj");
                ObjectInputStream si = new ObjectInputStream(file);
                tc = (TimeChecker) si.readObject();
                file.close();
            } catch(Exception e) {
                System.out.println("No file is found. I will use a new object");
                tc = new TimeChecker();
            }
            System.console().format("Object time is %d%n",tc.getTime());
            try {
                FileOutputStream fileout = new FileOutputStream("myobj");
                ObjectOutputStream so = new ObjectOutputStream(fileout);
                so.writeObject(tc);
                so.close();
            } catch(Exception e) {
                System.out.println("Cannot write out");
            }
        }
    }

We must note that the Java program which de-serializes the object must have the class definition of the object which is being deserialized, otherwise the class of the object cannot be identified. This is not a problem when the object is an instance of a standard Java class such as the LinkedList, but it matters for our own classes.

12.0.1 Exercises

  1. [ex:librarypersist] Improve the library example above so that the books and authors lists will be persisted before program exits.

12.1 Using Databases

Many database engines provide Java libraries. Here we cover the SQLite embedded database as an example since it requires little configuration overhead. However for large scale, high performance applications more capable database engines, such as PostGreSQL or Oracle, are recommended.

Information on SQLite can be found at http://www.sqlite.org/. The Java library used for this tutorial comes from http://www.zentus.com/sqlitejdbc/. Download the .jar file containing the library and keep it where either (i) your want to keep your source files, or (ii) inside the lib subdirectory of your Java JDK.

From an application programmer’s perspective all relational databases are somewhat similar since -almost- all use the Standard Query Language (SQL) for access and manipulation. When using a database one may create/destroy tables, add/delete/update or select records from these tables. It is possible to do all these operations using either (i) user interface programs that comes with the database which access the database directly (or indirectly or remotely, depending on the multi-tier structure and complexity of the database engine), or (ii) by writing programs which access the database using available libraries.

In the case of most high-performance, industrial grade database engines, access to database is controlled by a running process called the database engine. The engine makes sure that all access to database is properly authorized (usually using a fine grained access control mechanism) and also that no accidents happen when there are multiple concurrent accesses. However SQLite is simply an embedded database, and it does not have such an engine that is always up and running and keeping the gates. Instead an SQLite database is simply a file and any process who have access to this file have full access to the database. When one application is using the database it is locked and cannot be modified by another application. Therefore, as an embedded database, SQLite lacks many features in both fronts. But it is nevertheless practical and have a good performance, making it a simple and effective solution for some type of applications.

Despite these differences writing database programs are similar and Java SDK provides certain common aspects of database access already, except the implementations themselves. As other database systems, SQLite also uses the standard Java DataBase Connectivity layer (JDBC) and java standard edition SDK’s java.sql library. Following program demonstrates SQLite usage from Java:

/**
 * SQLite Java library usage example. Adopted from http://www.zentus.com/sqlitejdbc/
 */
import java.sql.*;
import org.sqlite.JDBC;
class SQLiteExample {
    public static void main(String[] args) throws Exception {
        new JDBC(); //initialize the SQLite JDBC system so that the database
                    // descriptor in the next line is usable
        Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
        Statement stat = conn.createStatement();
        stat.executeUpdate("drop table if exists people;");
        stat.executeUpdate("create table people (name, occupation);");
        PreparedStatement prep = conn.prepareStatement(
             "insert into people values (?, ?);");
        prep.setString(1, "Gandhi");
        prep.setString(2, "politics");
        prep.addBatch();
        prep.setString(1, "Turing");
        prep.setString(2, "computers");
        prep.addBatch();
        prep.setString(1, "Wittgenstein");
        prep.setString(2, "smartypants");
        prep.addBatch();

        conn.setAutoCommit(false);
        prep.executeBatch();
        conn.setAutoCommit(true);

        ResultSet rs = stat.executeQuery("select * from people;");
        while (rs.next()) {
            System.out.println("name = " + rs.getString("name"));
            System.out.println("job = " + rs.getString("occupation"));
        }
        rs.close();
        conn.close();
    }
}

To compile the above program you need to specify where the SQLite Java library is located. For example if the library (.jar file) is in the same directory with the program, compile it as follows: javac -cp sqlitejdbc-v054.jar SQLiteExample.java Similarly you will need to specify classpath when executing the program: java -cp .:sqlitejdbc-v054.jar SQLiteExample

If you read the program you will see that four classes are used for database access: Connection, Statement, PreparedStatement, and ResultSet. Connection represents a connection to the database. Location and type of database is indicated when a connection is opened. Statement and PreparedStatement classes are used to execute SQL statements. The latter is used in cases where a statement will be executed multiple times with different parameters. The ResultSet represents a list of records selected with a statement.

When using SQLite databases you must make sure that you close the connections as soon, otherwise it will be blocked for write access by other processes that use the same database.

Normally SQLite driver is set for auto commit, so that statements will be executed when they are issued. However in many cases it is faster and practical to execute a batch of related statements at once, so that they will either succeed or fail alltogether. Such transaction management is an essential practice in database programming to reduce errors, in addition to increasing performance in many cases.

12.1.1 Exercises

  1. [ex:librarysql] Redo the library example in Exercise [ex:librarypersist] using an SQLite database for persisting library data.

13 Java packages

So far we have put all classes needed for our applications in a single source file. This method does not scale well when applications get more complex. Java packages provide the mechanism for organizing code. Packages also provide an additional layer of isolation using the protected members as we will see.

We have been already using Java packages, whenever we have used the import statement in out programs. When we want to create a package like those, we need to do two things:

  1. Put a package declaration at the top of the source file such as package xxx. There is a certain package naming convention in the Java programming community. Packages that start with ’java.xxx’ comes from Sun Microsystems. Those taht start with org and com come from non-profit and for-profit organizations, respectively, usually denoting the organization or project name, such as org.apache.xml, etc.

  2. Place the source files for the same package under a directory structure that resembles its name. For example files for a package named org.bilgi.complex must go under directory org and in that a subdirectory named bilgi etc.

We have previously used only public or private modifiers for classes and their members, or used none. With the additional level of organization using Java packages we can cover one more modifier: the protected modifier. Table [tab:modifiers] summarized where can a class or its members be accessed from when each modifier is used or no modifier (so called package-private) is used:

[tab:modifiers]

Modifier Class Package Subclass World
public Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N

In addition to these, the final modifier prevents a class from being extended or a method from being overridden. The major type of situation where this might be useful is when part(s) of software is in an experimental state and sub-classing can cause a series of troubles. In such cases the final modifier can be used to prevent sub-classing until the package reaches some level of maturation.

As an example package we will put a complex number implementation and Julia set visualization GUI code (see below) into a package named org.bilgi. In order to do that we will create a directory named org and a subdirectory under it named bilgi. Inside that directory create a file, preferably named Complex.java for convenience (but it does not really matter as far as its extension is .java!). That file will contain the complex number implementation as follows:

package org.bilgi;

/**
 * A Complex number implementation for use in quadratic Julia set
 * computations
 */
class Complex {
    double r,i;
    Complex(double r, double i) {
        this.r=r;
        this.i=i;
    }
    double getReal() {return r;}
    double getImag() {return i;}
    Complex square() {
        double newr=r*r-i*i;
        double newi=r*i*2;
        return new Complex(newr,newi);
    }
    Complex add(Complex with) {
        return new Complex(r+with.getReal(),i+with.getImag());
    }
    double length() {
        return Math.sqrt(r*r+i*i);
    }
    /**
     * Return how fast the quadratic function converges
     */
    int julia(Complex c, int numIterations, double cutoff) {
        Complex next=new Complex(r,i);
        for(int i=0; i<=numIterations; i++) {
            next=next.square().add(c);
            if (next.length()>=cutoff)
                return i;
        }
        return numIterations;
    }
    /**
     * Return the quadratic function value for coloring
     */
    Complex juliaValue(Complex c, int numIterations) {
        Complex next=new Complex(r,i);
        for(int i=0; i<=numIterations; i++) {
            next=next.square().add(c);
        }
        return next;
    }
}

The source code starts with a declaration package org.bilgi; to indicate that it is part of a package with given name. Also some of the methods are declared as protected since they are only experimental and I do not want to make them available outside the package.

In a separate source file in the same directory I will place the Julia set visualization GUI, which makes use of the Complex class above. The file is almost the same with the file given at the end of the tutorial as an answer to the exercise, except that (i) Complex class is removed and placed in another file as we have seen above, and (ii) the code starts with a package declaration and and the application class is declared public so that it can be used when the package is imported elsewhere. I have chosen the name JuliaSetFractals.java for my file which goes as follows:

/**
 * Implementation of quadratic Julia sets.
 * Author: Mehmet Gencer, mgencer@cs.bilgi.edu.tr, 2008
 *
 * Try to redraw the Julia fractal using values:
 *   (-0.4,0.6), (0.285,0.01), (-0.835,-0.2321)
 * clicking on a point on the display area will recenter the drawing
 */

package org.bilgi;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.event.*;


class JuliaSetFractals {
    static FractalGUI gui;
    static JFrame mywindow;
    public static void main(String[] args) {
      gui=new FractalGUI();
      mywindow = new JFrame("Julia Set Fractal Renderer");
      mywindow.setSize(400, 400);
      mywindow.add(gui);
      mywindow.setVisible(true);
      mywindow.addWindowListener(new MyWindowAdapter());
    }
}

class FractalGUI extends JPanel{
    JButton button;
    JTextField r,i;
    int centerX,centerY;
    double scale=150; //scaling
    Complex c;
    FractalGUI () {
        button=new JButton("Click here to draw fractal");
        button.setActionCommand("click");
        button.addActionListener(new MyActionListener(this));
        r=new JTextField("-0.4",10);
        i=new JTextField("0.6",10);
        add(r);
        add(i);
        add(button);
        addMouseListener(new MyMouseListener(this));
        centerX=200;
        centerY=200;
        c=new Complex(-0.4,0.6);
    }
    public void paintComponent(Graphics g) {
        g.clearRect(0,0,getSize().width,getSize().height);
        int numiter=20;
        double cutoff=scale;
        for (int x=0;x<getSize().width;x=x+1)
            for (int y=0;y<getSize().height;y=y+1) {
                double real=(x-centerX)/scale;
                double imag=(y-centerY)/scale;
                Complex p=new Complex(real,imag);
                int pj=p.julia(c,numiter,cutoff);
                Color color;
                if (pj>=numiter) {
                    Complex pjv=p.juliaValue(c,numiter);
                    color=Color.getHSBColor((float)(pjv.length()/scale),(float)pjv.length(),(float)pjv.length());
                }
                else
                    color = new Color((float)pj/numiter,(float)pj/numiter,(float)pj/numiter);
                g.setColor(color);
                g.fillRect(x, y, 1,1);
            }
        //draw the axes
        g.setXORMode(Color.white);
        g.drawLine(centerX,0,centerX,getSize().height);
        g.drawLine(0,centerY,getSize().width,centerY);
        g.setPaintMode();
    }
    void recenter(int newx, int newy) {
        System.out.println("Recentering");
        centerX=newx;
        centerY=newy;
        repaint();
    }
    void redraw() {
        try {
            double newr=Double.parseDouble(r.getText());
            double newc=Double.parseDouble(i.getText());
            c=new Complex(newr,newc);
        } catch(NumberFormatException e) {
            System.out.println("Invalid value given!");
        }
        repaint();
    }
    void revalue(int newx, int newy) {
        double real=(newx-centerX)/scale;
        double imag=(newy-centerY)/scale;
        c=new Complex(real,imag);
        r.setText(String.format("%f",real));
        i.setText(String.format("%f",imag));
        repaint();
    }
}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent event) {
        System.exit(0);
    }
}

class MyActionListener  implements ActionListener {
    FractalGUI gui;
    MyActionListener(FractalGUI gui) {
        this.gui=gui;
    }
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("click"))
            gui.redraw();
    }
}

class MyMouseListener extends MouseInputAdapter {
    FractalGUI gui;
    MyMouseListener(FractalGUI gui) {
        this.gui=gui;
    }
    public void mouseClicked(MouseEvent e) {
        int newx=e.getX();
        int newy=e.getY();
        if (e.getButton()==MouseEvent.BUTTON3) //if right-click, choose 'c' from mouse position
            gui.revalue(newx,newy);
        else
            gui.recenter(newx,newy); //if left-click, recenter drawing
    }
}

Note that we do not need to import the Complex class although it is in a separate file. This is because the two source files are part of the same package. The trick, however, lies in the fact that the two files must be compiled at once, as follows:

  javac Complex.java JuliaSetFractals.java

Any attempts to compile the first, then the second will fail!

As I have a new package, I can now write applications which use the package:

import org.bilgi.*;

public class PackageUser {
    public static void main(String[] args) {
        JuliaSetFractals jsf=new JuliaSetFractals();
        jsf.main(args);
    }
}

When compiling the message make sure that either the org directory where our package resides is in the same directory with the program, or you modify the Java classpath (using -cp option of javac command) when compiling and running the program.

13.0.1 Distributing multi-file Java applications: jar archives

When your application consists of one or more packages and some other files that use those packages, it becomes hard to distribute them. You will need to provide detailed instructions for users to create the proper directory structure, which creates quite an error prone situation. A solution for these type od situations is to use Java archives, or simply jar’s.

Sun JDK comes with a program named jar to create or extract such archives. For example you can create an archive containing our package and the application that uses the package as follows:

  jar cvf bundle.jar org PackageUser.java

However jar is more powerful than, for example, zip archives. It is possible to use jar files as executables. In order to do that we must tell Java which class is the one to be loaded as an application. The way to do this is to create a file named manifest.mft which contains the following:

Manifest-Version: 1.0
Main-Class: PackageUser
Class-path: .

then use the jar command as follows:

  jar cvfm bundle.jar manifest.mft org PackageUser.java

Now you can execute the created archive as follows:

  java -jar bundle.jar

This makes distribution of multi-file Java software more practical.

14 A guide for coding style

[app:codingconventions] Computer programs are not merely for compilers and interpreters. On the contrary, a more frequent type of access happens when we open the program for improving, or finding bugs, or when a team-mate does the same. Therefore, a program needs to be understandable when we need to recollect what we have done previously, or when it is the object of collective work. In this regard, programming is an art form, not only because it is an applied craft of mathematical abstraction, but also as the presentation of this abstraction in the form of a program is a piece of writing which should demonstrate a pleasant and readable style.

A first condition for coding style is consistency in using symbols and delimiting parts of program. When one writes literature, one follows certain established rules in using punctuation marks (i.e. periods at the end of sentence), capital letters (i.e. first letter of sentence, or private names start with capital letters), or demarcating text (i.e. starting new paragraphs or pages). Similar rules emerged through the programming practice in half a century of its existence. These rules are not universal, just as different national languages vary in their rules of writing them. Different programming languages, or some programmer communities can differ in the style rules they follow. In this guide we try to present most common rules used in the world of programming.

14.1 Demarcation

One of these established rules regards demarcation of different scopes in a program. This is established by using consistent indentation for program statements that are at the same level, and increasing indentation level as scopes are nested within one another. Following piece of Java code demonstrates how this is applied:

 int factorial (int n) {
     if (n<=1)
         return 1;
     else
         return n * (n-1);
 }

In the above program the function scope is indented with four spaces. The nested scope of ’if’ statement is indented further:

 int factorial (int n) {
 --->if (n<=1)
 ------->return 1;
 --->else
 ------->return n * (n-1);
 }

The program also demarcates parts of statements with spaces. For example if is written as below:

 int factorial(int n){
 if (n<=1) return 1; else return n*(n-1);}

it becomes considerably less appealing to its reader and very hard to understand.

There are minor variations in how this rule is applied. For example some prefer to place brackets encapsulating scopes as follows:

 int factorial (int n)
 {
     if (n<=1)
         return 1;
     else
         return n * (n-1);
 }

Although this variant of the rule seems more logical, we will follow the first version of the rule, merely due to the fact that it is more common in the programming community.

14.2 Organization

Generally the data has precedence over the process. This is reflected in our second rule of placing variable declaration statements before other statements in the programs. For example in defining a Java class as follows:

 class Complex {
     double real;
     double imaginary;

     Complex (double real, double imaginary) {
         this.real = real;
         this.imaginary = imaginary;
     }

     double getMagnitude () {
       return Math.sqrt(real*real + imaginary*imaginary);
     }
     ...

Different programming languages may follow further refinements in code organization. For example in Java programming, it is a common practice to place static members before non-static members, and constructor methods before any other method. Therefore on top of variables preceding methods, static variables must precede non-static ones, and static methods precede non-static ones but come after constructors. For example:

 class Circle {
     static double PI = 3.14;
     double radius;

     Circle (double radius) {
         this.radius = radius;
     }

     static double area (Circle c) {
         return PI * c.radius * c.radius;
     }

     double area () {
         return area(this);
     }
     ...

14.3 Explanation

Each programmer have a different and unique approach, and even ones approach will be different in two year’s time. Although how you do things may in many cases seem trivial to you, it is a good practice to explain key elements of your program in plain natural language. For this reason all programming languages provide a means of placing comments, lines or blocks of text which is marked to be excluded from program compilation or interpretation, but rather put for the human readers. Today it became a common practice to place short or long comments at top of program files, near classes, functions, or variables, and even within intermediate points inside functions to explain what is going on. The following example uses such comments extensively (some lines are split to fit on the page):

 /** A program to draw Julia set fractals.
   * Author: Mehmet Gencer, mgencer@cs.bilgi.edu.tr
   * Created: 24 Nov 2008
   *
   * This program is free software and provided without any guarantees.
   * You can redistribute this program in original or modified form
   * provided that this copyright notice is preserved.
   */

 /**
   * Complex class represents a complex number, and provides additional
   * methods for convergence checking in quadratic Julia sets.
   */
 class Complex {
     double real;      // real part of the complex number
     double imaginary; // imaginary part of the complex number

     ...

     /**
       * Return square of the complex number
       */
     Complex square () {
        double newr = real*real - imaginary*imaginary;
        double newi = real*imaginary*2;
        return new Complex(newr,newi);
     }

     /**
       * Check whether a quadratic function in the form z_(i+1)=z_i^2+c
       * diverges for given z when iterated. If the magnitude of z
       * exceeds 'threshold' after at most 'maxIterations' number of iterations
       * it returns true, otherwise it returns false.
       */
     static boolean checkDivergence
       (Complex z, Complex c, double treshold, int maxIterations) {
         Complex znext; //variable to store next value in iteration
         //iterate up to maxIterations,
         // but if threshold is exceeded in the meantime, return true immediately
         znext=z;
         for (int i=0; i < maxIterations; i = i+1) {
           znext=znext.square().add(c);
           if (znext.getMagnitude() > treshold)
               return true;
         }
         return false;
      }
      ...

In the above example the comments at the top of the program briefs what program does, who wrote it and when, and what one can do with it. Each class and method is preceded with a long comment. All variables are succeeded with short comments. And the relatively longer method, checkDivergence(), has comments within the method body.

The above example demonstrates a very common way of code documentation, used in java and C/C++. Indeed there are various programs written to produce software reference documentation automatically from such code comments. However this rule also has variations. For example Python programmers place code comments after method or class definitions, an Python environment has documentation tools based on this.

14.4 Explication

Excessive use of comments may become a handicap to readability of the program. One remedy for this problem is to choose explicit, self-explanatory names for your methods or variables which eliminates further explanation in code comments. For example if the factorial function was declared as follows, it would definitely require code comments:

 int f (int i) {
     ...
 }

as the function name is nowhere near being self-explanatory. Long names may feel cumbersome at the beginning, but you’ll come to appreciate their virtue as you re-visit your programs.

14.5 Naming conventions

There are various names in a program: for classes, for variables, for methods, etc. Also in related to explication, you may have to have variable or method names that are longer than a single word. There are competing trends in how one should choose names. Here we describe the most common methods in the Java programming world:

Brooks, Frederick P. 1995. The mythical man-month : essays on software engineering. Addison-Wesley.

Felleisen. 2004. How to Design Classes.

Zakhour, Sharon, Scott Hommel, Jacob Royal, Isaac Rabinovitch, Tom Risser, and Mark Hoeber. The Java Tutorial: A Short Course on the Basics, 4th Edition. java.sun.com/docs/books/tutorial/java/nutsandbolts/index.html.


  1. Some languages like C are not as strict concerning types. However, this is generally a dangerous preference and only remains to allow low level hacking of computer systems.

  2. For two reasons: (i)that since the code is already parsed, and (ii)compilers have the advantage of using CPU specific optimizations.

  3. Portability is the ability of a computer program to work on different types of hardware and operating systems.