Object-Oriented Programming Foundations

The `this` Keyword and Method Overloading

ReadingPreview

আপনি একটি free preview lesson দেখছেন।

Lesson Overview

Constructor এবং method parameters-এর name অনেক সময় object fields-এর name-এর সঙ্গে same রাখা হয়।

Example:

class Course {

    String title;

    Course(
            String title
    ) {
        title = title;
    }
}

Codeটি compile করলেও object field expectedভাবে initialize হবে না।

কারণ constructor parameter title, field title-কে shadow করেছে।

Current object-এর field explicitly refer করতে Java-তে this keyword ব্যবহার করা হয়।

this.title = title;

this আরও ব্যবহার করা যায়:

  • Current object refer করতে
  • Current object-এর fields এবং methods access করতে
  • একটি constructor থেকে অন্য constructor call করতে
  • Current object অন্য method-এ pass করতে

এই lesson-এ আমরা method এবং constructor overloading-ও শিখব।

Overloading একই operation-এর meaningful variations support করতে পারে। কিন্তু unnecessary overloads object API confusing করে তুলতে পারে।


Learning Objectives

এই lesson শেষ করার পর আপনি পারবেন:

  • this কী represent করে তা ব্যাখ্যা করতে
  • Field shadowing identify করতে
  • this.field ব্যবহার করে field এবং parameter আলাদা করতে
  • this() দিয়ে constructor chaining করতে
  • Constructor duplication কমাতে
  • Method overloading explain করতে
  • Constructor overloading implement করতে
  • Compiler কীভাবে overload select করে তা বুঝতে
  • Return type alone দিয়ে overload কেন করা যায় না তা ব্যাখ্যা করতে
  • Ambiguous এবং unnecessary overload avoid করতে

What Does this Mean?

একটি instance method বা constructor execute হওয়ার সময় this current object-কে refer করে।

Example:

Course javaCourse =
        new Course(
                "Java and OOP Foundation",
                20
        );

Constructor execute হওয়ার সময়:

this

javaCourse যে নতুন object-কে refer করবে, সেই current Course object-কে represent করে।


Field Shadowing

একটি local variable বা parameter-এর name field-এর name-এর same হলে field shadowed হয়।

public class Course {

    String title;

    Course(
            String title
    ) {
        title = title;
    }
}

Constructor body-এর দুই পাশের title parameter-কে refer করে।

Conceptually:

parameter title = parameter title

Object field unchanged থেকে যায়।


Using this.field

Current object-এর field refer করতে:

this.title

Correct constructor:

public class Course {

    String title;

    Course(
            String title
    ) {
        this.title = title;
    }
}

এখানে:

this.title → Current object's field
title      → Constructor parameter

Why Same Names Are Common

Alternative parameter name ব্যবহার করা যায়:

Course(
        String initialTitle
) {
    title =
            initialTitle;
}

এটিও correct।

তবে Java code-এ field এবং parameter-এর same name common:

Course(
        String title,
        int totalLessons
) {
    this.title =
            title;

    this.totalLessons =
            totalLessons;
}

এতে public constructor contract এবং object field names consistent থাকে।


A Complete Constructor with this

public class Course {

    String title;
    int totalLessons;
    long priceInPaisa;

    Course(
            String title,
            int totalLessons,
            long priceInPaisa
    ) {
        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course title is required."
            );
        }

        if (totalLessons <= 0) {
            throw new IllegalArgumentException(
                    "Total lessons must be greater than zero."
            );
        }

        if (priceInPaisa < 0) {
            throw new IllegalArgumentException(
                    "Price cannot be negative."
            );
        }

        this.title =
                title.strip();

        this.totalLessons =
                totalLessons;

        this.priceInPaisa =
                priceInPaisa;
    }
}

this validation-এর জন্য required নয়।

এটি assignment-এর সময় field এবং parameter distinguish করেছে।


this Is Often Optional

যখন naming conflict নেই, this optional।

void publish() {
    published = true;
}

এটি একই:

void publish() {
    this.published = true;
}

প্রথম version সাধারণত cleaner।

Useful rule:

this প্রয়োজন হলে বা meaning clearer করলে ব্যবহার করুন; every field access-এর আগে mechanically ব্যবহার করার দরকার নেই।


Calling Methods with this

Current object-এর method call করতে this ব্যবহার করা যায়।

boolean canPublish() {
    return title != null
            && !title.isBlank()
            && totalLessons > 0;
}

void publish() {
    if (!this.canPublish()) {
        return;
    }

    published = true;
}

এখানে this optional:

if (!canPublish()) {
    return;
}

দুটিই current object-এর method call করে।


Passing the Current Object

কখনো current object অন্য method-এ pass করা যায়।

auditService.recordCourseUpdate(
        this
);

এখানে this current Course object।

তবে domain object-এর ভেতরে services pass করা বা external side effects perform করা carefully design করতে হয়।

Beginner level-এ শুধু conceptটি মনে রাখুন:

this = current object reference

this Cannot Be Used in a Static Context

static method কোনো specific object-এর সঙ্গে execute হয় না।

Therefore:

static void displayTitle() {
    System.out.println(
            this.title
    );
}

compile হবে না।

কারণ static context-এ current object নেই।

Static এবং instance members পরবর্তী lesson-এ বিস্তারিত শেখানো হবে।


Constructor Overloading

একটি class-এ multiple constructors থাকতে পারে, যদি তাদের parameter lists different হয়।

Example:

public class Course {

    String title;
    int totalLessons;
    long priceInPaisa;

    Course(
            String title,
            int totalLessons
    ) {
        this.title =
                title;

        this.totalLessons =
                totalLessons;

        this.priceInPaisa = 0;
    }

    Course(
            String title,
            int totalLessons,
            long priceInPaisa
    ) {
        this.title =
                title;

        this.totalLessons =
                totalLessons;

        this.priceInPaisa =
                priceInPaisa;
    }
}

Usage:

Course freeCourse =
        new Course(
                "Java Fundamentals",
                20
        );

Course paidCourse =
        new Course(
                "Backend Development",
                30,
                799_000L
        );

এটিকে constructor overloading বলা হয়।


The Duplication Problem

আগের constructors-এ same assignment logic repeat হয়েছে।

this.title = title;
this.totalLessons = totalLessons;

Validation add করলে duplication আরও বাড়বে।

Duplicate constructor logic risk তৈরি করে:

  • Validation এক constructor-এ update হলেও অন্যটিতে না হতে পারে
  • Defaults inconsistent হতে পারে
  • Maintenance কঠিন হয়

Constructor chaining duplication কমায়।


Calling Another Constructor with this()

একটি constructor থেকে একই class-এর অন্য constructor call করতে:

this(...)

Example:

public class Course {

    String title;
    int totalLessons;
    long priceInPaisa;

    Course(
            String title,
            int totalLessons
    ) {
        this(
                title,
                totalLessons,
                0
        );
    }

    Course(
            String title,
            int totalLessons,
            long priceInPaisa
    ) {
        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course title is required."
            );
        }

        if (totalLessons <= 0) {
            throw new IllegalArgumentException(
                    "Total lessons must be greater than zero."
            );
        }

        if (priceInPaisa < 0) {
            throw new IllegalArgumentException(
                    "Price cannot be negative."
            );
        }

        this.title =
                title.strip();

        this.totalLessons =
                totalLessons;

        this.priceInPaisa =
                priceInPaisa;
    }
}

Two-argument constructor:

Course(
        String title,
        int totalLessons
)

three-argument constructor-কে call করেছে এবং default price দিয়েছে:

0

this() Must Be the First Statement

Constructor chaining call constructor body-এর first statement হতে হবে।

Wrong:

Course(
        String title,
        int totalLessons
) {
    System.out.println(
            "Creating course"
    );

    this(
            title,
            totalLessons,
            0
    );
}

Compile হবে না।

Correct:

Course(
        String title,
        int totalLessons
) {
    this(
            title,
            totalLessons,
            0
    );
}

Reason:

Java constructor initialization order predictable রাখতে চায়।


Avoid Recursive Constructor Calls

Invalid design:

Course(
        String title
) {
    this(
            title,
            0
    );
}

Course(
        String title,
        int totalLessons
) {
    this(
            title
    );
}

প্রতিটি constructor অন্যটিকে call করছে।

এটি recursive constructor invocation এবং compile হবে না।

একটি primary constructor actual initialization করবে।

Other constructors সেটিতে delegate করতে পারে।


Choosing a Primary Constructor

A useful pattern:

  • One constructor accepts complete required state
  • Shorter constructors provide meaningful defaults
  • Validation and assignments remain in the complete constructor

Example:

Course(
        String title,
        int totalLessons,
        long priceInPaisa
)

Primary constructor।

Course(
        String title,
        int totalLessons
)

Free course তৈরি করার convenience constructor।


Overloaded Constructors Must Represent Meaningful Creation Paths

Overloading শুধু syntax convenience-এর জন্য নয়।

Each constructor should represent a clear valid way to create the object।

Reasonable:

new Course(
        "Java Fundamentals",
        20
);

Meaning:

Create a free course

Reasonable:

new Course(
        "Backend Development",
        30,
        799_000L
);

Meaning:

Create a paid course

Potentially confusing:

Course(
        String title
)

যদি total lesson count required invariant হয়, title-only constructor invalid object তৈরি করতে পারে।

Convenience should not weaken object validity।


Method Overloading

একই class-এ একই method name-এর multiple methods declare করা যায়, যদি parameter lists different হয়।

Example:

void completeLesson() {
    completeLessons(1);
}

boolean completeLessons(
        int lessonCount
) {
    if (lessonCount <= 0) {
        return false;
    }

    int updatedCount =
            completedLessons
            + lessonCount;

    if (
            updatedCount
            > totalLessons
    ) {
        return false;
    }

    completedLessons =
            updatedCount;

    return true;
}

এখানে method names exact same নয়:

completeLesson
completeLessons

তাই এটি overloading নয়।

Actual overloading:

boolean complete(
        int lessonCount
) {
    // Complete by count
}

boolean complete(
        Lesson lesson
) {
    // Complete a specific lesson
}

Same method name:

complete

Different parameter types:

int
Lesson

Valid Method Overloading

Methods overload হতে পারে parameter-এর:

  • Number different হলে
  • Types different হলে
  • Type order different হলে

Different Parameter Count

void changePrice(
        long priceInPaisa
) {
}

void changePrice(
        long priceInPaisa,
        boolean applyImmediately
) {
}

Technically valid।

তবে boolean argument call clarity কমাতে পারে।


Different Parameter Types

void complete(
        int lessonCount
) {
}

void complete(
        Lesson lesson
) {
}

Different Parameter Order

void register(
        String email,
        int age
) {
}

void register(
        int age,
        String email
) {
}

Technically valid, কিন্তু poor design হতে পারে।

Argument order ভুল হওয়ার risk এবং API confusion বাড়ে।


Return Type Alone Cannot Overload a Method

Invalid:

int calculateProgress() {
    return 80;
}

double calculateProgress() {
    return 80.0;
}

Parameter lists same:

calculateProgress()
calculateProgress()

Compiler method call দেখে কোনটি choose করবে বুঝতে পারবে না।

Caller লিখেছে:

enrollment.calculateProgress();

Return value use না করলে return type থেকে selection অসম্ভব।

Therefore:

Method signature-এর overloading distinction parameters দিয়ে হয়, return type দিয়ে নয়।


Method Signature

Beginner level-এ method signature বলতে সাধারণত বোঝানো হয়:

  • Method name
  • Parameter types
  • Parameter order

Example:

complete(int)
complete(Lesson)
complete(int, boolean)

Return type signature distinction তৈরি করে না।

Parameter names-ও overload distinction তৈরি করে না।

Invalid:

void update(
        int completed
) {
}

void update(
        int total
) {
}

দুটির signature same:

update(int)

How Java Selects an Overload

Compiler method call-এর arguments দেখে matching method select করে।

Given:

void printValue(
        int value
) {
    System.out.println(
            "int: " + value
    );
}

void printValue(
        String value
) {
    System.out.println(
            "String: " + value
    );
}

Calls:

printValue(10);
printValue("Nur");

Compiler selects:

10    → printValue(int)
"Nur" → printValue(String)

Numeric Conversion and Overload Selection

Consider:

void show(
        int value
) {
}

void show(
        long value
) {
}

Call:

show(10);

10 is an int literal, so exact int overload selected হবে।

Call:

show(10L);

long overload selected হবে।

Overload resolution numeric conversions-এর কারণে complex হতে পারে।

Beginner-friendly API-তে overloads clearly distinguishable রাখা ভালো।


Ambiguous Overloads

Consider:

void notifyLearner(
        String message
) {
}

void notifyLearner(
        EmailTemplate template
) {
}

Call:

notifyLearner(null);

null both reference types-এর সঙ্গে compatible।

Compiler decide করতে নাও পারে কোন overload use হবে।

Result:

Ambiguous method call

This is one reason overloads carefully design করতে হয়।


Autoboxing Can Complicate Overloading

Consider:

void process(
        int value
) {
}

void process(
        Integer value
) {
}

Calls এবং null values-এর behaviour beginner-এর জন্য confusing হতে পারে।

Unless both overloads have a strong use case, such designs avoid করা ভালো।


Overloading vs Different Method Names

Overloading useful যখন operations conceptually same।

Good candidate:

findById(long id)
findById(String externalId)

But even here method names may be clearer:

findByDatabaseId(long id)
findByExternalId(String externalId)

Different names often communicate domain meaning better।

Ask:

Are these truly the same operation with different input forms, or are they different concepts?


Meaningful Overloading Example

Suppose a course price can be changed using either:

  • Exact amount
  • Percentage discount

Using same primitive type would be confusing:

changePrice(10);

Does 10 mean:

  • 10 paisa?
  • 10 taka?
  • 10 percent?

Overloading cannot solve semantic ambiguity if types are same।

Clear methods:

changePrice(
        long newPriceInPaisa
);

applyDiscountPercentage(
        int discountPercentage
);

Different names are stronger।


Constructor Overloading vs Static Factory Methods

Multiple constructors sometimes become hard to understand:

new Course(
        "Java",
        20,
        0
);

What does 0 mean?

A named creation method can be clearer:

Course.freeCourse(
        "Java",
        20
);

Or:

Course.paidCourse(
        "Backend Development",
        30,
        799_000L
);

These are static factory methods, which will make more sense after learning static members।

For now, remember:

Constructor overloads are useful, but constructors cannot have descriptive names beyond the class name।


A Focused Course Example

Course.java

public class Course {

    String title;
    int totalLessons;
    long priceInPaisa;

    boolean published;

    Course(
            String title,
            int totalLessons
    ) {
        this(
                title,
                totalLessons,
                0
        );
    }

    Course(
            String title,
            int totalLessons,
            long priceInPaisa
    ) {
        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Course title is required."
            );
        }

        if (totalLessons <= 0) {
            throw new IllegalArgumentException(
                    "Total lessons must be greater than zero."
            );
        }

        if (priceInPaisa < 0) {
            throw new IllegalArgumentException(
                    "Price cannot be negative."
            );
        }

        this.title =
                title.strip();

        this.totalLessons =
                totalLessons;

        this.priceInPaisa =
                priceInPaisa;
    }

    boolean changeTitle(
            String title
    ) {
        if (
                title == null
                || title.isBlank()
        ) {
            return false;
        }

        this.title =
                title.strip();

        return true;
    }

    boolean changePrice(
            long priceInPaisa
    ) {
        if (priceInPaisa < 0) {
            return false;
        }

        this.priceInPaisa =
                priceInPaisa;

        return true;
    }

    boolean canPublish() {
        return !title.isBlank()
                && totalLessons > 0;
    }

    boolean publish() {
        if (!canPublish()) {
            return false;
        }

        published = true;

        return true;
    }
}

Using the Constructors

public class Main {

    public static void main(String[] args) {
        Course freeCourse =
                new Course(
                        "Java Fundamentals",
                        20
                );

        Course paidCourse =
                new Course(
                        "Backend Development",
                        30,
                        799_000L
                );

        paidCourse.changeTitle(
                "Backend Development with Spring Boot"
        );

        paidCourse.publish();

        System.out.println(
                freeCourse.title
        );

        System.out.println(
                freeCourse.priceInPaisa
        );

        System.out.println(
                paidCourse.title
        );

        System.out.println(
                paidCourse.published
        );
    }
}

Output:

Java Fundamentals
0
Backend Development with Spring Boot
true

Engineering Note: Avoid Convenience That Hides Meaning

Overloading is convenient, but convenience alone is not enough।

This call is technically simple:

new Course(
        "Java",
        20
);

Its meaning should be documented or obvious:

A constructor without price creates a free course.

If default meaning is not obvious, a named factory may later be better।

Strong API design prioritizes:

  • Clarity
  • Validity
  • Predictability

over saving a few characters।


Common Mistakes

Writing title = title

Course(
        String title
) {
    title = title;
}

Parameter assigns to itself।

Correct:

this.title =
        title;

Overusing this

void publish() {
    this.published = true;
}

Valid, but this is optional here।

published = true;

is simpler।


Using this in Static Methods

static void display() {
    System.out.println(
            this.title
    );
}

Invalid, because static context has no current object।


Placing this() After Another Statement

Course(
        String title
) {
    validate(title);

    this(
            title,
            10
    );
}

Invalid।

this() must be first।


Duplicating Constructor Validation

Multiple constructors each contain same validation logic।

Better:

  • One primary constructor
  • Other constructors delegate with this()

Overloading by Return Type Only

int value() {
}

double value() {
}

Invalid because parameter lists are same।


Overloading with Different Parameter Names Only

void update(
        int completed
) {
}

void update(
        int total
) {
}

Invalid because both signatures are update(int)


Creating Ambiguous Overloads

Too many related reference-type overloads can make null calls ambiguous।


Using Overloading for Different Concepts

process(int price)
process(String learnerName)

The methods accept different types, but the shared name process expresses no useful domain concept।


Practice Exercises

Exercise 1: Fix Field Shadowing

Correct this constructor:

public class Learner {

    String name;
    String email;

    Learner(
            String name,
            String email
    ) {
        name = name;
        email = email;
    }
}

Exercise 2: Constructor Chaining

Create a Course class with:

Course(
        String title,
        int totalLessons
)

for free courses, and:

Course(
        String title,
        int totalLessons,
        long priceInPaisa
)

for paid courses।

The shorter constructor must delegate to the complete constructor।


Exercise 3: Select the Primary Constructor

For an Enrollment, consider:

learnerName
courseTitle
completedLessons
totalLessons

Decide which constructor should be primary।

Explain which values can have meaningful defaults।


Exercise 4: Identify Overloads

Which method pairs are valid overloads?

Pair A

void update(int value)
void update(long value)

Pair B

int progress()
double progress()

Pair C

void enroll(Learner learner)
void enroll(String learnerEmail)

Pair D

void update(int completed)
void update(int total)

Exercise 5: Improve an Unclear API

Improve:

course.update(10);
course.update(true);
course.update("Java");

Use meaningful method names based on possible intentions।


Exercise 6: Find Ambiguity

Explain why this call may be ambiguous:

notify(null);

Given:

void notify(String message)
void notify(EmailTemplate template)

Exercise 7: Decide Between Overloading and Different Names

Design methods for:

  • Changing exact course price
  • Applying a discount percentage

Decide whether they should share one overloaded method name or use different names।

Explain your choice।


Predict the Result

Question 1

public class Learner {

    String name;

    Learner(
            String name
    ) {
        name = name;
    }
}
Learner nur =
        new Learner(
                "Nur"
        );

System.out.println(
        nur.name
);

Question 2

public class Learner {

    String name;

    Learner(
            String name
    ) {
        this.name =
                name;
    }
}

What will nur.name contain?


Question 3

Given:

void show(
        int value
) {
    System.out.println(
            "int"
    );
}

void show(
        long value
) {
    System.out.println(
            "long"
    );
}

What will this print?

show(10);

Question 4

Will this compile?

int calculate() {
    return 1;
}

double calculate() {
    return 1.0;
}

Predict the Result Answers

Answer 1

null

Parameter নিজের কাছেই assign হয়েছে। Field initialize হয়নি।

Answer 2

Nur

this.name current object field refer করেছে।

Answer 3

int

10 একটি int literal, তাই exact int overload select হবে।

Answer 4

না।

Return type alone method overloading support করে না।


Knowledge Check

Question 1

this কী represent করে?

Question 2

Field shadowing কী?

Question 3

this.title = title-এ দুইটি title কী represent করে?

Question 4

this কি সব field access-এর আগে required?

Question 5

this static method-এ ব্যবহার করা যায় না কেন?

Question 6

Constructor overloading কী?

Question 7

this() কী কাজে ব্যবহৃত হয়?

Question 8

this() constructor body-এর কোথায় থাকতে হয়?

Question 9

Constructor chaining-এর benefit কী?

Question 10

Method overloading কী?

Question 11

Return type alone দিয়ে overload করা যায় না কেন?

Question 12

Parameter names different হলে কি overload তৈরি হয়?

Question 13

Ambiguous overload কী?

Question 14

Different method names overloading-এর চেয়ে কখন clearer হতে পারে?


Knowledge Check Answers

Answer 1

Current object reference।

Answer 2

Local variable বা parameter same name ব্যবহার করে field-কে hide করলে।

Answer 3

  • this.title current object-এর field
  • title method বা constructor parameter

Answer 4

না। Naming conflict না থাকলে এটি optional।

Answer 5

Static method কোনো specific object-এর সঙ্গে execute হয় না, তাই current object নেই।

Answer 6

Different parameter listsসহ same class-এ multiple constructors declare করা।

Answer 7

একটি constructor থেকে একই class-এর অন্য constructor call করতে।

Answer 8

First statement হিসেবে।

Answer 9

Duplicate validation এবং initialization logic কমায়।

Answer 10

Same method name-এর multiple methods, যাদের parameter lists different।

Answer 11

Method call-এর arguments দেখে compiler method select করে। Same parameters হলে return type selection-এর জন্য যথেষ্ট নয়।

Answer 12

না। Parameter types এবং order same হলে signature same।

Answer 13

যখন compiler supplied arguments-এর জন্য একটি unique overload select করতে পারে না।

Answer 14

যখন operations technically different input নেয়, কিন্তু domain meaning একই নয় বা overload call ambiguous হয়।


Lesson Summary

এই lesson-এ আমরা শিখেছি:

  • this current object-কে refer করে
  • Same-name parameter field-কে shadow করতে পারে
  • this.field object field এবং parameter distinguish করে
  • Naming conflict না থাকলে this optional
  • Static context-এ current object না থাকায় this unavailable
  • Multiple constructors different creation paths support করতে পারে
  • this() দিয়ে constructor chaining করা যায়
  • this() constructor-এর first statement হতে হয়
  • One primary constructor validation এবং assignment centralize করতে পারে
  • Constructor overloads meaningful valid creation paths represent করা উচিত
  • Method overloading same operation-এর input variations support করে
  • Parameter count, types, এবং order overload distinguish করতে পারে
  • Return type alone overload distinguish করতে পারে না
  • Parameter names overload distinction তৈরি করে না
  • Too many overloads API confusing করতে পারে
  • Ambiguous overloads compiler errors এবং caller confusion তৈরি করে
  • Different method names অনেক ক্ষেত্রে domain meaning better express করে
  • Convenience-এর চেয়ে clarity এবং validity বেশি গুরুত্বপূর্ণ

Next Lesson

পরবর্তী lesson:

Encapsulation, Access Control, and Object Invariants

আমরা শিখব:

  • Why direct field access is dangerous
  • private fields
  • Public object API
  • Access modifiers
  • Getters and setters
  • Why every field should not have a setter
  • Protecting object invariants
  • Behavior-focused methods
  • Keeping objects valid after construction