Classes and Objects

By the Syncfusion DevTutorials team · Last updated

Create your own types with classes, make objects with new, use fields, methods, this and constructors, control access with modifiers, and see objects on the stack and heap.

Think about a house plan drawn by an architect.

The plan shows where the rooms, doors and windows go. But you cannot live in a plan. A builder uses it to build real houses. One plan can produce many houses, and each house can have its own paint colour and its own family.

In Java, a class is the plan. An object is a real house built from it.

In simple words: a class describes what something has and what it can do, and an object is one real thing made from that description.

What You Will Learn

In this lesson, you will learn:

  1. What classes and objects are, and how they relate.
  2. How to declare a class and create objects with new.
  3. How object references work.
  4. How to give a class fields and instance methods.
  5. What the this keyword means.
  6. How constructors set up a new object, including overloading and chaining.
  7. How access modifiers control who can use a class's members.
  8. Where objects and variables live in memory: the stack and the heap.

Start With a Working Example

Press Run.

One class, two separate objects

public class Main {
    public static void main(String[] args) {
        Car first = new Car("Red", 2020);
        Car second = new Car("Blue", 2024);

        first.describe();
        second.describe();
    }
}

class Car {
    String colour;
    int year;

    Car(String colour, int year) {
        this.colour = colour;
        this.year = year;
    }

    void describe() {
        System.out.println("A " + colour + " car from " + year);
    }
}

Expected output:

A Red car from 2020
A Blue car from 2024

Car is the class. first and second are two objects made from it. Each object keeps its own colour and year.

Try This

Create a third car, new Car("Green", 2018), and call describe() on it. You did not have to change the Car class at all.

Introduction to Classes

So far, you have used built-in types like int, String and arrays. Real programs deal with things those types cannot describe on their own: a student, a bank account, an order.

A class lets you make your own type. It groups related data and actions under one name.

  • The data are called fields. A student has a name and a roll number.
  • The actions are called methods. A student can enrol in a course.

This style of programming is called object-oriented programming (OOP). You build programs out of objects that each look after their own data.

Classes and Objects

A class is a blueprint. It describes what every object of that type will have.

An object is one real thing made from the class. Making an object is called instantiation, and each object is an instance of its class.

ClassObjects of that class
StudentAsha, Ravi, Meena
Caryour red car, my blue car
BankAccountaccount 1001, account 1002

Think of a cookie cutter. The cutter is the class. Each cookie is an object. All the cookies have the same shape, but you can decorate each one differently.

Class Declaration

You declare a class with the class keyword, a name, and a body in curly braces.

class Student {
    // fields
    // constructors
    // methods
}
  • Class names use PascalCase: Student, BankAccount, OrderItem.
  • A file can hold many classes, but only one can be public, and its name must match the file name.

In this course, every runnable cell lives in a file called Main.java. So only Main is public. Other classes in the same cell, like Car, have no public keyword.

Object Creation

You create an object in three steps, usually written on one line:

Student s = new Student();
  1. Declare a variable of the class type: Student s.
  2. Create the object with new Student().
  3. Assign the new object to the variable with =.

After that, you use the dot . to reach the object's fields and methods: s.name, s.enrol().

new Keyword

The new keyword does three jobs:

  1. It finds space in memory for the new object.
  2. It runs the class's constructor to set the object up.
  3. It returns a reference to the new object.

Every call to new makes a brand-new, separate object.

Object References

A class-type variable does not hold the object itself. It holds a reference, which is like the address of the object in memory.

Think of a house address written on a card. The card is not the house. If you copy the card, both copies lead to the same house.

Two references can point to the same object

public class Main {
    public static void main(String[] args) {
        Account a = new Account();
        a.balance = 500;

        Account b = a;
        b.balance = 900;

        Account c = new Account();
        c.balance = 500;

        System.out.println("a: " + a.balance);
        System.out.println("b: " + b.balance);
        System.out.println("c: " + c.balance);
        System.out.println("a == b? " + (a == b));
        System.out.println("a == c? " + (a == c));
    }
}

class Account {
    int balance;
}

Expected output:

a: 900
b: 900
c: 500
a == b? true
a == c? false

Account b = a; does not copy the object. It copies the reference. So a and b point to the same account, and changing b.balance also changes what a sees.

c was made with its own new, so it is a separate object.

A reference that points to no object holds null. Using a null reference, like x.balance when x is null, stops the program with a NullPointerException.

Fields

A field is a variable that belongs to a class. Fields hold an object's data.

Instance Fields

An instance field belongs to each object separately. Every object gets its own copy.

If you have 30 Student objects, there are 30 separate name fields, one in each object.

Field Initialization

A field can get its starting value in three ways:

  • Default value. If you give no value, Java uses 0, 0.0, false or null, depending on the type.
  • At the declaration. int lives = 3; gives every new object 3 lives.
  • In a constructor. The constructor sets values that differ from object to object.

Default values and declared starting values

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

        System.out.println("name: " + p.name);
        System.out.println("score: " + p.score);
        System.out.println("isActive: " + p.isActive);
        System.out.println("lives: " + p.lives);
        System.out.println("level: " + p.level);
    }
}

class Player {
    String name;
    int score;
    boolean isActive;
    int lives = 3;
    String level = "Beginner";
}

Expected output:

name: null
score: 0
isActive: false
lives: 3
level: Beginner

name, score and isActive were not given a value, so they hold the defaults. lives and level were given starting values in the class.

Fields get default values. Local variables inside a method do not. That is why Java complains when you use an uninitialized local variable, but not an uninitialized field.

Local variables inside a method do not get default values. Only fields do. That is why int count; count++; inside a method does not compile, while an int count; field simply starts at 0.

Instance Methods

An instance method is a method that belongs to an object. It has no static keyword, and it can read and change that object's fields.

You call it on an object: cart.addItem(250).

Methods change the object they are called on

public class Main {
    public static void main(String[] args) {
        Cart mine = new Cart();
        Cart yours = new Cart();

        mine.addItem(250);
        mine.addItem(120);
        yours.addItem(999);

        mine.showTotal();
        yours.showTotal();
    }
}

class Cart {
    int total = 0;
    int items = 0;

    void addItem(int price) {
        total += price;
        items++;
    }

    void showTotal() {
        System.out.println(items + " item(s), total " + total);
    }
}

Expected output:

2 item(s), total 370
1 item(s), total 999

mine.addItem(250) changes only mine. The yours cart keeps its own total and items.

this Keyword

Inside a method or constructor, this means "the current object", the object the method was called on.

The most common use is to tell a field apart from a parameter with the same name.

class Student {
    String name;

    Student(String name) {
        this.name = name;   // field = parameter
    }
}

this.name is the field. name on its own is the parameter.

Without this, name = name; would just copy the parameter into itself. The field would stay null.

Without this, the field is never set

public class Main {
    public static void main(String[] args) {
        WithThis good = new WithThis("Asha");
        WithoutThis bad = new WithoutThis("Asha");

        System.out.println("With this: " + good.name);
        System.out.println("Without this: " + bad.name);
    }
}

class WithThis {
    String name;
    WithThis(String name) {
        this.name = name;
    }
}

class WithoutThis {
    String name;
    WithoutThis(String name) {
        name = name;
    }
}

Expected output:

With this: Asha
Without this: null

In WithoutThis, both sides of name = name; mean the parameter. The field was never touched.

Constructors

A constructor is a special method that runs automatically when an object is created with new. Its job is to set up the new object.

A constructor:

  • has the same name as the class;
  • has no return type, not even void.

Default Constructor

If you write no constructor at all, Java adds an empty one for you. This is the default constructor. It takes no parameters and leaves every field at its default or declared value.

That is why new Player() worked earlier, even though Player had no constructor.

Once you write any constructor yourself, Java stops adding the default one.

Parameterized Constructor

A parameterized constructor takes values, so each object can start with different data.

Constructor Overloading

A class can have several constructors, as long as their parameters differ. This is constructor overloading, just like method overloading.

Constructor Chaining

One constructor can call another constructor of the same class with this(...). This is constructor chaining.

It lets you keep the setup code in one constructor, and have the others pass their values to it.

this(...) must be the first line of the constructor.

Three constructors, one place that does the work

public class Main {
    public static void main(String[] args) {
        Book a = new Book();
        Book b = new Book("Wings of Fire");
        Book c = new Book("Malgudi Days", 250);

        a.show();
        b.show();
        c.show();
    }
}

class Book {
    String title;
    int price;

    Book() {
        this("Untitled");
    }

    Book(String title) {
        this(title, 100);
    }

    Book(String title, int price) {
        this.title = title;
        this.price = price;
        System.out.println("Created: " + title);
    }

    void show() {
        System.out.println(title + " costs " + price);
    }
}

Expected output:

Created: Untitled
Created: Wings of Fire
Created: Malgudi Days
Untitled costs 100
Wings of Fire costs 100
Malgudi Days costs 250

new Book() calls the first constructor. It passes "Untitled" to the second one, which passes 100 to the third. Only the third constructor actually sets the fields.

So "Created" prints once per book, from one place.

Constructor typeParametersWritten by
Default constructorNoneJava, only if you write no constructor
No-argument constructorNoneYou
Parameterized constructorOne or moreYou

Object Initialization

When you write new Book("Malgudi Days", 250), Java sets up the object in this order:

  1. Memory is set aside, and every field gets its default value (0, null, false).
  2. Fields with a declared value, like int lives = 3;, get that value.
  3. The constructor body runs.
  4. new returns a reference to the finished object.

So a constructor can always rely on declared field values already being in place.

Declared values are set before the constructor runs

public class Main {
    public static void main(String[] args) {
        Ticket t = new Ticket(4);
        System.out.println("Seats: " + t.seats + ", total: " + t.total);
    }
}

class Ticket {
    int pricePerSeat = 150;
    int seats;
    int total;

    Ticket(int seats) {
        System.out.println("Price already set to " + pricePerSeat);
        this.seats = seats;
        this.total = seats * pricePerSeat;
    }
}

Expected output:

Price already set to 150
Seats: 4, total: 600

pricePerSeat was already 150 when the constructor started. So the constructor could use it to work out the total.

Access Modifiers

An access modifier controls which other code can use a class, field, method or constructor.

Think of the rooms in a house. Anyone may enter the front garden. Only family members may enter the bedrooms. Some rooms are open to relatives, and some only to the people in that house.

public

public means any code, anywhere, can use the member.

private

private means only code inside the same class can use the member. This is the strictest level.

Fields are usually private, so other classes cannot change them directly.

protected

protected means code in the same package, plus child classes in other packages, can use the member. You will see child classes in the Inheritance lesson.

default

If you write no modifier, the member gets default access, also called package-private. Only code in the same package can use it.

A package is a folder of related classes, like java.util.

ModifierSame classSame packageChild class elsewhereAny other code
publicYesYesYesYes
protectedYesYesYesNo
default (none)YesYesNoNo
privateYesNoNoNo

Another class cannot reach a private field

public class Main {
    public static void main(String[] args) {
        Wallet w = new Wallet();
        w.cash = 1000000;
        System.out.println(w.cash);
    }
}

class Wallet {
    private int cash = 500;
}

The compiler reports cash has private access in Wallet. Only code inside Wallet can touch cash.

To let other code read or change a private field safely, the class adds public methods. You will learn this pattern in the Encapsulation lesson.

Easy Way to Remember: start with private for every field. Make something more open only when another class truly needs it.

Memory View

When a Java program runs, the JVM uses two main areas of memory: the stack and the heap.

Stack

The stack holds each method's local variables and parameters.

  • Every method call gets its own small block, called a frame.
  • When the method ends, its frame is removed, and its local variables disappear.
  • Primitive local variables (int, double and so on) store their value right here.
  • Reference variables store only the address of an object here.

Heap

The heap holds every object created with new, together with its fields.

  • Objects stay on the heap as long as some reference points to them.
  • When no reference points to an object any more, the garbage collector frees its memory automatically.
   STACK (main's frame)            HEAP
  ┌───────────────────┐
  │ int count = 2     │
  │ Car first  ───────┼──────►  ┌───────────────────┐
  │                   │         │ Car               │
  │ Car second ───────┼───┐     │ colour = "Red"    │
  └───────────────────┘   │     │ year   = 2020     │
                          │     └───────────────────┘
                          └──►  ┌───────────────────┐
                                │ Car               │
                                │ colour = "Blue"   │
                                │ year   = 2024     │
                                └───────────────────┘

count is a primitive, so its value, 2, sits on the stack. first and second are references. The stack only holds their addresses. The Car objects themselves live on the heap.

StackHeap
HoldsLocal variables and parametersObjects and their fields
Created whenA method is callednew runs
Removed whenThe method endsNo reference points to the object
Managed byMethod calls and returnsThe garbage collector

Common mistakes

The following mistakes are common when writing classes, constructors and objects. Each row shows what you see, why it happens and how to fix it.

SymptomCauseFix
cannot be applied to given types on newThe constructor you call does not existAdd a matching constructor
A field stays null or 0 after constructionname = name; without thisWrite this.name = name;
NullPointerExceptionThe reference was never given an objectCreate the object with new first
has private accessAnother class used a private memberUse a public method instead
call to this must be first statementthis(...) came after other codeMove it to the first line
Changing one object changes anotherBoth variables point to the same objectCreate a second object with new

What to Remember

  • A class is a blueprint. An object is one instance of it, created with new.
  • A class-type variable holds a reference. Copying it shares the same object.
  • Fields hold an object's data and get default values. Instance methods act on that object's fields.
  • this means the current object. Use this.field = parameter when names match.
  • Constructors have the class's name and no return type. They can be overloaded and chained with this(...).
  • public, protected, default and private control who can use each member. Make fields private by default.
  • Local variables live on the stack. Objects live on the heap, and the garbage collector frees them.

Next: Static Members