Skip to content
Ameen Abozaid
PublishedBEG-025-L01

How objects know each other

  • Lesson 1 of 5
  • 10 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

Until now your objects mostly lived alone: an Account held numbers and strings, and main poked it from outside. Real programs are built from many objects that work together, and for one object to ask another to do something, it must be able to reach it. In Java, that reach is always a reference.

In this module we will use a family of contacts as a picture. Some people in your phone you know for life (a sibling), some you call once (the plumber), and some you only recognise because you were handed a card. Objects are the same: how long and how closely one object knows another depends on where it keeps the reference.

Why this matters: the way objects are connected is the design of a backend system. Customers, accounts, orders, and payments are all connected objects, and later they become connected database tables.

This lesson builds on classes, constructors, encapsulation, and polymorphism from earlier modules. It needs no new Java syntax.

Learning Objectives

By the end of this lesson you will be able to:

  • Explain that an object can only call another object it holds a reference to.
  • Name the three places a reference can come from: a field, a parameter, or a local variable.
  • Explain how the place of the reference decides how long the relationship lasts.
  • Show that two objects can share one third object through references.
  • Read and state multiplicity: one, zero or one, many.
  • Predict and fix a NullPointerException caused by a missing link.

Written Explanation

An object needs a reference to call another

You already know that a variable like Account a1 does not hold the account itself, but a reference to it. To call a1.deposit(50) the caller must have such a variable in scope. No reference, no call. So the question "how do these objects know each other?" is really "where is the reference stored?"

Three places a reference can live

WhereExampleHow long it lasts
A fieldprivate final Customer owner;As long as the object itself lives
A parameterString render(Account account)Only during that method call
A local variableReceipt receipt = new Receipt();Until the method ends

The field is the long-lived link: every method of the object can use it, and it is part of the object's state. The parameter and the local variable are short-lived uses: the object meets the other one, does its job, and forgets it.

In contact terms, a field is a name saved in your phone book. A parameter is a number someone shouts at you for this one call.

Sharing: many references, one object

Two objects can hold references to the same third object. Nothing is copied. If a1 and a2 both have an owner field pointing at the same Customer, then there is exactly one customer in memory and two accounts that know it. The expression a1.getOwner() == a2.getOwner() compares references, so it is true. Example 1 shows this.

Multiplicity: how many?

When you name a relationship, say how many objects are on each side. This is called multiplicity:

WrittenMeaningTypical Java
1exactly onea field that must never be null
0..1zero or onea field that may be null
* (or 0..*)zero or morea collection of references (next lesson)

Read it from both ends. "One customer has many accounts; each account has exactly one owner" gives Customer 1 and Account *. Which side is "many" decides how you write the code: a single field for "one", a collection for "many".

Naming the relationship

Say in a sentence what the link means: "an account is owned by a customer", "a receipt prints an account". A verb tells you whether the link should be a field or only a parameter. If the answer to "does it need to remember?" is yes, make it a field. If not, pass it in.

When the link is missing

A field that was never filled holds null. Calling a method on null throws NullPointerException. In modern Java the message names the exact expression that was null, which makes this error easy to locate. Most of these errors mean "a relationship that was supposed to be set up, was not." Example 3 shows one.

Examples

Example 1: a field link, shared by two accounts (simple)

java
class Customer {
    private final String name;
    Customer(String name) { this.name = name; }
    String getName() { return name; }
}

class Account {
    private final String number;
    private final Customer owner;          // field: long-lived link
    Account(String number, Customer owner) {
        this.number = number;
        this.owner = owner;
    }
    Customer getOwner() { return owner; }
    String describe() { return number + " owned by " + owner.getName(); }
}

public class Main {
    public static void main(String[] args) {
        Customer amal = new Customer("Amal");
        Account a1 = new Account("A-1", amal);
        Account a2 = new Account("A-2", amal);
        System.out.println(a1.describe());
        System.out.println(a2.describe());
        System.out.println(a1.getOwner() == a2.getOwner());
    }
}

Output (compiled and run with JDK 21):

text
A-1 owned by Amal
A-2 owned by Amal
true

There is one Customer object and two Account objects that reach it through their owner field.

Example 2: a parameter and a local variable (practical)

Add a class that only uses an account for one call:

java
class Receipt {
    String render(Account account) {       // parameter: short-lived use
        return "RECEIPT: " + account.describe();
    }
}

and in main:

java
Receipt receipt = new Receipt();           // local variable
System.out.println(receipt.render(a1));

Output:

text
RECEIPT: A-1 owned by Amal

Receipt has no field of type Account. It meets an account for the length of one call and then forgets it. main holds receipt in a local variable that disappears when main ends.

Example 3: the missing link (realistic)

Suppose some code creates an account and passes null for the owner by mistake:

java
Account orphan = new Account("A-3", null);
System.out.println(orphan.describe());

Output:

text
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Customer.getName()" because "this.owner" is null
	at Account.describe(Main.java:15)
	at Main.main(Main.java:37)

The message says what happened: this.owner is null, so getName() cannot be called. The constructor accepted a broken link, and the failure appeared later, in a different method. Lesson 5 of this module returns to this: set up relationships completely, in one place, so they cannot be left half-built.

Backend Insight

A backend system is mostly a web of objects: a Customer knows its Accounts, an Order knows its OrderLines, a Payment knows its Order. When you later store these in a database, each link becomes a column that points to another row. A design that is vague about "who knows whom, and how many" turns into confusing tables and tangled code.

Two habits start here. First, choose the shortest link that does the job: a parameter before a field. Second, always know the multiplicity: it decides whether you store one reference or a collection.

Common Mistakes

Mistake 1: Making everything a field

  • Incorrect: giving Receipt a field Account account just so render() can use it, even though every call passes a different account.
  • Correct: pass the account as a parameter. A field means "this object remembers that one."

A field that is overwritten before each use is a parameter in disguise, and it breaks as soon as two callers share the object.

Mistake 2: Thinking assignment copies the object

Customer b = amal; does not create a second customer. Both variables point to the same object. Changes made through one are visible through the other.

Mistake 3: Leaving a required link null

If the relationship is "exactly one", reject null in the constructor so the mistake appears at the place where it was made, not three method calls later.

Mistake 4: Comparing with == when you mean "the same customer"

== on objects asks whether it is the very same object, not whether two objects look alike. That is the right question for "do these two accounts share one owner object?", but not for "do these have the same name?" A later module covers equality in detail.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. For each line, say whether the reference lives in a field, a parameter, or a local variable:

java
class Bank {
    private Account main;                   // (a)
    void audit(Account acc) {               // (b)
        Account copy = acc;                 // (c)
    }
}
Show solution A1

A1. (a) field; (b) parameter; (c) local variable.

A2. Which lives longer: a reference in a field or in a parameter? Why?

Show solution A2

A2. The field. It lives as long as the object. A parameter exists only during one method call.

A3. Write the multiplicity for each side: (a) one passport belongs to exactly one person, and a person may have no passport or one; (b) one teacher teaches many classes, and each class has exactly one teacher.

Show solution A3

A3. (a) Person 0..1 — 1 Passport: each passport has exactly one person; each person has zero or one passport. (b) Teacher 1 — * Class: a class has exactly one teacher; a teacher has zero or more classes.

Level B: Application

B1. Write classes Course (with a title and getter/setter) and Student (with a name and a Course field). Student needs a describe() returning "<name> studies <title>". Create two students on the same course, then change the course title and print both descriptions. Predict first: what do they show?

Show solution B1

B1. Prediction: both show the new title, because there is only one Course object. Code (we compiled and ran it):

java
class Course {
    private String title;
    Course(String title) { this.title = title; }
    void setTitle(String title) { this.title = title; }
    String getTitle() { return title; }
}

class Student {
    private final String name;
    private final Course course;
    Student(String name, Course course) {
        this.name = name;
        this.course = course;
    }
    String describe() { return name + " studies " + course.getTitle(); }
}

With Course java = new Course("Java 1"); shared by sara and omar, then java.setTitle("Java 2");, the output is:

text
Sara studies Java 2
Omar studies Java 2

B2. A class Printer has a method print(Report r). Another class Office calls it. Name the two relationships and say which one should be a field and which should not.

Show solution B2

B2. Office depends on Printer (it calls it) and Printer depends on Report (it receives it as a parameter). Report should be a parameter, because each call can print a different report. Whether Office keeps a Printer in a field depends on whether it uses the same printer for its whole life; if so, a field is right.

B3. The constructor of Student accepts null for the course. Change it so that a missing course is rejected immediately with a clear message.

Show solution B3

B3. Add a guard at the top of the constructor:

java
if (course == null) {
    throw new IllegalArgumentException("course must not be null");
}

Running new Student("Lina", null) then fails at once:

text
Exception in thread "main" java.lang.IllegalArgumentException: course must not be null
	at Student.<init>(Main.java:13)
	at Main.main(Main.java:29)

Level C: Challenge

C1. A Book is held by a Library, and sometimes borrowed by a Member. Decide for each of these facts whether it should be a field or a parameter, and give the multiplicity: (a) the member currently borrowing the book; (b) the member asking whether a book is available.

Show solution C1

C1. (a) A field in Book, multiplicity 0..1 (a book is borrowed by zero or one member at a time), because the book must remember the state. (b) A parameter, for example boolean isAvailableTo(Member m): it is a one-off question, and the book does not need to remember who asked.

C2. Two accounts share one Customer object. Code changes the customer's name through a1.getOwner(). Does a2 see the change? Explain, and say what would be different if each account had its own separate Customer copy.

Show solution C2

C2. Yes. Both accounts point to the same object, so a2.getOwner().getName() shows the new name (assuming Customer has a setter). With separate copies, only one account's customer would change, and the two copies could disagree about who the owner is.

Mini Challenge

Choose a small system you know, such as a school, a cinema, or a garage. Pick three classes. For each pair that has a link:

  1. Write one sentence naming the link with a verb ("a ticket is for a screening").
  2. Write the multiplicity at both ends.
  3. Decide whether it should be a field or only a parameter, and justify it in one sentence.

Check your work: every link has a verb and two multiplicities, and each field is something the object truly has to remember.

Summary & Next Lesson

Key takeaways

  • An object can call another only through a reference to it.
  • A reference can live in a field (long-lived), a parameter, or a local variable (short-lived).
  • Several objects can share one object; assignment copies the reference, not the object.
  • Multiplicity states how many objects sit at each end: 1, 0..1, *.
  • A link that was never set is null, and the first call on it throws NullPointerException.

Next lesson

The next lesson, "Association, aggregation, composition", takes the field link and splits it into three kinds of "has" relationship, depending on who owns whom and what happens when the owner disappears. It also shows how to store the "many" side in code.

Self-check

  1. Name two places where a reference to another object can come from.
  2. Which is longer-lived: a field or a parameter?
  3. Two accounts hold the same Customer. How many customer objects exist?
  4. What does multiplicity 0..1 mean?
  5. Why is it better to reject null in the constructor for a required link?
Show answers
  1. A field and a method parameter (a local variable is also valid).
  2. The field, which lives as long as the object.
  3. One. Both accounts hold references to it.
  4. Zero or one: the link is optional.
  5. The error shows up where the broken object was created, rather than later when the missing link is used.

References

  • Oracle, The Java Language Specification, Java SE 21, chapter 4. Section 4.3 supports that a variable of class type holds a reference to an object or null, and that several variables can refer to one object, so a change through one is visible through the others.
  • The Java examples were compiled and run with JDK 21 for this lesson. The "family of contacts" picture is this course's own teaching analogy.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.