Chapter 4: Objects and Classes

In the early 1960s, two researchers at the Norwegian Computing Center in Oslo, Ole-Johan Dahl and Kristen Nygaard, were trying to write programs that simulated real systems — ships moving through a harbour, customers waiting at counters, jobs queuing for a machine. The mathematics was not the hard part. The hard part was the program itself.

A simulation of a harbour has a great many ships in it. Every ship carries its own facts — its length, its cargo, where it currently is — and every ship does the same kinds of things: it arrives, it waits, it berths, it leaves. Written in the style of the day, the program became a sprawl of separate arrays, one for each fact, with the code that acted on those facts scattered somewhere else entirely. Change one detail about a ship and you had to hunt through the whole listing.

Their solution was to let the program contain small self-contained units, each holding its own data together with the operations on that data — and to describe each kind of unit once, in a single template from which any number of units could be built. They called the units objects and the templates classes. Every language you are likely to meet today, Java included, inherits that idea. Fig. 4.0-1 shows the shift in thinking.

Diagram

Fig. 4.0-1 – two panels side by side; left panel labelled “Data and code kept apart”: three separate boxes labelled Data arrays, Functions, Program logic, with many crossing arrows between them; right panel labelled “Data and code kept together”: three identical rounded units labelled Ship 1, Ship 2, Ship 3, each drawn as an inner box “own data” wrapped by an outer ring “own operations”, with a single arrow from each unit to a template box on the left labelled “Class Ship”

NoteCuriosity Corner

Q1. If a class is only a description on paper, what exactly comes into existence in the computer’s memory when the program runs? Q2. Two objects are built from the same class. What is allowed to be different between them, and what must be the same? Q3. Why does Java make you write new before you can use an object, when an ordinary int needs nothing of the kind? Q4. A variable written inside a class, a variable written inside a method, and a variable marked static — why does the same program treat these three so differently? Q5. Programmers often hide a class’s data behind methods that simply fetch it and set it. Why go to that trouble instead of using the data directly?

This chapter answers all five questions; keep them in mind as you read.

4.1 Two Ways of Organising a Program

Every program you have ever written contains two kinds of things: information, and actions performed on that information. A marks program holds marks and calculates totals. A billing program holds prices and quantities and computes an amount. The information and the actions are both unavoidable.

What is not fixed is how you arrange them. You can put all the information in one place and all the actions in another, or you can keep each piece of information together with the actions that belong to it. Those two arrangements produce very different programs from the same problem.

The second arrangement is the one this chapter is about. To see why it was invented, it helps to first watch the first arrangement fail.

4.1.1 The Procedural View and Where It Strains

In Class XI you wrote programs as a sequence of statements, grouped into methods, working on variables and arrays declared for the purpose. A method was the unit of organisation: you decided what steps the computer should carry out, and in what order. This way of building a program is called procedural programming — the program is designed around its procedures, that is, around the actions it performs.

For a short program this works perfectly well, and you should not think of it as a mistake. It begins to strain only when the program has to keep track of many things of the same kind.

A library that outgrows its arrays

Suppose a school library program has to hold three facts about each of three hundred books: its title, its author, and whether it is currently issued. In the procedural style you would declare three arrays.

String title[] = new String[300];
String author[] = new String[300];
boolean issued[] = new boolean[300];

The three facts about one particular book are now sitting in three different arrays. Nothing in the language records that they belong together. The only thing joining them is the index: whatever is at position 40 in each array is understood, by you alone, to describe the same book. Fig. 4.1-1 shows this arrangement.

Diagram

Fig. 4.1-1 – three horizontal arrays drawn one below the other, labelled title, author and issued, each shown with cells at positions 39, 40 and 41; a single vertical dashed line cuts down through cell 40 of all three arrays, labelled “the only link is the index”; a caption arrow points to the dashed line reading “nothing in the program enforces this”

Reading the data back works as long as that understanding holds:

for (int i = 0; i < count; i++)
{
    if (issued[i] == false)
    {
        System.out.println(title[i] + " by " + author[i]);
    }
}

The trouble starts the moment the arrays have to change. Removing a book means editing three arrays in exactly the same way, and remembering to do so every single time.

shifting one array and forgetting the others What students write:

for (int i = pos; i < count - 1; i++)
{
    title[i] = title[i + 1];
}
count--;

What happens: the program compiles cleanly and runs without any error message. But only the titles have moved up. From position pos onwards, every title is now printed next to the author of a different book, and the issue status of a third. The data is silently corrupted, and the fault will usually be noticed days later, in output that merely looks odd. The fix: shift all three arrays inside the same loop. That works — but notice that the language gave you no help at all. Nothing warned you, because nothing in the program ever said that these three arrays describe one thing.

Two further weaknesses follow from the same root. First, every method in the program can reach into any of the three arrays and change it, so a bug anywhere can damage the data everywhere. Second, adding a fourth fact — the price of a book, say — means declaring another array and then revisiting every method that inserts, deletes or displays a book. The cost of a small change is spread across the whole listing.

Take the three arrays above and add a fourth fact, the price of each book. On paper, list every place in a library program that would have to be edited: declaration, input, display, insertion, deletion, searching. Keep the list; you will compare it with the object oriented version later in this chapter.

4.1.2 The Object Oriented View

Now arrange the same problem the other way. Instead of one array per fact, make one self-contained unit per book. Each unit holds that book’s title, author and issue status inside itself, and it also holds the operations that make sense for a book — issue it, return it, display it.

The gain is immediate. The three facts about a book are no longer joined by an unwritten promise about indexes; they are joined because they are physically inside the same unit. Removing a book removes one thing, not three. Adding the price adds one field in one place.

The second gain is protection. If the data sits inside the unit and the outside world can only reach it through the unit’s own operations, then no stray method elsewhere in the program can quietly corrupt it. The unit decides what may be done to its own data.

This is why the approach is usually described as one in which the stress is laid on the data rather than on the functions. The design question changes from “what steps must the program carry out?” to “what things does this problem contain, and what does each of them know and do?”

Such a self-contained unit is called an object, and the description from which any number of such units can be built is called a class. A class is written once; objects are made from it as often as the program needs. Sections 4.2 and 4.3 examine each of them properly.

NoteDefinition

Object oriented programming is a way of building a program as a set of self-contained units called objects, each holding its own data together with the operations that act on that data, where each kind of object is described once by a class.

The style of programming built on these two ideas is object oriented programming (OOP). Java is an object oriented language, which is why even the smallest Java program you have written had to be placed inside a class.

Q. If a program is written in Java, is it automatically object oriented?

A. No. You can write one large class containing three arrays and a set of static methods that operate on them, exactly as in 4.1.1. Java will compile it happily, but the design is procedural; only the outer wrapper is a class. What makes a program object oriented is that the data has been distributed among objects that own it, not that the file happens to contain the word class.

4.1.3 What Object Orientation Buys You

Four consequences follow from that one design decision, and they are worth stating plainly.

The program is built around its data rather than around its actions. A large problem is broken into a number of objects, each small enough to be understood on its own. Objects exchange information by calling one another’s methods rather than by reading one another’s variables. And because the data can be shut away inside an object, it is protected from interference by the rest of the program.

There is a fifth consequence, which becomes important later in the book. Once a class exists, a new class can be written that keeps everything the old one had and adds to it, instead of copying the code. This property is called reusability, and it is one of the strongest practical arguments for the whole approach.

Table 4.1 – Procedural and object oriented organisation compared

Feature Procedural organisation Object oriented organisation
Unit of organisation The method The object
Program is designed around The sequence of actions to be performed The things the problem contains
Where the data about one entity lives Spread across several variables or arrays Together, inside one object
Who can change that data Any method in the program Normally only the object’s own methods
Adding one more fact about an entity Another array, plus edits to every method that touches it One more field, in one place
Reuse of existing code By copying methods into the new program By building a new class on an existing one

Restraint is worth keeping here. Object orientation is not a superior way of writing every program; it is a way of controlling complexity, and complexity is what it charges you for. A ten-line program that adds two numbers gains nothing from being redesigned around objects — it only becomes longer. Objects also occupy memory individually and are reached indirectly, so a design with thousands of tiny objects can be slower than three plain arrays.

The honest statement is this: when a program keeps track of many things of the same kind, and is expected to be changed and extended over time, organising it around objects usually costs less over the life of the program than organising it around procedures. That is the trade the rest of this chapter assumes you have accepted.

4.2 Objects

The idea named at the end of the last section now needs a proper look. An object is not a piece of Java syntax you have to memorise; it is a way of describing something so that a program can hold it. Before any Java appears, it is worth learning to see objects in the world, because that is where the design of a program begins.

Look at any single thing around you — a ceiling fan, a bus, a shop’s weighing scale. Two questions can be asked about it, and only two matter here. What does it know about itself? And what can it do?

4.2.1 Attributes and Behaviour

Take a ceiling fan in a classroom. It knows certain facts about itself: how many blades it has, what speed setting it is running at, what its power rating is. These facts are its attributes — also called its characteristics, or, once the fan becomes a program object, its data.

The same fan also does certain things: it can be switched on, its speed can be raised or lowered, it can be switched off. These are its behaviour — the actions that can be carried out on it or by it. In a program, behaviour is written as methods.

An object, then, is one particular thing that carries its own attributes and its own behaviour together. Fig. 4.2-1 shows the fan drawn this way, with the data enclosed and the behaviour forming the surface through which the rest of the world reaches it.

Diagram

Fig. 4.2-1 – a single rounded unit labelled “Fan object”; at its centre an inner box labelled “Attributes” listing blades, speed, powerRating; around the inner box an outer ring divided into three labelled segments switchOn(), setSpeed(), switchOff(); three arrows come from outside the unit and touch only the outer ring, none reaching the inner box

NoteDefinition

An object is a single, distinct entity that holds a set of attributes — the data describing it — together with the behaviour, that is, the operations that may be performed on that data.

The attributes and the behaviour of the classroom fan can be set out side by side.

Table 4.2 – Attributes and behaviour of a ceiling fan, as a program would record them

Attributes (what it knows) Behaviour (what it does)
Number of blades Can be switched on
Current speed setting Can have its speed changed
Power rating in watts Can be switched off
Values change, the object does not

Notice what happens when the speed is raised from 2 to 4. The fan has not become a different fan; one of its attribute values has changed. The set of attributes an object has is fixed when it is designed. The values held in those attributes at any moment are what change as the program runs, and it is the object’s behaviour that changes them.

This is why attributes are sometimes described as holding the current state of the object. Reading the state tells you what the object is like right now; calling its behaviour is how that state is allowed to move.

Q. Two fans in a room have the same number of blades, the same rating and the same speed setting. Are they one object or two?

A. Two. An object is a distinct entity, and identity does not come from the values it happens to hold. Switching one fan off changes that fan alone, which is precisely what proves they are separate. Two objects can carry identical values and still be two objects — a point that returns in 4.4 when the same thing happens in Java.

4.2.2 Reading a Real World Object as Data and Actions

Being able to look at something in the world and split it cleanly into data and actions is the first real design skill in this subject. Work through a second example carefully, and the method becomes clear.

Consider a bus on a school route, as a transport office program would have to record it. The facts it must know are its route number, its seating capacity and the stop it has currently reached. The actions that make sense on it are starting the trip, halting at a stop, and completing the trip.

Table 4.3 – A school bus described as attributes and behaviour

Attributes Behaviour
Route number Start the trip
Seating capacity Halt at the next stop
Current stop Complete the trip
What to include is a decision, not a discovery

A real bus has hundreds of facts attached to it — tyre pressure, seat fabric, the year it was built. None of them appear in Table 4.3, and their absence is not carelessness.

The attributes worth recording depend entirely on what the program is for. A transport office program tracking routes needs the route number and the current stop. A workshop program tracking servicing would drop both of those and record engine number, kilometres run and date of last service instead. The same real object yields two different lists because two different programs are asking two different questions.

So the correct question is never “what is true about this thing?” but “what must my program know about this thing in order to do its job?” Everything else is deliberately left out. This deliberate leaving out has a name in object oriented programming, and section 4.8.2 returns to it.

Telling an attribute from a behaviour

A quick test settles most doubtful cases. An attribute is a fact that can be stored and later read back — it has a value. A behaviour is something that happens — it has an effect, or it produces an answer.

“Seating capacity” stores a number, so it is an attribute. “Halt at the next stop” changes which stop the bus has reached, so it is behaviour. “Number of passengers currently on board” stores a number and is therefore an attribute, even though it changes often; frequent change does not make a fact into an action.

Some behaviour does not change anything at all — displaying the route number, or reporting whether any seats are free. That is still behaviour, because the object is doing something on request rather than merely holding a value.

Choose one object from your own school — a wall clock, a water cooler, a library issue counter’s register. Write down four attributes and three behaviours for it, as in Table 4.3. Then write one sentence saying what program you imagined it being part of, and check whether any attribute on your list would drop out if the program’s purpose changed.

4.3 Classes

A program that needed only one fan would hardly need a new way of thinking. Real programs need thirty fans, or three hundred books, and every one of them has the same list of attributes and the same list of behaviour — only the values differ.

Writing that list out thirty times would be absurd. It is written once, as a description, and the individual objects are produced from that description. That written description is the class.

4.3.1 A Class as a Blueprint

The word most often used for a class is blueprint, and the comparison is worth taking seriously. An architect’s blueprint for a classroom fixes how many windows there will be, how wide the door is and where the board is mounted. It fixes the structure. It is not itself a classroom — you cannot sit in a blueprint, and no student is ever inside one.

A class works the same way. It fixes which attributes every object of that kind will have and which behaviour every such object will offer. It does not itself hold the values. The class Fan says that every fan has a speed; it does not say that the speed is 3. That is the business of an individual object.

NoteDefinition

A class is a description from which objects are created. It states the attributes every object of that kind will have and defines the behaviour every such object will offer, without itself holding the values of those attributes.

From one class, any number of objects can be produced, and they may all differ. Fig. 4.3-1 shows one class and three objects made from it.

Diagram

Fig. 4.3-1 – on the left a single box labelled “Class Fan”, containing the two lists “Attributes: blades, speed, powerRating” and “Behaviour: switchOn(), setSpeed(), switchOff(), display()”; three arrows lead from it to the right, to three separate boxes labelled Fan object 1, Fan object 2 and Fan object 3; each object box holds actual values, respectively blades 3 speed 0 rating 75, blades 3 speed 4 rating 50, blades 4 speed 2 rating 60; caption under the arrows reads “same structure, different values”

Three fans, one description. Each object carries its own copy of the attribute values, so raising the speed of the second fan leaves the other two untouched. What they share is the structure and the behaviour, not the data.

By long-standing convention, a class name in Java begins with a capital letter — Fan, Bus, StringTokenizer — while variables and methods begin with a small letter. The compiler does not insist on this, but every Java program you read will follow it, and code that breaks the convention is harder for others to read.

4.3.2 Writing a Class in Java

A class in Java is written by naming it and then placing its contents inside a pair of braces. The general form is short:

class ClassName
{
    // variables declared here describe what an object of this class knows

    // methods written here describe what an object of this class does
}

The variables written directly inside the class body, outside every method, are the data members of the class — they are the attributes of Table 4.2 turned into Java declarations. The methods written inside the class body are its member methods — the behaviour, turned into code.

Build the fan class one part at a time. First the data members, one for each attribute:

class Fan
{
    int blades;
    int speed;
    int powerRating;

Each of these is declared exactly as you would declare any variable, with a type and a name. Note that no values are given. A class describes; it does not hold. Values arrive only when an object is made.

Next the behaviour. Switching the fan on means setting its speed to the lowest setting and reporting that it has started:

    void switchOn()
    {
        speed = 1;
        System.out.println("Fan started at speed " + speed);
    }

The line speed = 1; deserves attention. There is no declaration of speed inside this method, and none is needed — speed is a data member of the class, so every method of the class can use it directly. This is the whole point of putting the data and the behaviour in the same place.

Changing the speed needs a value from outside, so that method takes an argument:

    void setSpeed(int s)
    {
        speed = s;
        System.out.println("Speed changed to " + speed);
    }

Switching off, and displaying the fan’s current state, complete the class:

    void switchOff()
    {
        speed = 0;
        System.out.println("Fan switched off");
    }

    void display()
    {
        System.out.println("Blades: " + blades + ", Speed: " + speed + ", Rating: " + powerRating + " W");
    }
}

Put together, those five fragments form one complete class definition:

class Fan
{
    int blades;
    int speed;
    int powerRating;

    void switchOn()
    {
        speed = 1;
        System.out.println("Fan started at speed " + speed);
    }

    void setSpeed(int s)
    {
        speed = s;
        System.out.println("Speed changed to " + speed);
    }

    void switchOff()
    {
        speed = 0;
        System.out.println("Fan switched off");
    }

    void display()
    {
        System.out.println("Blades: " + blades + ", Speed: " + speed + ", Rating: " + powerRating + " W");
    }
}

This class compiles. It does not run, and cannot, because nothing in it is a main method and no object has been created from it — a blueprint with no building. Section 4.4 supplies both, and the first output of the chapter appears there.

declaring a data member again inside a method What students write:

    void switchOn()
    {
        int speed = 1;
        System.out.println("Fan started at speed " + speed);
    }

What happens: the class compiles and the line printed looks perfectly correct. But int speed = 1; has created a brand new variable that exists only until the method ends. The fan’s own speed was never touched, so calling display() afterwards still reports a speed of 0. Nothing warns you, because writing a new variable inside a method is a perfectly legal thing to do. The fix: drop the type. Write speed = 1;, which assigns to the data member the class already declared. A variable is declared once, where it belongs — as a data member if the object must remember it, inside a method if it is scratch working. Section 4.6 sets out the distinction in full.

4.3.3 Class and Object Distinguished

These two words are used constantly in the same sentence, so the difference between them has to be sharp.

A class is written by the programmer, once, in the source file. It occupies no memory for data, because it holds none. An object is produced while the program runs, and it does occupy memory, because it holds actual values. One class can produce many objects; every object belongs to exactly one class.

Table 4.4 – Class and object compared

Feature Class Object
What it is A description of a kind of thing One particular thing of that kind
When it exists Written in the source code, before the program runs Created while the program is running
Attribute values Only names and types, no values Actual values, its own copy of each
Memory for data None occupied Occupied, separately for each object
How many One per kind of thing As many as the program needs
Relationship Produces objects Produced from a class

Q. Can two classes describe the same kind of thing in one program?

A. They can, and sometimes they should. A transport office program might have a class Bus holding route details while a workshop program has a different class, also about buses, holding service details. Each class answers the question its own program asks — the point made in 4.2.2. What cannot happen is one object belonging to two classes at once; every object is created from exactly one class.

4.4 Instantiating a Class

The class Fan is written, and so far nothing has happened. No fan exists, no memory has been set aside, and there is nothing to switch on. A class by itself is inert.

Producing an object from a class is called instantiation, and the object produced is called an instance of that class. This section does it, examines what the computer actually does when it happens, and ends with the chapter’s first working program.

4.4.1 The new Operator and What a Reference Holds

An object is created with the new operator. The general form is:

ClassName objectName = new ClassName();

For the fan class, one particular fan is created like this:

Fan hall = new Fan();

Read the line in two halves, because two different things are happening on either side of the equals sign, and confusing them is the source of most early misunderstanding.

What the right-hand side does

new Fan() builds the object. The computer sets aside a block of memory large enough to hold one copy of every data member the class declared — one blades, one speed, one powerRating — and fills each of them with a default value, since no value has been supplied yet.

Those defaults are fixed by the language, not chosen at random.

Table 4.5 – Default values given to the data members of a newly created object

Type of data member Default value
byte, short, int, long 0
float, double 0.0
char the character with code 0
boolean false
Any class type, such as String null

So the moment new Fan() finishes, a fan exists in memory with 0 blades, speed 0 and a rating of 0 W. It is a real object; it simply has uninteresting values. Section 4.5 shows how to give it sensible ones from the start.

Q1. If a class is only a description on paper, what exactly comes into existence in the computer’s memory when the program runs?

A. A block of memory holding one copy of each data member the class declared, filled with the default values of Table 4.5. That block is the object. The methods are not copied into it — they are written once in the class and shared by every object made from it, because all objects of a class behave in the same way and differ only in their data.

What the left-hand side does

Fan hall does not create a fan. It creates a variable named hall whose type is Fan, and such a variable does not hold an object at all. It holds a reference variable value — in plain terms, the location at which an object can be found.

The equals sign then stores in hall the location of the object that new has just built. Fig. 4.4-1 shows the arrangement.

Diagram

Fig. 4.4-1 – left side, a small labelled box named hall drawn as a variable holding no numbers, with an arrow leaving it; right side, a larger box labelled “Fan object” divided into three labelled cells blades 0, speed 0, powerRating 0; the arrow from hall points to the top of the object box; below the small box a caption reads “holds where the object is”, below the large box a caption reads “holds the object’s data”; for contrast, a separate small box at the bottom left labelled n of type int containing the value 5, with no arrow

The contrast at the bottom of the figure is the whole point. When you write int n = 5;, the variable n contains 5 itself. When you write Fan hall = new Fan();, the variable hall contains no fan — it contains the means of reaching one.

Q3. Why does Java make you write new before you can use an object, when an ordinary int needs nothing of the kind?

A. Because the two kinds of variable work differently. Declaring int n; reserves storage for the value itself, and the value is complete as soon as it is assigned. Declaring Fan hall; reserves storage only for a reference, and a reference is useless until something exists for it to refer to. The new operator is what builds that something. Until it runs, the reference points nowhere, and the compiler will not let you use it.

NoteDefinition

An object created from a class is called an instance of that class, and the act of creating it is called instantiating the class.

4.4.2 Reaching Members with the Dot Operator

Once an object exists, its data members and its methods are reached through the dot operator, written as a full stop between the object’s name and the member’s name:

hall.blades = 3;
hall.switchOn();

The first line stores 3 in the blades member of this particular fan. The second calls switchOn() on this particular fan. The dot should be read as the words “belonging to”: hall.speed is the speed belonging to hall.

This is why a method never has to be told which object it is working on. Inside switchOn(), the statement speed = 1; sets the speed of whichever object the method was called on. Call it on hall and hall’s speed changes; call it on another fan and that fan’s speed changes instead.

calling a method with no object What students write:

    public static void main(String args[])
    {
        switchOn();
    }

What happens: the program does not compile. The compiler objects that a non-static method cannot be referenced from a static context — in plain words, switchOn() is behaviour belonging to a fan, main is not a fan, and no fan has been named. The fix: create an object first and call the method on it.

    public static void main(String args[])
    {
        Fan hall = new Fan();
        hall.switchOn();
    }

Behaviour written in a class always belongs to an object of that class, so there is always an object on the left of the dot.

A related failure happens when the reference exists but no object does. Fan hall; followed by hall.switchOn(); will not compile, because hall has never been given a value. If the reference is deliberately set to null, the program does compile and then fails while running, since there is nothing at the far end of the arrow in Fig. 4.4-1.

4.4.3 Many Objects from One Class

Everything so far has used a single fan, which hides the property that matters most. Two objects created from the same class are genuinely separate: each has its own copy of every data member, so changing one leaves the other exactly as it was.

Fig. 4.4-2 shows two fans in memory alongside the single copy of the class’s methods.

Diagram

Fig. 4.4-2 – two object boxes side by side labelled hall and lab, each divided into three cells blades, speed, powerRating holding different values, hall showing 3, 4, 75 and lab showing 4, 1, 60; below them a single wide box labelled “Methods of class Fan: switchOn(), setSpeed(), switchOff(), display()”; an arrow runs from each object box down to the single methods box, both arrows labelled “shared, one copy only”

The program below creates two fans, gives them different values, operates on them independently and displays both.

creating two objects of a class and operating on them separately Problem: Using the class Fan of section 4.3, create two fan objects representing a hall fan and a laboratory fan. Set the number of blades and the power rating of each, switch both on, change the speed of the hall fan only, display the state of both fans, then switch the hall fan off and display it again. All values are fixed inside the program; no input is read.

class Fan
{
    int blades;
    int speed;
    int powerRating;

    void switchOn()
    {
        speed = 1;
        System.out.println("Fan started at speed " + speed);
    }

    void setSpeed(int s)
    {
        speed = s;
        System.out.println("Speed changed to " + speed);
    }

    void switchOff()
    {
        speed = 0;
        System.out.println("Fan switched off");
    }

    void display()
    {
        System.out.println("Blades: " + blades + ", Speed: " + speed + ", Rating: " + powerRating + " W");
    }

    public static void main(String args[])
    {
        Fan hall = new Fan();
        Fan lab = new Fan();

        hall.blades = 3;
        hall.powerRating = 75;
        lab.blades = 4;
        lab.powerRating = 60;

        hall.switchOn();
        hall.setSpeed(4);
        lab.switchOn();

        hall.display();
        lab.display();

        hall.switchOff();
        hall.display();
    }
}

Sample output:

Fan started at speed 1
Speed changed to 4
Fan started at speed 1
Blades: 3, Speed: 4, Rating: 75 W
Blades: 4, Speed: 1, Rating: 60 W
Fan switched off
Blades: 3, Speed: 0, Rating: 75 W

Variable description:

[Table:] Table 4.6 – Variable description for the two-object fan program [/Table] | Variable | Type | Purpose | |—|—|—| | blades | int | Number of blades of a fan | | speed | int | Current speed setting, 0 when the fan is off | | powerRating | int | Power rating of the fan in watts | | s | int | Formal argument of setSpeed(), the speed to be set | | hall | Fan | Refers to the fan object representing the hall fan | | lab | Fan | Refers to the fan object representing the laboratory fan |

Notes: main is placed inside Fan itself so that the whole example is one file that can be keyed in and run directly. The data members are set here by writing to them through the dot operator, which is convenient for a first example but not good practice — 4.8.1 explains why, and 4.5 shows the proper way to give an object its starting values.

The third line of output repays a second look. lab.switchOn() printed a speed of 1 even though the hall fan was already running at 4, because lab has its own speed member which was still 0 at that moment. The trace below follows both objects statement by statement.

the main method of the fan program, following the speed member of each object

Statement executed hall.speed lab.speed Printed
Fan hall = new Fan(); 0 — —
Fan lab = new Fan(); 0 0 —
hall.switchOn(); 1 0 Fan started at speed 1
hall.setSpeed(4); 4 0 Speed changed to 4
lab.switchOn(); 4 1 Fan started at speed 1
hall.display(); 4 1 Blades: 3, Speed: 4, Rating: 75 W
lab.display(); 4 1 Blades: 4, Speed: 1, Rating: 60 W
hall.switchOff(); 0 1 Fan switched off
hall.display(); 0 1 Blades: 3, Speed: 0, Rating: 75 W

Result: the final output is the seven lines shown above. At no point does an operation on one object alter a value inside the other — every row changes at most one of the two columns, which is exactly what “each object has its own copy of the data” means in practice.

Q2. Two objects are built from the same class. What is allowed to be different between them, and what must be the same?

A. The values of the data members may differ freely, and each object keeps its own copy of them, as the two columns of the dry run show. What cannot differ is the structure and the behaviour: both objects have exactly the same data members with the same names and types, and both use the same single copy of the class’s methods. The class fixes what an object is made of; the object fixes what it currently holds.

Add a third fan to the program, called library, with 3 blades and a rating of 50 W. Switch it on, set its speed to 2, and display all three fans one after another. Before you run it, write down the seven lines the earlier fans will print and the two new lines you expect, then check your prediction against what the program actually prints.

4.5 Constructors

At the end of the last section a promise was left open. The fan program set the blades and the rating by writing to the data members from outside, and the note under the program called that convenient but not good practice. This section explains what should happen instead.

The example changes with it. A bus ticket is a good object to think with: it has a number, a destination and a fare, and unlike a fan it is meaningless until all three are known.

4.5.1 Why an Object Needs Initialising

Suppose the ticket class is written exactly in the style of section 4.3 — three data members and a display() method, nothing more:

class Ticket
{
    int ticketNo;
    String destination;
    int fare;

    void display()
    {
        System.out.println("Ticket " + ticketNo + " to " + destination + " : Rs " + fare);
    }
}

Creating a ticket from it and displaying it at once would print this:

Ticket 0 to null : Rs 0

Every value is the default of Table 4.5, and null is what a String member holds when nothing has been put in it. The object exists, but as a ticket it is nonsense.

Three separate assignments through the dot operator would repair it. That approach has three drawbacks, and they get worse as programs grow.

First, every place in the program that creates a ticket must remember to write all three assignments. Second, between the moment the object is created and the moment the last assignment runs, a broken ticket exists and any method called on it will use meaningless values. Third — and most seriously — nothing in the language obliges the programmer to do any of it. Forgetting is silent.

What is needed is a way of giving an object its starting values as part of creating it, so that the two cannot come apart. Java provides exactly that, in the form of a constructor.

NoteDefinition

A constructor is a special member of a class that runs automatically when an object of that class is created, and whose purpose is to give the new object its initial values. It carries the same name as the class and has no return type, not even void.

Fig. 4.5-1 shows the order of events when an object is created from a class that has a constructor.

Diagram

Fig. 4.5-1 – flow: new Ticket(1041, "Sanganer", 35) → memory set aside for one object → every data member filled with its default value → the constructor body runs and overwrites those defaults → the reference to the finished object is handed back to the variable on the left of the equals sign

The defaults are still applied — a constructor does not replace that step, it follows it. This is why a data member the constructor forgets to set is left at 0 or null rather than at anything unpredictable.

4.5.2 The Default Constructor

The fan program of 4.4.3 created objects with new Fan() although the class Fan had no constructor written in it. That worked because of a rule worth stating carefully.

If a class contains no constructor at all, the compiler supplies one automatically. It takes no arguments and does nothing beyond letting the defaults stand. This compiler-supplied constructor is called the default constructor, and it is the reason new Fan() compiled at all.

A programmer may also write a constructor that takes no arguments and does something useful, such as filling in sensible starting values:

    Ticket()
    {
        ticketNo = 0;
        destination = "Not booked";
        fare = 0;
    }

In many books this too is loosely called a default constructor, and in ISC usage the phrase is often applied to both. It is worth keeping the distinction in mind: the true default constructor is the one the compiler writes for you when you have written none, while the one above is a constructor you have written that happens to take no arguments. The important consequence is the same either way — a no-argument constructor is what makes new Ticket() legal.

Q. What happens to the compiler’s default constructor once you write a constructor of your own?

A. It disappears. The compiler supplies one only when the class declares no constructor whatever. So if the only constructor in Ticket is one that takes three arguments, the statement new Ticket() no longer compiles, because there is nothing for it to call. Adding a class’s first constructor can therefore break code elsewhere that was creating objects with no arguments — which is why classes that need both forms simply provide both.

4.5.3 Parameterised Constructors and Constructor Overloading

A constructor that takes no arguments can only ever produce identical objects. To create a ticket that is actually for something, the values must come in from outside, and a constructor that accepts arguments is called a parameterised constructor.

    Ticket(int n, String d, int f)
    {
        ticketNo = n;
        destination = d;
        fare = f;
    }

Now new Ticket(1041, "Sanganer", 35) produces a complete, usable ticket in a single statement. The object is never in a half-built state, and the compiler itself enforces that the three values are supplied, because a call that omits them will not compile.

A class may contain more than one constructor, provided they differ in the number or the types of their arguments. Writing several constructors for the same class in this way is called constructor overloading, and it lets one class serve situations that know different amounts at the moment of creation. When the object is created, Java decides which constructor to run by looking at the arguments in the new statement.

a ticket class with two constructors Problem: Define a class Ticket with data members for the ticket number, the destination and the fare. Provide one constructor that takes no arguments and marks the ticket as unbooked, and a second that accepts a ticket number, a destination and a fare. Create one object with each constructor and display both. All values are fixed inside the program; no input is read.

class Ticket
{
    int ticketNo;
    String destination;
    int fare;

    Ticket()
    {
        ticketNo = 0;
        destination = "Not booked";
        fare = 0;
    }

    Ticket(int n, String d, int f)
    {
        ticketNo = n;
        destination = d;
        fare = f;
    }

    void display()
    {
        System.out.println("Ticket " + ticketNo + " to " + destination + " : Rs " + fare);
    }

    public static void main(String args[])
    {
        Ticket blank = new Ticket();
        Ticket sold = new Ticket(1041, "Sanganer", 35);

        blank.display();
        sold.display();
    }
}

Sample output:

Ticket 0 to Not booked : Rs 0
Ticket 1041 to Sanganer : Rs 35

Variable description:

[Table:] Table 4.7 – Variable description for the ticket program [/Table] | Variable | Type | Purpose | |—|—|—| | ticketNo | int | Serial number printed on the ticket | | destination | String | Stop the passenger is travelling to | | fare | int | Fare payable, in rupees | | n | int | Ticket number received by the parameterised constructor | | d | String | Destination received by the parameterised constructor | | f | int | Fare received by the parameterised constructor | | blank | Ticket | Refers to the ticket created with no arguments | | sold | Ticket | Refers to the ticket created with all three values |

Notes: the two constructors differ in their argument lists, which is what allows both to exist in one class. Neither has a return type — adding one would change its meaning entirely, as the box below shows. display() is an ordinary method and is called only when asked for, while the constructors ran without being called at all.

giving a constructor a return type What students write:

    void Ticket()
    {
        ticketNo = 0;
        destination = "Not booked";
        fare = 0;
    }

What happens: the class compiles without complaint, and new Ticket() still works — so nothing appears to be wrong. But those three assignments never run. Because of the word void, this is not a constructor at all; it is an ordinary method that happens to be named Ticket, and like any method it runs only when it is called. The class now declares no constructor, so the compiler quietly supplies the default one, and the new ticket shows a destination of null. The fix: delete the return type. A constructor is recognised by two things together — its name matches the class exactly, and it has no return type of any kind.

Constructors are often written with argument names identical to the data members, as in Ticket(int ticketNo, ...). The argument then hides the data member, and ticketNo = ticketNo; would assign the argument to itself. Java solves this with the keyword this, which means “the object this constructor is working on”, so the line becomes this.ticketNo = ticketNo;. The this operator is taken up properly along with methods; until then, giving the arguments different names, as above, avoids the clash entirely.

4.5.4 How a Constructor Differs from a Method

A constructor sits inside a class alongside the methods and is written in a similar shape, which makes the two easy to confuse. They differ in four ways, and every one of them matters.

Table 4.8 – Constructor and member method compared

Feature Constructor Member method
Name Must be exactly the class name Any valid identifier, by convention not the class name
Return type None at all, not even void Compulsory — a type, or void
When it runs Automatically, when an object is created with new Only when it is explicitly called
How often Once per object, at creation Any number of times, on any object
Purpose To put the new object into a valid starting state To carry out the object’s behaviour afterwards

The row on return types is the one students trip over most, and the reason behind it is worth knowing. A constructor is not asked to produce an answer; the outcome of new is the object itself, handed back automatically. There is therefore nothing for a constructor to return, and the language forbids it from declaring that it does.

Add a third constructor to Ticket that accepts only a ticket number and a destination, and sets the fare to 20. Create an object with it, display all three tickets, and then predict what would happen if you added a fourth constructor taking a ticket number and a fare, both int. Try it and see whether the compiler accepts it.

4.6 Variables Inside a Class

Every class so far has declared its variables in one place — directly inside the class body — and used a few more inside its methods without comment. Those are not the same kind of variable, and Java treats them very differently.

Three kinds can appear in a class. They differ in where they are written, how long they live, and how many copies of them exist. Getting them straight settles a whole family of puzzling bugs, including the one in the box at the end of section 4.3.

The running example here is a city bus, which is useful because one fact belongs to each bus separately, one belongs to the fleet as a whole, and one is needed only while a calculation is going on.

4.6.1 Instance Variables

A variable declared inside the class body but outside every method, constructor and block is an instance variable. All the data members you have written so far — blades, speed, ticketNo, destination — are instance variables.

The name says exactly what matters about them. An instance variable belongs to an instance, that is, to one object. Every object created from the class gets its own copy, which is why hall and lab in section 4.4 could hold different speeds at the same moment.

NoteDefinition

An instance variable is a variable declared inside a class but outside any method, constructor or block, of which every object of the class holds its own separate copy.

An instance variable comes into existence when the object is created, is given the default value of Table 4.5 unless a constructor sets it, and lasts exactly as long as the object does. Every method of the class can use it by name, without being passed it.

For the bus class, the route number is an instance variable: bus 12 and bus 47 must be able to hold different route numbers at once.

4.6.2 Local Variables

A variable declared inside a method, inside a constructor, or inside a block such as the body of a loop is a local variable. The formal arguments of a method are local variables too.

Local variables exist only while the method is running. When the method finishes, its local variables are gone, and calling the method again produces fresh ones. Nothing about them survives from one call to the next.

NoteDefinition

A local variable is a variable declared within a method, constructor or block, which exists only while that method, constructor or block is being executed and cannot be used outside it.

The region of a program in which a variable can be used is called its scope. The scope of a local variable is the block in which it is declared; the scope of an instance variable is the whole class. This is the rule behind the error in section 4.3: writing int speed = 1; inside a method created a local variable whose scope ended with the method, leaving the object’s own speed untouched.

One difference from instance variables catches almost everyone once.

using a local variable that has not been given a value What students write:

    void fareFor(int stops)
    {
        int fare;
        fare = fare + 8 * stops;
        System.out.println("Fare Rs " + fare);
    }

What happens: the program does not compile. The compiler reports that the variable fare may not have been initialised, and refuses to go further. The fix: give a local variable a value before reading it — int fare = 0;, or simply int fare = 8 * stops;. Instance variables receive defaults automatically, but local variables do not, and Java deliberately treats reading one as an error rather than quietly using a leftover value.

In the bus class, the fare for a journey is a natural local variable. It is worked out when it is asked for, printed, and then no longer needed; there is no reason for a bus to remember it.

4.6.3 Class Variables

Some facts belong to the class as a whole rather than to any one object. How many buses have been created so far is such a fact — it is not a property of bus 12 or of bus 47, but of the fleet.

A variable declared with the keyword static is a class variable, also called a static variable. Only one copy of it exists, no matter how many objects are created, and every object shares that single copy. If one object changes it, every object sees the change, because there is nothing else to see.

NoteDefinition

A class variable is a variable declared inside a class with the keyword static, of which exactly one copy exists and is shared by all the objects of that class.

Because a class variable belongs to the class and not to any object, it exists even before the first object is created, and it can be used without any object at all. It is normally reached through the class name:

        System.out.println("Buses created so far: " + Bus.busCount);

Fig. 4.6-1 shows the three kinds of variable in memory together.

Diagram

Fig. 4.6-1 – three regions drawn on one page; at the top a box labelled “Class Bus” containing a single cell busCount = 2, marked “one copy, shared”; below it two separate object boxes labelled b1 and b2, each containing its own cell routeNo, holding 12 and 47 respectively, marked “one copy per object”; at the bottom a dashed box labelled “inside fareFor() while it runs” containing cells stops and fare, marked “created on entry, destroyed on exit”; a curved arrow from each object box points up to the single busCount cell

Table 4.9 – The three kinds of variable in a class

Feature Instance variable Local variable Class variable
Where declared In the class, outside every method Inside a method, constructor or block In the class, with the keyword static
Number of copies One per object One per call, while the call lasts Exactly one, for the whole class
Lifetime As long as its object exists Only while the block is executing For as long as the class is in use
Default value Given automatically None; must be set before use Given automatically
Where it can be used Anywhere in the class Only inside its own block Anywhere in the class, and outside through the class name
Needs an object to be used Yes Not applicable No

The program below puts all three to work. The route number is an instance variable, the fare is a local variable, and the count of buses is a class variable increased inside the constructor — a natural place for it, since the constructor runs exactly once per object.

instance, local and class variables in one class Problem: Define a class Bus in which each bus stores its own route number, the class keeps a count of how many buses have been created, and a method calculates the fare for a journey at a flat rate of Rs 8 per stop. Create two buses, print the fare for a journey on each, and then print how many buses have been created. All values are fixed inside the program; no input is read.

class Bus
{
    int routeNo;
    static int busCount = 0;

    Bus(int r)
    {
        routeNo = r;
        busCount = busCount + 1;
    }

    void fareFor(int stops)
    {
        int fare = 8 * stops;
        System.out.println("Route " + routeNo + " : " + stops + " stops, fare Rs " + fare);
    }

    public static void main(String args[])
    {
        Bus b1 = new Bus(12);
        Bus b2 = new Bus(47);

        b1.fareFor(3);
        b2.fareFor(5);

        System.out.println("Buses created so far: " + Bus.busCount);
    }
}

Sample output:

Route 12 : 3 stops, fare Rs 24
Route 47 : 5 stops, fare Rs 40
Buses created so far: 2

Variable description:

[Table:] Table 4.10 – Variable description for the bus program [/Table] | Variable | Type | Purpose | |—|—|—| | routeNo | int | Instance variable holding the route number of one bus | | busCount | static int | Class variable counting how many buses have been created | | r | int | Route number received by the constructor | | stops | int | Number of stops in the journey being charged for | | fare | int | Local variable holding the fare worked out for one journey | | b1, b2 | Bus | Refer to the two bus objects created |

Notes: busCount is set to 0 where it is declared rather than in the constructor, since a constructor runs once per object and would reset the count every time. The fare is calculated fresh on each call and never stored in the object, because it describes a journey, not a bus.

the bus program, following one instance variable and the class variable

Statement executed b1.routeNo b2.routeNo busCount Printed
class loaded — — 0 —
Bus b1 = new Bus(12); 12 — 1 —
Bus b2 = new Bus(47); 12 47 2 —
b1.fareFor(3); 12 47 2 Route 12 : 3 stops, fare Rs 24
b2.fareFor(5); 12 47 2 Route 47 : 5 stops, fare Rs 40
System.out.println(...) 12 47 2 Buses created so far: 2

Result: the three lines of output above. Notice the difference in the shape of the columns — the two routeNo columns each change once, when their own object is created, while the single busCount column changes on both creations. That is the whole difference between one copy per object and one copy in total.

Q4. A variable written inside a class, a variable written inside a method, and a variable marked static — why does the same program treat these three so differently?

A. Because they answer three different questions. A variable written inside the class records something each object must remember for itself, so every object gets its own copy. A variable written inside a method is scratch working for one calculation, so it is created when the method starts and thrown away when it ends. A variable marked static records something true of the class as a whole rather than of any single object, so exactly one copy exists and all objects share it. Where you write the declaration is how you tell Java which of the three you mean.

There is an honest cost to class variables, and it is worth naming. Because every object shares the one copy, a change made anywhere is felt everywhere, and a bug in one part of a program can show up as wrong data in a completely different part. Use a class variable only when the fact genuinely belongs to the class — a count of objects, a rate that is the same for all of them — and keep everything that varies from object to object in instance variables.

4.7 Analysing a Real World Problem in Terms of Objects and Classes

Everything up to this point has started from a class that was already decided. Real work starts one step earlier, with a problem written in ordinary language and nothing else. Turning that description into a class is the part of the job no compiler can do for you.

The problem below is small enough to hold in your head and large enough to have real decisions in it.

A school stationery counter keeps a few items for sale. For each item the counter records a code, a name, the rate per unit and the quantity in stock. When a student buys some units of an item, the stock must fall and the amount payable must be worked out. The counter also needs to see an item’s details and the value of the stock it is holding.

4.7.1 Identifying the Objects

A useful first move is mechanical: underline every noun in the description. Here they are — counter, item, code, name, rate, quantity in stock, student, units, amount, value of stock.

That list is not the answer; it is the raw material. Each noun now has to face two questions. Does the program need to remember it? And does it have behaviour of its own, or is it only a value?

Work through them. Code, name, rate and quantity in stock are plain values — they are facts about something else, and something else is what holds them. Units and amount appear only during a sale and vanish afterwards; nothing needs to remember them. Student is mentioned, but the description never asks the program to record anything about a student, so it stays out; recall from 4.2.2 that what a program does not need is deliberately left out.

Value of stock looks like a fact, but read it again — it can always be worked out from the rate and the quantity. Storing it as well would mean two places that must agree, and sooner or later they will not. It is behaviour, not data.

That leaves item and counter. An item has facts of its own and things that happen to it, so it becomes a class. A counter that holds many items would be a second class, but holding many objects needs arrays of objects, which come later in the course. For now the counter is left as the main method that creates the items and works with them — a limitation of this design, and worth being honest about rather than hiding.

4.7.2 Deciding the Attributes and the Behaviour

The four surviving values become the attributes of the class. The verbs in the description — buys, falls, worked out, see, holding — become its behaviour.

Table 4.11 – Design of the class Item, from the problem description

Attribute Type Why it is needed
Code int Identifies the item on the price list
Name String Printed on the bill and on the display
Rate int Rate per unit in rupees, used to work out the amount
Stock int Quantity currently held, which a sale reduces
Behaviour What it does
Sell a number of units Reduces the stock and reports the amount payable
Display the item Prints code, name, rate and stock
Report the stock value Returns rate multiplied by stock, without storing it

One decision inside the selling operation needs settling before any code is written. What should happen if a student asks for more units than the counter holds?

Leaving it unanswered is not an option, because the arithmetic would still run and the stock would become negative — a quantity that cannot exist. The operation must therefore check the request against the stock and refuse it if it cannot be met. Checking that incoming values make sense before acting on them is ordinary defensive practice, and it belongs in the design, not in an afterthought.

selling a quantity of an item Input: the number of units requested; the item’s current stock and rate. Output: either a refusal, or the amount payable, with the stock reduced by the units sold. Method:

1. If the units requested are more than the stock in hand:
2.     report that only the stock in hand is available, and stop.
3. Otherwise, subtract the units requested from the stock.
4. Multiply the units requested by the rate to get the amount.
5. Report the units, the item name and the amount.

Why it works: the subtraction in step 3 is reached only when the units requested are not more than the stock, so the stock can never fall below zero. Every path through the steps either changes nothing or changes the stock by exactly the quantity charged for, so the stock and the bill always agree. Cost: a fixed number of steps, whatever the quantity requested and whatever the stock. Nothing in it grows with the size of the data.

Fig. 4.7-1 shows the finished design in the form programmers usually sketch it before writing any code.

Diagram

Fig. 4.7-1 – a single rectangle divided into three stacked compartments; the top compartment holds the class name Item; the middle compartment lists the attributes with their types, int code, String name, int rate, int stock; the bottom compartment lists the behaviour as method headings, Item(int, String, int, int), void sell(int), void display(), int stockValue()

4.7.3 From Design to a Working Class

The design translates almost line for line. The four attributes of Table 4.11 become the data members, the constructor takes all four values so that no item can exist half-defined, and the three behaviours become three methods.

One of them is a new shape. stockValue() does not print anything — it works out a number and hands it back to whoever called it, so it is declared with the return type int rather than void and ends with a return statement. That lets the caller add the values of two items together, which printing inside the method would have made impossible.

a stationery counter item, designed from a problem description Problem: Define a class Item for a school stationery counter, storing the code, name, rate per unit and quantity in stock of one item. Provide a constructor that accepts all four values, a method to sell a given number of units that refuses a sale larger than the stock, a method to display the item, and a method that returns the value of the stock held. Create two items, display them, attempt three sales, display them again, and print the total value of stock at the counter. All values are fixed inside the program; no input is read.

class Item
{
    int code;
    String name;
    int rate;
    int stock;

    Item(int c, String n, int r, int s)
    {
        code = c;
        name = n;
        rate = r;
        stock = s;
    }

    void sell(int units)
    {
        if (units > stock)
        {
            System.out.println("Only " + stock + " units of " + name + " in stock. Sale refused.");
        }
        else
        {
            stock = stock - units;
            int amount = units * rate;
            System.out.println(units + " x " + name + " = Rs " + amount);
        }
    }

    void display()
    {
        System.out.println(code + "  " + name + "  Rs " + rate + "  stock " + stock);
    }

    int stockValue()
    {
        return rate * stock;
    }

    public static void main(String args[])
    {
        Item pen = new Item(101, "Gel pen", 12, 50);
        Item pad = new Item(102, "Note pad", 35, 8);

        pen.display();
        pad.display();

        pen.sell(3);
        pad.sell(10);
        pad.sell(2);

        pen.display();
        pad.display();

        System.out.println("Stock value at the counter: Rs " + (pen.stockValue() + pad.stockValue()));
    }
}

Sample output:

101  Gel pen  Rs 12  stock 50
102  Note pad  Rs 35  stock 8
3 x Gel pen = Rs 36
Only 8 units of Note pad in stock. Sale refused.
2 x Note pad = Rs 70
101  Gel pen  Rs 12  stock 47
102  Note pad  Rs 35  stock 6
Stock value at the counter: Rs 774

Variable description:

[Table:] Table 4.12 – Variable description for the stationery counter program [/Table] | Variable | Type | Purpose | |—|—|—| | code | int | Code identifying the item | | name | String | Name of the item | | rate | int | Rate per unit in rupees | | stock | int | Quantity currently in stock | | c, n, r, s | int, String, int, int | Values received by the constructor for the four data members | | units | int | Number of units requested in a sale | | amount | int | Local variable holding the amount payable for one sale | | pen, pad | Item | Refer to the two item objects created |

Notes: the refused sale changes nothing at all — the third and seventh lines of output show a stock of 8 and then 6, the difference being the two units of the sale that succeeded, not the ten that failed. The stock value is deliberately not stored as a data member; it is recomputed from rate and stock each time it is asked for, so it can never drift out of step with them.

the three sales, following the stock of each item

Statement executed pen.stock pad.stock Printed
after both objects created 50 8 —
pen.sell(3); 47 8 3 x Gel pen = Rs 36
pad.sell(10); 47 8 Only 8 units of Note pad in stock. Sale refused.
pad.sell(2); 47 6 2 x Note pad = Rs 70
pen.stockValue() 47 6 — (returns 564)
pad.stockValue() 47 6 — (returns 210)
System.out.println(...) 47 6 Stock value at the counter: Rs 774

Result: the eight lines of output above. The trace shows the check doing its work — the middle row is the only one in which a sale statement leaves both stock columns unchanged.

The design method, in short

Four steps produced this class, and they will produce the next one too. List the nouns in the problem. Keep as classes those that have both data and behaviour of their own, and turn the rest into attributes or discard them. Take the verbs as the behaviour. Then decide, before writing any code, what each operation must do when it is given something it cannot honour.

Practical link: class design with a constructor and member methods; file this under the work file assignment on objects and classes. Design and write a class Parking for a school cycle and scooter stand. Each vehicle records its registration number and the number of hours parked. The charge is Rs 5 per hour, subject to a minimum of Rs 10. Provide a constructor that accepts the registration number and the hours, a method that computes the charge, and a method that displays the registration number, the hours and the charge. Create two objects with hours of 4 and 7 and check the output. Then test it with the unseen input of 1 hour, and confirm that the charge shown is 10 and not 5.

4.8 The Basic Principles of Object Oriented Programming

Objects and classes are the materials of object oriented programming. Four principles describe what is done with them, and every later chapter of this course rests on one or more of them: encapsulation, abstraction, inheritance and polymorphism.

This section introduces all four and shows each at work in a small way. Three of them — inheritance, interfaces and polymorphism — are large enough to deserve chapters of their own later in the course, so the treatment here is deliberately a first acquaintance rather than the full account.

4.8.1 Encapsulation

Look again at the fan program of 4.4.3. It set the blades by writing hall.blades = 3; from inside main, reaching straight into the object’s data from outside. It worked, and it was a bad habit.

Nothing stopped main from writing hall.blades = -7;. The object had no say in what was done to its own data, which is the very problem that arrays had in section 4.1.1, reappearing in a smarter disguise.

Encapsulation is the principle of wrapping the data and the methods of a class together in one unit and letting the outside world reach the data only through those methods. The wrapping is what a class does anyway; the second half — restricting the way in — is what turns it into encapsulation.

NoteDefinition

Encapsulation is the wrapping up of data and the methods that operate on it into a single unit, in such a way that the data can be reached from outside only through those methods.

In Java it is achieved with access specifiers, the keywords written in front of a declaration to say who may use it. Two are needed here. A member declared private can be used only inside its own class. A member declared public can be used from anywhere. The rule of thumb follows immediately: data members are made private, and the methods that are meant to be used from outside are made public.

Because the data can then be reached only through methods, the class gets to inspect every value before accepting it. Fig. 4.8-1 shows what that looks like from outside.

Diagram

Fig. 4.8-1 – a class box labelled Score divided into two zones; the inner zone, shaded and labelled private, holds name and marks; the outer zone, labelled public, holds setMarks(int), getMarks() and display(); an arrow from an outside box labelled main to the outer zone is drawn solid and ticked “allowed”; a second arrow from main going straight to the inner zone is drawn crossed out and labelled “rejected by the compiler”

Keeping the data private and hiding it behind methods in this way is called data hiding. The two words are often used as if they meant the same thing; the accurate statement is that encapsulation is the wrapping, and data hiding is the restriction that encapsulation makes possible.

a class that protects its own data Problem: Define a class Score that stores a candidate’s identifier and marks, both private. Provide a constructor that takes the identifier and sets the marks to zero, a method to set the marks that accepts a value only if it lies between 0 and 100, a method that returns the marks, and a method that displays them. Set a valid mark, display it, attempt an invalid mark, display again, and read the marks back. All values are fixed inside the program; no input is read.

class Score
{
    private String name;
    private int marks;

    Score(String n)
    {
        name = n;
        marks = 0;
    }

    void setMarks(int m)
    {
        if (m < 0 || m > 100)
        {
            System.out.println("Marks must be between 0 and 100. Value rejected.");
        }
        else
        {
            marks = m;
        }
    }

    int getMarks()
    {
        return marks;
    }

    void display()
    {
        System.out.println(name + " : " + marks);
    }

    public static void main(String args[])
    {
        Score s1 = new Score("Roll 21");

        s1.setMarks(78);
        s1.display();

        s1.setMarks(150);
        s1.display();

        System.out.println("Marks read back: " + s1.getMarks());
    }
}

Sample output:

Roll 21 : 78
Marks must be between 0 and 100. Value rejected.
Roll 21 : 78
Marks read back: 78

Variable description:

[Table:] Table 4.13 – Variable description for the score program [/Table] | Variable | Type | Purpose | |—|—|—| | name | private String | Identifier of the candidate whose marks are held | | marks | private int | Marks obtained, kept between 0 and 100 | | n | String | Identifier received by the constructor | | m | int | Marks offered to setMarks(), checked before being accepted | | s1 | Score | Refers to the score object created |

Notes: the object refused the value 150 and kept the 78 it already held, which is why the second display is identical to the first. The check lives inside the class, so it applies to every attempt from anywhere in the program — a guarantee that no amount of care in main could have provided.

reaching into private data from outside What students write:

        s1.marks = 150;

What happens: the program does not compile. The compiler reports that marks has private access in Score, and stops. The fix: go through the method the class provides — s1.setMarks(150); — and accept the answer it gives. The error is not an obstacle to be worked around; it is the class doing exactly what it was designed to do.

Q5. Programmers often hide a class’s data behind methods that simply fetch it and set it. Why go to that trouble instead of using the data directly?

A. Because a method can refuse, and a variable cannot. Once marks is private, every value entering the object has to pass through setMarks(), which checks it — so an impossible mark of 150 is rejected once, in one place, no matter how many parts of the program try to write it. Direct access gives that up: the object would have to accept whatever it was handed. The method also lets the class change how it stores the data later without breaking any program that uses it, because the way in stays the same.

4.8.2 Abstraction

You have driven past a traffic signal a thousand times and never once thought about the timer circuit inside it. You know what it shows and what you must do; how it decides is not your concern, and hiding it makes the road usable.

Abstraction is the same idea in a program: showing what an object does while keeping the details of how it does it out of sight. Section 4.7 already used it twice — once when the bus’s tyre pressure was left out of the design, and again when sell() was described by what it achieves rather than by the statements inside it.

NoteDefinition

Abstraction is the representation of only the essential features of something, leaving out the background details of how those features are provided.

Encapsulation and abstraction are close relatives and are often confused. Encapsulation is a mechanism — data and methods bound together with the data restricted. Abstraction is a design attitude — deciding what to show and what to leave out. Encapsulation is one of the ways abstraction is achieved.

Java offers two further devices for abstraction, and both are studied in full later in the course.

An abstract class is a class declared with the keyword abstract. It may contain an abstract method — a method declared with its name and arguments but with no body at all, because no sensible general version can be written. A class carrying an abstract method must itself be abstract, and no object can be created from an abstract class; a class built on it supplies the missing bodies.

abstract class Phone
{
    abstract void ring();
}

An interface goes further. It is declared with the keyword interface and, in the version of Java this course assumes, every method it declares is automatically public and has no body. It holds no constructor, and therefore no object can be created from it either. A class states that it will supply the missing bodies by using the keyword implements.

interface Chargeable
{
    void charge();
}

The two devices answer slightly different needs.

Table 4.14 – Abstract class and interface, at a first look

Feature Abstract class Interface
Declared with abstract class interface
Method bodies May have some methods with bodies and some without Declares methods without bodies
Objects Cannot be created from it Cannot be created from it
Constructor May have one, used by the classes built on it Has none
A class connects to it using extends implements
How many can one class use One only More than one

The last row is the practical reason interfaces exist at all, and section 4.8.3 explains what it is a response to.

4.8.3 Inheritance

Suppose a program needs a class for scooters and another for lorries. Both must record the number of wheels; both must be able to display themselves. Writing those members twice is wasteful, and worse, the two copies will drift apart as the program is edited.

Inheritance allows one class to be built on another, taking over everything the first class has and adding to it. The class that is inherited from is called the super class — also referred to as the base class or parent class — and the class that inherits is called the derived class, also called the subclass. In Java the connection is made with the keyword extends.

NoteDefinition

Inheritance is the property by which one class acquires the members of another class, so that the acquiring class has both the members it inherits and any it adds of its own.

class Vehicle
{
    int wheels;

    void show()
    {
        System.out.println("Wheels: " + wheels);
    }
}

class Scooter extends Vehicle
{
    int engineCC;

    void showAll()
    {
        show();
        System.out.println("Engine: " + engineCC + " cc");
    }
}

Scooter never declares wheels and never defines show(), yet an object of Scooter has both. That is inheritance doing its work, and it is the reusability mentioned in section 4.1.3, now with a mechanism behind it.

One caution belongs here, because the temptation is strong. Inheritance should not be used merely because a class happens to have a method you would like to borrow. It should be used when the derived class genuinely is a special kind of the super class — a scooter is a kind of vehicle. Where that relationship does not hold, inheritance produces a tangle that is hard to undo.

Inheritance is classified by the shape of the arrangement, and Java supports the four forms below.

4.8.3.1 Single Inheritance

One derived class extends one super class, and nothing more. This is the arrangement of the Vehicle and Scooter classes above, and it is shown in Fig. 4.8-2.

Diagram

Fig. 4.8-2 – two boxes one above the other, the upper labelled “Class A (super class)” and the lower labelled “Class B (derived class)”, with a single arrow from B pointing up to A, the arrow labelled “class B extends A”

Single inheritance is the simplest form and by far the most common.

4.8.3.2 Multilevel Inheritance

A derived class may itself be extended, so that a class is both a derived class and a super class at once. This is multilevel inheritance, and it is shown in Fig. 4.8-3.

Diagram

Fig. 4.8-3 – three boxes in a vertical chain labelled Class A at the top, Class B in the middle and Class C at the bottom; an arrow from C up to B labelled “class C extends B” and an arrow from B up to A labelled “class B extends A”

Class C inherits the members of B, and because B inherited from A, C has A’s members too. Members travel down the whole chain, however long it is.

4.8.3.3 Hierarchical Inheritance

Several derived classes may extend the same super class. This is hierarchical inheritance, and it is the arrangement the vehicle example really calls for — scooter, lorry and bus all extending one Vehicle class.

Diagram

Fig. 4.8-4 – one box at the top labelled Class A, with two boxes below it side by side labelled Class B and Class C; an arrow from each of B and C points up to A, labelled “class B extends A” and “class C extends A”

Everything common to all vehicles is written once in the super class, and each derived class adds only what is peculiar to itself.

4.8.3.4 Hybrid Inheritance

Hybrid inheritance is not a fifth shape but a combination of two or more of the above in one program. Fig. 4.8-5 shows a single inheritance from A to B, with B then serving as the super class for two derived classes — a hierarchical arrangement built on top of a single one.

Diagram

Fig. 4.8-5 – Class A at the top; below it Class B with an arrow up to A; below B two boxes side by side, Class C and Class D, each with an arrow up to B; a dashed outline around A and B labelled “single”, a second dashed outline around B, C and D labelled “hierarchical”

Table 4.15 – The four forms of inheritance

Form Arrangement
Single One derived class extends one super class
Multilevel A derived class is itself extended, forming a chain
Hierarchical Several derived classes extend the same super class
Hybrid Two or more of the above forms combined in one program

There is one arrangement deliberately absent from that list. A class in Java cannot extend two classes at once — the form in which a single class inherits directly from two different super classes is not permitted, because it raises questions the language refuses to guess at, such as which of two inherited versions of the same method should apply. Where the effect is wanted, a class implements two interfaces instead, which is the reason for the last row of Table 4.14.

Q. If a derived class inherits everything, what is the point of writing the derived class at all?

A. A derived class inherits everything and then does one of two things with it: it adds members the super class never had, as Scooter added engineCC, or it replaces an inherited method with a version of its own. The second of those is method overriding, and it leads directly into the next principle.

4.8.4 Polymorphism

The word comes from two Greek roots, poly meaning many and morph meaning form. In programming it means that the same name can take more than one form — one method name serving several related operations, with the right one chosen automatically.

NoteDefinition

Polymorphism is the ability of the same method name to serve more than one operation, the particular operation being chosen according to the situation in which the name is used.

Java provides it in two ways, distinguished by when the choice is made.

4.8.4.1 Compile Time Polymorphism

Writing several methods with the same name in one class, differing in the number or the types of their arguments, is called method overloading. You have already used it without the name: the two constructors of the Ticket class in section 4.5.3 were overloaded.

The compiler decides which version to run by matching the arguments in the call against the argument lists of the available methods. Because the decision is taken while the program is being compiled, this is called compile time polymorphism.

one method name serving three shapes Problem: Define a class Area with three methods, all named area: one that takes the side of a square and returns its area, one that takes the length and breadth of a rectangle and returns its area, and one that takes the radius of a circle as a double and returns its area, taking pi as 3.14. Call all three from main and display the results. All values are fixed inside the program; no input is read.

class Area
{
    int area(int side)
    {
        return side * side;
    }

    int area(int length, int breadth)
    {
        return length * breadth;
    }

    double area(double radius)
    {
        return 3.14 * radius * radius;
    }

    public static void main(String args[])
    {
        Area a = new Area();

        System.out.println("Square    : " + a.area(6));
        System.out.println("Rectangle : " + a.area(4, 9));
        System.out.println("Circle    : " + a.area(2.5));
    }
}

Sample output:

Square    : 36
Rectangle : 36
Circle    : 19.625

Variable description:

[Table:] Table 4.16 – Variable description for the overloaded area program [/Table] | Variable | Type | Purpose | |—|—|—| | side | int | Side of the square | | length | int | Length of the rectangle | | breadth | int | Breadth of the rectangle | | radius | double | Radius of the circle | | a | Area | Refers to the object on which the three methods are called |

Notes: the first two calls return the same number, 36, by two different routes — proof that the choice of method depends on the argument list and not on the answer. The third call is matched to the double version because 2.5 is a double literal; had it been written a.area(2), the first version would have run instead.

The rule the compiler follows is worth stating plainly. Overloaded methods must differ in the number of their arguments, or in the types of their arguments, or in the order of those types. Two methods differing only in their return type are not overloaded — they are a compile-time error, because a call gives the compiler nothing to choose by.

4.8.4.2 Run Time Polymorphism

The second form appears only with inheritance. When a derived class defines a method with exactly the same name and arguments as one it inherited, the new version replaces the inherited one for objects of the derived class. This is called method overriding.

class Scooter extends Vehicle
{
    int engineCC;

    void show()
    {
        System.out.println("Scooter, wheels: " + wheels + ", engine: " + engineCC + " cc");
    }
}

Now the same call, show(), does one thing for a plain vehicle and another for a scooter. Which version runs depends on the object the call is made on, and since the object involved may not be known until the program is actually running, the decision has to be made then rather than at compilation. Deciding at run time which version of an overridden method to execute is called dynamic binding, and polymorphism achieved this way is called run time polymorphism.

The full account of overriding — how the super class version can still be reached, and the visibility rules that go with it — belongs with inheritance and is taken up later in the course. What matters here is the difference between the two forms.

Table 4.17 – Method overloading and method overriding compared

Feature Method overloading Method overriding
Where the methods are In the same class In a super class and a derived class
Method name Same Same
Argument list Must differ in number, type or order Must be exactly the same
Inheritance needed No Yes
When the version is chosen While compiling While running
Form of polymorphism Compile time Run time
The four principles together

It is worth seeing how the four fit. Encapsulation binds an object’s data to its methods and controls the way in. Abstraction decides what that way in should show and what it should conceal. Inheritance lets a new class be built on an existing one instead of repeating it. Polymorphism lets one name serve several forms of an operation, so that programs written against the general case keep working when a special case is added.

None of them is a rule you must obey to make a program run. They are the reasons object oriented programs stay workable as they grow, which is the claim section 4.1.3 made and this chapter has now had to earn.

4.9 Summary

Two ways of organising a program
  1. A program contains information and actions on that information. Procedural programming organises it around the actions, taking the method as its unit; object oriented programming organises it around the data, taking the object as its unit.
  2. Keeping the facts about one entity in separate arrays joined only by a shared index leaves the program with no protection: a change made to one array and not the others corrupts the data silently, and adding one more fact means editing every method that touches it.
  3. Object orientation controls that complexity, but it charges for it. A very small program gains nothing from being redesigned around objects. The gain appears when a program keeps track of many things of the same kind and has to be changed over time.
Objects and classes
  1. An object is a single distinct entity holding its attributes — the data describing it — together with its behaviour, the operations that may be performed on that data.
  2. Which attributes an object should have is a decision, not a discovery: it depends entirely on what the program has to do. The same real thing yields different attribute lists in different programs.
  3. An attribute stores a value that can be read back; a behaviour has an effect or produces an answer. Frequent change does not turn a fact into an action.
  4. A class is the description from which objects are created. It fixes the attributes every such object will have and the behaviour every such object will offer, and holds no values itself.
  5. Variables declared in the class body are its data members; methods written in the class body are its member methods. A class is written once, before the program runs, and occupies no memory for data; objects are created while it runs and each occupies its own.
Creating objects
  1. Creating an object from a class is called instantiation, and the object created is an instance of the class.
  2. The new operator sets aside memory for one copy of every data member, fills each with its default value — zero for the numeric types, false for boolean, null for any class type — and hands back a reference to the finished object.
  3. A variable of a class type does not hold the object. It holds a reference, that is, the means of reaching the object. A variable of a primitive type holds the value itself, which is why an object needs new and an integer does not.
  4. The dot operator reaches a member belonging to a particular object. Behaviour written in a class always belongs to an object of that class, so a method call always has an object on the left of the dot.
  5. Every object gets its own copy of the data members; the methods exist once in the class and are shared. Two objects of one class may hold entirely different values, and an operation on one never alters the other.
Constructors
  1. A constructor runs automatically when an object is created and gives it its initial values, so that an object never exists in a half-built state. It carries the same name as the class and has no return type of any kind.
  2. If a class declares no constructor at all, the compiler supplies a default one taking no arguments. Once any constructor is written, that supplied one is no longer available.
  3. A parameterised constructor accepts values from outside, and the compiler enforces that they are supplied. Several constructors may exist in one class provided they differ in the number or types of their arguments; this is constructor overloading.
  4. Giving a constructor a return type turns it into an ordinary method with a confusing name. It then never runs on its own, and the object is left holding defaults.
Variables in a class
  1. An instance variable is declared in the class body outside every method, and every object holds its own copy. It receives a default value and lives as long as its object does.
  2. A local variable is declared inside a method, constructor or block. It exists only while that block runs, receives no default value, and must be given one before it is read.
  3. A class variable is declared with the keyword static. Exactly one copy exists, shared by every object, and it can be used through the class name without any object at all. Its cost is that a change made anywhere is felt everywhere, so it suits only facts that genuinely belong to the class.
  4. The scope of a variable is the region of the program in which it can be used — the whole class for an instance variable, the enclosing block for a local one.
Designing a class from a problem
  1. List the nouns in the problem description. Those that have both data and behaviour of their own become classes; those that are merely values become attributes; those the program need not remember are left out.
  2. The verbs become the behaviour. A value that can always be worked out from other values is behaviour, not data, since storing it creates two places that must agree.
  3. Decide before writing any code what each operation must do when it is given something it cannot honour. Checking incoming values inside the class is what keeps an object’s data in a state that can actually exist.
The four principles
  1. Encapsulation is the wrapping of data and methods into one unit with the data reachable only through those methods. Data members are declared private and the methods meant for outside use are declared public; the resulting restriction is called data hiding. Its value is that a method can refuse a value, while a variable cannot.
  2. Abstraction is representing only the essential features of something and leaving out the details of how they are provided. Encapsulation is a mechanism; abstraction is the design decision it serves. Java offers two further devices for it — the abstract class, which may declare methods with no body, and the interface, which declares methods without bodies, holds no constructor, and may be implemented by a class alongside others.
  3. Inheritance lets a derived class acquire the members of a super class and add its own. It is justified only when the derived class is genuinely a special kind of the super class. Its four forms are single, multilevel, hierarchical and hybrid. A class cannot extend two classes at once; where that effect is needed, a class implements more than one interface.
  4. Polymorphism is one method name serving more than one operation. Method overloading places several versions in one class, differing in the number, types or order of their arguments, and the version is chosen while compiling. Method overriding replaces an inherited method with a version of the same name and the same arguments in a derived class, and the version is chosen while running, which is called dynamic binding.
  5. None of the four principles is needed to make a program run. They are the reasons an object oriented program stays workable as it grows.

4.10 Key Terms

  1. Abstract class — a class declared with the keyword abstract, from which no object can be created, and which may declare methods with no body for other classes to supply.
  2. Abstract method — a method declared with its name and arguments but no body, left for another class to define.
  3. Abstraction — representing only the essential features of something while leaving out the details of how those features are provided.
  4. Access specifier — a keyword such as private or public written before a declaration to state who may use that member.
  5. Attribute — a fact about an object that can be stored and read back; in a program, a data member.
  6. Behaviour — what an object does or what may be done to it; in a program, its methods.
  7. Class — a description from which objects are created, fixing the attributes and behaviour every such object will have.
  8. Class variable — a variable declared with the keyword static, of which exactly one copy exists and is shared by every object of the class.
  9. Constructor — a member that runs automatically when an object is created, giving it its initial values; it has the class’s name and no return type.
  10. Constructor overloading — writing more than one constructor in a class, differing in the number or types of their arguments.
  11. Data hiding — keeping a class’s data private so that it can be reached only through the class’s own methods.
  12. Data member — a variable declared inside the class body, outside every method.
  13. Default constructor — the no-argument constructor the compiler supplies when a class declares no constructor of its own.
  14. Default value — the value a data member automatically receives when an object is created, before any constructor runs.
  15. Derived class — a class that inherits the members of another class, also called a subclass.
  16. Dot operator — the full stop written between an object’s name and a member’s name to reach the member belonging to that object.
  17. Dynamic binding — deciding while the program is running which version of an overridden method should be executed.
  18. Encapsulation — wrapping data and the methods that act on it into one unit, with the data reachable only through those methods.
  19. Hierarchical inheritance — an arrangement in which several derived classes extend the same super class.
  20. Hybrid inheritance — an arrangement combining two or more forms of inheritance in one program.
  21. Inheritance — the property by which one class acquires the members of another and may add its own.
  22. Instance — an object created from a class.
  23. Instance variable — a variable declared in the class body outside every method, of which each object holds its own copy.
  24. Instantiation — the act of creating an object from a class.
  25. Interface — a declaration of methods without bodies, holding no constructor, which a class connects to using implements.
  26. Local variable — a variable declared inside a method, constructor or block, existing only while that block is being executed.
  27. Member method — a method written inside the class body, describing part of the behaviour of its objects.
  28. Method overloading — writing several methods with the same name in one class, differing in the number, types or order of their arguments.
  29. Method overriding — defining in a derived class a method with the same name and the same arguments as one it inherited, replacing it for objects of that class.
  30. Multilevel inheritance — an arrangement in which a derived class is itself extended, forming a chain of classes.
  31. Object — a single distinct entity holding its own attributes together with its behaviour.
  32. Object oriented programming (OOP) — building a program as a set of objects, each holding its own data with the operations on it, every kind of object described once by a class.
  33. OOP — object oriented programming.
  34. Parameterised constructor — a constructor that accepts arguments, so that an object can be given its values as it is created.
  35. Polymorphism — the ability of one method name to serve more than one operation, the right one being chosen according to the situation.
  36. Procedural programming — building a program around the actions it performs, taking the method as the unit of organisation.
  37. Reference variable — a variable of a class type, which holds not the object itself but the means of reaching it.
  38. Reusability — building a new class on an existing one instead of copying its code.
  39. Scope — the region of a program in which a variable can be used.
  40. Single inheritance — an arrangement in which one derived class extends one super class.
  41. Super class — the class whose members are inherited by another, also called the base class or parent class.

4.11 Points to Ponder

  1. A class whose data members are public can still be written so that the program produces entirely correct output. If nothing goes wrong on the day the program is written, what exactly has been lost by leaving the data public — and when would the loss first become visible?

  2. The stationery counter answered a sale it could not meet by printing a refusal and changing nothing. What other responses could a class give when it is handed a value it cannot accept, and on what grounds would you choose between them?

  3. Every class variable could be replaced by an instance variable that all the objects happen to hold the same value in. What would such a program lose, and is there anything it would gain?

  4. Inheritance is said to be justified only when the derived class is genuinely a special kind of the super class. The compiler never checks this. So who decides, and what actually goes wrong in a program when the judgement is made badly?

  5. A class can be given several constructors, or a single constructor together with methods that fill in the remaining values afterwards. What kind of problem makes the first design the better one, and what kind makes the second?

  6. Using one method name for three different operations in a class is called polymorphism and is treated as good design. Using one variable name for two different variables in a class is treated as a hazard. Why should the same idea be welcome in one case and unwelcome in the other?

4.12 Objective Questions

  1. Which of the following comes into existence only while the program is running? [1 mark]
  1. A class
  2. An object
  3. A source file
  4. A method definition
  1. The value automatically given to a data member of type boolean when an object is created is: [1 mark]
  1. 0
  2. true
  3. false
  4. null
  1. Which statement about a constructor is correct? [1 mark]
  1. It must be declared with the return type void
  2. It must have the same name as its class
  3. It is called through the dot operator whenever it is needed
  4. A class may contain only one of them
  1. A variable of which kind has exactly one copy, shared by every object of the class? [1 mark]
  1. Instance variable
  2. Local variable
  3. Class variable
  4. Formal argument
  1. Writing several methods with the same name in one class, differing in the types of their arguments, is called: [1 mark]
  1. Method overriding
  2. Method overloading
  3. Inheritance
  4. Encapsulation
  1. A class in Java may extend: [1 mark]
  1. Any number of classes
  2. Exactly two classes
  3. One class only
  4. No class at all, in any circumstances
  1. Assertion (A): A local variable must be given a value before it is read. Reason (R): Local variables are not given default values when they are created. Choose the correct option: [1 mark]
  1. Both A and R are true and R is the correct explanation of A
  2. Both A and R are true but R is not the correct explanation of A
  3. A is true but R is false
  4. A is false but R is true
  1. Assertion (A): A class occupies memory for its data as soon as it is written in the source file. Reason (R): A class is a description from which objects are created. Choose the correct option: [1 mark]
  1. Both A and R are true and R is the correct explanation of A
  2. Both A and R are true but R is not the correct explanation of A
  3. A is true but R is false
  4. A is false but R is true
  1. Match each keyword in Column A with what it does, in Column B. [4 marks]
Column A Column B
a. new i. Makes a member usable only inside its own class
b. static ii. Connects a derived class to its super class
c. private iii. Creates an object of a class
d. extends iv. Makes one copy of a variable, shared by all objects
  1. Fill in the blank: the variables declared inside a class but outside every method, constructor and block are called ____________ variables. [1 mark]

  2. Fill in the blank: a constructor is written with no ____________ of any kind, not even void. [1 mark]

  3. State whether true or false: an object can be created from an abstract class. [1 mark]

  4. State whether true or false: two methods in a class that differ only in their return type are overloaded methods. [1 mark]

  5. Give the full form of OOP. [1 mark]

4.13 Check Your Concepts

  1. Define a class. Name one real world entity you would represent as a class, and state one attribute and one behaviour it would have. [2 marks]

  2. What is meant by instantiation? Name the operator that performs it. [2 marks]

  3. Name the four basic principles of object oriented programming. [2 marks]

  4. Differentiate between a class and an object, with reference to memory occupied and to the number of each that can exist. [3 marks]

  5. Differentiate between an instance variable and a class variable, giving one situation in which each is the right choice. [3 marks]

  6. Distinguish between method overloading and method overriding, stating clearly when the version to be executed is chosen in each case. [3 marks]

  7. Explain, with a short example of your own, why the data members of a class are usually declared private while its useful methods are declared public. State one thing a program loses when the data members are left public. [4 marks]

  8. A class Ticket contains only one constructor, which accepts three arguments. Explain what happens when a program contains the statement Ticket t = new Ticket(); and give the reason. State one way of making the statement legal. [4 marks]

  9. Name the form of inheritance in each of the following, giving a reason for each answer. [4 marks]

  1. Classes Bus, Lorry and Scooter each extend the class Vehicle.
  2. Class C extends class B, and class B extends class A.
  3. A single program contains both of the arrangements above.
  4. Class Scooter extends class Vehicle, and no other class extends anything.
  1. A program must record three facts about each of two hundred books in a school library, and must allow a book to be added or removed. Compare organising this program around procedures with organising it around objects. Your answer should cover where the three facts about one book are stored, what can go wrong when a book is removed, and what has to change if a fourth fact is added later. [6 marks]

  2. Explain the difference between encapsulation and abstraction. Support your answer by outlining a class of your own — its name, its data members with their access specifiers, and its method headings only — and pointing out where each of the two ideas appears in it. [6 marks]

4.14 Output & Debugging

  1. Study the class below and write the exact output. In one sentence, explain why both displayed lines show the same value for count. [3 marks]
class Counter
{
    static int count = 0;
    int id;

    Counter()
    {
        count++;
        id = count;
    }

    void show()
    {
        System.out.println("id = " + id + ", count = " + count);
    }

    public static void main(String args[])
    {
        Counter p = new Counter();
        Counter q = new Counter();
        p.show();
        q.show();
    }
}
  1. The class below does not compile. Identify the single error, explain why the compiler rejects it, and rewrite the faulty line correctly. [3 marks]
class Box
{
    int len;

    void Box(int l)
    {
        len = l;
    }

    void show()
    {
        System.out.println("Length = " + len);
    }

    public static void main(String args[])
    {
        Box b = new Box(5);
        b.show();
    }
}
  1. The class below compiles and runs. Write its output, and explain in one sentence why the value 240 does not appear. [3 marks]
class Meter
{
    int reading;

    void setReading(int r)
    {
        int reading = r;
    }

    void show()
    {
        System.out.println("Reading = " + reading);
    }

    public static void main(String args[])
    {
        Meter m = new Meter();
        m.setReading(240);
        m.show();
    }
}
  1. Write the exact output of the class below, and state which method is invoked by each of the two calls and why. [3 marks]
class Charge
{
    int cost(int units)
    {
        return units * 6;
    }

    double cost(double units)
    {
        return units * 6.5;
    }

    public static void main(String args[])
    {
        Charge c = new Charge();
        System.out.println(c.cost(4));
        System.out.println(c.cost(4.0));
    }
}

4.15 Programming Practice

  1. Design a class WaterTank for a school overhead tank. [6 marks] Data members: length, breadth and height of the tank, all in metres, and the volume in cubic metres. Member methods:
  1. a constructor that accepts the three dimensions and stores them;
  2. a method that calculates the volume;
  3. a method that displays the three dimensions, the volume, and the capacity in litres, taking 1 cubic metre as 1000 litres. Write main to create one object with dimensions 4, 3 and 2 and call the methods on it. To be submitted: the complete class and a variable description table.
  1. Design a class Coupon for a school function, in which every coupon issued is numbered automatically. [6 marks] Data members: the serial number of the coupon, the name of the stall it is valid at, and a count of how many coupons have been issued so far, shared by all coupons. Member methods:
  1. a constructor that accepts the stall name, increases the count of coupons issued, and gives the new coupon the next serial number;
  2. a method that displays the serial number and the stall name;
  3. a method that displays how many coupons have been issued in total. Write main to create three coupons for stalls of your choice, display each of them, and then display the total issued. To be submitted: an algorithm for the constructor, the complete class, and a variable description table.
  1. Design a class Convert that changes a length given in feet and inches into centimetres, using method overloading. [5 marks] Member methods:
  1. a method named change that accepts a length in whole feet and returns the equivalent in centimetres, taking 1 foot as 30.48 cm;
  2. a second method, also named change, that accepts feet and inches separately and returns the equivalent in centimetres, taking 1 inch as 2.54 cm. Write main to call each method once, with 5 feet for the first and 5 feet 7 inches for the second, and display both results. To be submitted: the complete class, a variable description table, and one line stating what makes the two methods overloaded rather than duplicated.