Association: Uses-A
Before You Start
Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.
Not sure? Take the 60-second self-check.
1. HAS-A marker. What syntactic element establishes a HAS-A relationship?
Check
A field declaration of another class’s type. private Engine engine; in a Car class says Car HAS-A Engine.
2. IS-A marker. What keyword in a class header establishes IS-A?
Check
extends (for class inheritance) or implements (for interface implementation).
3. Parameter scope. How long does a method parameter remain in scope?
Check
Only for the duration of the method call. When the method returns, the parameter is out of scope and can be garbage-collected if no other references exist.
Try This First
public class Sorter {
public void sort(final Player[] arr, final Comparator<Player> cmp) {
Arrays.sort(arr, cmp);
}
}
Before reading: does Sorter HAS-A Comparator<Player>? Why or why not?
Check
No. cmp is a method parameter, not a field. The Sorter class uses a Comparator<Player> for the duration of the sort call but does not store it. This is association (uses-a), not HAS-A.
What You Need To Walk In With
The Insight: Association is the weakest form of object relationship. It is “uses-a” rather than “has-a.” The marker is where the type appears: a method parameter or a local variable (association) versus a field (HAS-A). Most uses of types in code are associations, not HAS-A; the class does not own or store the object, it merely receives and uses it for one call. The ability to trace where a type reference lives in a class declaration (field, parameter, or local) is what separates a confident reader of unfamiliar code from a confused one.
You can: identify any type reference in a class as IS-A, HAS-A, or association; state why a method parameter cannot be HAS-A; spot the anti-pattern of stashing a parameter into a field; and classify every type reference in a worked example before checking the answer.
How It Works
What association looks like
public class BankTeller {
public Receipt processWithdrawal(final Customer customer, final int amount) {
// customer is in scope only for this method call
// BankTeller does not "have a" Customer permanently
return new Receipt(customer.getId(), amount);
}
}
BankTeller USES-A Customer during one transaction. The customer existed before the call and persists after it. No field stores the customer. This is association.
The distinction: where the type appears
| Position of type | Relationship |
|---|---|
private FieldType field; |
HAS-A (aggregation or composition) |
returnType method(FieldType param) |
Association (uses-a) |
LocalType local = ...; inside a method |
Association |
Why parameters are not HAS-A
HAS-A is a structural relationship encoded in field declarations. It persists across method calls: the same Engine field is still there after accelerate() returns. A parameter exists only during one invocation. When processWithdrawal returns, customer is gone. No state is retained between calls.
Quick check
Check your understanding
A class has these two type references to Scanner: (1) a field ‘private Scanner input;’ and (2) a method parameter ‘public void read(final Scanner src)’. Which reference establishes a HAS-A relationship?
Worked Example: Predict Then Check
public class FraudCheck {
private final RulesEngine rules; // (a)
public FraudCheck(final RulesEngine rules) {
this.rules = rules; // (b)
}
public boolean isValid(final Customer c) { // (c)
List<Rule> applicableRules = rules.getRulesFor(c.getCountry()); // (d)
return applicableRules.stream().allMatch(r -> r.passes(c));
}
}
For each marked item, state the relationship type: IS-A, HAS-A, or association.
Show answer
(a) HAS-A: rules is a field of type RulesEngine. (b) The assignment in the constructor stores the parameter as a field. The relationship established is HAS-A (specifically aggregation, since the RulesEngine was constructed externally). (c) Association: Customer c is a method parameter. (d) Association: applicableRules is a local variable.
Common Misconceptions
Misconception: storing a method parameter into a field opportunistically
Wrong mental model: “I’ll save the customer reference into a field during this call so the next method can use it.”
Why it breaks: Stashing a parameter into a field silently changes the relationship from association to aggregation. The class’s state now depends on a reference whose lifetime it did not declare itself responsible for. The caller may modify or discard the object, and the class will see those changes unexpectedly.
How to correct: If a class genuinely needs to remember a reference across calls, declare a field with that intent in the class declaration. Make the dependency explicit. If the relationship is truly transient, accept it as a parameter on every call that needs it.
Source: Bloch, Effective Java, Item 17.
Quick check
Check your understanding
A student writes: ‘this.lastCustomer = customer;’ inside processWithdrawal to save the Customer parameter into a private field. Which statement best describes what changed?
Formal Definition
UML 2.5 defines association as a structural relationship between two or more types where objects of one type are connected to objects of the other. In Java, the weakest form of association is the “uses” dependency: a type appears in a method signature or local variable but is not stored as a field.
Mental Model
Think of association as borrowing. A bank teller borrows your debit card for 30 seconds to process a transaction. The teller does not own the card; the teller does not keep it; after the transaction, the card goes back to you and the teller has no record of which card it was. That borrowing relationship is association. HAS-A (aggregation or composition) is more like owning: the object is kept in a drawer after the interaction.
Connections
Within CSCD 210/211: Every Arrays.sort(arr, cmp) call in the comparator material is an association: the sort method uses the comparator for one call, does not store it.
Looking back: The prior lesson on IS-A Is Inheritance distinguished IS-A from HAS-A. This lesson introduces the weakest form of the “uses” relationship that sits below HAS-A.
Looking ahead: Aggregation: Has-A, Can Outlive covers the first true HAS-A form, where the contained object is received from outside and can outlive the container.
Go Deeper (optional)
None of this is needed to write correct code today. It is here for the curious reader who wants to know where these ideas connect to the wider world of software.
Association is so common that it is effectively invisible in daily coding: every method parameter in Java is an association. That ubiquity is why it rarely gets its own arrow in a UML diagram unless it carries a meaningful name or multiplicity. In professional design reviews and architecture documents, though, the three relationship types (association, aggregation, composition) each have their own UML arrow, and reading them correctly is a standard expectation. A junior developer who can look at a class diagram and immediately classify every connector is prepared for technical design discussions in a way that takes some engineers years to develop.
The lifetime distinction matters beyond diagram conventions. When you trace a parameter through a method call, you are reasoning about object lifetime: who created the object, who is responsible for it while the method runs, and who owns it after the method returns. That kind of thinking is the foundation of correct memory management, thread-safety reasoning (a shared mutable Customer passed as a parameter to two concurrent tellers is a race condition), and API contract design (a method that accepts a Customer parameter promises not to retain it, which the caller relies on). Knowing the vocabulary makes it easier to read and write those contracts clearly.
In professional Java codebases, the discipline of not promoting a parameter to a field without declaring the intent upfront traces directly to the single-responsibility idea that David Parnas formalized in 1972: a module should know only what it needs to know, and “stashing” a reference is a covert way of expanding what the module knows.
Practice
Level 1
Classify each relationship:
// (a)
class PrintService {
public void print(final Document doc, final Printer p) { ... }
}
// (b)
class PrintService {
private final Printer printer;
public PrintService(final Printer printer) { this.printer = printer; }
}
Show answer
(a) Association: both doc and p are method parameters. (b) HAS-A: printer is a field.
Level 2
In S20.Lab2.CSCD211Lab2Methods, most methods have signatures like menu(Scanner kb) and printPersons(Person[] arr, PrintStream ps). The class has no instance fields. What is the relationship between CSCD211Lab2Methods and Person?
Show answer
Association. Person appears only in method parameters. CSCD211Lab2Methods does not store a Person in any field; it uses Person objects transiently during each method call.
Source: S20.Lab2.CSCD211Lab2Methods.java.
Level 3
A student adds this field to BankTeller after seeing a method that receives a Customer:
private Customer lastCustomer;
public Receipt processWithdrawal(final Customer customer, final int amount) {
this.lastCustomer = customer; // stash for later
...
}
Explain what changed and what problems this introduces.
Show answer
The relationship with Customer changed from association (method parameter, no stored state) to aggregation (stored field). The problems: (1) BankTeller now holds a reference to a Customer object whose lifetime it does not control. (2) If the caller modifies the Customer after the transaction (changes an address, closes the account), lastCustomer reflects those changes silently. (3) Two concurrent transactions on the same BankTeller would overwrite lastCustomer, causing race conditions. Making the dependency explicit in the class declaration and constructor was the right approach if the teller genuinely needs to remember the last customer; stashing it opportunistically inside a method is hidden state.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
In the class below, what is the relationship between BankTeller and Customer? public class BankTeller { public Receipt processWithdrawal(final Customer customer, final int amount) { return new Receipt(customer.getId(), amount); } }
Which position of a type reference establishes a HAS-A relationship rather than association?
Predict the relationship type for each marked reference in this class: public class FraudCheck { private final RulesEngine rules; // (a) public boolean isValid(final Customer c) { // (b) List<Rule> applicable = rules.getRulesFor(c.getCountry()); // (c) return applicable.stream().allMatch(r -> r.passes(c)); } } What are (a), (b), and (c) in order?
A student modifies BankTeller by adding ‘private Customer lastCustomer;’ and writing ‘this.lastCustomer = customer;’ inside processWithdrawal. Which of the following best describes the problem this introduces?
In S20.Lab2.CSCD211Lab2Methods, the class has no instance fields and all methods have signatures like printPersons(Person[] arr, PrintStream ps). What is the relationship between CSCD211Lab2Methods and Person, and why?