Object-Oriented Programming Foundations
Object References, `null`, Identity, Equality, and `toString()`
You are viewing a free preview lesson.
Lesson Overview
Java-তে object variable সাধারণত object নিজে ধারণ করে না।
এটি object-এর একটি reference ধারণ করে।
Course javaCourse =
new Course(
"JAVA-FOUNDATION",
"Java and OOP Foundation"
);
এখানে:
javaCourse
একটি reference variable।
new Course(...)
একটি object তৈরি করেছে।
Reference এবং object-এর পার্থক্য না বুঝলে কয়েকটি common problem হয়:
- একটি reference দিয়ে change করলে অন্য reference-এও change দেখা যায়
- Assignment-কে object copy মনে হয়
nullথেকেNullPointerExceptionহয়==দিয়ে object content compare করা হয়equals()এবংhashCode()inconsistent হয়- Debugging output meaningful হয় না
এই lesson-এ আমরা শিখব:
- Object reference কী
- Multiple references একই object point করলে কী হয়
- Reference reassignment
nullNullPointerException- Object identity
- Reference equality এবং logical equality
==এবংequals()hashCode()contract- Meaningful
toString() - Equality design-এর practical rules
Learning Objectives
এই lesson শেষ করার পর আপনি পারবেন:
- Object এবং object reference আলাদা করতে
- Shared reference বা aliasing ব্যাখ্যা করতে
- Reference assignment এবং object copying-এর পার্থক্য বুঝতে
nullsafely handle করতেNullPointerException-এর common কারণ identify করতে==এবংequals()সঠিকভাবে ব্যবহার করতে- Logical equality-এর জন্য stable identity নির্বাচন করতে
equals()এবংhashCode()একসঙ্গে implement করতে- Useful এবং safe
toString()লিখতে
Object Reference
Object তৈরি করার একটি familiar statement:
Course javaCourse =
new Course(
"JAVA-FOUNDATION",
"Java and OOP Foundation"
);
এখানে তিনটি গুরুত্বপূর্ণ অংশ আছে:
Course
Reference type।
javaCourse
Reference variable।
new Course(...)
নতুন object তৈরি করে।
Conceptually:
javaCourse
│
└──> Course object
Reference ব্যবহার করে object-এর methods call করা হয়।
javaCourse.publish();
Reference Assignment
Consider:
Course selectedCourse =
javaCourse;
এখানে নতুন Course object তৈরি হয়নি।
শুধু reference value copy হয়েছে।
javaCourse
│
├──> Same Course object
│
selectedCourse
এখন দুইটি variables একই object refer করছে।
Shared References and Aliasing
একই object-এর multiple references থাকাকে aliasing বলা হয়।
Course firstReference =
new Course(
"JAVA-FOUNDATION",
"Java Foundation"
);
Course secondReference =
firstReference;
তারপর:
secondReference.changeTitle(
"Java and OOP Foundation"
);
Now:
System.out.println(
firstReference.getTitle()
);
Output:
Java and OOP Foundation
কারণ firstReference এবং secondReference same object point করছে।
Reference Assignment Is Not Object Copying
এই code object copy করে না:
Course secondCourse =
firstCourse;
Separate object দরকার হলে নতুন object create করতে হবে।
Course secondCourse =
new Course(
firstCourse.getCode(),
firstCourse.getTitle()
);
এখন দুইটি object আছে।
তবে একই values ব্যবহার করে new object তৈরি করলেই সেটি domain perspective-এ valid copy হবে—এমন নয়।
Copying strategy depend করতে পারে:
- Identity copy করা যাবে কি না
- Mutable state কীভাবে copy হবে
- Nested objects share হবে নাকি copy হবে
- Audit fields preserve হবে কি না
Copy constructor বা copy factory future design topic হতে পারে।
Reassigning a Reference
Course course =
new Course(
"JAVA-FOUNDATION",
"Java Foundation"
);
course =
new Course(
"BACKEND",
"Backend Development"
);
এখন course দ্বিতীয় object point করছে।
প্রথম object-এর অন্য কোনো reachable reference না থাকলে সেটি garbage collection-এর জন্য eligible হতে পারে।
Important:
Reference reassign করা object change করা নয়। Variableটি অন্য object point করা শুরু করে।
Passing References to Methods
Java object reference value-এর একটি copy method-এ pass করে।
static void publishCourse(
Course course
) {
course.publish();
}
Call:
publishCourse(
javaCourse
);
Caller এবং method parameter same object access করে।
তাই object mutation caller থেকে visible।
Reassigning a Method Parameter
static void replaceCourse(
Course course
) {
course =
new Course(
"NEW",
"New Course"
);
}
Call:
Course original =
new Course(
"JAVA",
"Java Foundation"
);
replaceCourse(original);
original এখনও original object point করে।
কারণ method শুধু তার local reference copy reassign করেছে।
What Is null?
null মানে একটি reference কোনো object point করছে না।
Course course = null;
Conceptually:
course ──> no object
null কোনো empty Course object নয়।
এটি object-এর absence represent করে।
NullPointerException
যদি null reference দিয়ে instance member access করা হয়:
Course course = null;
course.publish();
Runtime-এ:
NullPointerException
কারণ method call করার মতো কোনো object নেই।
Same risk:
course.getTitle();
course.changeTitle("Java");
Common Sources of null
null আসতে পারে:
- Field initialize না হলে
- Method optional result হিসেবে
nullreturn করলে - Collection search result না পেলে
- External data missing হলে
- Reference manually
nullassign করলে - Dependency properly initialize না হলে
Example:
private Course selectedCourse;
Object তৈরি হলে selectedCourse defaultভাবে null।
Basic Null Check
if (course != null) {
course.publish();
}
Alternative:
if (course == null) {
return;
}
course.publish();
Early return nesting কমায়।
Null Check Is Not Always the Best Design
Application-এর সব জায়গায় এমন code থাকলে:
if (course != null) {
}
এটি indicate করতে পারে object lifecycle unclear।
Better design হতে পারে:
- Constructor-এ required dependency নেওয়া
- Missing value boundary-তে handle করা
- Empty collection return করা
Optionalব্যবহার করা যেখানে absence meaningful- Null values domain object-এর ভেতরে না ঢুকতে দেওয়া
Important principle:
Required values-এর absence যত দ্রুত সম্ভব reject করুন।
Comparing with null
null comparison-এর জন্য == এবং != সঠিক।
if (course == null) {
}
if (course != null) {
}
এখানে equals() call করা উচিত নয়।
Wrong:
if (course.equals(null)) {
}
যদি course null হয়, callটি নিজেই NullPointerException দেবে।
Object Identity
Identity নির্ধারণ করে আমরা কোন specific object বা domain entity-এর সঙ্গে কাজ করছি।
Java memory perspective-এ দুইটি separately created objects-এর identity আলাদা।
Course first =
new Course(
"JAVA",
"Java Foundation"
);
Course second =
new Course(
"JAVA",
"Java Foundation"
);
Even though values same, objects separately created।
Reference Equality with ==
Objects-এর ক্ষেত্রে == check করে:
দুইটি references কি exact same object point করছে?
System.out.println(
first == second
);
Output:
false
কারণ two separate objects।
Same Reference with ==
Course first =
new Course(
"JAVA",
"Java Foundation"
);
Course second =
first;
System.out.println(
first == second
);
Output:
true
দুই references same object point করে।
Logical Equality
Logical equality domain rules অনুযায়ী decide করে দুইটি objects same entity বা same value represent করছে কি না।
Example:
Course code: JAVA
যদি course code unique এবং stable হয়, তাহলে একই code থাকা দুইটি Course objects logically same course represent করতে পারে।
Course first =
new Course(
"JAVA",
"Java Foundation"
);
Course second =
new Course(
"JAVA",
"Java and OOP Foundation"
);
Titles different হলেও course code same।
Domain rule হতে পারে:
Course identity is determined by course code.
Then:
first.equals(second)
should return:
true
Default equals() Behavior
যদি class equals() override না করে, Object class-এর default implementation reference identity compare করে।
Conceptually, এটি ==-এর মতো behavior দেয়।
Course first =
new Course(
"JAVA",
"Java Foundation"
);
Course second =
new Course(
"JAVA",
"Java Foundation"
);
System.out.println(
first.equals(second)
);
Custom equals() না থাকলে result:
false
Overriding equals()
Logical equality define করতে equals() override করা যায়।
@Override
public boolean equals(
Object other
) {
if (this == other) {
return true;
}
if (
other == null
|| getClass()
!= other.getClass()
) {
return false;
}
Course course =
(Course) other;
return code.equals(
course.code
);
}
Step by step বুঝি।
Step 1: Same Object Check
if (this == other) {
return true;
}
একটি object নিজের সঙ্গে অবশ্যই equal।
এটি fast path।
Step 2: Null and Type Check
if (
other == null
|| getClass()
!= other.getClass()
) {
return false;
}
Rules:
- কোনো object
null-এর equal নয় - Different class-এর object এই equality strategy-তে equal নয়
Step 3: Cast
Course course =
(Course) other;
Type check-এর পরে other safely Course হিসেবে cast করা যায়।
Step 4: Compare Identity Field
return code.equals(
course.code
);
Equality course code-এর ওপর based।
Title বা published state compare করা হয়নি।
Choosing Equality Fields
Equality fields select করা গুরুত্বপূর্ণ design decision।
Good candidates সাধারণত:
- Stable
- Meaningful
- Unique বা identity-defining
- Object lifetime-এ unchanged
Course example:
courseCode
Potentially weak equality fields:
title
published
price
lessonCount
এগুলো change হতে পারে এবং multiple courses-এ same হতে পারে।
Mutable Fields in Equality
Suppose equality uses title:
return title.equals(
course.title
);
তারপর title change হলো।
course.changeTitle(
"Modern Java"
);
Object-এর equality এবং hash code change হয়ে যেতে পারে।
Hash-based collection-এ object থাকলে এটি serious bug তৈরি করতে পারে।
Practical rule:
Equality এবং
hashCode()-এ mutable fields ব্যবহার করা carefully avoid করুন।
The equals() Contract
একটি correct equals() implementation-এর properties:
Reflexive
x.equals(x)
must be true।
Symmetric
যদি:
x.equals(y)
true হয়, তাহলে:
y.equals(x)
ও true হতে হবে।
Transitive
যদি:
x equals y
y equals z
তাহলে:
x equals z
হতে হবে।
Consistent
Relevant state unchanged থাকলে repeated calls same result দেবে।
Non-null
x.equals(null)
must be false।
hashCode()
equals() override করলে hashCode()-ও override করতে হয়।
Contract:
যদি দুইটি objects
equals()অনুযায়ী equal হয়, তাদের hash code অবশ্যই same হতে হবে।
The reverse is not required।
Same hash code থাকা two objects unequal হতে পারে। এটিকে collision বলা হয়।
Implementing hashCode()
@Override
public int hashCode() {
return code.hashCode();
}
Or:
@Override
public int hashCode() {
return Objects.hash(
code
);
}
Required import:
import java.util.Objects;
Why hashCode() Matters
Hash-based collections use hashCode():
HashSet
HashMap
Future collections lesson-এ এগুলো বিস্তারিত শেখানো হবে।
যদি equals() logical equality define করে কিন্তু hashCode() old identity-based behavior রাখে, equal objects different hash buckets-এ যেতে পারে।
Result:
- Duplicate values
HashSet-এ থাকতে পারে HashMaplookup fail করতে পারে- Collection behavior inconsistent হয়
Rule:
Override
equals()andhashCode()together.
Using Objects.equals()
Nullable values compare করতে:
Objects.equals(
firstValue,
secondValue
);
Behavior:
Both null → true
One null → false
Both non-null → firstValue.equals(secondValue)
Example:
return Objects.equals(
code,
course.code
);
যদি constructor code কখনো null হতে না দেয়, direct code.equals(...) safe।
Objects.equals() null-safe comparison-এর জন্য useful।
Equality Strategy Is a Domain Decision
সব classes একইভাবে equality define করবে না।
Value Object
Example:
Money
EmailAddress
Coordinates
সব meaningful values equality-তে অংশ নিতে পারে।
Entity
Example:
Course
Learner
Enrollment
Stable identity field equality define করতে পারে।
Simple Data Transfer Object
সব fields compare করা useful হতে পারে।
No universal rule:
Always compare all fields
বা:
Always compare database ID
দুটিই oversimplification।
Engineering Note: Database-Generated IDs
Production entity-এর ID database insert-এর পরে assign হতে পারে।
Before persistence:
id = null
After persistence:
id = 1042
যদি equality শুধু database ID-এর ওপর depend করে, object-এর equality lifecycle-এর মধ্যে change করতে পারে।
এটি ORM এবং hash-based collection use-এ subtle সমস্যা তৈরি করে।
Common strategies:
- Application-generated stable ID
- Immutable business key
- Carefully designed persistence identity
- Reference identity before persistence
এই topic advanced persistence design-এর অংশ।
Beginner level-এর key lesson:
Equality field stable হওয়া উচিত এবং object lifecycle বুঝে নির্বাচন করতে হবে।
String Comparison
Strings objects।
String content compare করতে:
firstString.equals(
secondString
);
Avoid:
firstString
== secondString
== references compare করে।
Example:
String first =
new String("Java");
String second =
new String("Java");
System.out.println(
first == second
);
System.out.println(
first.equals(second)
);
Output:
false
true
Null-Safe String Comparison
If variable may be null:
"Java".equals(
courseTitle
);
এটি safe, কারণ literal null নয়।
Or:
Objects.equals(
firstTitle,
secondTitle
);
তবে required domain fields constructor-এ non-null রাখা stronger design।
What Is toString()?
Every Java object inherits toString() from Object।
Default output সাধারণত এমন:
Course@5acf9800
এটি class name এবং hash-related representation-এর মতো দেখায়, কিন্তু business debugging-এর জন্য useful নয়।
toString() override করে meaningful representation দেওয়া যায়।
Overriding toString()
@Override
public String toString() {
return "Course{"
+ "code='"
+ code
+ '\''
+ ", title='"
+ title
+ '\''
+ ", published="
+ published
+ '}';
}
Usage:
System.out.println(
javaCourse
);
Java automatically toString() call করবে।
Possible output:
Course{code='JAVA', title='Java and OOP Foundation', published=false}
What Should toString() Include?
Useful fields:
- Stable identity
- Important state
- Debugging-relevant information
Avoid including:
- Password
- Access token
- Secret key
- Full payment card information
- Sensitive personal information
- Very large collections
- Recursive object graphs
Example unsafe:
return "User{"
+ "email='"
+ email
+ '\''
+ ", password='"
+ password
+ '\''
+ '}';
Logs-এ secrets leak হতে পারে।
toString() Is Not a Serialization Format
toString() debugging এবং human-readable representation-এর জন্য।
এটিকে depend করা উচিত নয়:
- API response format হিসেবে
- Database storage format হিসেবে
- Stable machine-readable protocol হিসেবে
- CSV বা JSON replacement হিসেবে
toString() implementation future-এ change হতে পারে।
Complete Course Example
Course.java
import java.util.Objects;
public class Course {
private final String code;
private String title;
private boolean published;
public Course(
String code,
String title
) {
if (
code == null
|| code.isBlank()
) {
throw new IllegalArgumentException(
"Course code is required."
);
}
if (
title == null
|| title.isBlank()
) {
throw new IllegalArgumentException(
"Course title is required."
);
}
this.code =
code.strip()
.toUpperCase();
this.title =
title.strip();
this.published = false;
}
public boolean changeTitle(
String newTitle
) {
if (
newTitle == null
|| newTitle.isBlank()
) {
return false;
}
title =
newTitle.strip();
return true;
}
public boolean publish() {
if (published) {
return false;
}
published = true;
return true;
}
public String getCode() {
return code;
}
public String getTitle() {
return title;
}
public boolean isPublished() {
return published;
}
@Override
public boolean equals(
Object other
) {
if (this == other) {
return true;
}
if (
other == null
|| getClass()
!= other.getClass()
) {
return false;
}
Course course =
(Course) other;
return code.equals(
course.code
);
}
@Override
public int hashCode() {
return Objects.hash(
code
);
}
@Override
public String toString() {
return "Course{"
+ "code='"
+ code
+ '\''
+ ", title='"
+ title
+ '\''
+ ", published="
+ published
+ '}';
}
}
Using Equality and toString()
Main.java
public class Main {
public static void main(String[] args) {
Course first =
new Course(
"java",
"Java Foundation"
);
Course second =
new Course(
"JAVA",
"Java and OOP Foundation"
);
Course third =
first;
System.out.println(
first == second
);
System.out.println(
first.equals(second)
);
System.out.println(
first == third
);
first.publish();
System.out.println(first);
System.out.println(second);
}
}
Output:
false
true
true
Course{code='JAVA', title='Java Foundation', published=true}
Course{code='JAVA', title='Java and OOP Foundation', published=false}
Interpretation:
first == second
false, কারণ separate objects।
first.equals(second)
true, কারণ code same এবং equality code-based।
first == third
true, কারণ same object reference।
A Subtle Design Observation
Previous example-এ two different objects same course identity represent করছে, কিন্তু titles এবং published states different।
Same identity
Different current state
এটি possible, especially when:
- Different application sessions
- Cached and fresh copies
- Database entity loaded multiple times
- Distributed services hold separate representations
Logical equality same entity identify করতে পারে, কিন্তু state synchronization automatically করে না।
Equal objects মানেই একই in-memory object নয়।
getClass() vs instanceof
equals()-এ two common type checks দেখা যায়।
getClass()
!= other.getClass()
অথবা:
!(other instanceof Course)
Inheritance-এর সঙ্গে equality design subtle।
getClass() exact same runtime class require করে।
instanceof subclasses allow করতে পারে, যা symmetry বা transitivity problems তৈরি করতে পারে।
এই module inheritance focus করছে না।
Beginner domain entities-এর জন্য exact-class comparison একটি clear starting point।
Common Mistakes
Using == for Logical Equality
Wrong:
if (firstCourse == secondCourse) {
}
এটি same object check করে, same course নয়।
Use:
firstCourse.equals(
secondCourse
);
যদি logical equality implemented থাকে।
Comparing Strings with ==
Wrong:
title == "Java"
Use:
"Java".equals(title)
Calling a Method on null
Course course = null;
course.publish();
Result:
NullPointerException
Overriding equals() Without hashCode()
Hash-based collections inconsistent হতে পারে।
Including Mutable Fields in Equality
Title বা published state change হলে equality change হতে পারে।
Stable identity prefer করুন।
Using Every Field in Entity Equality
Entity-এর current state এবং identity এক জিনিস নয়।
সব fields compare করলে same entity-এর updated copy unequal হয়ে যেতে পারে।
Returning Secrets from toString()
Logs-এ sensitive data leak হতে পারে।
Treating toString() as JSON
toString() stable machine contract নয়।
Practice Exercises
Exercise 1: Trace Shared References
Predict করুন:
Course first =
new Course(
"JAVA",
"Java Foundation"
);
Course second =
first;
second.changeTitle(
"Modern Java"
);
System.out.println(
first.getTitle()
);
Result explain করুন।
Exercise 2: Separate Objects
Create two separate Course objects with the same code।
Compare using:
==
equals()
Explain the different results।
Exercise 3: Implement Learner Equality
Create a Learner class with:
learnerId
name
email
Assume learnerId stable এবং unique।
Implement:
equals()
hashCode()
toString()
Do not include email in toString() if you consider it unnecessary personal data for logs।
Exercise 4: Fix String Comparison
Fix:
if (
course.getCode()
== "JAVA"
) {
}
Exercise 5: Null Safety
Rewrite safely:
course.publish();
when course may be null।
Then explain why preventing null earlier may be better।
Exercise 6: Equality Field Selection
Choose appropriate equality fields for:
CourseMoneyEnrollmentEmailAddress
Explain whether each behaves more like an entity or value object।
Exercise 7: Safe toString()
Review:
@Override
public String toString() {
return "User{"
+ "email='"
+ email
+ '\''
+ ", password='"
+ password
+ '\''
+ '}';
}
Identify the security problem and fix it।
Predict the Result
Question 1
Course first =
new Course(
"JAVA",
"Java"
);
Course second =
first;
System.out.println(
first == second
);
Question 2
Course first =
new Course(
"JAVA",
"Java"
);
Course second =
new Course(
"JAVA",
"Modern Java"
);
System.out.println(
first == second
);
System.out.println(
first.equals(second)
);
Assume equality code-based।
Question 3
String first =
new String("Java");
String second =
new String("Java");
System.out.println(
first == second
);
System.out.println(
first.equals(second)
);
Question 4
Course course = null;
System.out.println(
course.getTitle()
);
Predict the Result Answers
Answer 1
true
Both references same object point করে।
Answer 2
false
true
References different, logical identity same।
Answer 3
false
true
== references compare করেছে। equals() String content compare করেছে।
Answer 4
Runtime-এ:
NullPointerException
Knowledge Check
Question 1
Object reference কী?
Question 2
Reference assignment কি object copy করে?
Question 3
Aliasing কী?
Question 4
Reference reassign করা এবং object mutate করার পার্থক্য কী?
Question 5
null কী represent করে?
Question 6
NullPointerException কখন হয়?
Question 7
Objects-এর ক্ষেত্রে == কী compare করে?
Question 8
equals() কী compare করতে পারে?
Question 9
equals() override করলে hashCode() কেন override করতে হয়?
Question 10
Equal objects কি same object হতে হবে?
Question 11
Mutable fields equality-তে risky কেন?
Question 12
toString()-এর purpose কী?
Question 13
toString()-এ sensitive data include করা উচিত নয় কেন?
Question 14
String content compare করতে == না equals() ব্যবহার করা উচিত?
Knowledge Check Answers
Answer 1
Object-এর location বা access path represent করা value, যা reference variable ধারণ করে।
Answer 2
না। এটি reference value copy করে।
Answer 3
Multiple references একই object point করলে।
Answer 4
Reference reassign করলে variable অন্য object point করে। Object mutate করলে referenced object-এর state change হয়।
Answer 5
Reference কোনো object point করছে না।
Answer 6
Null reference দিয়ে instance field বা method access করলে।
Answer 7
দুই references exact same object point করছে কি না।
Answer 8
Domain-defined logical identity বা value equality।
Answer 9
Equal objects-এর same hash code থাকা contract-এর requirement।
Answer 10
না। Separate objects logically equal হতে পারে।
Answer 11
Field change হলে object-এর equality এবং hash code change হতে পারে।
Answer 12
Human-readable debugging এবং logging representation দেওয়া।
Answer 13
Logs এবং error messages-এর মাধ্যমে secrets বা private information leak হতে পারে।
Answer 14
equals()।
Lesson Summary
এই lesson-এ আমরা শিখেছি:
- Object variable সাধারণত reference ধারণ করে
- Reference assignment নতুন object তৈরি করে না
- Multiple references same object point করতে পারে
- Shared reference দিয়ে mutation সব references থেকে visible
- Reference reassign করলে variable অন্য object point করে
- Java object reference values by value pass করে
nullobject absence represent করে- Null reference access করলে
NullPointerExceptionহয় - Required values early validate করলে null handling কমে
==object reference identity compare করেequals()logical equality define করতে পারে- Default
equals()reference identity-based - Stable identity fields entity equality-এর জন্য useful
- Mutable fields equality-তে risky
equals()contract reflexive, symmetric, transitive, consistent এবং non-nullequals()override করলেhashCode()-ও override করতে হয়- Equal objects same hash code দেয়
Objects.equals()null-safe comparison দেয়- String content
equals()দিয়ে compare করতে হয় toString()useful debugging representation দেয়toString()sensitive data expose করা উচিত নয়toString()serialization contract নয়- Equal objects একই in-memory object হওয়া বাধ্যতামূলক নয়
- Equality strategy একটি domain design decision
Next Lesson
পরবর্তী lesson:
Composition and Object Relationships
আমরা শিখব:
- One object referencing another object
has-arelationships- Association এবং composition
Learner,Course, এবংEnrollmentআলাদা objects হিসেবে model করা- Duplicate state avoid করা
- Object collaboration
- Relationship ownership
- Composition কেন inheritance-এর চেয়ে অনেক ক্ষেত্রে safer