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”
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.
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.
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.
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.
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.
| 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
The attributes and the behaviour of the classroom fan can be set out side by side.
| 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.
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.
| 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.
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.
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.
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.
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.
| 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 |
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.
| 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.
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.
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.
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.
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.
| 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.
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.
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.
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.
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.
| 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.
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.
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.
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.
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.
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
| 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.
| 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.
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.
| 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.
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.
| 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.
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.
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.
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.
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.
| 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.
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”
| 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.
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.
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.
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.
| 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
- 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.
- 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.
- 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
- 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.
- 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.
- 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.
- 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.
- 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
- Creating an object from a class is called instantiation, and the object created is an instance of the class.
- The
newoperator sets aside memory for one copy of every data member, fills each with its default value — zero for the numeric types,falseforboolean,nullfor any class type — and hands back a reference to the finished object. - 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
newand an integer does not. - 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.
- 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
- 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.
- 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.
- 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.
- 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
- 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.
- 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.
- 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. - 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
- 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.
- 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.
- 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
- 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.
- 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.
- 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.
- 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.
- 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
- 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. - Abstract method — a method declared with its name and arguments but no body, left for another class to define.
- Abstraction — representing only the essential features of something while leaving out the details of how those features are provided.
- Access specifier — a keyword such as
privateorpublicwritten before a declaration to state who may use that member. - Attribute — a fact about an object that can be stored and read back; in a program, a data member.
- Behaviour — what an object does or what may be done to it; in a program, its methods.
- Class — a description from which objects are created, fixing the attributes and behaviour every such object will have.
- Class variable — a variable declared with the keyword
static, of which exactly one copy exists and is shared by every object of the class. - 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.
- Constructor overloading — writing more than one constructor in a class, differing in the number or types of their arguments.
- Data hiding — keeping a class’s data private so that it can be reached only through the class’s own methods.
- Data member — a variable declared inside the class body, outside every method.
- Default constructor — the no-argument constructor the compiler supplies when a class declares no constructor of its own.
- Default value — the value a data member automatically receives when an object is created, before any constructor runs.
- Derived class — a class that inherits the members of another class, also called a subclass.
- Dot operator — the full stop written between an object’s name and a member’s name to reach the member belonging to that object.
- Dynamic binding — deciding while the program is running which version of an overridden method should be executed.
- Encapsulation — wrapping data and the methods that act on it into one unit, with the data reachable only through those methods.
- Hierarchical inheritance — an arrangement in which several derived classes extend the same super class.
- Hybrid inheritance — an arrangement combining two or more forms of inheritance in one program.
- Inheritance — the property by which one class acquires the members of another and may add its own.
- Instance — an object created from a class.
- Instance variable — a variable declared in the class body outside every method, of which each object holds its own copy.
- Instantiation — the act of creating an object from a class.
- Interface — a declaration of methods without bodies, holding no constructor, which a class connects to using
implements. - Local variable — a variable declared inside a method, constructor or block, existing only while that block is being executed.
- Member method — a method written inside the class body, describing part of the behaviour of its objects.
- Method overloading — writing several methods with the same name in one class, differing in the number, types or order of their arguments.
- 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.
- Multilevel inheritance — an arrangement in which a derived class is itself extended, forming a chain of classes.
- Object — a single distinct entity holding its own attributes together with its behaviour.
- 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.
- OOP — object oriented programming.
- Parameterised constructor — a constructor that accepts arguments, so that an object can be given its values as it is created.
- Polymorphism — the ability of one method name to serve more than one operation, the right one being chosen according to the situation.
- Procedural programming — building a program around the actions it performs, taking the method as the unit of organisation.
- Reference variable — a variable of a class type, which holds not the object itself but the means of reaching it.
- Reusability — building a new class on an existing one instead of copying its code.
- Scope — the region of a program in which a variable can be used.
- Single inheritance — an arrangement in which one derived class extends one super class.
- Super class — the class whose members are inherited by another, also called the base class or parent class.
4.11 Points to Ponder
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?
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?
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?
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?
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?
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
- Which of the following comes into existence only while the program is running? [1 mark]
- A class
- An object
- A source file
- A method definition
- The value automatically given to a data member of type
booleanwhen an object is created is: [1 mark]
- 0
truefalsenull
- Which statement about a constructor is correct? [1 mark]
- It must be declared with the return type
void - It must have the same name as its class
- It is called through the dot operator whenever it is needed
- A class may contain only one of them
- A variable of which kind has exactly one copy, shared by every object of the class? [1 mark]
- Instance variable
- Local variable
- Class variable
- Formal argument
- Writing several methods with the same name in one class, differing in the types of their arguments, is called: [1 mark]
- Method overriding
- Method overloading
- Inheritance
- Encapsulation
- A class in Java may extend: [1 mark]
- Any number of classes
- Exactly two classes
- One class only
- No class at all, in any circumstances
- 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]
- Both A and R are true and R is the correct explanation of A
- Both A and R are true but R is not the correct explanation of A
- A is true but R is false
- A is false but R is true
- 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]
- Both A and R are true and R is the correct explanation of A
- Both A and R are true but R is not the correct explanation of A
- A is true but R is false
- A is false but R is true
- 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 |
Fill in the blank: the variables declared inside a class but outside every method, constructor and block are called ____________ variables. [1 mark]
Fill in the blank: a constructor is written with no ____________ of any kind, not even
void. [1 mark]State whether true or false: an object can be created from an abstract class. [1 mark]
State whether true or false: two methods in a class that differ only in their return type are overloaded methods. [1 mark]
Give the full form of OOP. [1 mark]
4.13 Check Your Concepts
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]
What is meant by instantiation? Name the operator that performs it. [2 marks]
Name the four basic principles of object oriented programming. [2 marks]
Differentiate between a class and an object, with reference to memory occupied and to the number of each that can exist. [3 marks]
Differentiate between an instance variable and a class variable, giving one situation in which each is the right choice. [3 marks]
Distinguish between method overloading and method overriding, stating clearly when the version to be executed is chosen in each case. [3 marks]
Explain, with a short example of your own, why the data members of a class are usually declared
privatewhile its useful methods are declaredpublic. State one thing a program loses when the data members are left public. [4 marks]A class
Ticketcontains only one constructor, which accepts three arguments. Explain what happens when a program contains the statementTicket t = new Ticket();and give the reason. State one way of making the statement legal. [4 marks]Name the form of inheritance in each of the following, giving a reason for each answer. [4 marks]
- Classes
Bus,LorryandScootereach extend the classVehicle. - Class
Cextends classB, and classBextends classA. - A single program contains both of the arrangements above.
- Class
Scooterextends classVehicle, and no other class extends anything.
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]
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
- 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();
}
}- 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();
}
}- 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();
}
}- 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
- Design a class
WaterTankfor 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:
- a constructor that accepts the three dimensions and stores them;
- a method that calculates the volume;
- a method that displays the three dimensions, the volume, and the capacity in litres, taking 1 cubic metre as 1000 litres. Write
mainto 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.
- Design a class
Couponfor 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:
- a constructor that accepts the stall name, increases the count of coupons issued, and gives the new coupon the next serial number;
- a method that displays the serial number and the stall name;
- a method that displays how many coupons have been issued in total. Write
mainto 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.
- Design a class
Convertthat changes a length given in feet and inches into centimetres, using method overloading. [5 marks] Member methods:
- a method named
changethat accepts a length in whole feet and returns the equivalent in centimetres, taking 1 foot as 30.48 cm; - 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. Writemainto 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.