Chapter 7
Classes and objects
So far you had single variables and arrays. But a bank account consists of an owner and a balance, and it can take money. A class bundles such data with the matching methods. It's the blueprint; with new you build as many objects from it as you like.
In the tasks, every class is in its own file named after it, e.g. Account.java. In the examples here, everything is in one file so you can see it at a glance. Then only Main may be public.
Fields, constructor, methods
- Fields are the data of each object. They are
private: only the class itself can access them. From outside, that goes through methods likegetBalance(), the getters. This is called encapsulation. - The constructor has the name of the class, no return type, and runs on
new Account("Ada"). It fills the fields. this.owneris the object's field,owneralone is the parameter. If both have the same name, you needthis.- Methods without
staticwork with the fields of the object you call them on:ada.deposit(50)only changes Ada's account. toString()defines what an object looks like as text.println(ada)calls it automatically.
final in front of a field means: it's set once in the constructor and never changed afterwards.
class Account {
private final String owner;
private double balance;
public Account(String owner) {
this.owner = owner;
this.balance = 0;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance;
}
public String toString() {
return owner + ": " + balance + " €";
}
}
public class Main {
public static void main(String[] args) {
Account ada = new Account("Ada");
Account bob = new Account("Bob");
ada.deposit(50);
ada.deposit(-10);
bob.deposit(20);
System.out.println(ada);
System.out.println(bob);
System.out.println("Ada has " + ada.getBalance());
}
}static and constants
A field without static exists once in every object. A field with static exists only once for the whole class; all objects share it. You can use it, for example, to count how many objects there are. You call a static method through the class name: Ticket.issued(). It has no this and so can't read normal fields. That's why everything was static so far: main runs without any object.
static final makes a constant, written in capitals: public static final int MAX = 7;.
A class can have several constructors. With this(...) in the first line, one calls the other, so the logic is in one place only:
public Duration(int minutes, int seconds) {
this(minutes * 60 + seconds);
}class Ticket {
public static final String OFFICE = "Town hall";
private static int counter = 0;
private final int number;
public Ticket() {
counter++;
this.number = counter;
}
public int getNumber() {
return number;
}
public static int issued() {
return counter;
}
}
public class Main {
public static void main(String[] args) {
Ticket a = new Ticket();
Ticket b = new Ticket();
Ticket c = new Ticket();
System.out.println(Ticket.OFFICE);
System.out.println("a: " + a.getNumber());
System.out.println("c: " + c.getNumber());
System.out.println("Issued: " + Ticket.issued());
}
}Records
For classes that only hold data together, there's a short form: record Point(int x, int y) { }. This line creates private final fields, a constructor, the getters x() and y() (without get), a toString() like Point[x=3, y=4] and an equals that compares the values.
A record can't be changed. If something should "change", a method returns a new record, like moved in the example. Math.abs(n) returns the absolute value of a number, i.e. without its sign.
record Point(int x, int y) {
public int distance(Point p) {
return Math.abs(x - p.x()) + Math.abs(y - p.y());
}
public Point moved(int dx, int dy) {
return new Point(x + dx, y + dy);
}
}
public class Main {
public static void main(String[] args) {
Point a = new Point(3, 4);
Point b = a.moved(1, -2);
System.out.println(a);
System.out.println(b);
System.out.println("x of b: " + b.x());
System.out.println("Distance: " + a.distance(b));
System.out.println(a.equals(new Point(3, 4)));
System.out.println(a == new Point(3, 4));
}
}Common mistakes
Field shadowed
If a parameter or local variable has the same name as a field, it shadows it. Both lines look right and don't change the field:
public Player(String name) { name = name; // parameter assigned to itself } public void addPoints(int points) { int score = this.score + points; // new local variable }Correct is
this.name = name;andscore = score + points;withoutint.Comparing objects with ==
==checks whether it's the same object. Two points with equal values are still two objects, as the last line of the record example shows. For equal values there'sequals, automatically for records.Forgetting toString
Without your own
toString(),println(book)prints something likeBook@1b6d3586. The method must be called exactlypublic String toString().Reading a field from a static method
A
staticmethod has no object and therefore nothis. If you access a normal field there, the compiler reportsnon-static variable cannot be referenced from a static context.Empty slots in an object array
new Measurement[7]creates seven empty slots, allnull. If you call a method on one, the program stops withNullPointerException. Only loop over the slots you've already filled.