Java - Lecture 2 - OOP 1
Java - Lecture 2 - OOP 1
Java - Lecture 2 - OOP 1
Contents of lecture 2:
• ‘Surfeit of Zen’ problem. In order to fully appreciate any one part, you need to understand
most of the other parts.
• Use of complex, technical-sounding terminology (which does not really capture the
simplicity of the principles behind OO programming). See example below.
Note, that the example shown above (drawn from an actual textbook) is technically accurate,
however, it is also utterly useless for teaching the fundamentals of OOP. Hopefully, the coverage
of OOP, and Java, within this course will try to avoid unnecessary technical baggage.
PAGE 16
LECTURE 2
PAGE 17
LECTURE 2
mov( loc1, al )
// Move specified memory address contents into CPU register.
add( loc2, al )
// Add specified memory address contents to CPU register.
mov( al, res )
// Move CPU register contents into the specified memory address.
In C we have:
Notice that the C code is considerably more compact and readily comprehended. This is in part
due to its syntactical similarity to normal mathematical notation and the use of variables instead of
memory offsets.
In the above examples we are not really adding anything new in terms of programming
functionality, instead we are simply providing higher-level abstractions that mean the programmer
can think about the problem at a higher level, without worrying about how variables, loops, etc.,
will be expressed in terms of machine code (i.e. the compiler does some of the work for the
programmer). Apart from quickening development times and reducing the number of program
bugs, such languages free up the programmer’s cognitive resources to tackle larger and more
difficult problems which would have been prohibitively complex to write using only assembly
language.
PAGE 18
LECTURE 2
Aside: Aristotle was probably the first person to carefully study the concept of type; he
spoke of the ‘class of fishes and the class of birds’. The idea that all objects, whilst being
unique are also part of a class of objects that have characteristics and behaviors in common
was used directly in the first object oriented language Simula-67, which introduced the
keyword ‘class’.
Aside: Simula, as the name suggests, was created for developing simulations such as the
classic ‘bank teller program’ where you have a bunch of tellers, customers, accounts,
transactions, units of money, etc. However, whilst Simula was the first object-oriented
language, it is Smalltalk that holds the honor of being the first successful and widely known
OO language (in part, Java is based on Smalltalk).
PAGE 19
LECTURE 2
Diagrammatically the relationship between objects and classes can be viewed as follows:
Interface:
User- manual
Class:
CD Player
blueprints
4 Objects:
CD Players
In order to use an object, all that is needed is knowledge of its interface which provides details of
methods and data available to the programmer (i.e. those declared as public, etc.).
PAGE 20
LECTURE 2
There are four principle concepts upon which object oriented design and
programming rest. They are: Abstraction, Polymorphism, Inheritance and
Encapsulation (i.e. easily remembered as A-PIE). In what follows, each of
these four concepts will be introduced and further explored.
Aside: Whilst A-PIE may be easy to remember, the principles build
upon one another in the following order: Abstraction, Encapsulation,
Inheritance and Polymorphism.
Aside: As mentioned OOP is not a new idea; in fact it’s very old (by computing standards).
The first object-oriented programming language was Simula-67, produced over 35 years ago.
Data Abstraction
In order to process something from the real world we have to extract the essential characteristics of
that object. Consider the following example:
Registration
• Vehicle
Identification
Number
• License plate
• Current Owner
• Tax due, date
Owner Garage
Data abstraction can be viewed as the process of refining away the unimportant details of an
object, so that only the useful characteristics that define it remain. Evidently, this is task specific.
For example, depending on how a car is viewed (e.g. in terms of something to be registered, or
alternatively something to be repaired, etc.) different sets of characteristics will emerge as being
important.
Formulated as such, abstraction is a very simple concept and one which is integral to all types of
computer programming, object-oriented or not.
PAGE 21
LECTURE 2
• Something unnecessary was abstracted, i.e. some data is redundant. This may or may not be a
problem, but it is bad design.
• Something needed was not abstracted. This is a more serious problem, usually discovered
later in the design or coding stages, and entails that the design needs to be changed to
incorporate the missing data item, code changed, etc.
Functional Abstraction
The process of modeling functionality suffers from the same pitfalls and dangers as found when
abstracting the defining characteristics, i.e. unnecessary functionality may be extracted, or
alternatively, an important piece of functionality may be omitted. The programmer goes about
determining which functionality is important in much the same way as they determine which data
items are important.
Encapsulation is one step beyond abstraction. Whilst abstraction involves reducing a real world
entity to its essential defining characteristics, encapsulation extends this idea by also modeling and
linking the functionality of that entity.
Consider the following data items and operations:
PAGE 22
LECTURE 2
Broadly speaking, OOD (Object Oriented Design) can be broken down into the following
processes:
Step 2: Initially model the problem by defining classes for each object, in
terms of the data needed to represent the object and the operations that can be
performed on the object (abstraction and encapsulation)
The above process is somewhat abstract, however, it simply amounts to working out what classes
are needed to model the problem, what data and methods these classes should contain, how the
classes should relate to one another, and finally, how instances of the classes should interact to
solve the problem (i.e. you firstly model the problem, and then secondly solve the problem).
You may have noticed that there has been no coverage on how to identify which objects need to
be modeled given a problem description. Unfortunately, as with determining relevant data and
functionality, the ability to select appropriate objects is something that improves through the
accumulation of experience (and not something that can be profitably taught).
Step 3 will be explored within the next lecture. Step 4 can only really be built up from
accumulated practical experience, i.e. by actively solving problems (this can be gained, in part,
from the practical packs).
PAGE 23
LECTURE 2
Object-oriented Programming:
Java Style
Class syntax
where <classname> is the name given to the class. Java requires that each class be stored in the
corresponding Java file: <classname>.java
Constructors
Each class has a constructor that is called whenever an instance of that class is
created. If the class does not explicitly define a constructor then default methods
are invoked (which might range from doing nothing, to calling the relevant
constructor of a superclass).
public class <classname>
Several constructors can be defined for a class, {
differing in terms of the parameters they accept. // Constructor
Constructors never return any values. public <classname>()
{…}
// Constructor
public <classname>( <arglist> )
{…}
}
PAGE 24
LECTURE 2
The procedure when an object is created follows (e.g. SomeClass myObj = new SomeClass() ):
1. Sufficient memory to store the class data is allocated. This memory is then cleared, i.e. all
values set to null, 0, etc. (this guarantees starting values for class data).
2. The class constructor is called. Note, the constructors of parent classes are always called
first (either explicitly with super(…) or implicitly). The rest of the constructor’s code is
then called.
The finalize method accepts no parameters, nor does it public class <classname>
return any value. There can be only one finalize method {
for a class. // Destructor
public void finalize()
The finalize method should be used to free up any
{…}
special resources which have been allocated (i.e. file
}
handles, db locks, etc.). Thankfully, Java’s built-in
garbage collection is very good, and the finalize method
is rarely needed.
Note that an overloaded method cannot have variants that share the same argument list but differ
only in their return value, as there is no means of determining which method should be called,
e.g.:
int CalculateWage( String name )
float CalculateWage( String name )
PAGE 25
LECTURE 2
Data modifiers
Below, two useful data modifiers are briefly explored (data modifiers alter how items are
accessed and used).
<Methods…>
}
iNumEmployees = 3
PAGE 26
LECTURE 2
Each instance of Employee holds a certain amount of information, in particular each Employee
object contains a unique name, dept and iPay variable. However, notice that the static
iNumEmployees is not stored by any one Employee object, rather it is global across all
instances of that class.
Note that variables declared to be static exist even if no objects of that class exist.
Hence, if no Employee objects exist, then iNumEmployees = 0. Because of this a
means of accessing static data when there are no instances of the class is provided.
This is done by prefixing the static data item by the class name, e.g.
Employee.iNumEmployees (assuming the static data has been declared to be public
and hence accessible outside of the class).
A method can also be declared as static. Primarily this is of use to provide a means of accessing
static data that has been declared private (class data should rarely be declared public).
public class Employee System.out.println( “Num Employees =
{ Employee.numPeople()” );
private static int iNumEmployees
Blocks of data and classes may also be declared to be static, however, this is of limited use.
Aside: ‘static’ is not a very good name. It originated from C and referred to data that was
allocated statically at compile time. Whenever you see the keyword ‘static’ in Java it is best
to think ‘once-only-per-class’
Blank final variables are useful when the data value cannot be obtained before run-time, or is too
complex to pre-calculate. A method or class that is defined to be final cannot be extended or
modified by any sub-classes that inherit from the method or class. This is useful to ensure that the
functionality of a method cannot be modified, or to ensure that a class cannot be extended via
inheritance.
Aside: final also has a number of more subtle uses. If a method or class is defined
to be final then the Java Virtual Machine can execute method calls faster (this has
to do with polymorphism, where Java has to check the type of each object. If
declared final, Java does not need to perform the check).
For example, the Java Math class is primarily declared to be final for this reason
(methods within the Math class are also static, hence no instances of the class
need to exist to call the method, e.g. Math.pow(), etc.).
PAGE 27
LECTURE 2
Access Modifiers
A summary of the different access modifiers follows:
Keyword Effect
private Members are not accessible outside the class. Making a constructor private
prevents the class from being instantiated. Making a method private means
that it can only be called from within the class.
public Members are accessible anywhere the class is accessible. A class can be
given either package or public access.
In Java, package access broadly equates to public access between all Java files in the same
directory, e.g.
Assume Printout.java contains a method PrintResults()
Directory: C:/SamsProject
which has package access. If so, PrintResults can freely
[3 files]
be called from within either the Process or Control
Control.java
classes. However, it cannot be called from Project as
Process.java
Project.java is found within a different directory.
Printout.java
Note, in general data should not be declared as public,
Directory: C:/JillsProject instead helper read/write methods should be provided.
[1 file]
Project.java
PAGE 28
LECTURE 2
The code fragment represents a fictional case where Tom originally has a Ford car, which he then
shares with Paul. Finally, Tom gets a new car, a Mazda. When executed the above code will result
in the following data items being created:
Line 1
tomCar Create a new reference, tomCar (initially it refers to no
null object)
Line 2
tomCar Car1 object
Car1 Name:ford Model: Milage:
Line 3
tomCar Car1 object
Car1 Name:Ford Model: Milage:
Line 4
tomCar Car1 object
Car1 Name:Ford Model: Milage:
Line 5
tomCar Car1 object
Car2 Name:Ford Model: Milage:
PAGE 29
LECTURE 2
When a variable of any class type is declared it is simply a reference variable that can hold a
pointer to an instance of the relevant class. This is a process known as indirect addressing (i.e.
tomCar is an intermediary that holds a pointer to a Car object).
As such, this has important consequences when it comes to comparing objects, or passing objects
into methods, as will be shown.
Aside: Classes are an example of non-primitive data. Java also contains primitive data types:
such as int, float, boolean, char, etc. (there are a total of 8 primitive types). A primitive type
is defined as not being composed of any other types (whereas non-primitive classes contain
other data items and methods, etc.). As primitive types are not objects, they do not use
indirect addressing, instead they use direct addressing. Compare and contrast:
Comparing objects
Consider the following code fragment:
String first = new String( “Hello” );
String second = new String( “Hello” );
Consider the statement ‘if( first == second )’, will this be evaluated as true or false? In this case
it will be evaluated as false, the reason being that the statement is interpreted as meaning: Does
the ‘first’ reference refer to the same object as the ‘second’ reference. Evidently, they do not
refer to the same object, hence the statement evaluates as false.
This is a common source of program errors. It is important to be aware if a comparison is to be
made between references (i.e. pointers to objects) or between objects (i.e. the data internal to an
object). For this example, in order to compare the object’s contents we should use the String
method equals, e.g. if( first.equals(second) ), which compares the String’s contents.
The above principle also impinges upon multiple references to the same object, e.g.:
PAGE 30
LECTURE 2
Evidently, changing an object’s data through one particular reference will affect the data that is
retrieved by another reference that points to the same object.
Whenever Java calls the processEmployee method it passes a copy of the reference to the
object, i.e.:
tom Emp1 object
Name: Tom
Emp1
Copy
copyTom
Method
processEmployee Emp1
Hence, any changes made to the Employee object’s data inside the processEmployee
method remain after the method has returned. As such, this provides an elegant means of
changing an object’s data within a method. However, the programmer must be mindful not to
inadvertently change an object’s data from within the method.
There is one caveat to the above outlined procedure: it only applies to non-primitive data (i.e.
that which is accessed through a reference). When primitive data (e.g. int, float, etc.) is passed
into a method, a copy of the actual data is made, and any changes within the method are not
reflected when the method returns, e.g.
PAGE 31
LECTURE 2
Practical 2
After this lecture you should explore the second practical pack which should enable you to
investigate the material in this lecture.
Learning Outcomes
Once you have explored and reflected upon the material presented within this lecture and the
practical pack, you should:
• Have knowledge of the syntax and functionality on offer within Java when
constructing classes and be able to successfully employ Java to create appropriate classes
given a straightforward class design.
• Understand the differences between classes, objects and references within Java (including
primitive and non-primitive data items) and the consequences thereof when comparing or
passing objects/references.
More comprehensive details can be found in the CSC735 Learning Outcomes document.
PAGE 32