INTRODUCTION TO PROGRAMMING IN JAVA: THE PRINCIPLES OF OBJECT ORIENTED PROGRAMMING

NOTE: This set of www pages is not the set of www pages for the curent version of COMP101. The pages are from a previous version that, at the request of students, I have kept on line.


CONTENTS

1. An object oriented solution to a problem
2. Association
3. Objects, classes and inheritance
4. Constructors
4.1. Garbage collection
5. Fields
6. Methods
6.1. Overloading
 
6.2. Method calls
7. Summary
8. Anatomy of a Java class definition
9. Anatomy of a Java method definition
10. Output
10.1. String literals
11. First application program ("HELLO WORLD!")
11.1. Note on layout



1. AN OBJECT ORIENTED SOLUTION TO A PROBLEM

We have already (if briefly) introduced the Object Oriented (OO) methodology; in this section we will embellish this introduction to give a much wider overview of the approach. Remember that in the object oriented paradigm a solution to a problem is constructed by defining a set of interacting objects and classes. (Objects are defined by what is termed a class; we say the objects "belong" to a class, or are instances of a class.) We can envisage these objects existing in what we might call an object space. The objects in this space each have a particular function and can be arranged in such a manner that they can communicate with one another (send messages) to produce a solution to a problem, i.e. the objects and classes inside this space can then be considered to produce various elements (sub-solutions) of the desired end solution.

For example if we wish to determine the result of the following sum:

X = ((1+2) * (3+4)) - 5

we might decide that we require three sorts of object:

  1. A multiplication object
  2. An addition object
  3. A subtraction object

To obtain the solution to the above problem these objects will have to communicate with each other (send messages). Thus the subtraction object would have to send the sum (1+2) * (3+4) to the multiplication object to carry out the desired multiplication; which in turn would have to send the sums 1+2 and 3+4 to the addition object. Objects will also have to send messages back containing appropriate results.

 

For all this to happen we need an additional "control" method typically contained in what is called an application class to start the process off; in Java this method always has the name main.

Figure 1 shows an object space in which are contained three objects of the form described above:

  1. A cubic object which carries out addition operations.
  2. A cylindrical object which carries out multiplication operations.
  3. A spherical object which carries out subtraction operations.

Each of these objects is defined by a class definition. Note that within this definition the operations which instances of this class can perform are expressed. In the Figure there is only one instance of each class but of course there is no reason why there cannot be many instances of the same class. The figure also includes an ApplicationClass which contains a method called main. This is a special method from which the solution process will start (there can only be one main method per application). The solution process then comprises the objects sending messages ("talking") to each other so that collectively they can produce the desired result. Note that in theory any object can "talk" to any other object, however the nature of the desired communication must be expressed in the class definition. Thus, although in theory the spherical object can talk to the cubic object, there is nothing in the class definition for the spherical objects that tells instances of this class how to do so!

EXAMPLE OF A CLASS HIERARCHY

Figure 1: An object oriented solution to the X = ((1+2) * (3+4)) - 5 problem (the messaging process is indicated by the directed arcs).




2. ASSOCIATION

The objects/classes depicted in Figure 1 clearly have a special relationship with one another in that one "type" of object makes use of the functionality provided by another "type" of object. In OO terms this relationship is called association. The term describes a group of "links" between classes.

There are two different ways (in Java) in which objects of one class can make use of the functionality provided by some other class/object:

  1. Use the functionality provided by another class directly, or
  2. Use the functionality provided by another class indirectly by first creating an instance of that class.

we will refer to the first as a "uses" association, and the second as a "creates" association. Which to use depends on the nature of the definition of the members in the class under consideration. The second approach requires that the object created is "contained" in the class in which it is created --- a practice known as aggregation or composition.

Figure 2 shows the association that might exist between the classes depicted in Figure 1. Note that we have used filled arrows and labelled them with the nature of the association --- "creates" (and then presumably uses) and "uses".

ASSOCIATION

Figure 2: Association ("creates" and "uses" relationships)

WARNING: The notation used in Figure 2 is not strictly UML, however it will suffice with respect to this introductory module.




3. OBJECTS, CLASSES, INHERITANCE

Thus, from the above, Object oriented programming is founded on the concept of objects --- the entities making up the solution to a problem. Objects are usually associated with a noun (i.e. a thing) in a requirements statement. Classes describe categories of object; this is why we say that a particular object is an instance of a class. Classes define the fields (attributes or data) that can be associated with an object, and the methods (operations) that can be applied to those fields. Collectively the fields and methods belonging to a class are referred to as the members (features) of that class.

Classes are often arranged in a hierarchy whereby sub-classes (child classes) inherit features from super-classes (parent classes). The advantage is that we do not constantly have to redefine members which have already been defined previously. Inheritance is an important feature of OOP, but note that inheritance is not the same as association (the realtionships are different).

An example class hierarchy is presented in Figure 3. Note that:

The arrows in such a class diagram always point up the hierarchy.
The arrows are open to differentiate the inheritance relationship from the association relationship described in above.
By convention class identifiers (names) in Java always commence with an upper case letter.

Where a class inherits from another class anywhere in the hierarchy, an instance of any sub-class in the hierarchy is also a legal instance of all its super-classes and thus has (at least in principle) all the fields and methods associated with the super classes available to it.

 
EXAMPLE OF A CLASS HIERARCHY

Figure 3: Class diagram demonstrating a "family tree" class hierarchy.

Thus in Figure 3 an instance of the class Child is also an instance of the class Parent and the class GrandParent (but not the classes ParentSibling and ChildSibling). We say that the class child extends the class Parent which in turn extends the class GrandParent. Alternatively we sometimes say that a certain sub-class is derived from a super-class.

Three categories of membership are identified:

  1. PUBLIC. Members which can be accessed from anywhere in a program.
  2. PRIVATE. Members which can only be accessed from within an object (to access such members from outside the object we must use a public member method).
  3. PROTECTED. Private members which are inherited by instances of classes derived from the current class.

Note that, since one of the principals of OOP is data hiding, field members are normally categorised as private members of a class.




4. CONSTRUCTORS

To create an instance of a class (i.e. to create an object) we use a special method called a constructor, we say that a constructor creates an instance of a class. When this happens access to the methods defined for the class and a completely new set of fields (of the form defined for the class) is "bundled" up with the instance identifier. Consequently we refer to instance fields and methods.

Sometimes, given a particular application, we wish to include members in a class for which we do not wish there to be a unique copy for each instance --- such members are called class members or static members; thus in this case we refer to class fields and methods as opposed to instance fields and methods. The term static is used to indicate that such members cannot be "copied" to form part of an object.

Figure 4 gives a class diagram of a single class called grandParent (taken from Figure 3) which has two fields and one method which is a constructor.

EXAMPLE CLASS WITH CLASS AND INSTANCE FIELDS

Figure 4: Example Class containing a class field and an instance field.

Note that:

The first field, averageAge, is a class field because it is preceded by the modifier static.
By default the second field, age, is an instance field.
 
Both fields are private members/features, i.e. they can only be accessed from within the class.
Constructors always have the same name as the class with which they are associated.

If, given some application, we now want to create instances of this class, say mary, we would invoke the GrandParent constructor as follows:

GrandParent mary = new GrandParent();

The keyword new indicates that a new instance of a class is to be created; when this happens appropriate storage for a completely new set of instance fields members, i.e. the field age in the example class (but not the class field averageAge), is set aside for the newly created object. The area within primary memory where the required storage is created is known as the heap.

Note that we can have more than one constructor associated with a particular class. Also a constructor may have one or more formal parameters (or arguments) associated with it --- more on this later.


4.1 Garbage collection

Once an object has been created the memory space for this object is "freed-up" as soon as the object is no longer referred to in the program through a process known as garbage collection. The Java garbage collector runs in the back ground when executing a Java program and tracks objects. When ever an object is no longer referenced the garbage collector removes it from storage (although it might defer doing so till an appropriate moment in the execution process). This ensures efficient use of available storage space.




5. FIELDS

A field describes an attribute/data item associated with a class. For example the GrandParent class given in Figure 4 has a class field called averageAge and an instance field called age. From within a class the fields belonging to that class can be accessed directly by referring to them by their name alone (regardless of whether they are private, public or protected members). From outside the class a field can only be accessed if it is a public class member using either:

The name of an object in the case of an instance field, or
 
The name of the class in the case of a class field.

We use the dot operator to do this (sometimes referred to as the membership operator). In the first case this is prefixed by an instance identifier (name) and in the second case by a class identifier. Thus:

mary.age

or

Grandparent.averageAge



6. METHODS

A method is a named sequence of instructions called statements. We can identify four types of method:

  1. Constructors (see above),
  2. main methods (from which processing commences),
  3. Instance methods, and
  4. Class methods

where instance methods are associated with a particular instance of a class and class methods with an entire class. Figure 5 shows a redefinition of the GrandParent class used earlier (Figures 1) such that the class includes an instance method outputAge, and a class method outputAverageAge.

EXAMPLE CLASS WITH CLASS AND INSTANCE METHODS

Figure 5: Example Class containing a class method and an instance method.


6.1 Overloading

It is possible to overload method names; i.e. to have two or more methods with the same name in a single class. However, they must be differentiated by the number and nature of their arguments.

 

One common use of overloading is to have several different constructor methods for the same class.


6.2 Method Calls

As with fields, from within their class, methods can be referred to by their name alone, but when used from outside the class the method must be a public class member and referred to with either:

The name of the class in the case of a class method.
The name of an object in the case of an instance method, or

Again we use the dot operator to do this. In the first case this is prefixed by a class identifier (name) and in the second case by an instance identifier.

GrandParent.outputAverage();

or

mary.outputAge();

The formal parameters (the arguments for the operation) are optional. When we reference a method in this manner we are causing it to execute with respect to the class or instance that it is linked to. The above is therefore referred to as a method call. The object with which a method is invoked is sometimes referred to as the receiving object or the receiver (in that it may "receive" information returned by the method).




7. SUMMARY

Objects: The real world entities which a programmer wishes to "model".
Classes: Definition of a "type" of object.
Instances: An object belonging to a particular class.
Field or Attribute: A data item associated with an instance/class.
Methods: An operation associated with an instance/class.
 
Members: The collective name for fields and methods.
Private, public and protected members: Categories of class membership.
Constructor: A special kind of method used to create an instance of a class.
Instance members: the methods and fields that can be associated with a instances of a class.
Class members: Special (static) methods and fields that can not be associated with a particular instance.



8. ANATOMY OF A JAVA CLASS DEFINITION

A Java program consists of a set of one or more classes many of which will be related to one another in some form of hierarchy; however, not every class need be related to every other and the kinds of relationship may vary. In Table 1 a framework for a Java class definition is presented.

import  PACKAGE_NAME ;

class CLASS_NAME
{
   < FIELD DEFINITIONS>

   < METHOD DEFINITIONS>
}

Table 1: Framework for a Java class

The bold text in Table 1 indicates reserved words that have a special meaning. When writing your own programs it is of course not necessary to emphasise different words in this manner.

Notes with respect to the framework presented in Table 1:

  1. We commence by indicating any packages that we might wish to use. For example if we wished to include the java.lang package we would write:
 
    import java.lang.* ;
    
    The .* indicates that we wish to use all the classes defined in this package. Instead we could have define particular classes that we wished to use, e.g. import java.lang. System; (Note that the java.lang package is included in every Java program automatically without actually requiring an import statement).
  1. The class name must be the same as that associated with the file. Thus if we wished to create a HelloWorld class then we would have to store the class definition in a file called HelloWorld.java (tradition holds that the first program that you write when learning a new programming language always prints "Hello World!" out to the screen and nothing else).
  2. The combination of the reserved word class and the name of the class is called the class heading.
  3. Although we have declared the field members before the methods there is no syntactical requirement to do this, however it is good software engineering practice to adopt some sort of convention like this so as to enhance readability/understandability and hence ease the maintenance task.
  4. A class does not necessarily have to have any fields but it would be rather pointless if it then also did not have any methods.




9. ANATOMY OF A JAVA METHOD DEFINITION

< MODIFIERS > RETURN_TYPE METHOD_NAME( < ARGUMENT_LIST > ) {
    < LOCAL DATA DEFINITIONS AND CODE STATEMENTS >
    }

Table 2: Framework for a Java method

Table 2 gives a similar frame work for a Java method to that given in Table 1 for a Java class. Note that:

  1. The first line of the definition is referred to as the method's signature, the remainder (enclosed in curly brackets --- { ... }) is the body.
  2. Modifiers are key words such as public, private and protected to indicate the category of the method, and/or key words such as static to indicate whether the method is a class method or not.
  3. Every method in Java must have a return type. This describes the nature of the data item that is to be returned by the method. For example we might define a method which adds two integers in which case we would probably wish to return the result and consequently would indicate this. In cases where we do not wish to return anything we use the keyword void.
  4. Names in computer languages are called identifiers. An identifier in Java consists of letters, underscores and digits commencing with a letter. Java is a case sensitive language thus (for example) the method identifier myMethod is not the same as myMETHOD. Further, unlike some languages, Java does not allow spaces, instead programmers use capital letters for "inner words" (alternatively the under score character may be used).
 
  1. You should always use meaningful identifiers as this enhances understandability. You should not be afraid of using long identifiers, although anything with more than 32 characters is probably overdoing it.
  2. Often we wish to pass data to a method for it to work with. For example in the case of a method which adds two integers we would pass in the integers as formal parameters (or arguments) to the method.
  3. This first line of the definition (comprising modifiers, the return type, method name and the formal parameter list) is called the signature of the method (some authors use the term method heading or prototype). The part contained between the curly brackets is termed the body.
  4. The body contains definitions of any further local data items (other than the formal parameters and instance fields) that might be required and the individual code statements. A method is not required to include local data items however there would be little point if it also did not include any code statements.
  5. Methods may also have inner classes, declared for specific purposes, but may not have their own local methods --- this is called nesting.



10. OUTPUT

In this Section we will describe the mechanisms provided by Java to achieve output. We have seen that for a program to do anything it must receive some input data via an input stream and produce some output data to be sent to the output stream. The input may simply be a signal to run the program (with no actual input data), but it would be pointless to write a program which did not produce any output. Thus the simplest Java program we can write must comprise a single output statement. We have noted that traditionally the output from a first program written when learning a new programming language comprises the phrase "Hello World!" (we will abide by this tradition).

To facilitate output Java provides a number of classes. One of these is called PrintStream. This class contains (amongst other things) the methods print, println and printf. The first takes one formal parameter which it outputs to an output stream (e.g. the screen, secondary storage, etc.). The second is used in an identical manner except that it automatically includes a new line character at the end of the output. Note that in both cases the formal parameter must be a sequence of one or more characters. Such a sequence is called a string and is indicated by enclosing the characters with double quotes. Strings are discussed in further detail in 8.1 below.

The printf method allows formatted print and will be discussed inm more detail later.

 

A class diagram indicating the relationship the PrintStream class has with some other significant classes, at least in the context of output, is given in Figure 6. Both print and println are instance methods and therefore require an appropriate object of the type PrintStream. In addition, to use either method, we must tell Java which output stream we wish to direct the output to. Java provides us with a special "screen output" object to facilitate output to your computer screen (called out) which is contained within the class System. Because out is an instance of the PrintStream class it carries with it all the paraphernalia associated with that class, i.e. access to the methods print and println and so on. The class System is contained in the package java.lang which (remember) is always compiled into every Java program.

Thus if we wish to output Hello World! to the screen we might include the following statement in a piece of Java code:

System.out.print("Hello World!");

or:

System.out.println("Hello World Again!");

Note the ';' character, every Java program statement must end with a ';' character. Note also that println when called without any arguments, i.e. println(), will simply cause a "carriage return" (newline character) to be passed to the output stream without any other output.

CLASS DIAGRAM SHOWING API CLASSES ASSOCIATED WITH SIMPLE SCREEN OUTPUT

Figure 6: Class diagram showing API classes associated with simple screen output.



10.1. String Literals

Any sequence of characters enclosed in quotes, such as "Hello World" is called a string literal or simply a string. If we wish to include a quote character (") within a string we must prefix it with a backslash character (\). This is called the escape character. For example:

System.out.print("Hello \"Frans\".");

would produce the output Hello "Frans".. Without the escape characters the Java compiler would recognise this as two strings Hello and ., separated by the "operator" Frans; this is bound to confuse the compiler! Combinations of back slashes and special characters such as the quote character are sometimes referred to as escape sequences. The concept of escape sequences is common to many languages, for example C and C++. Further examples of escape sequences include \n which indicates a carriage return and \t which indicates a tabulation ("tab") marker. Thus instead of writing System.out.println("Hello World Again") we could have written:

 
System.out.print("Hello World Again\n");

One further comment on strings. Sometimes, when programming, a string gets too long to fit on a single line in the editor window. If we simply press the return key and continue typing in the next line we will have introduced a newline control character into the string which the editor can understand but the Java compiler would have problems with. One option would be to use a sequence of print methods. Alternatively we can concatenate a sequence of strings together using the '+' concatenation operator. For example:

System.out.print("A very long string " +
    "literal that, unfortunately is " +
    "so wide that it disappears of " +
    "the end of the screen, however " +
    "we can avoid this undesirable " +
    "feature by splitting the string " +
    "up into a sequence of window " +
    "wide sub-strings and link them " +
    "together using the Java \"\+\" " +
    "concatenation operator.\n");

Note the use of the escape character in \"\+\".




11. FIRST APPLICATION PROGRAM ("HELLO WORLD!")

We are now in a position to put all of the above together and write our first Java application program (Table 3).

// HELLO WORLD PROGRAM
// Frans Coenen
// Monday 15 January 1999
// The University of Liverpool, UK

public class HelloWorld {
   // ------------ METHODS ------------
    
   /* Main method */
    
   public static void main(String argv[]) 
      {
      System.out.println("Hello World ");
      }
   }      

Table 3: Hello world Java application program

Once compiled we can run this code using the java interpreter by typing:

java HelloWorld

This will produce:

Hello World!

Note that:

  1. This is the simplest Java programme that can be written. It comprises a single application class (a class with a main method in it) from where the execution process commences. No instances of other classes are created therefore no constructors are called. It does not include am import statement because the only package used is the Java.Lang package which is automatically "compiled in" with the code.
  2. Lines of code commencing with a `//' or `/*' and are comment lines. These are ignored by the compiler. There are two standard types of comment available in Java:
    Single line comment denoted by `//' (also found in C++, and imperative languages such as Ada). For example:
    // this is a one line comment
    
    Multiple line comments indicated by a /* at the start and a */ at the end. For example:
 
      /* A block of comments. 
      Many programmers consider 
      this to be much more elegant 
      than a sequence of single 
      line comments. */
      
      This approach is also a feature of languages such as C (and C++).

    It is good programming practice to include comments in your code, thus in the above case we commence with the name of the program (class), the author, the date when it was written, and where it was written. This information is all extremely useful when it comes to maintaining the code.
  1. The program makes no use of features of external classes. Access to the print and println methods are encapsulated into the out instance which is included in the java.lang package which is compiled into every Java program.in the package java.io.
  2. The class name must be the same as the source code file in which it is stored (but with the suffix java), thus the above should be contained in a file called HelloWorld.java. Care should be taken to choose meaningful names for classes so that a clear indication of the functionality of classes can be obtained simply by inspection of class names.
  3. There is one method called main. Every Java application program must have a method called main, this is the method from which the Java interpreter starts processing the code.
  4. The main method always has the modifiers static and public to indicate that it is a class method and should not be associated with individual objects and that it can be accessed from anywhere within the program.
  5. Similarly the return type must always be void --- the top level method cannot return anything because it has not got anywhere to return it to!
  6. In the case of a main method we must provide information concerning the formal parameters for the method (unlike any other methods this information cannot simply be omitted). However, there is a slight complication in that the arguments cannot be passed to main from another method but must be provided when the program is invoked --- we refer to such arguments as command line arguments. This is a non-trivial concept and for the time being we will have to accept that this is indicated using String argv[].



11.1 Note on layout

As far as the Java compiler is concerned layout in terms of new lines and spaces (with the exception of strings) does not matter provided that the source code is syntactically correct. However, from a software engineering perspective a well laid out program is much easier to read/understand than one that is not well laid out. The following version of the above code presented in Table 3 will compile and execute, although it is very difficult to "read":

 
class HelloWorld{public static 
void main(String argv[]){System.
out.println("Hello World ");}}      

It is therefore a good idea to write programs neatly using appropriate indenting, comments and "white space" so as to enhance understandability. "If something looks good it probably is good!"




Created and maintained by Frans Coenen. Last updated 10 February 2015