SEN1001 · Week 10 · Introduction to Classes and Objects

Classes and objects: fields, methods, get/set

A class is a template, an object is an instance made from that template. Creating objects with new, instance variables, the dot operator, private fields and get/set methods, reference variables and null. The biggest topic of the final starts here.

classobjectinstanceinstantiationnewinstance variable (field)instance methoddot operatorreference variablenullNullPointerExceptionaccess modifierprivatepublicencapsulationget method (accessor)set method (mutator)validation

Until now you wrote everything inside main and in static methods. Real programs, however, are made of objects: accounts in a banking application, players in a game, students in a school system. Every object has its own data (fields) and its own behavior (methods). This week you will write your first classes. On the final, this topic comes as a writing question: “write a class with these fields and methods, create two objects in main”.

Golden rules:

  1. A class is a template, an object is an instance. From a Dog class you can make as many dog objects as you like.
  2. Every object has its own fields. Changing one does not affect another.
  3. A variable holds not the object but the object’s reference. b = a does not create a new object.
  4. Fields private, access through public methods (get/set).
  5. Instance methods are not static and are called on an object.

The first class

class Dog {
    String name;     // instance variables (instance variables / fields)
    int age;

    void bark() {    // instance method (instance method): NO static
        System.out.println(name + " (" + age + ") says Hav!");
    }
}

A class defines a type. By itself it runs nothing; there is no main in it. The code that uses it is in the main of another class:

Dog d1 = new Dog();          // create a new object (instantiation)
d1.name = "Karabas";
d1.age = 3;
d1.bark();
Dog d2 = new Dog();
System.out.println(d2.name + " " + d2.age);
d2.name = "Pamuk";
d2.bark();
d1.bark();
Karabas (3) says Hav!
null 0
Pamuk (0) says Hav!
Karabas (3) says Hav!

Observations:

  • new Dog() creates a new Dog object in memory and returns its address. d1 holds this address.
  • With the dot operator you access the object’s field and method: d1.name, d1.bark().
  • The name inside bark() is the field of the object that called the method. d1.bark() prints Karabas, d2.bark() prints Pamuk.
  • Before d2 is given values, its fields are at their default values: String null, int 0. (Local variables inside a method have no such default.)

A file can contain several classes, but only one can be public, and the file name is its name. In real projects each class goes in its own file: Dog.java, Main.java.

Encapsulation: private fields, get and set

If the fields were public, anyone could write acc.balance = -5000;. To prevent this, the fields are made private and controlled public methods are exposed. This is called encapsulation.

class Account {
    private String owner;
    private double balance;

    public String getOwner() { return owner; }                     // get (accessor)
    public void setOwner(String newOwner) { owner = newOwner; }    // set (mutator)
    public double getBalance() { return balance; }                 // NO set for balance

    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }

    public void withdraw(double amount) {
        if (amount <= balance) balance -= amount;
        else System.out.println("Insufficient funds");
    }
}
Account acc = new Account();
acc.setOwner("Deniz");
acc.deposit(500);
acc.withdraw(200);
acc.withdraw(1000);
System.out.println(acc.getOwner() + " " + acc.getBalance());
acc.deposit(-50);
System.out.println(acc.getBalance());
Insufficient funds
Deniz 300.0
300.0

The balance can only change through deposit and withdraw, and both check the rules. If you try to access it directly from outside:

Acc a = new Acc();
a.balance = 1000;
Main.java:7: error: balance has private access in Acc
Access modifierWho can access?
privateonly inside the same class
publiceverywhere
(none)classes in the same package

get/set naming

Fieldgetset
private String namepublic String getName()public void setName(String n)
private int agepublic int getAge()public void setAge(int a)
private boolean activepublic boolean isActive()public void setActive(boolean a)

The return type of a get method is the type of the field, and it has no parameters. A set method is void, and its parameter has the type of the field. You do not have to write a set for every field: for a field like the balance that should not be changed directly, no set is written.

Validation

class Thermostat {
    private double celsius;

    public void setCelsius(double value) {
        if (value >= 5 && value <= 35) celsius = value;    // out of range is rejected
    }
    public double getCelsius() { return celsius; }
    public double getFahrenheit() { return celsius * 9 / 5 + 32; }
}
// in main:
Thermostat t = new Thermostat();
t.setCelsius(45);
System.out.println(t.getCelsius());
t.setCelsius(22.5);
System.out.println(t.getCelsius() + " " + t.getFahrenheit());
0.0
22.5 72.5

45 was rejected, the field stayed at the default 0.0. getFahrenheit is not a field, it is a value computed from a field; there is no need to store it separately.

Reference variables

A primitive variable holds the value itself. An object variable holds the object’s reference (its place in memory).

Account a = new Account();
a.deposit(100);
Account b = a;              // the reference was copied, not the object
b.deposit(50);
System.out.println(a.getBalance() + " " + b.getBalance());
System.out.println(a == b);
Account c = new Account();
c.deposit(150);
System.out.println(a == c);
150.0 150.0
true
false
a ──┐
    ├──► [Account: balance 150.0]
b ──┘
c ─────► [Account: balance 150.0]     another object

With objects, == looks not at the contents but at whether it is the same object. The balances of a and c are equal but they are different objects: false. (This is also why we use equals with Strings.)

null

The value of a reference that points to no object is null. Calling a method through a null reference crashes the program:

Account n = null;
n.deposit(10);
NullPointerException

The code compiles, because the compiler only looks at the type (Account has deposit). The error appears at run time.

The difference between static and instance methods

main is static; it does not belong to an object. Instance methods, on the other hand, belong to an object. That is why, from main, an instance method is called on an object:

Acc a = new Acc();
System.out.println(Acc.getBalance());     // with the class name: WRONG
Main2.java:8: error: non-static method getBalance() cannot be referenced from a static context

The correct way is a.getBalance(). Whose balance? a’s. The class does not have a single balance; each object has its own. You will see static fields, which all objects share, in week 12.

static methodinstance method
How it is calledMath.sqrt(4), ClassName.m()object.m()
Is an object neededNoYes
Access to fieldsCannot access instance fields directlyAccesses the fields of its own object
ExampleisPrime(int n), maindeposit, getBalance

Worked example: a class writing question

Question: “Write a Rectangle class: private int width and height, set methods, getWidth(), methods that return the area and the perimeter.”

class Rectangle {
    private int width, height;
    public void setWidth(int w) { width = w; }
    public void setHeight(int h) { height = h; }
    public int getWidth() { return width; }
    public int area() { return width * height; }
    public int perimeter() { return 2 * (width + height); }
}

Grading is usually like this: the private declaration of the fields, the correct header of each method (the return type!), the correct formula in the body, and creating an object with new in main and calling the methods with a dot. For a 3 by 4 rectangle the area is 12 and the perimeter is 14.

Common mistakes

Wrong ideaThe truth
Dog d; creates an objectIt only declares a reference; the object comes with new Dog()
An instance method is written staticInstance methods are not static
Account.getBalance()On an object: acc.getBalance()
Fields are undefined at the start, it does not compileThey get a default value: 0, null, false
Two objects share the same fieldsEach object has its own copy
b = a; copies the objectIt copies the reference; the same object
a == b compares contentsIt checks whether it is the same object
Make the fields public, it is easierprivate + get/set, for validation
A get method is voidIt returns the type of the field
A set method returns a valueUsually void
A method call on a null reference does not compileIt compiles, NullPointerException while running

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

Counter has a private int count, increment() adds 1 to it and getCount() returns it. What is printed?

Counter c1 = new Counter();
Counter c2 = new Counter();
c1.increment();
c1.increment();
c2.increment();
System.out.println(c1.getCount() + " " + c2.getCount());
Show answer
2 1

Two separate news, two separate objects. Each object has its own count field. c1's counter is 2, c2's is 1.

Question 2medium

Using the same Counter class, what is printed?

Counter c3 = new Counter();
Counter c4 = c3;
c3.increment();
c4.increment();
c4.increment();
System.out.println(c3.getCount());
Show answer
3

c4 = c3 does not create a new object; both point to the same object. The three increment calls increase the same count: 3.

Question 3medium

deposit adds the amount only if it is positive; withdraw subtracts only if the amount is not more than the balance, otherwise it prints Insufficient funds. What is printed?

Account a = new Account();
a.deposit(300);
a.withdraw(100);
a.withdraw(250);
a.deposit(-20);
System.out.println(a.getBalance());
Show answer
Insufficient funds
200.0

Deposit 300 → 300. Withdraw 100 → 200. 250 > 200 → not withdrawn, the message is printed. -20 is not positive → ignored. Because balance is a double, 200.0 is printed.

Question 4easy

Dog has fields String name; and int age; with no initial values. What is printed?

Dog d = new Dog();
System.out.println(d.name + " " + d.age);
Show answer
null 0

Instance variables, unlike local variables, get a default value: object references (String) get null, int gets 0. That is why there is no compile error.

Question 5medium

What is printed?

class Box {
    private int size = 1;
    public void setSize(int s) { if (s > 0) size = s; }
    public int getSize() { return size; }
    public int volume() { return size * size * size; }
}
// in main:
Box bx = new Box();
bx.setSize(4);
bx.setSize(-2);
System.out.println(bx.getSize() + " " + bx.volume());
Show answer
4 64

The set method does validation: -2 is invalid, the field does not change. size stays 4, the volume is 4 * 4 * 4 = 64. This is the real benefit of a private field: an invalid value cannot get in.

Question 6hard

Using Account (deposit adds positive amounts), what is printed?

Account p = new Account();
Account q = new Account();
p.deposit(100);
q = p;
q.deposit(25);
p = new Account();
p.deposit(5);
System.out.println(p.getBalance() + " " + q.getBalance());
Show answer
5.0 125.0

After q = p both point to the first account; 100 + 25 = 125. Then p is redirected to a new account (q is still on the old one) and 5 is deposited. The empty object that q originally pointed to is no longer pointed to by anyone.

Question 7easy

Rectangle has private int width and height, setters, getWidth(), area() and perimeter(). What is printed?

Rectangle r = new Rectangle();
r.setWidth(3);
r.setHeight(4);
System.out.println(r.area() + " " + r.perimeter());
r.setWidth(r.getWidth() * 2);
System.out.println(r.area());
Show answer
12 14
24

The area is 3 * 4 = 12, the perimeter is 2 * (3 + 4) = 14. The width is read with get and set to twice its value: 6. The new area is 6 * 4 = 24.

Question 8easy

What is printed?

class Light {
    private boolean on;
    public void toggle() { on = !on; }
    public boolean isOn() { return on; }
}
// in main:
Light l = new Light();
l.toggle();
l.toggle();
l.toggle();
System.out.println(l.isOn());
Show answer
true

A boolean field starts as false. Each toggle flips it: true, false, true. By convention, boolean getters start with is: isOn().

Question 9medium

balance is declared private in class Acc. Which statement in main (another class) does not compile, and why?

  1. Acc a = new Acc();
  2. a.balance = 1000;
  3. System.out.println(a.getBalance());
  4. a.deposit(50);
Show answer
b

A private field can be accessed only from inside its own class. javac: balance has private access in Acc. Access from outside is done through public methods (getBalance, deposit).

Question 10medium

What happens when this code runs?

Account n = null;
n.deposit(10);
Show answer
NullPointerException at runtime

null means the reference points to no object. Since the compiler looks at the type, the code compiles, but when you call a method of an object that does not exist while running, a NullPointerException is thrown.

Question 11medium

Write the withdraw method of Account (private double balance): subtract amount only if it is positive and not more than the balance; otherwise print Insufficient funds.

Show answer
if (amount > 0 && amount <= balance) balance -= amount; else System.out.println("Insufficient funds");

An instance method is not static; it uses the object's field directly.public void withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; } else { System.out.println("Insufficient funds"); }}The example version on this page checks only amount <= balance; amount > 0 was added to block negative withdrawals too.

Question 12hard

Write a class Thermostat with a private double celsius, a setter that accepts only values from 5 to 35 (inclusive), a getter, and a method getFahrenheit().

Show answer
if (value >= 5 && value <= 35) celsius = value; · return celsius * 9 / 5 + 32;

class Thermostat { private double celsius; public void setCelsius(double value) { if (value >= 5 && value <= 35) celsius = value; } public double getCelsius() { return celsius; } public double getFahrenheit() { return celsius * 9 / 5 + 32; }}Test: setCelsius(45) is rejected, getCelsius() → 0.0 (the default). setCelsius(22.5) → 22.5, getFahrenheit() → 72.5. Because celsius is a double, * 9 / 5 does not fall into the int division trap.

Verification: All outputs were run with JDK 26 (verify/SEN1001/W10.java; the classes Dog, Account, Thermostat, Counter, Box, Rectangle and Light are in the same file). The answer to the withdraw writing question was run as is in the Account2 class in W11.java. The private access and static context errors were obtained with javac under verify/SEN1001/err/priv/.

Review card

Class = template object = an instance made with new Dog d = new Dog(); d is a REFERENCE (the address of the object), not the object itself Instance variable (field): inside the class, outside methods. Every object has its OWN copy Field defaults: int 0, double 0.0, boolean false, String/object null (not for local variables!) An instance method is NOT static: d.bark() it cannot be called from static main as Class.method() Dot operator: object.field, object.method() private: only from its own class public: from anywhere Encapsulation: fields private, access through public get/set getX() returns a value setX(v) assigns the value (+ validation) isX() for boolean b = a → the same object, b.method() changes a too a == b is it the same object? A reference pointing to nothing: null → a method call gives NullPointerException One public class per file, its name is the file name; other classes without public can be in the same file