Classes: fields, constructors and methods
A type of your own that carries data and the methods that work on it, built with a constructor and used through objects.
From methods that take data to data that carries methods
Six chapters of static methods kept every value separate: a name here, a number there, both handed to a method as arguments. A class turns that around. It gathers the values that belong together and keeps the methods that work on them alongside, so a single name — a book, an account, a row — holds everything about one thing.
This is the change promised in the methods chapter. A method that belongs to an object is no longer static: it works on that object. Java still has static methods, and main is one of them, but the work of a program moves into objects.
Fields, and the constructor that fills them
The variables inside a class are its fields. A Book has a title and a pages, and each object gets its own copy of both. Book(String title, int pages) is the constructor: it shares the class name and no other method does, and it runs exactly once, when new is used.
Inside the constructor, this.title = title means the field on the left and the parameter on the right. The word this is the current object, and it is the clearest way to say which of the two identical names you mean.
Two ways to build the same class
This example puts class Book at the top of the file and the public Main underneath. One file may hold several classes; only the public one has to match the file name, and that is why Main stays where it is.
private keeps a field out of reach of the rest of the program, so first.title would not compile from main. The methods of the class can still read it. Change a field later and only the class needs to change, which is the point of drawing the line.
An object is fields with methods attached
new Book(...) reserves a block for the fields, runs the constructor to fill them, and hands back a reference. The variable holds that reference, not the object itself. Two variables can point at one object, and a change through either is visible through both.
A class is the recipe; an object is one cake. The fields are per object, while a static field would be shared by the class. Keeping fields private and methods public is how the class controls what the rest of the program may do.
Constructors, overloads and toString
A constructor can be overloaded like any method: one takes a title and pages, another takes only a title and supplies a default page count. this(...) calls another constructor of the same class, and it must be the first line.
toString() is inherited from Object and is called whenever an object is printed or joined to a string. Overriding it turns an address into a sentence. Print the object in a test and the difference is immediate: one line names the class and a number, the other names the book. equals is the other method worth overriding when two objects should count as the same value.
equals and hashCode travel together
Overriding equals says when two objects count as the same value. Overriding hashCode says which bucket that value belongs in, and the two have to agree: equal objects must return the same hash. A class that overrides one and not the other compiles, and then behaves strangely in exactly the places that use hashing: as a HashMap key, in a HashSet, or in a contains call.
The rule is easy to state and easy to break. If two books with the same title and pages are equal, they must also hash alike, or a map will store both under different buckets and then fail to find either by an equal key. Let Objects.hash(title, pages) write the hash, and change the pair together rather than one at a time.
A class with state, and two objects built from it
class Counter {
private int count; // a field: one per object
Counter(int start) { // the constructor
this.count = start;
}
void add() { // a method on the object
count++;
}
int value() {
return count;
}
}
Counter a = new Counter(0); // an object
Counter b = new Counter(10); // a second, separate one
a.add();
a.add();
b.add();
System.out.println(a.value()); // 2
System.out.println(b.value()); // 11A class, and two books in it
Press Run and check that both lines describe a different object. Then add a third book of your own, and add a method to the class that answers whether the book has more than 300 pages.
Three class mistakes: forgetting new and trying to call a method on the class name, writing this.title = title when the parameter is named differently, and comparing objects with == when you mean equal contents. The first is a compile error, the second silently assigns the wrong thing, and the third compares references.
Try these next
- Add a constructor to
Bookthat takes only a title and sets a default page count. - Add a
toStringmethod to a class of your own and print an object without calling it by name. - Build two objects with the same field values and compare them with
==and with a hand-writtenequals.
An account that guards its own balance
Press Run and follow the balance through the deposit and the two withdrawals. Then try to take out more than the balance from main, and explain which method said no and how.
Read a constructor call as a sentence: new Book("The Hobbit", 310) builds one book and hands back the object. Store it in a variable and the object keeps its state for as long as you need it.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
When does a constructor run?
