Introduction to Object-Oriented Programming
A tutorial for programmers already familiar with procedural and functional programming.
Prepared by Brandon Smith

Contents

Introduction

In Object-Oriented Programming, everything is treated as an object. In fact, in Java, an integer can be represented not only by the statement int num = 94;, but also Integer num = new Integer(94);

Let's take a look at a Java class, and dissect it from there.

// class is public, meaning that it can be accessed from members
// outside of its own package. packages are going to be covered later
// classes and class members can be public or private
public class FirstClass
{
	// public: means that the 'main' function is accessible from any point 
	//         in the program. Other keywords that could have been used are 
	//         'private' and 'protected', which be be covered later
	// static: means that the 'main' method can be accessed without 
	//         referencing an object of the class (also touched on later)
	// void:   same use as it has in C (main doesn't return anything in this program)
	// String args[]: in Java, the main method has only one parameter, which is an 
	//                array of String objects, arguments entered in the command line.
	//                This will also be touched on later.
	public static void main(String args[])
	{
		int number = 42;
		
		// in Java, console printing is done with the System class.
		// the System class is always automatically included in a Java program, 
		// and therefore doesn't need to be explicitly included, as in C++
		// where one would have to type #include <iostream>
		System.out.println("Brandon's favorite number is: " + number);
		// as seen above, Java allows concatenation of Strings to other data types 
		// using the '+' operator, without the need to typecast
		
	} // end main
	
} // end FirstClass

Click here to download the Java source file for the above example

Static Methods

Now, let's take a look at exactly what it means for a method (function) to be static. A static method is a method that can be accessed without having to construct an object of a particular class. Let's look at the following code for an example of the difference between static and non-static methods.

// there are two classes defined in this one file
// usually this is not done, but for the sake of simplicity, 
// it's useful sometimes to do this when learning Java
// only one class per file can be public, and that class must
// have the same name as the file (minus the .java part)

public class StaticOrNot
{
	public static void main(String args[])
	{
		// since the 'add' and 'subtract' methods are static, 
		// they can be accessed like such:
		int num1 = Calculator.add(5.0, 6.0);
		System.out.println(num1);
		
		// however, because 'multiply' and 'divide' are not static, 
		// the must be used with an object of the 'Calculator' class
		// this is done with a constructor, which will be covered later
		Calculator calc = new Calculator();
		int num2 = calc.multiply(3.0, 3.0);
		System.out.println(num2);
		
		// we can also use objects to access static methods
		int num3 = calc.subtract(5.0, 2.0);
		
		// but, not vice-versa... the following line of code would 
		// cause a compiler error if it was not commented out
		int num4 = Calculator.divide(16.0, 2.0); // NOT VALID
	}
}

// simple class to demonstrate static methods
// 'add' and 'subtract' are static, 
// 'multiply' and 'divide' are not
class Calculator
{
	public static float add(float a, float b)
	{
		return a + b;
	}
	
	public static float subtract(float a, float b)
	{
		return a - b;
	}
	
	public float multiply(float a, float b)
	{
		return a * b;
	}
	
	public float divide(float a, float b)
	{
		return a / b;
	}
}

Click here to download the Java source file for the above example

Objects

From the Java objects tutorial :

Objects are key to understanding object-oriented technology. Look around right now and you'll find many examples of real-world objects: your dog, your desk, your television set, your bicycle.

Real-world objects share two characteristics: They all have state and behavior. Dogs have state (name, color, breed, hungry) and behavior (barking, fetching, wagging tail). Bicycles also have state (current gear, current pedal cadence, current speed) and behavior (changing gear, changing pedal cadence, applying brakes). Identifying the state and behavior for real-world objects is a great way to begin thinking in terms of object-oriented programming.

In order to use an object, it must first be instantiated, or constructed. There is a certain type of method used for construction, aptly called a constructor. It is only used once during the life of an object, and contains the routines and instructions in order to set the object up for use. For example, the following Java programs has a class named 'Car' that contains a String, used to specify color. A class may contain multiple constructors. If no constructors are coded, the compiler acts like there is a default constructor (one that contains no parameters) with no lines of code in it. For example, if the below class Car contained no constructors, the compiler would act as if there was a constructor coded public Car() {}.

public class Constructors
{
	public static void main(String args[])
	{
		Car pickup = new Car();
		System.out.println("This car is " + pickup.color);
		
		Car ferrari = new Car("red");
		System.out.println("This car is " + ferrari.color);
	}
}

class Car
{
	String color;
	
	// because this constructor contains to parameters, it is called
	// the 'default' constructor
	// if the programmer doesn't specify the color, 
	// then the default constructor specifies what value 'color' will have
	public Car()
	{
		color = "white";
	}
	
	// this allows the programmer to have direct control of what color
	// the car will be
	public Car(String c)
	{
		color = c;
	}
}

Click here to download the Java source file for the above example

The above code should output:

This car is white
This car is red

Fundamentals of OOP

Objects exhibit 3 traits in OOP: encapsulation, inheritance, and polymorphism. The easiest of these 3 to understand is encapsulation, which is why it will be covered first.

Encapsulation

Below is an example of encapsulation, which is an object containing an instance of another object.

public class Encapsulation
{
	public static void main(String args[])
	{
		Car ford = new Car();
		System.out.println("This car has " + ford.engine.horsePower + " horsepower.");
		ford.start();
		
		Car ferrari = new Car("400");
		System.out.println("This car has " + ferrari.engine.horsePower + " horsepower.");
		ferrari.start();
	}
}

class Car
{
	Engine engine;
	
	public Car()
	{
		engine = new Engine();
	}
	
	public Car(int hp)
	{
		// passes the int 'hp' to the Engine constructor
		engine = new Engine(hp);
	}
	
	public void start()
	{
		engine.turnOn();
	}
}

class Engine
{
	int horsePower;
	
	// the engine defaults to 200 hp
	public Engine()
	{
		horsePower = 200;
	}
	
	// user-defined horsepower
	public Engine(int hp)
	{
		horsePower = hp;
	}
	
	public void turnOn()
	{
		System.out.println("putter, putter... VROOM!!!!");
	}
}

Click here to download the Java source file for the above example

The above code should output:

This car has 200 horsepower.
putter, putter... VROOM!!!!
This car has 400 horsepower.
putter, putter... VROOM!!!!

The Car class contains a single reference to engine. While this program doesn't really do anything useful, encapsulation becomes very important when coding in real-life situations. For example, a simple linked list can be implemented using encapsulation, each node object containing another node object.

Inheritance

From the Wikipedia page for inheritance :

In object-oriented programming, inheritance is a way to form new classes (instances of which are called objects) using classes that have already been defined. The inheritance concept was invented in 1967 for Simula.

For example, let's say that we want to extend the functionality of the Car class, but only for certain types of cars. In this instance, we will be adding a child class of Car called Truck, and we will be adding a towing capacity variable to Truck (assuming that towing will only be done by Trucks, and not Cars).

public class Encapsulation
{
	public static void main(String args[])
	{
		Truck chevy = new Truck("blue", 12000);
		System.out.println("This " + chevy.color + " truck can tow " 
			+ chevy.towingCapacity + " lbs.");
	}
}

class Car
{
	String color;
	
	public Car()
	{
		color = "white";
	}
	
	public Car(String c)
	{
		color = c;
	}
}

// inheritance is specified using the 'extends' keyword
class Truck
{
	int towingCapacity; // expressed in pounds
	
	// since there is no default constructor, the compiler acts like 
	// I have typed in:
	// public Truck() {}
	
	// this constructor is specific to Truck, and cannot be used by a Car object
	public Truck(String c, int tc)
	{
		// the keyword 'super' is used to pass variables to the parent class constructor,
		// also referred to as the superclass
		// this must be the first statement in any constructor of a child class
		// (also called a subclass)
		// if this is not included, the compiler acts as if the programmed had typed:
		// super();
		// which calls the default constructor of the parent class
		super(c);
		towingCapacity = tc;
	}
}

Click here to download the Java source file for the above example

The above code should output:

This blue truck can tow 12000 lbs.

Variable Access

As we see in the above example, a reference to a child class has access not only to its own data members, but also that of its parent class. However, this can be controlled, using the public, private, and protected keywords. These keywords specify which classes are allowed access to the class member variables. Previously, all the examples that have class member variable didn't contain any reference to these keywords, and as such, the default behavior of public was implied. However, this is not good programming practice, and one of the main principles of OOP is controlling variable access. Normally, class member variables are declared as private or protected. Variables declared private can only be accessed by methods (functions) inside the same class. Variables declared using the protected keyword are similar to private variables, but they can also be used inside of classes that have been declared as a subclass of the containing class.

To declare a variable as private or protected, the keyword is placed right before the data type. For example: private int amount; or protected Calculator calc = new Calculator();

These keywords may only be used with variables declared inside of a class. These keywords have no function inside of a method, as variable declared in a method "die" when the method completes anyway.

If the programmer attempts to access a variable in a manner contradictory to its access keyword, the program will not compile.

Polymorphism

Polymorphism is one of the more difficult OOP fundamentals to understand, but I'll attempt to make it as easy as possible.

At it's very basic form, polymorphism means "many forms". In OOP, polymorphism refers to the ability of a class to take many forms and implementations, depending on the need of the programmer. Understanding polymorphism in Java requires understanding of keywords like interface and abstract.

NOTE: For an advanced look at polymorphism with C#, click here. For polymorphism with C++, click here.

Interfaces

OK, so what exactly is an interface? Interfaces are like class, except their methods are not defined, and they can only contain constant data members (using the final keyword, like the const keyword in C/C++). Let me give you an example:

public interface Interface
{
	int PI = 3.1415;
	String MONEY = "We all want lots of it!";
	
	public static int[] sort(int list[]);
}

Click here to download the Java source file for the above example

NOTE: Arrays in Java automatically contain their sizes, and thus a separate variable to indicate array size is not necessary. If I have an array named list, then I can determine its size by using list.length, like this: int listLength = list.length;. This differs from C++, and in my mind, makes things much, much easier when dealing with arrays. Java arrays are not dynamically resizable, however, and the line of code list.length = 20; will cause the compiler to become very angry with you. In order to change array size, the user must use a statement similar to list = new int[20];, redefining the array and destroying the previous values. For a tutorial in Java arrays, click here.

What the heck was that? You may have noticed that the method ended with a semicolon, and that there were no curly braces or function definitions. There were variables, but the had to be initialized when they were declared, and they can't be changed (as per the rules of constant variables). Interfaces aren't meant to be used directly by programmers, but rather as an outline for creating implementations. Interfaces can also be used to demonstrate an association between classes, allowing various objects of various classes to have similar roles. For example, in the above interface, the sort method is not defined. That's because there are many ways to sort an array of ints, but so long as the sorting is implemented, the implementation doesn't matter.

.. Tell you what, it may just be easier to show you what I mean:

public class UsingInterfaces
{
	public static void main(String args[])
	{
		int array[] = {3, 2, 4, 5, 1};
		
		// interfaces can't be directly constructed, 
		// but they can be constructed using a class that implements them
		Sorter bubble = new BubbleSorter();
		
		printArray(array);
		bubble.sort(array);
		printArray(array);
	}
	
	// just used to print the array
	public static void printArray(int array[])
	{
		for (int k = 0; k < array.length; k++)
			System.out.print(array[k] + " ");
		System.out.println(); // moves caret to next line
	}
}

interface Sorter
{
	public static void sort(int list[]);
}

// the 'BubbleSorter' class implements the 'Sorter' interface
class BubbleSorter implements Sorter
{
	// the implementing method must use the same keywords,
	// returning data type, name, and parameter list as the 
	// method that it's implementing from the interface
	public static void sort(int list[])
	{
		// just a simple bubble sort to get the job done
		int n = list.length;
		for (int pass = 1; pass < n; pass++)
			for (int i = 0; i < n-pass; i++)
				if (list[i] > list[i+1])
				{
					int temp = list[i];
					list[i] =list[i+1];
					list[i+1] = temp;
				}
	}
}

Click here to download the Java source file for the above example

The above code should output:

3 2 4 5 1
1 2 3 4 5

One of the significant ways in which interfaces are used is in the Java Collections Framework. In this framework, there is an interface named Collection, which represents the common functionality of all collection-type date structures. Since every data structure has functionality allows the adding and removing of data members, Collection sets forth method declarations (but not implementations) of various functions, like add, remove, toArray, contains, and other such functions. There are also subinterfaces (similar in declaration to subclasses) to Collection, such as List and Set, representing further specific functionality to the different families of data structures.

The usefulness of these interfaces becomes apparent when writing a program that requires a data structure, such as a list. Instead of writing a program specific to one implementation, the programmer could ask for a List object as a parameter, allowing the call to be made with a LinkedList, an ArrayList, a Vector, etc. Since these classes all implement List, they all act validly as a list, albeit with different implementations.

Tutorial Incomplete. Revision date: 03 March 2009
For more information, check out the following links:
http://gd.tuwien.ac.at/languages/c/c++oop-pmueller/
http://java.sun.com/docs/books/tutorial/
http://java.sun.com/docs/books/tutorial/java/concepts/