Chapter 10: Class as User Defined and Constructors

In the early 1960s, two researchers at the Norwegian Computing Center in Oslo, Ole-Johan Dahl and Kristen Nygaard, were trying to write simulations — programs that imitate a real system so that decisions can be tested before money is spent on them. One of the problems they worked on was the kind of question a port authority asks: how many ships can a harbour handle in a day, how long will each wait, where does the queue build up?

The languages of that time gave them arrays and procedures. So a harbour with forty ships became a scatter of parallel arrays — one array of arrival times, one of cargo weights, one of berth numbers — and a set of procedures that had to be handed the right index every single time. Ship number seventeen was not a thing in the program. It was a subscript that several unrelated arrays happened to agree about.

Dahl and Nygaard’s answer was to let the programmer describe a ship once — everything it knows and everything it can do, kept together — and then create as many ships as the harbour needed, each carrying its own values. Their language, Simula 67, gave those two ideas the names we still use: class and object. Java inherited both, and this chapter is about how you build them yourself.

Diagram

Fig. 10.0-1 – left half: three separate labelled arrays (arrivalTime, cargo, berth) with an index 17 marked in each and dashed lines linking the three seventeenth cells; right half: three self-contained boxes each titled “Ship”, each box holding its own arrivalTime, cargo and berth values plus a list of actions (dock, unload); caption contrast: “data scattered by index” versus “data and behaviour kept together”

NoteCuriosity Corner

Q1. Two objects are made from the same class, yet each remembers different values. Where is all that data actually kept, and what decides how much space one object needs? Q2. Sometimes a program needs one figure — a running total, a count of how many objects exist — that belongs to no single object. Can a class hold such a value? Q3. Every method you have written so far declares what it returns, even if that is nothing. Why does a constructor declare no return type at all? Q4. If a method’s parameter has exactly the same name as an instance variable, which of the two does an assignment change — and how can you make your intention clear? Q5. You can pass a number to a method. Can you pass a whole object in the same way, and what is it that actually travels into the method?

Keep these five questions in mind as you read. Each one is answered somewhere in this chapter, at the point where the idea behind it has been built.

10.1 The Class as a User Defined Type

Every program you wrote in Class XI worked with values that Java already knew about — whole numbers, real numbers, single characters, true and false. The language supplies those types, and it supplies the operations that go with them.

Real data is rarely a single value. A library issue is a title, an accession number, a borrower’s roll number and a due date, all describing one event. Java has no built-in type for that, and no compiler can invent one, because only you know what a library issue is.

What Java gives you instead is a way to describe such a thing yourself. That description is a class, and the rest of this chapter is about writing one well.

10.1.1 Why a Program Needs Types of Its Own

Suppose a school library program must keep, for each issued book, an accession number and the number of days it is overdue. Using only the types you already have, you would write two separate arrays and keep them in step by hand.

int acc[] = new int[200];
int overdue[] = new int[200];

Nothing in that code says the two arrays are related. The connection lives only in the position: acc[17] and overdue[17] describe the same book because the programmer remembers that they do. Sort one array without the other and the data quietly becomes nonsense.

There is a second problem, and it matters more. The rule for calculating a fine belongs to an issued book as surely as the overdue count does, yet a method written separately has to be told which position to look at every time it is called.

A class solves both problems at once. It is a description you write yourself, naming the values that belong together and the operations that act on them, and Java then treats that description as a type — a user defined data type you can use much as you use int.

NoteDefinition

A class is a description, written by the programmer, of the data a thing holds and the operations it can perform. It defines a new type; it does not by itself hold any values.

That last clause is worth reading twice. Writing a class reserves no memory for data, in the same way that writing the word int reserves nothing. Both are descriptions. Values appear only when something of that type is actually created, which is the subject of section 10.2.

Q. A class has been written and compiled successfully. How many values does it now hold?

A. None. Compiling a class only checks and records the description. Storage for data appears when an object of the class is created at run time, not when the class is compiled.

10.1.2 Attributes and Behaviour: Data Members and Member Methods

Anything a program models can be described under two headings: what it knows, and what it can do. A bus route knows its number, its length in kilometres and its fare per kilometre; it can calculate a ticket price and print its details.

What it knows becomes the class’s data members — the variables declared inside the class. What it can do becomes its member methods — the methods declared inside the same class. Together they are called the members of the class.

The important design idea is that these two are written in one place, inside one pair of braces. The method that calculates a fine sits beside the overdue count it works on, and needs no index passed to it.

Keeping data and the methods that act on it inside a single unit is called encapsulation. When that unit is also arranged so that outside code cannot reach the data directly, but must go through the methods, the class is said to practise data hiding. Section 10.4 shows the keyword that enforces this.

A class definition can also contain a third kind of member, a constructor, which runs automatically whenever something of the class is created. Constructors are important enough to have all of section 10.8; for now, note only that they exist and that they are written inside the class like everything else. Figure 10.1-1 shows the elements a class definition may contain.

Diagram

Fig. 10.1-1 – tree diagram; single top box “Class”; three branches to “Variables (data members)”, “Constructors”, “Member methods”; the “Variables” box branches further into three boxes “Instance variables”, “Class variables”, “Local variables (declared inside a method)”; a note beside the tree reading “access specifiers control who may use each member”

Notice that local variables appear on that chart too, although they are not members of the class. They live inside a method, exist only while it runs, and are included here only so that all three kinds of variable can be told apart. Section 10.3 draws that distinction carefully.

10.1.3 Defining a Class in Java

A class definition has a header and a body. The header is the keyword class followed by the name you choose; the body is everything between the braces that follow. The general form is shown below.

class ClassName
{
    type dataMember1;
    type dataMember2;

    returnType methodName1(parameter list)
    {
        // statements
    }

    returnType methodName2(parameter list)
    {
        // statements
    }
}

Two rules of layout are followed throughout this book, and you should follow them in your own work. The opening brace of a class or method is written on its own line below the header, and every level inside a pair of braces is indented by four spaces. Consistent indentation is how a reader — including an examiner reading a handwritten program — sees at a glance which method a statement belongs to.

The class name is an ordinary Java identifier, but convention gives it an initial capital letter, and joins multi-word names without spaces: Fare, BusFare, IssueRecord. Method and variable names conventionally begin with a small letter. Java does not enforce this; every experienced Java programmer does.

The word public may be written before class, and you will meet it in many books. It is optional, and it carries one condition worth remembering: if a class is declared public, the file must be named after that class. A class declared without it can live in a file of any name.

Here is a small but complete class definition for the bus route described earlier.

class Fare
{
    int distance;
    double rate;

    double amount()
    {
        return distance * rate;
    }

    void show()
    {
        System.out.println("Distance = " + distance + " km");
        System.out.println("Fare     = Rs." + amount());
    }
}

Read it as a description, not as an instruction to be carried out. It says: a Fare is something that has a distance and a rate, that can work out an amount from them, and that can display itself. Nowhere does it say what any particular distance is.

Notice also that show() calls amount() without any object name in front of it. A method of a class may call another method of the same class directly, because both belong to whatever object is currently executing them. Some books call this a nested member method; it is simply an ordinary call.

a semicolon after a method header What students write:

void show( );
{
    System.out.println("Distance = " + distance);
}

What happens: the compiler reads void show( ); as a complete declaration with no body, and then meets a block of statements floating inside the class with no method around it. The message names an illegal start of expression or a misplaced construct, and it points at the line after the mistake, which makes the real cause easy to miss. The fix: delete the semicolon. A method header is followed directly by its opening brace, never by a semicolon. The same applies to the class header itself — class Fare; is wrong.

Some school textbooks call the class ClassName { } shell the outer wrapper, and everything inside it the inner contents. The words are convenient in class discussion, but they are not part of the Java language. This book uses class header and class body.

Key in the class Fare exactly as shown and compile it. It has no main method, so nothing will run — check that compilation nevertheless succeeds and produces Fare.class. Now add a data member routeNumber of type int and print it inside show(), and compile again.

10.2 Objects as Instances of a Class

A class, as section 10.1 established, is only a description. Nothing in it holds a value, and a program made only of class definitions does nothing at all.

The working parts of a program are the things built from those descriptions. Each one is an object: a real region of memory, created while the program runs, carrying its own values for the data members its class named.

NoteDefinition

An object is an instance of a class — a particular thing created from the class’s description at run time, holding its own copy of the class’s instance variables and able to perform the class’s member methods.

The word instance is used constantly and means exactly “one particular case of”. The act of creating an object is called instantiation. Fare is a class; the fare for route 24 is an instance of it.

10.2.1 Modelling Real Situations as Classes and Objects

Before any Java is written, a problem has to be read as a set of things. This is a skill worth practising deliberately, because a class chosen badly makes every method that follows awkward.

A workable method is to read the problem statement and mark the nouns that the program must remember something about. Each such noun is a candidate class. The facts recorded about it become data members, and the actions the problem asks for become member methods.

Take a school library issue register. The problem says: for each book issued, record the accession number and the number of days it has been kept; a book kept for more than seven days attracts a fine of two rupees for each extra day; print the details of each issue.

Reading it that way gives one clear noun, an issue. The facts recorded are the accession number and the days kept, plus the fine that will be worked out from them. The actions asked for are calculating the fine and printing the details.

So the class is Issue, its data members are accNo, days and fine, and its member methods calculate and display. Each book actually issued becomes one object of that class, and two hundred issues are two hundred objects — not two hundred sets of loose variables.

Notice what has been left out. The library’s name, the shelf layout and the librarian are all nouns in the room, but the problem asks the program to remember nothing about them, so none of them becomes a class. A class earns its place by holding data the program uses.

Table 10.1 – Class and object compared

Feature Class Object
What it is A description of data and behaviour, written by the programmer A particular thing created from that description while the program runs
When it exists Written and compiled before the program runs Created at run time, by new
Memory for data None reserved by the definition itself Own copy of every instance variable
How many One definition As many as the program creates
Analogy The design of a bus route ticket One printed ticket, with a route and a fare on it

10.2.2 Creating an Object with the new Operator

An object is created by the new operator, which is followed by the class name and a pair of parentheses. The usual statement takes this form.

Issue b1 = new Issue();

That one line does three separate jobs, and separating them in your mind prevents a great deal of later confusion.

First, Issue b1 declares a variable of type Issue. Second, new Issue() sets aside memory at run time for one object, large enough for that class’s instance variables. Third, the object’s data members are initialised and the address of the new object is stored in b1.

The variable b1 is called a reference variable, and this is the point students most often pass over too quickly. A reference variable does not contain the object. It contains a reference to the object — in effect, the address of the memory where the object sits. Figure 10.2-1 shows the arrangement.

Diagram

Fig. 10.2-1 – left: a small box labelled b1 with an arrow leaving it; right: a larger box labelled “Issue object” divided into three labelled cells accNo, days, fine; the arrow from b1 points at the larger box; caption: “the reference variable holds the address, not the data”

The declaration and the creation may also be written as two statements, and doing so once makes the split obvious.

Issue b1;
b1 = new Issue();

After the first line alone, b1 exists but refers to no object; there is nothing yet for it to point at. Only the second line brings an object into being.

The parentheses after the class name are not decoration. They are a call to a constructor, a special member that runs automatically when an object is created. A class that declares no constructor of its own is given one by the compiler, which sets every instance variable to a standard initial value — zero for numeric types, false for boolean, null for objects. Section 10.8 takes constructors up properly; until then, the empty parentheses are enough.

using a reference before an object exists What students write:

Issue b1;
b1.days = 5;

What happens: the compiler refuses the second line with a message that the variable b1 may not have been initialised. Where the reference has been deliberately set to null instead, the program compiles and then stops at run time with a NullPointerException. The fix: create the object before using the reference — Issue b1 = new Issue();. Declaring a reference and creating an object are two different acts, and only the second one produces something to work with.

10.2.3 Memory Allocation for Objects

When two objects of the same class exist, each has its own copy of every instance variable. They share the class’s description, and they share its member methods, but they share none of their data.

This is what makes objects useful. The two hundred issues in the register do not interfere with one another, and no index has to be kept in step by hand, because each object physically holds its own accession number and its own day count.

The space one object occupies depends on the instance variables its class declares — two int members and one double member need more room than a single int. Member methods add nothing per object: the code of a method exists once for the whole class, however many objects call it.

Diagram

Fig. 10.2-2 – two reference variables b1 and b2 on the left, each with an arrow to its own object box; the b1 box holds accNo 1042, days 5, fine 0.0; the b2 box holds accNo 1177, days 12, fine 10.0; below both boxes a single shaded box labelled “member methods: assign(), computeFine(), show() — one copy for the class”

Q1. Two objects are made from the same class, yet each remembers different values. Where is all that data actually kept, and what decides how much space one object needs?

A. The data is kept in the object itself, in memory set aside by new at run time, and each object holds its own separate copy of every instance variable the class declares. That is why changing b1’s day count leaves b2 untouched. The space one object needs is decided by its instance variables — their number and their types. The member methods do not add to it, because a single copy of each method serves every object of the class.

10.2.4 Calling Member Methods through an Object

Once an object exists, its members are reached through the reference variable, using the dot operator: the reference, a full stop, and the member’s name.

b1.computeFine();

Read that as an instruction addressed to a particular object: this Issue, work out your fine. The same call written with b2 addresses a different object, and works on that object’s data members.

A data member can be reached the same way, as b1.days, whenever the class permits it. Section 10.4 explains how a class can forbid exactly this, and why forbidding it is usually the better design.

The program below assembles everything so far into a class that can actually be run.

recording two library issues and calculating the fine on each Problem: For each book issued, store the accession number and the number of days it has been kept. A book kept for seven days or fewer attracts no fine; beyond that, the fine is two rupees for each extra day. Create two issues with values fixed in the program, calculate each fine and print the details of both.

class Issue
{
    int accNo;
    int days;
    double fine;

    void assign(int a, int d)
    {
        accNo = a;
        days = d;
    }

    void computeFine()
    {
        if (days <= 7)
        {
            fine = 0.0;
        }
        else
        {
            fine = (days - 7) * 2.0;
        }
    }

    void show()
    {
        System.out.println("Accession number = " + accNo);
        System.out.println("Days kept = " + days);
        System.out.println("Fine = Rs." + fine);
    }

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

        b1.assign(1042, 5);
        b2.assign(1177, 12);

        b1.computeFine();
        b2.computeFine();

        b1.show();
        b2.show();
    }
}

Sample output:

Accession number = 1042
Days kept = 5
Fine = Rs.0.0
Accession number = 1177
Days kept = 12
Fine = Rs.10.0

Variable description:

[Table:] Table 10.2 – variable description for the class Issue, listing each variable with its type and purpose [/Table] | Variable | Type | Purpose | |—|—|—| | accNo | int | Accession number of the issued book | | days | int | Number of days the book has been kept | | fine | double | Fine payable, calculated by computeFine() | | a | int | Formal argument of assign(), receiving the accession number | | d | int | Formal argument of assign(), receiving the day count | | b1, b2 | Issue | Reference variables for the two issue objects |

Notes: The fine is stored as double because money is not a whole number in general, which is why the output reads 0.0 and 10.0 rather than 0 and 10. The values are supplied through assign() only because no better tool is available yet; you will see in section 10.8 that a constructor does this job automatically and cannot be forgotten. Note also that main() here sits inside the class it uses, which is convenient for a small program; a class can equally be used from a main() written in another class.

Q. In main(), both b1.computeFine() and b2.computeFine() run the same lines of code. How does each call know which day count to use?

A. The reference before the dot decides it. A member method always works on the object through which it was called, so days inside computeFine() means b1’s days in the first call and b2’s days in the second.

Run the program as it stands, then change b2’s day count to exactly 7 and predict the fine before running it again. Now add a third object b3 with any accession number and 20 days, calculate its fine and display it, and check that b1 and b2 print the same values as before.

10.3 Variables Declared inside a Class

Not every variable that appears inside a class definition means the same thing. Three kinds exist, and they differ in two respects: where they are declared, and how many copies of them exist while the program runs.

Getting these three apart is not a naming exercise. It decides whether a value survives after a method finishes, whether two objects see the same value, and whether Java will give the variable an initial value for you.

10.3.1 Instance Variables

An instance variable is declared inside the class but outside every method and constructor. It is the ordinary data member you have used so far — accNo and days in section 10.2 were both instance variables.

Every object gets its own copy of every instance variable, created when the object is created and destroyed with it. This is the source of the word instance: the variable belongs to one instance, not to the class.

Instance variables receive default initial values if you do not set them. A numeric member starts at zero, a boolean member at false, and a member whose type is a class starts at null, meaning it refers to no object yet.

class Meter
{
    int reading;       // starts at 0
    double units;      // starts at 0.0
    boolean billed;    // starts at false
    String owner;      // starts at null
}

Relying on these defaults is legal but poor practice, because a reader of your program cannot tell whether zero was intended or merely happened. Section 10.8 shows the proper tool for setting initial values deliberately.

10.3.2 Class Variables

A class variable is also declared inside the class and outside every method, but with the keyword static written before its type. That one word changes how many copies exist.

class Meter
{
    int reading;
    static int connections;
}

Here every Meter object has its own reading, but there is only one connections in the entire program, no matter how many objects are created — one hundred objects, one connections. It belongs to the class itself rather than to any object, which is why it is called a class variable, and why it is also described as a static data member.

Because it belongs to the class, a class variable exists from the moment the program starts, even if no object is ever created, and it may be referred to through the class name: Meter.connections. It is the natural home for a running total or a count of objects made, and section 10.5 develops both uses along with the methods that go with them.

A class variable may also be made constant by adding final, which fixes its value so that no later assignment is allowed. The names of such constants are conventionally written in capitals.

static final double SERVICE_CHARGE = 25.0;

10.3.3 Local Variables

A local variable is declared inside a method, a constructor or a block, and belongs to that block alone. The formal arguments of a method are local variables too, created afresh on every call.

A local variable is created when execution enters its block and destroyed when execution leaves it. Nothing of it survives to the next call, which is exactly why a counter kept in a local variable resets to nothing every time.

The rule about initial values is the opposite of the one for instance variables, and this catches a great many students. A local variable receives no default value at all, and Java refuses to compile any attempt to read it before something has been assigned to it.

assuming a local variable starts at zero What students write:

void addUp(int marks[])
{
    int sum;
    for (int i = 0; i < marks.length; i++)
    {
        sum = sum + marks[i];
    }
}

What happens: the program does not run at all. The compiler reports that the variable sum may not have been initialised, pointing at sum + marks[i], because the very first addition reads a variable that has never been given a value. The fix: write int sum = 0;. The default of zero applies to instance and class variables, never to local ones. Java’s refusal here is a service — it is the language stopping you from adding to a quantity that means nothing yet.

A local variable may share its name with an instance variable of the same class. That is legal, and inside the method the local name wins, hiding the member. Section 10.6 shows the keyword that lets you refer to the hidden member when you need it.

10.3.4 Scope and Lifetime Compared

Two words describe what separates these three kinds of variable. The scope of a variable is the region of the program in which its name may be used, and its lifetime is the period during which it actually exists in memory. Figure 10.3-1 shows where each kind lives.

Diagram

Fig. 10.3-1 – three labelled memory regions side by side. Left region “class area”, containing one box labelled “static int connections — one copy, exists from program start”. Middle region “objects”, containing two separate object boxes each holding its own “reading” cell, both labelled “one copy per object, exists while the object exists”. Right region “method in progress”, containing a stack frame box holding “sum” and “i”, labelled “created on entry to the method, destroyed on exit”. Arrows from the two object boxes to the single static box show that all objects share it

Table 10.3 – the three kinds of variable in a class

Feature Instance variable Class variable Local variable
Declared Inside the class, outside all methods Inside the class, outside all methods, with static Inside a method, constructor or block
Number of copies One per object One for the whole class One per call of the method
Scope The whole class The whole class, and outside it through the class name Only the block in which it is declared
Lifetime As long as its object exists From the start of the program to the end Only while its block is executing
Default initial value Yes — 0, false or null Yes — 0, false or null None; must be assigned before use
Typical use A fact about one object, such as a roll number A total or count shared by all objects A temporary working value, such as a loop counter

The program below uses two instance variables and two local variables together, so that the difference can be seen in one place.

totalling a student’s subject marks Problem: Store a student’s roll number and the total of three subject marks. The marks are supplied to a method as an array; the method must add them up and store the total in the object. Display the roll number and the total.

class Report
{
    int roll;
    int total;

    void record(int r, int marks[])
    {
        int i;
        int sum = 0;
        for (i = 0; i < marks.length; i++)
        {
            sum = sum + marks[i];
        }
        roll = r;
        total = sum;
    }

    void show()
    {
        System.out.println("Roll number = " + roll);
        System.out.println("Total marks = " + total);
    }

    public static void main(String args[])
    {
        int m1[] = {72, 65, 80};
        Report s1 = new Report();
        s1.record(11, m1);
        s1.show();
    }
}

Sample output:

Roll number = 11
Total marks = 217

Variable description:

[Table:] Table 10.4 – variable description for the class Report, listing each variable with its type and purpose [/Table] | Variable | Type | Purpose | |—|—|—| | roll | int | Instance variable holding the student’s roll number | | total | int | Instance variable holding the total of the marks | | r | int | Formal argument of record(), receiving the roll number | | marks | int[] | Formal argument of record(), receiving the subject marks | | i | int | Local loop counter inside record() | | sum | int | Local variable accumulating the marks inside record() | | m1 | int[] | The three marks, fixed in main() | | s1 | Report | Reference variable for the student object |

Notes: sum deliberately accumulates in a local variable and is copied into total only at the end, so that a half-finished total never sits in the object. The choice matters: had the loop added directly into total, calling record() a second time would have added the new marks to the old total instead of replacing it.

the loop inside record() for m1 holding 72, 65 and 80

Test of i < 3 i marks[i] sum after the addition
true 0 72 72
true 1 65 137
true 2 80 217
false 3 — 217, loop ends

Result: sum finishes at 217, which is then copied into total and printed. The trace also shows the local variables vanishing at the closing brace of record() — only roll and total, which live in the object, are still available when show() runs.

Delete the = 0 from the declaration of sum and compile the program; read the exact message the compiler gives. Restore it, then move the declaration int sum = 0; above the class’s methods so that it becomes an instance variable, call record() twice with the same array, and explain the total that is printed the second time.

10.4 Access Specifiers and Data Hiding

Section 10.1 described encapsulation as keeping data and the methods that act on it in one unit. So far, though, nothing has stopped code outside the class from reaching straight past those methods and changing a data member directly.

Java lets you close that door. An access specifier is a keyword written before a member’s declaration that decides which code may use the member. Because they control what is visible from where, they are also called visibility modes.

Three specifiers are studied here: private, public and protected. A member declared with none of them is also possible, and is discussed at the end of this section.

10.4.1 private

A member declared private can be used only inside the class in which it is declared. No other class may read it, assign to it, or call it — the compiler simply refuses.

class Marks
{
    private int mark;
}

This looks at first like a way of making a class harder to use, and students reasonably ask why anyone would lock away the very data the program needs. The answer is that the data is not locked away; it is put behind a door that the class itself controls.

If mark is private, no outside code can set it to 130. The only way in is a method the class provides, and that method can check the value before storing it. The class becomes responsible for keeping its own data sensible, instead of trusting every part of the program to be careful.

This is data hiding put into practice, and it is why an instance variable is declared private unless there is a definite reason not to.

10.4.2 public

A member declared public may be used from anywhere — from inside the class, from any other class, throughout the program.

Member methods that form the class’s intended service to the rest of the program are declared public. In the class Marks, the method that stores a mark after checking it and the method that supplies the stored mark are both public, because outside code is meant to call them.

The keyword may also be written before class itself, as noted in section 10.1. A public class can be used from anywhere, and its file must carry its name.

10.4.3 protected

A member declared protected behaves like a private member as far as ordinary outside code is concerned. It differs in one respect: a class derived from this one may use it.

Deriving one class from another is inheritance, which is taken up in a later chapter. Until you meet it, read protected as “private, except to my own descendants”, and note that this is exactly the situation it exists for — a member that a specialised version of the class will need, but that no unrelated class should touch.

10.4.4 Choosing a Visibility for a Member

A member written with no specifier at all is not public, although several school textbooks state that it is. It has what is called default or package visibility: it can be used by any class in the same package, and by no class outside it.

The confusion is easy to explain. Programs written in a school laboratory usually keep every class in one folder, so they all sit in the same package, and a member with no specifier does then appear to be reachable from everywhere. Put the classes in different packages and the appearance vanishes. Write the specifier you mean, and the question never arises.

Figure 10.4-1 shows the arrangement a well-built class aims for.

Diagram

Fig. 10.4-1 – a large rounded boundary labelled “class Marks”; inside it a shaded inner box labelled “private int mark”; two openings drawn in the boundary labelled “public void setMark(int)” and “public int getMark()”, each with an arrow crossing the boundary; outside the boundary a box labelled “any other class” with an arrow reaching the two openings, and a third arrow aimed straight at the shaded inner box drawn crossed out

Table 10.5 – where a member can be used, under each visibility

Can it be used from… private default (no specifier) protected public
The same class Yes Yes Yes Yes
Another class in the same package No Yes Yes Yes
A derived class No Only if in the same package Yes Yes
Any unrelated class anywhere No No No Yes
Usual use Data members Rarely chosen deliberately Members a derived class will need Member methods offered to other classes

The working rule that follows from the table is short: make data members private, make the methods that others must call public, and reach for protected only when inheritance is involved.

The program below applies that rule. It is written as two classes in one file, saved as MarksTest.java and run as MarksTest, because a class can never demonstrate its own privacy — code inside a class may always use its own private members.

protecting a mark with private data and public methods Problem: Store one subject mark, which must lie between 0 and 100. Provide a method that stores a mark only if it is valid and reports it otherwise, and a method that supplies the stored mark. From a separate class, store a valid mark, attempt an invalid one, and display the stored value after each attempt.

class Marks
{
    private int mark;

    public void setMark(int m)
    {
        if (m < 0 || m > 100)
        {
            System.out.println("Invalid mark ignored: " + m);
        }
        else
        {
            mark = m;
        }
    }

    public int getMark()
    {
        return mark;
    }
}

class MarksTest
{
    public static void main(String args[])
    {
        Marks p = new Marks();

        p.setMark(83);
        System.out.println("Stored mark = " + p.getMark());

        p.setMark(130);
        System.out.println("Stored mark = " + p.getMark());
    }
}

Sample output:

Stored mark = 83
Invalid mark ignored: 130
Stored mark = 83

Variable description:

[Table:] Table 10.6 – variable description for the classes Marks and MarksTest [/Table] | Variable | Type | Purpose | |—|—|—| | mark | int | Private instance variable holding the validated subject mark | | m | int | Formal argument of setMark(), receiving the mark offered | | p | Marks | Reference variable in MarksTest for the object being tested |

Notes: The check lives inside the class, not in main(), which is the whole point — every route to mark passes through it, so no caller can bypass the rule by forgetting to check. The invalid mark leaves the old value undisturbed rather than storing a zero, because silently replacing good data with a default is worse than refusing the change.

reaching for private data from outside What students write:

Marks p = new Marks();
p.mark = 130;

What happens: the program does not compile. The message reports that mark has private access in Marks, and names the line in the other class. The fix: call the public method — p.setMark(130); — and let the class decide what to do with the value. If a genuine need exists for outside code to read the member, add a public method that returns it, rather than widening the member to public.

Q. If getMark() hands out the value anyway, what has privacy actually gained?

A. Control of change. Reading a value harms nothing; writing one can. With mark private, the class can allow reading freely while insisting that every write pass its own test — a choice that is impossible once the member is public.

Add the line p.mark = 55; inside main() and compile the program; note the exact message. Remove the line, change private int mark; to public int mark;, compile again and observe that the same statement is now accepted even though 55 was never checked. Restore private before moving on.

10.5 Static Members of a Class

Most of what a class describes belongs to each object separately: this book’s accession number, that student’s total. Some facts, though, belong to the class as a whole.

The number of bills a counter has recorded is not a property of any one bill. The total sale for the day is not a property of any one sale. Values like these are needed by every object and owned by none, and Java marks them with the keyword static.

10.5.1 Static Data Members

A static data member, introduced in section 10.3.2 as a class variable, is declared inside the class with static before its type. Exactly one copy of it exists for the whole class.

class Sale
{
    private double amount;          // one per object
    private static double total;    // one for the class
}

Because there is only one copy, an assignment made through any object is seen by all of them. This is precisely what makes a static member the right tool for an accumulator or a counter: every object adds into the same box, as Fig. 10.5-1 shows.

Diagram

Fig. 10.5-1 – two object boxes side by side labelled s1 and s2, each holding its own cells item, qty, rate and amount; below them a single wider box labelled “class Sale — static area” holding two cells, count and total; an arrow from each object box down to the static box, both arrows labelled “adds into”; a note beside the static box reading “one copy, whatever the number of objects”

A static member exists from the time the class is loaded, before any object is created, and continues to exist until the program ends. It takes the same default initial values as an instance variable — zero for numeric types, false for boolean, null for object types.

Since it belongs to the class rather than an object, the natural way to refer to it from outside is through the class name.

Sale.total

Writing s1.total is also accepted by the compiler, but it is misleading, because it suggests the value belongs to s1. Prefer the class name; it says what is true.

Q2. Sometimes a program needs one figure — a running total, a count of how many objects exist — that belongs to no single object. Can a class hold such a value?

A. Yes, by declaring the member static. A static data member is a class variable: one single copy exists for the entire class, no matter how many objects are created, and it exists even if none is created at all. Every object reads and updates that same copy, so a total added into it by one object is immediately visible to the rest. Section 10.5.2 adds the matching tool — a static method, which can report such a value without any object being involved.

10.5.2 Static Member Methods

A static member method is declared with static before its return type. Like a static data member, it belongs to the class and not to any object, and it is called through the class name.

Sale.showTotal();

You have in fact been writing a static method since your first program. main() is declared static for a plain reason: when the program starts, no object of your class exists yet, so there is nothing to call main() through. It must be callable through the class alone.

A static method is the right choice when the work it does concerns the class rather than any single object — reporting a shared total, counting the objects created, or performing a calculation that uses only its own arguments.

10.5.3 What a Static Method May and May Not Use

A static method may use static data members and call other static methods freely. It may not use instance variables, and it may not call instance methods, directly.

The reason is worth stating rather than memorising. A static method is called through the class, so no object is involved in the call. When such a method mentions amount, there is no object whose amount could be meant, and the compiler says so.

using an instance variable inside a static method What students write:

static void showTotal()
{
    System.out.println("Total = " + total);
    System.out.println("Last amount = " + amount);
}

What happens: the class does not compile. The message reports that the non-static variable amount cannot be referenced from a static context, naming the second line. The fix: decide which the value really is. If it belongs to one object, drop static from the method and call it through an object. If it belongs to the class, declare the member static too. A static method can also work on an object handed to it as an argument, which is how main() reaches objects at all.

The restriction runs one way only. An ordinary member method may use static members whenever it wants, because an object always has a class behind it. That is exactly what the recording method in the program below does.

Table 10.7 – instance members and static members

Feature Instance member Static member
Belongs to One object The class as a whole
Number of copies One per object Exactly one, whatever the number of objects
Exists While its object exists From class loading to the end of the program
Normally called or referred to as objectName.member ClassName.member
May use instance members directly Yes No
May use static members directly Yes Yes
Typical example A student’s marks; a method that prints them A count of students; a method that prints the count

recording sales at a counter with a shared total Problem: For each sale record the item name, quantity and rate, and calculate the amount for that sale. Keep, for the counter as a whole, the number of sales recorded and the total of all amounts. Record two sales with values fixed in the program, print each sale, then print the counter’s totals without using any object.

class Sale
{
    private String item;
    private int qty;
    private double rate;
    private double amount;

    private static int count;
    private static double total;

    void record(String i, int q, double r)
    {
        item = i;
        qty = q;
        rate = r;
        amount = qty * rate;
        count = count + 1;
        total = total + amount;
    }

    void show()
    {
        System.out.println(item + " : " + qty + " x " + rate + " = Rs." + amount);
    }

    static void showTotal()
    {
        System.out.println("Sales recorded = " + count);
        System.out.println("Total sale = Rs." + total);
    }

    public static void main(String args[])
    {
        Sale s1 = new Sale();
        Sale s2 = new Sale();

        s1.record("Notebook", 4, 45.0);
        s2.record("Pen", 10, 8.5);

        s1.show();
        s2.show();

        Sale.showTotal();
    }
}

Sample output:

Notebook : 4 x 45.0 = Rs.180.0
Pen : 10 x 8.5 = Rs.85.0
Sales recorded = 2
Total sale = Rs.265.0

Variable description:

[Table:] Table 10.8 – variable description for the class Sale [/Table] | Variable | Type | Purpose | |—|—|—| | item | String | Instance variable holding the name of the item sold | | qty | int | Instance variable holding the quantity sold | | rate | double | Instance variable holding the rate per unit | | amount | double | Instance variable holding the amount for this sale | | count | static int | Class variable counting the sales recorded | | total | static double | Class variable accumulating the amount of all sales | | i, q, r | String, int, double | Formal arguments of record() | | s1, s2 | Sale | Reference variables for the two sale objects |

Notes: record() is an ordinary method because it works on one sale’s data, yet it updates count and total in the same breath — an instance method reaching a static member, which is always allowed. showTotal() is static because it uses nothing but static members, and the call Sale.showTotal() shows why that matters: the counter’s summary can be printed without any sale object being involved.

the two calls of record(), tracing the shared members

Call amount of the calling object count after the call total after the call
s1.record("Notebook", 4, 45.0) s1.amount = 180.0 1 180.0
s2.record("Pen", 10, 8.5) s2.amount = 85.0 2 265.0

Result: each object keeps its own amount, but both calls add into one count and one total, which finish at 2 and 265.0. Had count and total not been static, each object would have counted only itself and the printed total would have been 85.0.

Remove the word static from count and total, adjust showTotal() so that the class still compiles, and run the program again; explain the totals that now appear. Then restore the statics, add a third sale of any item, and check that count and total change without any change to showTotal().

10.6 Referring to the Current Object: the this Keyword

When s1.show() and s2.show() run the same lines yet print different values, something must be telling the method which object it is working on. That something has a name in Java, and you can write it down.

Inside every member method, the keyword this refers to the current object — the object through which the method was called. During s1.show(), this is s1; during s2.show(), the very same method sees this as s2.

The keyword has been present in every program of this chapter without being written. When show() names item, Java reads it as this.item, and supplies the object for you. Most of the time that is exactly what you want, and writing this adds nothing.

Two situations make it necessary rather than optional. The first is a clash of names, and it is much the more common.

10.6.1 When a Local Name Hides an Instance Variable

Section 10.3.3 noted that a local variable — including a formal argument — may carry the same name as an instance variable, and that inside the method the local name wins.

This happens constantly in real classes, because the natural name for the argument of a method that stores a number of hours is hours, and the natural name for the member that keeps it is also hours. Java does not object. It simply takes every plain hours in the method to mean the argument.

The result is one of the quietest bugs a beginner can write.

assigning a parameter to itself What students write:

void issue(int number, int hours)
{
    number = number;
    hours = hours;
    charge = hours * 5.0;
}

What happens: the class compiles without error, and the program runs. Nothing is stored. The first two statements copy each argument into itself, leaving the instance variables at their defaults, so the object prints Token 0 : 0 hours afterwards. The charge is calculated correctly, from the argument, which makes the output look half right — Rs.15.0 beside a token numbered 0 — and that mixture is the usual clue. The fix: say which number you mean. this.number = number; assigns the argument on the right to the member on the left, and the same for hours. Renaming the arguments to n and h also works, and is a perfectly respectable alternative when the class is small.

Writing this.number on the left and number on the right is not a trick. The two names refer to different variables, and this is what distinguishes them: with the keyword, the member; without it, the argument that hides the member.

Diagram

Fig. 10.6-1 – centre: a box labelled “issue(int number, int hours)” containing two cells for the arguments, number = 17 and hours = 3; to its right two object boxes labelled t1 and t2, each with cells number, hours, charge; a bold arrow labelled “this” runs from inside the method box to the t1 box only, with the caption “during t1.issue(17, 3) the current object is t1”; a small note beside the argument cells reading “plain number means these”

The program below is the corrected version in full.

issuing tokens at a cycle stand, with arguments named after the members Problem: For each token, store the token number and the number of hours the cycle is parked, and calculate the charge at five rupees per hour. Issue two tokens with values fixed in the program and display each one.

class Token
{
    private int number;
    private int hours;
    private double charge;

    void issue(int number, int hours)
    {
        this.number = number;
        this.hours = hours;
        charge = this.hours * 5.0;
    }

    void show()
    {
        System.out.println("Token " + number + " : " + hours + " hours, Rs." + charge);
    }

    public static void main(String args[])
    {
        Token t1 = new Token();
        Token t2 = new Token();

        t1.issue(17, 3);
        t2.issue(18, 6);

        t1.show();
        t2.show();
    }
}

Sample output:

Token 17 : 3 hours, Rs.15.0
Token 18 : 6 hours, Rs.30.0

Variable description:

[Table:] Table 10.9 – variable description for the class Token [/Table] | Variable | Type | Purpose | |—|—|—| | number | int | Instance variable holding the token number | | hours | int | Instance variable holding the hours parked | | charge | double | Instance variable holding the amount payable | | number, hours | int | Formal arguments of issue(), sharing the members’ names | | t1, t2 | Token | Reference variables for the two token objects |

Notes: charge needs no this, because no argument is called charge and the name cannot be misread. It is written as this.hours * 5.0 deliberately, to make the reader see that the stored value is being used; hours * 5.0 would give the same answer here but would be reading the argument. Inside show() there are no arguments at all, so the plain names are unambiguous.

Q4. If a method’s parameter has exactly the same name as an instance variable, which of the two does an assignment change — and how can you make your intention clear?

A. The parameter wins. Inside the method, every plain use of the name means the local parameter, and the instance variable is hidden — which is why hours = hours; compiles happily and stores nothing at all. To reach the hidden member, write this and a dot before it: this.hours = hours; takes the value from the parameter on the right and stores it in the object’s own member on the left. Choosing different names for the arguments avoids the clash altogether, and both solutions are acceptable.

10.6.2 Other Uses of this

Because this is an ordinary reference to the current object, it can be used anywhere such a reference is wanted, and three further uses are worth knowing.

It can be passed to another method as an argument, so that the method receives the object it was called from. A method written as register(this) hands over the current object for another class to record or work on.

It can be returned from a method whose return type is the class itself, with return this;, when the calling code should be given back the object it started with.

Inside a constructor, this(...) with arguments calls another constructor of the same class, and must be the first statement in that constructor. Constructors are the subject of section 10.8; the use is mentioned here so that the list is complete.

One restriction applies, and section 10.5.3 has already prepared it. The keyword this cannot be used inside a static method, because such a method is called through the class and no current object exists for this to refer to.

Q. Does each object store its own copy of this?

A. No. this is not a data member; nothing is stored for it in the object. It is a reference made available to a method while that method is running, holding the address of whichever object the call was made through.

Change this.hours = hours; back to hours = hours;, leaving the rest of the program unchanged, and predict both lines of output before you run it. Then rename the arguments of issue() to n and h, remove every this from the method, and confirm that the original output returns.

10.7 Objects as Arguments and Return Values

A class, once written, is a type. Anywhere Java allows a type — the declaration of a variable, the parameter list of a method, the return type of a method — a class name may be written in place of int or double.

That single fact is what this section is about. A method can be handed a whole object to work on, and a method can hand a whole object back.

10.7.1 Passing an Object to a Method

A parameter whose type is a class receives an object. The method then reaches that object’s members through the parameter name and a dot, exactly as main() does.

void add(Weight a, Weight b)

Two things surprise students here, and both are worth settling before the program.

The first is that a method of Weight may read a.kg even though kg is private. This is allowed, and it is not a loophole. Privacy in Java is decided per class, not per object: code inside Weight may use the private members of any Weight, because that code is exactly what was trusted with them. A method in a different class still could not.

The second concerns what actually travels into the method. When you pass an int, the method receives a copy of the number, and changing it inside the method leaves the caller’s variable untouched. When you pass an object, what is copied is the reference — the address — and the copy points at the very same object. There is no second object anywhere.

The consequence is direct: a method that changes a member of the object it was given changes the caller’s object, because there is only one object involved. A method that assigns a whole new object to its parameter changes nothing outside itself, because it has only redirected its own copy of the address.

Table 10.10 – passing a primitive value and passing an object

Feature Primitive argument Object argument
What the method receives A copy of the value A copy of the reference
How many values or objects exist Two — the caller’s and the copy One object, with two references to it
Changing a member inside the method Not applicable The caller sees the change
Assigning a new value or object to the parameter Caller unaffected Caller unaffected
Typical use A single number, character or flag A whole record the method must read or update

Diagram

Fig. 10.7-1 – top: three reference boxes labelled w1, w2, w3 in main(), each with an arrow to its own object box holding cells kg and gm (2/750, 1/400, and 0/0); below: a method frame labelled “w3.add(a, b)” containing two parameter boxes a and b, with arrows from a to the same object as w1 and from b to the same object as w2, and a third arrow labelled “this” to the w3 object; caption: “the parameters hold copies of the addresses, not copies of the objects”

The program below adds two weights, each recorded in kilograms and grams, and stores the result in a third object.

adding two weights recorded in kilograms and grams Problem: A shop records each purchase as a weight in kilograms and grams, where 1000 grams make one kilogram. Store two weights fixed in the program, add them into a third object so that the grams are carried correctly, and display all three.

class Weight
{
    private int kg;
    private int gm;

    void set(int kg, int gm)
    {
        this.kg = kg;
        this.gm = gm;
    }

    void add(Weight a, Weight b)
    {
        kg = a.kg + b.kg;
        gm = a.gm + b.gm;

        if (gm >= 1000)
        {
            gm = gm - 1000;
            kg = kg + 1;
        }
    }

    void show()
    {
        System.out.println(kg + " kg " + gm + " g");
    }

    public static void main(String args[])
    {
        Weight w1 = new Weight();
        Weight w2 = new Weight();
        Weight w3 = new Weight();

        w1.set(2, 750);
        w2.set(1, 400);

        w3.add(w1, w2);

        w1.show();
        w2.show();
        w3.show();
    }
}

Sample output:

2 kg 750 g
1 kg 400 g
4 kg 150 g

Variable description:

[Table:] Table 10.11 – variable description for the class Weight [/Table] | Variable | Type | Purpose | |—|—|—| | kg | int | Instance variable holding the whole kilograms | | gm | int | Instance variable holding the grams, less than 1000 after adding | | a, b | Weight | Formal arguments of add(), referring to the two weights to be added | | w1, w2 | Weight | Reference variables for the two weights to be added | | w3 | Weight | Reference variable for the object that receives the sum |

Notes: add() writes into the object it was called through — the plain kg and gm on the left mean this.kg and this.gm, so the call must be made on the object that is to hold the answer. The carry is done once, and once is enough: each gm is already below 1000, so their sum is below 2000 and a single subtraction restores the range. Had the grams been allowed to hold any value, a while would have been needed in place of the if.

expecting a method to replace the object it was given What students write:

void clear(Weight w)
{
    w = new Weight();
}

What happens: the program compiles and runs, and the caller’s object is completely unchanged. The method made a fresh object and pointed its own copy of the address at it; the caller’s reference still points where it always did. The new object is then discarded when the method ends. The fix: change the object rather than the reference — w.set(0, 0); — or return the new object and let the caller store it, as section 10.7.2 shows.

Q5. You can pass a number to a method. Can you pass a whole object in the same way, and what is it that actually travels into the method?

A. Yes — a parameter may have a class as its type, and w3.add(w1, w2) passes two whole objects. What travels is not the object itself but a copy of the reference to it, so the parameter inside the method points at the caller’s object and no second object is made. That is why a method can change the members of an object it was given and the caller sees the change, and equally why pointing the parameter at a brand new object changes nothing outside the method.

10.7.2 Returning an Object from a Method

A method’s return type may also be a class name. Such a method must return a reference to an object of that class, and the caller normally stores it in a reference variable.

The add() method above works by being called on the object that is to hold the answer, which forces the caller to create that object first. An alternative design lets the method make the answer itself and hand it back. Adding the method below to the class Weight provides it.

    Weight plus(Weight b)
    {
        Weight t = new Weight();

        t.kg = kg + b.kg;
        t.gm = gm + b.gm;

        if (t.gm >= 1000)
        {
            t.gm = t.gm - 1000;
            t.kg = t.kg + 1;
        }

        return t;
    }

The header declares Weight as the return type, a new object is created inside the method and filled in, and return t; sends back its reference. With the call written as

        Weight w4 = w1.plus(w2);
        w4.show();

the printed line is 4 kg 150 g, the same answer by a different route.

Notice that the object t does not vanish when the method ends, even though t itself is a local variable. The variable disappears; the object survives, because a reference to it has been handed to the caller and stored in w4. Figure 10.7-2 shows the moment the reference is passed back.

Diagram

Fig. 10.7-2 – left: a method frame labelled “w1.plus(w2)” containing a local reference box t with an arrow to a newly drawn object box holding kg 4 and gm 150; right: the caller’s reference box w4; a broad arrow labelled “return t” from t to w4, and after it a dashed outline where the method frame used to be, with both t’s box and the frame greyed out while the object box and w4’s arrow to it remain solid

Which of the two designs is better depends on the problem. A method that returns an object reads more naturally in an expression and leaves the caller free of the job of creating the result. A method that fills in the current object avoids creating anything, which matters when many results are produced in a loop. Both appear in ISC class specifications, and the specification always makes clear which one is wanted: a method described with the return type Weight must return an object, and one described as void must not.

Q. Could plus() have returned the object this instead of a new object?

A. It could, but only by changing w1 itself, since this refers to the calling object. The caller would then find that adding two weights had altered one of them — a surprise no reader of the code expects. Producing a new object leaves both operands as they were.

Add plus() to the class, call it as shown, and then display w1 again to confirm that adding did not alter it. Next, write a method boolean heavierThan(Weight b) that returns true when the current object weighs more than the object passed to it, and test it on w1 and w2.

10.8 Constructors

Every program in this chapter so far has created an object and then, in a second step, put values into it — through assign(), set(), issue() or record(). The two steps are separate, and that is the weakness.

A constructor removes the gap. It is a member of the class that runs automatically at the moment an object is created, so an object is never handed to the program in an unfinished state.

10.8.1 Why Initialisation Cannot Be Left to the User

Consider what the class Weight in section 10.7 depends on. Its add() method assumes that every weight it is given has fewer than 1000 grams; its output assumes that both members hold real measurements.

Nothing enforces either assumption. A caller who writes new Weight() and forgets the call to set() gets an object holding two zeros, and the program cheerfully adds nothing to nothing and prints the result.

The trouble is not that the caller is careless. It is that the class has published a rule — fill me in before using me — and has provided no way to insist on it. Any rule that depends on every future caller remembering it will eventually be broken.

A constructor turns the rule into a mechanism. Because it is called by new itself, there is no way to create the object and skip it.

NoteDefinition

A constructor is a member of a class, having the same name as the class and no return type, which is invoked automatically when an object of that class is created, and whose purpose is to initialise the object’s instance variables.

10.8.2 Features of a Constructor

Five properties define a constructor, and each of them follows from what it is for.

  1. Its name is exactly the name of the class, including the capitalisation. This is how the compiler recognises it as a constructor rather than an ordinary method.

  2. It declares no return type — not int, not String, and not even void. It is not called by your code and has no caller to return a value to.

  3. It is invoked automatically when an object is created with new, and at no other time. You never write t1.Trip();.

  4. It may take arguments, and a class may have several constructors with different parameter lists. Section 10.8.7 develops this.

  5. It may carry an access specifier. public is usual, since other classes must be able to create objects; a private constructor is legal Java and has the effect of preventing creation from outside the class.

Note carefully what is not in that list. A constructor is not obliged to be public, although several school textbooks state that it always is, and nothing prevents it from containing calculations — a constructor that computes a fare from a distance it has just stored is perfectly ordinary. What it must not do is return a value.

Q3. Every method you have written so far declares what it returns, even if that is nothing. Why does a constructor declare no return type at all?

A. Because a return type answers the question “what does this give back to the code that called it?”, and nothing in your program calls a constructor. It is invoked by new, as part of creating the object, and what new produces is the object itself — there is no caller waiting for a separate value. This is also why void is wrong rather than merely unnecessary: void is a return type, and writing it turns the construct into an ordinary member method that happens to share the class’s name, which new will then ignore.

writing void before a constructor What students write:

class Trip
{
    private int route;

    void Trip(int route)
    {
        this.route = route;
    }
}

What happens: the class compiles without a single complaint, which is what makes this error so troublesome. void Trip(int) is not a constructor at all but an ordinary method named Trip, so the class is left with no constructor of its own. The statement new Trip(24) is then rejected — the compiler reports that no suitable constructor was found — while new Trip() is accepted and leaves route at zero. The fix: delete void. A constructor header consists of the access specifier, if any, then the class name, then the parameter list.

10.8.3 The Default Constructor

A class need not declare a constructor at all. Every class in this chapter before now has managed without one, and new Issue() worked perfectly well.

That is because a class which declares no constructor is given one by the compiler. It takes no arguments, its body is empty, and its effect is to leave every instance variable at the default value described in section 10.3.1 — zero, false or null according to type. This compiler-supplied constructor is called the default constructor.

class Sample
{
    int n;          // 0 after new Sample()
    double d;       // 0.0
    boolean b;      // false
    String s;       // null
}

One consequence of this arrangement surprises almost everyone the first time. The default constructor is supplied only when the class declares no constructor whatsoever. Write a constructor that takes two arguments, and the free no-argument one disappears; new Sample() will then fail to compile.

The remedy is simply to write the no-argument constructor yourself when you want both, which brings us to the next kind.

10.8.4 Non-parameterised Constructor

A non-parameterised constructor is one you write with an empty parameter list. It looks like the default constructor and is called in the same way, by new ClassName(), but its body is yours.

    Trip()
    {
        route = 0;
        km = 0.0;
    }

Writing zeros explicitly may look pointless, since the defaults would have supplied them. It is not. It states the intention, so a reader knows the initial state was chosen rather than inherited by accident, and it puts a place in the class where a more sensible starting value can later be written.

The distinction between this and the default constructor is a favourite of examiners and is easy to hold on to: the default constructor is supplied by the compiler and is invisible in your source, while a non-parameterised constructor is written by you and visible.

10.8.5 Parameterised Constructor

A parameterised constructor declares arguments, and the values for them are supplied inside the parentheses of the new statement.

    Trip(int route, double km)
    {
        this.route = route;
        this.km = km;
    }

The call new Trip(24, 13.5) creates the object and initialises it in one indivisible act. There is no moment at which a Trip exists with no route, and no way for a caller to forget the second step, because there is no second step.

Note the use of this here, exactly as section 10.6 explained. The arguments have been given the members’ own names, which reads well in the header, so each assignment must say which of the two it means.

10.8.6 Copy Constructor

Sometimes a new object should begin life holding the same values as an existing one. A copy constructor does this: it takes an object of the same class as its argument and copies that object’s members into the object being created.

    Trip(Trip t)
    {
        route = t.route;
        km = t.km;
    }

The call is new Trip(t2). As section 10.7.1 established, reading t.route from inside the class is allowed even though the member is private, because privacy is a matter of class rather than of object.

This is the point at which to be careful about a genuinely different operation that is often confused with it. The statement below copies no object at all.

        Trip t4 = t2;

It copies a reference. After it, t2 and t4 are two names for one object, and a change made through either name is seen through the other. A copy constructor makes a second object; assignment makes a second name. Figure 10.8-1 puts the two side by side, and the program that follows proves the difference by running it.

Diagram

Fig. 10.8-1 – two panels. Left panel titled “Trip t3 = new Trip(t2);”: reference boxes t2 and t3, each with an arrow to its own separate object box, the two boxes holding identical values route 24, km 13.5, with a dashed arrow between them labelled “values copied at creation”. Right panel titled “Trip t4 = t2;”: reference boxes t2 and t4 with both arrows meeting at a single object box holding route 24, km 13.5, labelled “one object, two names”

three constructors, and the difference between copying an object and copying a reference Problem: A school bus trip is described by a route number and the distance it covers in kilometres. Provide three ways of creating a trip: with no values, with a route and a distance supplied, and as a copy of an existing trip. Also provide a method that changes an existing trip. Create one trip of each kind, make a second name for one of them, change the trip through that second name, and display all four.

class Trip
{
    private int route;
    private double km;

    Trip()
    {
        route = 0;
        km = 0.0;
    }

    Trip(int route, double km)
    {
        this.route = route;
        this.km = km;
    }

    Trip(Trip t)
    {
        route = t.route;
        km = t.km;
    }

    void change(int route, double km)
    {
        this.route = route;
        this.km = km;
    }

    void show()
    {
        System.out.println("Route " + route + " covers " + km + " km");
    }

    public static void main(String args[])
    {
        Trip t1 = new Trip();
        Trip t2 = new Trip(24, 13.5);
        Trip t3 = new Trip(t2);
        Trip t4 = t2;

        t4.change(31, 20.0);

        t1.show();
        t2.show();
        t3.show();
        t4.show();
    }
}

Sample output:

Route 0 covers 0.0 km
Route 31 covers 20.0 km
Route 24 covers 13.5 km
Route 31 covers 20.0 km

Variable description:

[Table:] Table 10.12 – variable description for the class Trip [/Table] | Variable | Type | Purpose | |—|—|—| | route | int | Instance variable holding the bus route number | | km | double | Instance variable holding the distance covered | | route, km | int, double | Formal arguments of the parameterised constructor and of change() | | t | Trip | Formal argument of the copy constructor, the object to be copied from | | t1 | Trip | Trip created by the non-parameterised constructor | | t2 | Trip | Trip created by the parameterised constructor | | t3 | Trip | Trip created by the copy constructor, from t2 | | t4 | Trip | A second reference to the same object as t2 |

Notes: Three objects exist in this program, not four. The second and fourth lines of output are identical because t2 and t4 name one object, and the change made through t4 is therefore visible through t2. The third line proves that t3 is a genuinely separate object: it was filled from t2 at the moment of creation and has been untouched since.

the four references in main(), statement by statement

Statement Objects in existence, as (route, km) What the references name
Trip t1 = new Trip(); A(0, 0.0) t1 → A
Trip t2 = new Trip(24, 13.5); A(0, 0.0), B(24, 13.5) t1 → A, t2 → B
Trip t3 = new Trip(t2); A(0, 0.0), B(24, 13.5), C(24, 13.5) t3 → C, a new object
Trip t4 = t2; A, B, C unchanged t4 → B, no new object made
t4.change(31, 20.0); A(0, 0.0), B(31, 20.0), C(24, 13.5) references unchanged

Result: only three objects were ever created, and the single call to change() altered object B, which both t2 and t4 refer to. The trace shows why the copy constructor cannot be replaced by an assignment: assignment adds a name, not an object.

10.8.7 Constructor Overloading

The class Trip declares three constructors, all named Trip. Writing several constructors that differ in their parameter lists is called constructor overloading, and it is entirely ordinary.

The compiler decides which one to use from the arguments in the new statement — their number first, then their types. new Trip() matches the empty list, new Trip(24, 13.5) matches the int, double list, and new Trip(t2) matches the list expecting a Trip.

For this to work, no two constructors may have the same parameter list. Two constructors both taking a single int cannot be told apart, and the class will not compile, however different their bodies are.

Overloading is what makes a class convenient to use. The caller who has values supplies them, the caller who has none does not, and the caller holding an existing trip copies it — three natural ways to say “make me a Trip”, all served by the same class.

10.8.8 Constructor and Member Method Compared

The two are easily confused, because a constructor is written inside the class among the methods and looks much like them. Table 10.13 sets out the differences that matter.

Table 10.13 – constructor and member method compared

Feature Constructor Member method
Name Exactly the class name Any valid identifier, and by convention not the class name
Return type None, not even void Compulsory — a type, or void
When it runs Automatically, when an object is created with new When your code calls it explicitly
How often per object Once, at creation As often as it is called
Purpose To bring the object into a valid initial state To do the object’s work afterwards
May be overloaded Yes Yes

Q. A class has only the constructor Trip(int route, double km). What happens to new Trip()?

A. It fails to compile, with a message that the constructor Trip() cannot be found. Because the class declares a constructor of its own, the compiler no longer supplies the free no-argument one. Add a non-parameterised constructor if both forms are wanted.

Practical link: constructors and object creation — file this under the work file’s unit on classes and constructors. Design a class Plot that stores the length and the breadth of a rectangular plot in metres. Provide a non-parameterised constructor setting both to zero, a parameterised constructor that accepts a length and a breadth, a copy constructor, a method that returns the area, and a method that displays the length, breadth and area. In main(), create a plot of 30 by 20, copy it into a second object, change the breadth of the original to 25, and display both objects with a variable description table, so that the copy is seen to be unaffected. Test also with the unseen input 48 by 48.

10.9 Designing a Class from a Given Specification

In every program so far, the class was invented as the problem was read. In practice a class is more often handed to you already described — by a colleague, by a design document, or by the problem statement itself.

Such a description is called a class specification. It names the class, lists the data members with their types and meanings, and lists each method with what it must accept and what it must do. It stops short of saying how any of it is to be achieved; that part is yours.

Working from a specification is a skill of its own, and it is mostly a skill of reading carefully.

10.9.1 Reading a Specification and Planning the Class

A specification can be turned into a class skeleton almost mechanically, provided four questions are asked of it in order.

The first is which entries are data and which are behaviour. Data entries become instance variables, declared with the types the specification gives; behaviour entries become constructors and methods.

The second is which of the methods is a constructor. The give-away is the name: an entry named exactly like the class is a constructor, and it will be described as assigning or initialising the data members.

The third question is asked of every remaining method separately: what does it return, and what does it accept? A description that begins “to display” or “to store” returns nothing and takes void; one that begins “returns the…” needs a return type; one described with the class’s own name as its type must return an object, as section 10.7.2 showed.

The fourth is visibility. Unless the specification says otherwise, data members are private and methods are public, for the reasons set out in section 10.4.

Two habits are worth forming while you do this. Use the exact names the specification gives, because those names are the agreement between the person who wrote it and you — a method quietly renamed is a method the rest of the program cannot call. And write the skeleton in full, with empty bodies, before writing a single statement inside them; a class that compiles empty will not surprise you later with a missing brace.

10.9.2 A Complete Worked Design

Here is a specification of the kind you will meet, for a class that prepares a household water bill.

Table 10.14 – specification of the class WaterBill

Member Type or return type Description
name String Name of the consumer
units int Units of water consumed in the month
amount double Amount payable
WaterBill(String n, int u) — Constructor: assigns the name and the units, and sets the amount to zero
compute() void Calculates the amount payable from the units, using the slab below
display() void Displays the name, the units consumed and the amount payable

The slab is stated separately, as such rules usually are.

Table 10.15 – the water charge slab, giving the charge that applies to each band of units

Units consumed Charge
Up to 20 Rs. 150 fixed, whatever the consumption
21 to 50 Rs. 150 plus Rs. 4 for each unit above 20
Above 50 Rs. 150 plus Rs. 4 for each of units 21 to 50, plus Rs. 6 for each unit above 50

Read the slab twice before writing anything, because the whole difficulty of the class lives in it. The higher rate applies only to the units inside its own band, not to the entire consumption — a consumer of 70 units is not charged six rupees for all seventy. Figure 10.9-1 shows the bands.

Diagram

Fig. 10.9-1 – a horizontal number line of units from 0 to about 80, divided into three shaded bands with boundary marks at 20 and 50; the first band labelled “0–20: fixed Rs. 150”, the second “21–50: Rs. 4 per unit in this band”, the third “above 50: Rs. 6 per unit in this band”; below the line, a worked bar for 70 units split into three lengths labelled 150, 30 × 4 = 120 and 20 × 6 = 120, with a total of 390 marked at the right

With the bands understood, the calculation can be stated in words before any Java is written.

computing the amount payable from the units consumed Input: units, the whole number of units consumed in the month, not negative. Output: amount, the rupees payable. Method:

1. If units is 20 or less, set amount to 150.0 and stop.
2. If units is 50 or less, set amount to 150.0 + (units - 20) x 4.0 and stop.
3. Otherwise set amount to 150.0 + 30 x 4.0 + (units - 50) x 6.0.

Why it works: the three cases cover every possible value of units and no two of them overlap, because each test is reached only when the one before it has failed. In steps 2 and 3 the count of units charged at a higher rate is obtained by subtracting the boundary below it, so each unit is charged once and at the rate of the band it falls in. Step 3 uses 30 because band 21 to 50 is fully consumed and contains thirty units. Cost: constant — \(O(1)\), since a fixed number of comparisons and arithmetic operations is performed whatever the value of units.

The class follows directly.

preparing a household water bill from a slab Problem: For each consumer, store the name and the units of water consumed in a month, calculate the amount payable using the slab above, and display the name, the units and the amount. Prepare bills for two consumers with values fixed in the program.

class WaterBill
{
    private String name;
    private int units;
    private double amount;

    WaterBill(String n, int u)
    {
        name = n;
        units = u;
        amount = 0.0;
    }

    public void compute()
    {
        if (units <= 20)
        {
            amount = 150.0;
        }
        else if (units <= 50)
        {
            amount = 150.0 + (units - 20) * 4.0;
        }
        else
        {
            amount = 150.0 + 30 * 4.0 + (units - 50) * 6.0;
        }
    }

    public void display()
    {
        System.out.println(name + " used " + units + " units, amount Rs." + amount);
    }

    public static void main(String args[])
    {
        WaterBill b1 = new WaterBill("Meera", 35);
        WaterBill b2 = new WaterBill("Arun", 70);

        b1.compute();
        b1.display();

        b2.compute();
        b2.display();
    }
}

Sample output:

Meera used 35 units, amount Rs.210.0
Arun used 70 units, amount Rs.390.0

Variable description:

[Table:] Table 10.16 – variable description for the class WaterBill [/Table] | Variable | Type | Purpose | |—|—|—| | name | String | Instance variable holding the consumer’s name | | units | int | Instance variable holding the units consumed | | amount | double | Instance variable holding the amount payable | | n | String | Formal argument of the constructor, receiving the name | | u | int | Formal argument of the constructor, receiving the units | | b1, b2 | WaterBill | Reference variables for the two bills |

Notes: The chain of if, else if and else matters more than it looks. Written as three separate if statements, the second and third tests would still be reached after the first had succeeded, and the amount would be overwritten. The else if form makes the cases exclusive, exactly as the algorithm requires. The constructor sets amount to zero rather than leaving it to the default, so that an object displayed before compute() shows an honest zero rather than an accident.

Every class should be tried on the values where its behaviour changes, not only on comfortable ones. For this slab those values sit at the two boundaries.

Table 10.17 – test values for compute(), chosen at and around the slab boundaries

Units Band Amount expected
20 Top of the fixed band 150.0
21 First unit of the middle band 154.0
50 Top of the middle band 270.0
51 First unit of the highest band 276.0

If your program agrees with all four, the two comparisons are the right way round and neither band has been left a unit short. Testing only 35 and 70, as main() does, would never have revealed a < written where <= was meant.

charging the higher rate on the whole consumption What students write:

        else
        {
            amount = 150.0 + units * 6.0;
        }

What happens: the program compiles and runs, and every answer in the highest band is too large — 70 units produce Rs.570.0 instead of Rs.390.0. Nothing in the output looks broken, which is why an error of this kind survives until someone checks a figure by hand. The fix: charge each band separately — 150.0 + 30 * 4.0 + (units - 50) * 6.0. The rate of a band applies only to the units lying inside that band, and the units below it have already been paid for at their own rates.

Q. The specification says the constructor sets amount to zero. Why not let the constructor call compute() and be done with it?

A. Because the specification does not ask for it, and a class that quietly does more than its description says is a class no one can rely on. There is also a design reason: separating the calculation from the creation lets the same object be recomputed if its data ever changes, and keeps each method to one job.

Run the class on all four values in Table 10.17 and check each answer against the table. Then change units <= 50 to units < 50 and find, by testing, exactly which one consumer is now billed wrongly and by how much.

10.10 Summary

Classes and objects
  1. A class is a description, written by the programmer, of the data a thing holds and the operations it can perform. It defines a new type — a user defined data type — and by itself holds no values and occupies no memory for data.
  2. The values a class names become its data members; the operations become its member methods. Keeping the two together in one unit is encapsulation, and arranging matters so that outside code must go through the methods is data hiding.
  3. An object is an instance of a class: a real region of memory, created while the program runs, holding its own copy of every instance variable the class declares. Creating one is called instantiation.
  4. Reading a problem as a set of classes means finding the nouns the program must remember something about. A noun the program stores nothing about does not become a class.
  5. The new operator sets aside memory for one object, runs a constructor, and yields a reference to the object. A reference variable does not contain the object; it contains the address of the object.
  6. Every object has its own copy of the instance variables, and the space it occupies depends on those variables. Member methods exist once for the whole class, however many objects call them.
  7. Members are reached through a reference and the dot operator. A member method always works on the object through which it was called.
The three kinds of variable
  1. An instance variable is declared in the class outside every method; there is one copy per object, and it lives as long as its object.
  2. A class variable carries the keyword static; exactly one copy exists for the whole class, from the start of the program to the end, shared by every object and reachable through the class name.
  3. A local variable is declared inside a method, constructor or block, including every formal argument; it is created on entry to the block and destroyed on exit.
  4. Instance and class variables receive default initial values — zero for numeric types, false for boolean, null for object types. Local variables receive none, and the compiler refuses to read one before it has been assigned.
  5. Scope is the region in which a name may be used; lifetime is the period during which the variable exists. The three kinds differ in both.
Access specifiers
  1. An access specifier decides which code may use a member. A private member can be used only inside its own class; a public member from anywhere; a protected member behaves as private except to classes derived from it.
  2. A member written with no specifier is not public. It has default, or package, visibility: usable by classes in the same package only.
  3. The working rule is that data members are private and the methods offered to other classes are public. Privacy costs nothing in reading, since a public method can supply a value, and gains control over every change.
  4. Privacy is decided per class, not per object: a method of a class may use the private members of any object of that same class.
Static members
  1. A static data member suits any fact that belongs to the class rather than to one object — a counter of how many objects or transactions there have been, or an accumulator such as a running total.
  2. A static member method belongs to the class and is called through the class name, needing no object. main is static for exactly this reason: it must run before any object exists.
  3. A static method may use static members directly, but not instance variables or instance methods, because no object is involved in the call. The restriction does not run the other way — an ordinary method may freely use static members.
The current object
  1. Inside a member method, this refers to the current object, the one through which the method was called. It is present implicitly in every unqualified use of a member’s name.
  2. A local variable or formal argument may share a name with an instance variable, and inside the method the local name hides the member. Writing this before the name reaches the hidden member, which is what makes an assignment from an argument to a member of the same name work.
  3. The keyword can also be passed to a method, returned from one, and used at the start of a constructor to call another constructor of the same class. It cannot appear in a static method.
Objects as arguments and return values
  1. A class name may be used wherever a type is expected, including the parameter list and the return type of a method.
  2. Passing an object passes a copy of the reference, not a copy of the object. One object exists, with two references to it, so a method that changes a member of the object it was given changes the caller’s object.
  3. A method that assigns an entirely new object to its parameter changes nothing outside itself, because it has redirected only its own copy of the address.
  4. A method whose return type is a class returns a reference. An object created inside such a method survives the method’s end, because the caller now holds a reference to it.
Constructors
  1. A constructor is a member with the same name as the class and no return type, invoked automatically when an object is created, whose purpose is to initialise the instance variables. It closes the gap in which a half-built object could be used.
  2. It may take arguments, may carry any access specifier, and may be overloaded. Declaring void before it does not make it a constructor but an ordinary method that shares the class’s name.
  3. The default constructor is supplied by the compiler, takes no arguments and leaves every instance variable at its default value. It is supplied only when the class declares no constructor of its own.
  4. A non-parameterised constructor is one written by the programmer with an empty parameter list; a parameterised constructor accepts values in the new statement and initialises the object with them in a single act.
  5. A copy constructor takes an object of the same class and copies its members into the object being created. This is not the same as assigning one reference to another, which makes a second name for one object rather than a second object.
  6. Constructor overloading means declaring several constructors differing in the number or types of their arguments; the compiler chooses among them by the arguments in the new statement. No two may have the same parameter list.
Designing a class from a specification
  1. A class specification names the class, its data members with their types and meanings, and each method with what it accepts and what it must do. It states what, not how.
  2. Turning it into a skeleton is a matter of four questions: which entries are data and which are behaviour, which method is the constructor, what each remaining method returns and accepts, and what visibility each member should carry.
  3. The names in the specification are part of the agreement and are used exactly as given. The method is stated in words before any statement is written, and the class is tested at the values where its behaviour changes, not only at comfortable ones.

10.11 Key Terms

  1. Access specifier — a keyword written before a member’s declaration that decides which code may use that member; private, public and protected are the three studied here.
  2. Class — a description, written by the programmer, of the data a thing holds and the operations it can perform; it defines a type and holds no values itself.
  3. Class specification — a written description of a class, naming it and listing its data members with their types and its methods with what each accepts and does, without saying how any of it is to be done.
  4. Class variable — a variable declared inside a class with the keyword static, of which exactly one copy exists for the whole class, shared by every object.
  5. Constructor — a member of a class having the same name as the class and no return type, invoked automatically when an object is created, whose purpose is to initialise the instance variables.
  6. Constructor overloading — declaring several constructors in one class that differ in the number or the types of their arguments, among which the compiler chooses by the arguments in the new statement.
  7. Copy constructor — a constructor that accepts an object of the same class and copies its members into the object being created, producing a second object rather than a second name.
  8. Current object — the object through which the member method now running was called; it is what the keyword this refers to.
  9. Data hiding — arranging a class so that code outside it cannot reach the data directly but must go through the class’s own methods.
  10. Data members — the variables declared inside a class, holding what an object of that class knows.
  11. Default constructor — the argument-less constructor supplied by the compiler when a class declares no constructor of its own, which leaves every instance variable at its default initial value.
  12. Default initial value — the value an instance variable or class variable receives when none is assigned: zero for numeric types, false for boolean, and null for object types.
  13. Encapsulation — keeping data and the methods that act on that data together inside one unit, the class.
  14. Instance — one particular case of a class; the word from which instance variable and instantiation are formed.
  15. Instance variable — a data member declared inside the class and outside all methods, of which every object holds its own separate copy.
  16. Instantiation — the act of creating an object from a class.
  17. ISC — Indian School Certificate.
  18. Lifetime — the period during which a variable actually exists in memory.
  19. Local variable — a variable declared inside a method, a constructor or a block, including a formal argument; it exists only while that block is executing and has no default initial value.
  20. Member methods — the methods declared inside a class, describing what an object of that class can do.
  21. Non-parameterised constructor — a constructor written by the programmer with an empty parameter list, called as new ClassName().
  22. Object — an instance of a class: a region of memory created at run time, holding its own copy of the class’s instance variables and able to perform its member methods.
  23. Parameterised constructor — a constructor that declares arguments, whose values are supplied inside the parentheses of the new statement and used to initialise the object.
  24. Reference variable — a variable whose type is a class and which holds the address of an object, not the object itself.
  25. Scope — the region of a program in which a variable’s name may be used.
  26. Static data member — another name for a class variable: a member belonging to the class rather than to any object.
  27. Static member method — a method declared with static, belonging to the class rather than to any object, called through the class name and able to use static members only.
  28. User defined data type — a type created by the programmer rather than supplied by the language; in Java, a class.
  29. Visibility mode — another name for an access specifier, describing what it controls.

10.12 Points to Ponder

  1. A private data member can still be handed out by a public method that returns it. In what sense, then, is anything actually hidden — and what exactly would a program lose if every class simply made its data public and trusted every programmer who used it to be careful?

  2. A running total kept in a static member is shared by every object of the class, including objects created by parts of the program that know nothing about each other. When does that convenience turn into a liability, and how would you keep separate totals for two counters described by the same class?

  3. Java lets a formal argument carry the same name as an instance variable, hiding it, and then supplies this to undo the hiding. Would the language be better if the clash were simply forbidden, so that hours = hours; could never be written? What would such a rule cost the programmer who has to name arguments?

  4. Assigning one reference to another gives a second name for one object; a copy constructor gives a second object. Some languages make the second behaviour the meaning of =. Which choice would you defend for a class whose objects hold a great deal of data, and what would go wrong under the other one?

  5. The class in section 10.9 kept calculating and displaying in separate methods, and the specification insisted on it. Describe a concrete situation in which combining them into a single method would cost you something real — and one in which it genuinely would not matter.

  6. A constructor makes it impossible to use an object before it has been initialised. Does it make it impossible to use an object that has been initialised badly? If not, what else must a class do, and where in the class should that work live?

10.13 Objective Questions

  1. A data member declared without any access specifier can be used by:
  1. any class anywhere in the program
  2. only the class in which it is declared
  3. any class in the same package
  4. only classes derived from it [1 mark]
  1. Which of the following is true of a constructor?
  1. Its return type must be void
  2. It has no return type at all
  3. Its return type must be the class name
  4. It may return any type the programmer chooses [1 mark]
  1. After the statement Fee f = new Fee(); the variable f holds:
  1. the object itself
  2. a copy of every instance variable of the object
  3. the address of the object
  4. the name of the class [1 mark]
  1. A static member method may use directly:
  1. an instance variable of its class
  2. a static data member of its class
  3. the keyword this
  4. an instance method of its class [1 mark]
  1. Memory for the instance variables of an object is set aside:
  1. when the class is compiled
  2. when a reference variable of that class is declared
  3. when the new operator is executed
  4. when a member method is first called [1 mark]
  1. Assertion (A): A local variable must be assigned a value before it can be read. Reason (R): Local variables are not given any default initial value. Based on the two statements, choose the correct option:
  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 mark]
  1. Assertion (A): Assigning one object reference to another produces two independent objects. Reason (R): The new operator sets aside memory for an object at run time. Based on the two statements, choose the correct option:
  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 mark]
  1. Match each item in column A with the statement in column B that describes it.
Column A Column B
a. Class variable i. Exists only while the method in which it is declared is running
b. Local variable ii. Accepts an object of the same class and copies its members
c. Copy constructor iii. Has exactly one copy for the whole class
d. this iv. Refers to the object through which the method was called

[1 mark]

  1. Fill in the blank: A variable declared inside a class with the keyword ______ has a single copy shared by every object of that class. [1 mark]

  2. Fill in the blank: The constructor supplied by the compiler when a class declares no constructor of its own is called the ______ constructor. [1 mark]

  3. State whether true or false: A class reserves memory for its data members as soon as it is compiled. [1 mark]

10.14 Check Your Concepts

  1. Define an object, and state one way in which an object differs from the class it belongs to. [2 marks]

  2. What is meant by instantiation? Write the Java statement that instantiates a class named Fee and stores the reference in a variable f. [2 marks]

  3. State any two features of a constructor that distinguish it from an ordinary member method. [2 marks]

  4. Differentiate between an instance variable and a class variable, mentioning the number of copies of each and the period for which each exists. [3 marks]

  5. Differentiate between a default constructor and a non-parameterised constructor. [3 marks]

  6. Give reasons why a static member method cannot use an instance variable of its class directly, while an ordinary member method may freely use a static data member. [3 marks]

  7. Explain, with a short example of your own, how the keyword this resolves the clash that arises when a formal argument of a method carries the same name as an instance variable. [4 marks]

  8. A class Book declares only the constructor Book(String t, double p). State with reasons what the compiler does with the statement Book b = new Book();, and explain what must be added to the class so that both forms of creation work. [4 marks]

  9. Explain the difference between passing a primitive value to a method and passing an object to a method. Illustrate with statements of your own what the calling code sees after the method has changed (i) the primitive argument and (ii) a data member of the object argument. [6 marks]

  10. Compare a copy constructor with the assignment of one object reference to another. Write the statements needed for each, state how many objects exist in each case, and explain what happens to the second name when the first object is changed. [6 marks]

10.15 Output & Debugging

  1. Study the class below and answer the questions that follow.
class Ticket
{
    private int id;
    private static int made = 0;

    Ticket()
    {
        made = made + 1;
        id = made;
    }

    void show()
    {
        System.out.println("Ticket " + id + " of " + made);
    }

    public static void main(String args[])
    {
        Ticket a = new Ticket();
        Ticket b = new Ticket();
        Ticket c = new Ticket();

        a.show();
        c.show();
    }
}
  1. Write the exact output of the program.
  2. Explain why the number printed after the word “of” is the same in both lines, although the number after “Ticket” is not. [3 marks]
  1. The class below does not compile.
class Area
{
    int side;

    void set(int s)
    {
        side = s;
    }

    int square()
    {
        return side * side;
    }

    public static void main(String args[])
    {
        set(4);
        System.out.println(square());
    }
}
  1. Name the error and state the reason for it.
  2. Rewrite main() so that the class compiles and prints 16, changing nothing else. [3 marks]
  1. Study the class below and answer the questions that follow.
class Box
{
    int n;

    public static void main(String args[])
    {
        Box p = new Box();
        Box q = new Box();

        p.n = 5;
        q = p;
        q.n = 9;

        System.out.println(p.n + " " + q.n);
    }
}
  1. Write the output of the program.
  2. State how many objects were created and how many of them are still referred to by a variable when the last statement runs. [3 marks]
  1. Study the class below and answer the questions that follow.
class Note
{
    private int n;

    Note()
    {
        n = 1;
    }

    Note(int n)
    {
        this.n = n;
    }

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

    public static void main(String args[])
    {
        Note x = new Note();
        Note y = new Note(7);

        x.show();
        y.show();
    }
}
  1. Write the output of the program, and name the constructor that runs for each object.
  2. State what happens to the program if the first constructor is deleted and main() is left unchanged. [4 marks]

10.16 Programming Practice

  1. Design a class Cuboid with the following members.
Member Type or return type Description
length, breadth, height double The three dimensions
Cuboid() — Constructor setting each dimension to 1.0
Cuboid(double l, double b, double h) — Constructor assigning the three dimensions
volume() double Returns the volume of the cuboid
bigger(Cuboid c) boolean Returns true if the current object has the greater volume, and false otherwise
display() void Displays the three dimensions and the volume

Submit the complete class with a main() method that creates one object with each constructor, displays both, and prints a message saying which is larger. Include a variable description table. [6 marks]

  1. A school science exhibition sells tickets at its gate. Design a class Visitor with the following members.
Member Type or return type Description
name String Name of the visitor
tickets int Number of tickets bought by this visitor
count static int Number of visitors recorded so far
sold static int Total number of tickets sold so far
Visitor(String n, int t) — Constructor assigning the name and tickets, and updating both static members
display() void Displays this visitor’s name and tickets
report() static void Displays the number of visitors and the total tickets sold

Submit the complete class with a main() method that records three visitors of your choice, displays each of them, and then calls report() without using any object. State clearly which members are static and why. [6 marks]

  1. Design a class Fees that calculates a coaching fee from the number of months paid for, using the rates below.
Months paid for Rate
1 to 3 Rs. 500 for each month
4 to 8 Rs. 450 for each month
More than 8 Rs. 400 for each month

The class must have private data members for the student’s name, the number of months and the amount; a parameterised constructor that assigns the name and the months and sets the amount to zero; a copy constructor; a method compute() that calculates the amount; and a method display() that shows the name, the months and the amount.

Submit the algorithm for compute() in pseudocode, then the complete class with a main() method that creates one object, computes and displays it, then creates a second object as a copy of the first and displays that too. Test your class with 6 months, and then with the unseen input of 12 months. [6 marks]

  1. A class Length stores a distance as private members km (int) and m (int), where 1000 metres make one kilometre, and already has a constructor, an input method and a display method written for you.

Write only the method Length sum(Length d), which adds the distance held by the object passed to it to the distance held by the current object, and returns a new Length object holding the total with the metres correctly carried into kilometres. Neither object passed in nor the current object may be altered. State how the method would be called from main(). [4 marks]