Chapter XIV
Serious OOP
Chapter XIV Topics
14.1 Introduction
14.2 OOP Terminology
14.3
Default Constructors
14.4
Accessing Attributes and Methods
14.5
Constructor Overloading
14.6
Accessing Multiple Files
14.7 Set
Methods
14.8 Copy
Constructors
14.9
Scope of an Object
14.10
Objects Are References
14.11 Using
the "this" Reference
14.12
Nesting Classes with Composition
14.13
Information Hiding
14.14 Static
Attributes and Methods
14.15
Summary
14.1 Introduction
What kind of a chapter title is Serious OOP I ? Have we not
been serious about Object Oriented Programming before? Frankly, the whole OOP business with Java
presents some unique challenges in writing a textbook and teaching the topic.
Just take a look at this really simple program, in
figure 14.1, that was one of the first programs shown in the beginning of the
course.
Figure 14.1
|
public class
Java0202 { public static void main (String args[ ]) { System.out.println("Plain Simple
Text Output"); } } |
At the first introduction of this short program you
did not learn all of its features. You
did not know what a class was, why public or static is used and you did not know anything about an args array. All you really learned was that it was
possible to display text with a println method,
but then you also did not know what a method
was.
Languages like Pascal and C++ that support OOP are
simpler to teach because it is possible to ignore OOP in the beginning until
such a time that it is desirable to change gears and introduce Object Oriented
Programming. Java has no such comfort
because every statement must be placed inside a class. Even the simplest variable declaration or the
shortest program, such as the one above, will require a minimum of one
class.
|
Important Java
Reality |
|
A Java program
consists of one or more class declarations.
Every program statement must be placed inside a
class. |
It may be tricky to teach a programming language,
like Java, where you feel that everything needs to be introduced in the
beginning, but that actually is one of it appeals as a computer science
introductory language. During the last
couple of decades, Object Oriented Programming has gained steady ground as the
proper approach to program design. It is
possible with C++ to skirt around OOP or postpone this OOP business for a
considerable length of time. As you can
tell by our little program example in figure 14.1, you cannot even blow your
nose in Java without using a class.
A full-fledged treatment of OOP involves showing the
encapsulation of data (attributes) and methods (actions), but wait ... students
do not know anything about data types or variable declarations yet. In the very early chapters you learned
various concepts on faith. You were shown many Java program features,
told to use them and not ask too many questions with the promise that there
will be future explanations. As time
went on, you learned more and more about Object
Oriented Programming and you have already seen a chapter on Class Methods and Object Methods.
So we now have the strange situation where you have
already written many Java programs, and all of these programs have used at
least a little or perhaps a lot of OOP features. There is a good chance that you have quite a
good handle on many of Java's OOP concepts and I hope that such is the
case. At the same time there is a lot
left to be learned about this object business.
This chapter is called Serious OOP
I, because you now have the Java tools under your belt to take a serious
look at Object Oriented Programming. The
majority of this chapter will review concepts, which you have learned earlier
and take a more thorough approach to these topics. There will also be some new OOP issues
presented. You will be pleased to know
that this chapter has Roman Numeral I,
so you can expect this serious OOP stuff to continue in some later chapter.
14.2 OOP Terminology
There are people who believe that Object Oriented
Programming is not so bad; it is all this vocabulary that is hard to
digest. This section will review the key
OOP terms without program examples. Many
program examples will follow in the remaining sections. Right now let us review the terminology that
needs to be second nature for any serious Java programmer. Some definitions that follow may not be very
clear to you. Perhaps you never
understood their meaning at the first introduction, and maybe it still does not
make sense with this review presentation.
Well do not give up. You will
hear this terminology used very frequently and the nature of vocabulary is that
a clear understanding comes from using words in the proper context. The main purpose right now is to summarize
the language that will be used in this chapter and future Exposure Java
chapters.
|
Program Modules |
|
Program development
requires that large programs are divided into smaller program modules to be manageable.
This is the principle of divide
and conquer. |
|
Structured Programming |
|
Structured programming is an organized style of programming
that places emphasis on modular programming, which aids testing, debugging
and modifying. In structured
programming, modules are procedures and functions that process external data
passed by parameters. |
|
Object Oriented Programming,
a Casual Definition |
|
Object Oriented Programming is a programming style with heavy
emphasis on program reliability through modular programming. In object oriented
programming, modules contain both the data and subroutines that process the data. In Java the modules are called classes and
the process-subroutines are smaller modules called methods. |
|
Object Oriented
Programming, a formal definition |
|
Object Oriented Programming is a style of programming that
incorporates program development in a language with
the following three OOP traits: · Encapsulation · Polymorphism · Inheritance |
|
Encapsulation |
|
Encapsulation is the process of placing a data
structure’s data
(attributes) with the methods (actions) that act upon the
data inside the same module, called a class
in Java. |
|
Inheritance |
|
Inheritance is the process of using features
(both attributes and
actions) from an established higher class.
The higher class
is called the superclass. The
lower class is called the subclass. |
|
Polymorphism |
|
Polymorphism allows a single accessing feature,
such as an operator, method or
class identifier, to have many forms. This is hardly a clear
explanation. Since the word
polymorphism is used in the formal OOP definition, a brief explanation is
provided, but details of this powerful OOP concept will come in a later
chapter. |
|
Class |
|
A class is a
user-defined data type that encapsulates both data and the methods that act
upon the data. A class is a template
for the construction of objects. |
|
Object or Instance |
|
An object is one
instance of a class. A class is a type and an object is a variable. Cat is a class and Fluffy is an object or
one instance of the Cat class. Objects can be
discussed in a general sense, such as in Object Oriented
Programming. This causes confusion between Object, the
concept and object, the instance of a class.
There is a tendency to use instance
when referring to one variable example of a class. |
|
Attributes or Instance
Variables |
|
The data components
of a class are the class attributes
and they are also called instance
variables. Instance variables
should only be accessed by methods of the same class. |
|
Methods |
|
Methods are action modules that process
data. In other languages such modules
may be called subroutines, procedures and functions. In Java the modules are called methods. They are declared inside a class module and
process the instance variables. |
|
Instantiation |
|
Instantiation is the moment or instance that
memory is allocated for a specific object of a class. Statements like the construction of an object, the definition of an object, the
creation of an object all have the same meaning as the instantiation of an object. |
This is by no means a complete list of OOP
terminology. The definitions presented
in this section represent most of the general terms. Specific terms like set method, static method,
this reference, etc. will be
explained within their own respective section along with functional program
examples that help to explain the meaning of the concept.
14.3 Default
Constructors
I like using case studies to teach complex
topics. Case studies present concepts in
a series of programs that represent the steady growth of a program as it
develops through growing stages from the simplest start to the complex final
program. Case studies are a popular
approach in teaching computer science and have been used for many years.
In this chapter a case study will be started that
will continue in a future chapter. You
have seen explanations about OOP using a previous Piggy class and a CardDeck class. This time we will look at a Person class. As you look at the program examples that
follow you will find that each stage increments the number of the Person class. It starts with Person01 and then continues with Person02, Person03 and
so on. This approach makes it easier to
explain comparisons between different Person
class stages. It also makes compiling
the programs simpler. If every program
uses the same identifier, the result will be that each successive program
overrides the Person.class file of
the previous program.
A person is an object with many attributes and many
behaviors. Attributes include name, birthdate, height, weight, parents,
children, eye color, education, marital status, hobbies, and many
others. Behaviors include displaying the
values of all attributes along with going to school, getting married, buying a
house, going on vacation, taking a shower, getting dressed, sleeping, walking,
running, eating, and on goes the list.
Our Person
class will not be so ambitious to include a large list of attributes and
methods. There will only be a minimal
list that is sufficient to illustrate a variety of OOP concepts. In fact, our Person class starts off with
three modest attributes, which are name,
yearBorn and education.
You will note in program Java1401.java, shown in figure 14.2, that there are two class
declarations. There is the customary
program name class declaration, Java1401,
and the Person01 class declaration. Every executable application program needs at
least one class, and that class needs to contain the main method. The main method
will always be a static method and
the main method uses a String array parameter that can be used for command line
input.
If you look at demonstration programs provided by a
variety of Java sources you will find that it is customary to create one file
for one class. A practical class in the
real world can be quite large and multiple classes in one program cause
considerable complexity. Later in this
chapter you will be shown how to manage multiple files into a single
program. Right now it is easier to show
two small classes in the same program file.
Figure 14.2
|
// Java1401.java // Stage-1 of the
Person class. // Only the Person
class data attributes are declared. // Each stage of
the Person class will have its own number to // distinguish
between the different stages. public class
Java1401 { public static void main(String args[]) { System.out.println("Person
Class, Stage 1\n"); Person01 p = new Person01(); System.out.println(); }
} class Person01 { String name; int yearBorn; int education; } |
|
Java1401.java Output Person Class, Stage 1 |
Let us make some important observations about the Person class declaration. You need the Java reserved word class followed by a class
identifier. The class body is placed
between opening and closing braces.
Class attributes are declared inside the class body in the data-type followed by variable identifier format.
Notice how the Person
class module is declared outside the Java1401
class module. If you declare Person inside Java1401 you may find
that you get some bizarre results, like an output that continues on and on
until it gets stopped by an error message.
Java allows a class to be declared inside another class and calls this
an Inner Class. Explaining inner classes will follow in a
later chapter.
|
Class Declaration
Location |
|
In most cases a
class declaration is located outside any other class declaration. It is possible to declare one class inside
another class (inner class), which will be explained later. |
The Person01 class
had no process capabilities. It only
contained attributes. The program output
consisted of output generated by the main method of the Java1401 class. Nothing was
contributed by Person01. A p object
was in fact instantiated and that was done primarily to demonstrate that it is
possible to compile a class that stores only data. Program Java1402.java,
in figure 14.3, adds a constructor to the Person02
class.
|
Instantiation and
Construction |
|
An
object is created with the new operator. The creation of
a new object is called: instantiation of an object construction of an object The
special method that is called during the instantiation of a
new object is called a constructor. |
Figure 14.3
|
// Java1402.java // Stage-2 of the
Person class. // This stage adds
a default "no-parameter" constructor to the Person class. public class
Java1402 { public static void main(String args[]) { System.out.println("Person
Class, Stage 2\n"); Person02 p = new Person02(); System.out.println(); }
} class Person02 { String name; int yearBorn; int education; Person02() { System.out.println("Calling
Default Constructor"); name = "John Doe"; yearBorn = 1980; education = 0; } } |
|
Java1402.java Output Person Class, Stage 2 Calling Default Constructor |
There is evidence that the only method in Person02 must be called. The program output shows the statement Calling Default Constructor and such a
statement is only shown inside the constructor method. Constructor methods are somewhat odd. For starters, constructor methods are neither
void methods nor return methods. A
constructor is not called in a stand-alone statement with the method
identifier, nor is it called in a program statement that uses a value that is
provided by a return method. A
constructor is called by the new
operator in a statement like:
Person02 p = new Person02();
The use of constructors is one terrific feature in
OOP that greatly adds to reliability. Variables require values. Failure to initialize a variable with an
appropriate value can cause program logic errors during execution. An object of a complicated class has many
attributes that all need to start with a proper value. One important job of a constructor is to
initialize every instance variable of the new object with some value. The general purpose of a constructor is to
make an object ready to be used during program execution. Such a task may require considerably more
than assigning initial values. You may
remember the example of the CardDeck
class, which includes shuffling the cards when a new CardDeck object is instantiated.
What happens when you do not include a constructor
method with a new class declaration? In
such a case, Java still calls a constructor and tries to do a good job making
your object ready for use. The reality
is that you have lost control over your program. This is not good OOP design.
|
Constructor Notes |
|
A
constructor is a method with the same identifier as the class. Constructors
are neither void nor return methods. A
constructor is called during the instantiation of an object. Constructors
without parameters are default constructors. |
14.4 Accessing
Attributes and Methods
In the old Pre-OOP
days there were data structures that stored data and there were modules,
called subroutines, procedures or functions that accessed the data
directly. This was normally done with parameter
passing. As programs grew in size and
complexity, it became harder and harder to control proper data access. It was very common that one procedure altered
variable values in such a way that is caused problems for the proper processing
of another procedure. The biggest
problem is that special procedures that would insure proper handling of data
were either not used or could be bypassed very easily.
Is it such a big deal that data is handled in a
special way? There certainly are many
examples of simple programs, like the ones used in this chapter, where it is
easy to control proper program execution.
It is with complex programs that OOP assists by accessing data properly.
Consider a practical example outside the computer
program world. A bio-lab is processing
dangerous organisms in an effort to find cures for serious diseases. A special environment is created that seals
the deadly bacteria inside a container.
Can a lab technician reach inside the container to handle the
bacteria? Certainly not, such an action
may kill the lab technician and potentially start a serious epidemic. In such a case there are special robotic arms
that control the handling of the bacteria.
The lab technician uses joysticks outside the bio container to
manipulate the robot arms.
Your programs will not cause deadly epidemics if you
do not create special accessing methods to handle data but the malfunction of
programs has caused, major loss of money and yes sometimes ... death and injury
to people. The Denver International
Airport opened during the mid Nineties, six months behind schedule. The highly sophisticated computer program
that handled the luggage system was flawed.
The airport lost millions of dollars because of the late opening, all
caused by the malfunctioning of a computer program.
Program Java1403.java,
in figure 14.4, is a stage in the Person
class that shows a very serious nono. The instance variables of the Person object are accessed directly
without using any special methods. You
will find that the program works correctly, but keep in mind that this is a
very small program. What you see
demonstrated here is a total violation of the encapsulation principle.
Figure 14.4
|
// Java1403.java // Stage-3 of the
Person class. // This stage
accesses Person data directly, which is very poor OOP design // by violating
encapsulation, which may cause side effects. public class
Java1403 { public static void main(String args[]) { System.out.println("Person
Class, Stage 3\n"); Person03 p = new Person03(); System.out.println("Name: " + p.name); System.out.println("Born: " + p.yearBorn); System.out.println("Education: " + p.education); System.out.println(); }
} class Person03 { String name; int yearBorn; int education; Person03() { System.out.println("Calling
Default Constructor"); name = "John Doe"; yearBorn = 1980; education = 0; } } |
Figure 14.4 continued
|
Java1403.java Output Person Class, Stage 3 Calling Default Constructor Name: John Doe Born: 1980 Education: 0 |
As you see, it is possible to use the object name, p in this case, and access the data by
using a dot followed by the attribute identifier. Perhaps you are convinced that this is a bad
thing and you are surprised that a prominent language such as Java, and a
powerful programming feature, such as OOP, allows this bad style of
programming. Yes it is possible to write
a program in this manner, but Java includes some special protection to prevent
improper access of instance variables.
Program Java1404.java, in
figure 14.5, adds two very important reserved words: private and public. The data attributes are declared as private and the methods are declared as public. Program Java1404.java
is almost identical to Java1403.java. Only the reserved Java keywords public and private have been added. The
improper data access, which was possible in the previous program, is now
blocked and the compiler indicates three compile errors. There is one error for each access to private
data.
Figure 14.5
|
// Java1404.java // Stage-4 of the
Person class. // In this program
direct access to Person data is denied by declaring all // class data
private. This program will not
compile. public class
Java1404 { public static void main(String args[]) { System.out.println("Person
Class, Stage 4\n"); Person04 p = new Person04(); System.out.println("Name: " + p.name); System.out.println("Year
Born: " + p.yearBorn); System.out.println("Education: " + p.education); System.out.println(); }
} class Person04 { private String name; private int yearBorn; private int education; public Person04() { System.out.println("Calling
Default Constructor"); name = "John Doe"; yearBorn = 1980; |