0% found this document useful (0 votes)
5 views29 pages

Constructor Overloading & Copy Constructors

This document covers key concepts in Java including constructor overloading, the 'this' keyword, static members, and copy constructors. It explains how to create multiple constructors for a class, the difference between shallow and deep copies, and the importance of method chaining. Additionally, it discusses boxing and unboxing, providing practical examples and exercises for better understanding.

Uploaded by

yashpatill1505
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views29 pages

Constructor Overloading & Copy Constructors

This document covers key concepts in Java including constructor overloading, the 'this' keyword, static members, and copy constructors. It explains how to create multiple constructors for a class, the difference between shallow and deep copies, and the importance of method chaining. Additionally, it discusses boxing and unboxing, providing practical examples and exercises for better understanding.

Uploaded by

yashpatill1505
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Class 2: Constructors, This Keyword & Static Concepts

Objectives:

• Explore constructor overloading


• Understand how this and static interact with members and memory

Topics:

1. Constructor Overloading
o Multiple constructors
o this() for chaining
o Code reusability
2. Copy Constructor (Custom)
o Deep vs shallow copy
o When to use
3. Advanced this Keyword
o In constructor chaining
o this to call method in same class
o Returning this from method (method chaining)
4. Boxing and Unboxing
o Autoboxing: int → Integer
o Unboxing: Integer → int
5. Static Keyword
o What is static
o Static data member vs instance data member
o Static methods
o Access using class name
o Why main() is static
o this not allowed in static context
6. Scenarios
o Static calling static
o Non-static calling static
o Non-static calling non-static
o Static calling non-static
7. toString() Method
o Overriding
o Why and when

Homework:

• Create Box class with overloaded constructors and static counter

Use method chaining (this) in builder-style setter


Constructor Overloading
Before diving into constructor overloading, it's crucial to understand the purpose of constructors.

What is a Constructor?

• A special method used to initialize objects.


• It has the same name as the class.
• No return type, not even void.
• Automatically called when an object is created.

Why Do We Need Multiple Constructors?

Imagine you're creating a Student object. Sometimes you may only know the name, other times you may
know name + age, or even name + age + grade. You don’t want to write multiple classes — that’s where
constructor overloading comes in.

What is Constructor Overloading?

Creating more than one constructor in the same class, each with a different parameter list.

Rules:

1. Same name as the class.


2. Different number or types of parameters (signature must differ).
3. You can have any number of constructors as long as they’re distinguishable by parameters.

Example

class Student {
String name;
int age;

// Constructor 1: No parameters
Student() {
[Link]("Default constructor called");
}

// Constructor 2: One parameter


Student(String name) {
[Link] = name;
}

// Constructor 3: Two parameters


Student(String name, int age) {
[Link] = name;
[Link] = age;
}
}
Explanation:

• JVM determines which constructor to invoke based on arguments passed during object
creation.
• Provides flexibility: Developers can create an object with as much or as little data as they want.

this() for Constructor Chaining

What is this()?

• Used to call another constructor of the same class.


• Helps chain constructors to avoid repetition.

Rules of this():

1. Must be the first statement inside the constructor.


2. Can only be used within the same class.

Example with Chaining:

class Employee {
String name;
int age;
String dept;

Employee() {
this("John Doe", 25, "HR");
}

Employee(String name) {
this(name, 25, "HR");
}

Employee(String name, int age) {


this(name, age, "HR");
}

Employee(String name, int age, String dept) {


[Link] = name;
[Link] = age;
[Link] = dept;
}
}

Explanation:

• Every constructor reuses the logic of the most detailed one (name, age, dept).
• Avoids repeating assignment code in all constructors.

Common Mistakes:

Employee(String name) {
[Link]("Constructor start");
this(name, 25); // ❌ Compiler error: this() is not the first statement
}

Code Reusability

Why Constructor Overloading Helps:

• Eliminates need for repetitive assignment logic.


• Keeps code clean, shorter, and easier to maintain.
• Acts like a mini version of method overloading, tailored for object creation.

Comparison: Without vs With Chaining

Without Chaining:

Employee(String name) {
[Link] = name;
[Link] = 25;
[Link] = "HR";
}
Employee(String name, int age) {
[Link] = name;
[Link] = age;
[Link] = "HR";
}

With Chaining:

Employee(String name) {
this(name, 25);
}
Employee(String name, int age) {
this(name, age, "HR");
}
Employee(String name, int age, String dept) {
[Link] = name;
[Link] = age;
[Link] = dept;
}

Result:

• DRY Principle (Don’t Repeat Yourself)


• One place to change logic
• Improves readability, debugging, and modularity

Real-world analogy

Think of constructor overloading like different ways to order coffee:

• No sugar, no milk
• Only sugar
• Sugar + milk
All are coffee, just initialized with different configurations.

Exercises

Build a Laptop class with 3 constructors:

1. No parameters (default values)


2. Brand and price
3. Brand, price, and RAM

Use constructor chaining wherever possible.

Memory Interaction (for the curious)

• When constructor chaining is used, a stack of constructor calls is created until the most
detailed constructor executes, and values flow back up.
• JVM allocates memory only once — during object creation — but initializations are handled via
the chain.

Summary

Concept Key Idea


Constructor Overloading Multiple constructors in the same class with different parameters
this() Used to call one constructor from another
Code Reusability Reuse logic to avoid code duplication
Copy Constructor (Custom)
Learning Objectives

• Understand what a copy constructor is and why it's useful


• Learn how to implement custom copy constructors in Java
• Explore the difference between shallow and deep copy
• Know when and why to use a copy constructor in real-world design

Introduction

Imagine you create an object Student s1. Now you want to create another object s2 that is a copy of s1.
Should you manually set every field?
Or use =? Or maybe... write a constructor that does the copying for you?

That’s where a Copy Constructor comes in!

What is a Copy Constructor?

Definition:

A constructor that takes an object of the same class as a parameter and copies its data into a new
object.

Syntax:

ClassName(ClassName other) {
// copy fields
}

Example:

class Student {
String name;
int age;

Student(String name, int age) {


[Link] = name;
[Link] = age;
}

// Copy Constructor
Student(Student other) {
[Link] = [Link];
[Link] = [Link];
}
}
Explanation:

• You are copying the values of the other object into a new object.
• This is not the same as reference assignment (Student s2 = s1;) — you are creating a new
independent object.

Shallow Copy vs Deep Copy

Shallow Copy:

Copies the references of fields (for objects), not the actual content.

class Address {
String city;
}

class Person {
String name;
Address address;

Person(Person other) {
[Link] = [Link];
[Link] = [Link]; // Shallow copy!
}
}

Problem:
If you modify [Link] in person2, it also affects person1.

Deep Copy:

Creates a new copy of nested objects — not just copying references.

class Person {
String name;
Address address;

Person(Person other) {
[Link] = [Link];
[Link] = new Address([Link]); // Deep copy
}
}

Rule of Thumb:

• Primitive or Immutable fields (like int, String): Shallow copy is fine

Shallow copy is safe for immutable fields because even if the references are shared, those
objects cannot be altered — there's no risk of unwanted side-effects.
• Mutable objects: You must use deep copy to avoid shared references

Why Not Just Use Assignment (=)?

Student s1 = new Student("Alice", 21);


Student s2 = s1; // This copies the reference, not the data!

• s2 and s1 now point to the same object.


• Modifying [Link] = "Bob" will also reflect in s1.

A copy constructor creates a new object with the same data, ensuring independence.

When to Use a Copy Constructor

Common Scenarios:

1. Cloning objects without reference-sharing problems


2. Pass-by-value for object safety
3. Preventing unwanted side effects from shared references
4. Use in Immutable object wrappers
5. Used in Custom Collection Implementations or DTOs (Data Transfer Objects)

Avoid if:

• Object is too complex to deeply copy manually → Consider clone() with caution, or a utility
method
• Object doesn’t need duplication

Real-World Analogy

Imagine you lend your notebook to a friend (assignment by reference). If they write in it, it affects your
content too.
Instead, you photocopy it (copy constructor). Now they have the same notes, but editing theirs doesn’t
affect yours.
Full Example With Deep Copy

class Address {
String city;

Address(String city) {
[Link] = city;
}

// Copy constructor
Address(Address other) {
[Link] = [Link];
}
}

class Person {
String name;
Address address;

Person(String name, Address address) {


[Link] = name;
[Link] = address;
}

// Copy Constructor (Deep Copy)


Person(Person other) {
[Link] = [Link];
[Link] = new Address([Link]); // Deep copy of Address
}
}

public class Main {


public static void main(String[] args) {
// Original object
Address addr1 = new Address("New York");
Person p1 = new Person("Alice", addr1);

// Copy object using copy constructor


Person p2 = new Person(p1);

// Change copied object's name and city


[Link] = "Bob";
[Link] = "Los Angeles";

// Print both
[Link]("Original Person:");
[Link]("Name: " + [Link]);
[Link]("City: " + [Link]);

[Link]("\nCopied Person:");
[Link]("Name: " + [Link]);
[Link]("City: " + [Link]);
}
}
Output :

Original Person:
Name: Alice
City: New York

Copied Person:
Name: Bob
City: Los Angeles

Exercises

1. Implement a Book class:

• Fields: title, author, price (double), Publisher (custom class)


• Add a deep copy constructor

Memory Visualization

Object creation:

• Assignment copies the reference


• Copy constructor copies the data into a new memory location

Use diagrams to show:

Book b1 = new Book("Java", 500);


Book b2 = new Book(b1); // Different object, same content

Summary

Concept Key Idea


Copy Constructor A constructor that creates a new object by copying another
Shallow Copy Copies references, not content
Deep Copy Recursively copies object fields to avoid shared references
When to Use When you want a full independent copy of an object
Advanced this Keyword in Java
What is this?

The this keyword in Java is a reference to the current object — the one whose method or constructor is
being executed.

Think of this as the object speaking to itself.

this() — Constructor Chaining


What is Constructor Chaining? -- Using one constructor to call another within the same class.
Example:
class Car {
String brand;
int year;

Car() {
this("Unknown", 2020); // calls another constructor, must be the first statement
}

Car(String brand) {
this(brand, 2020); // reuses logic
}

Car(String brand, int year) {


[Link] = brand;
[Link] = year;
}
}

Rule:

• this() must be the first line in the constructor.


• Can only be used inside constructors, not regular methods.

this. — Accessing Methods or Fields


Use this. when:

1. You want to refer to instance variables that may be shadowed by parameters.


2. You want to call another method within the same class.
Example 1: Disambiguate field vs parameter
class Student {
String name;

Student(String name) {
[Link] = name; // disambiguate: [Link] = field, name = parameter
}
}

Example 2: Call a method from another method


class Calculator {
int a, b;

Calculator(int a, int b) {
this.a = a;
this.b = b;
}

void showResult() {
int sum = [Link](); // call add() from same object
[Link]("Sum is: " + sum);
}

int add() {
return this.a + this.b;
}
}

Note: this. is optional unless needed to avoid ambiguity — but it's often used for clarity.

return this — Method Chaining


What is Method Chaining? -- Returning this from a method allows us to call multiple methods on the
same object in one statement.
Example: Builder Style Method Chaining

class Pizza {
String size;
boolean cheese;
boolean pepperoni;

Pizza setSize(String size) {


[Link] = size;
return this;
}

Pizza addCheese() {
[Link] = true;
return this;
}

Pizza addPepperoni() {
[Link] = true;
return this;
}

void build() {
[Link]("Pizza built with: " + size +
(cheese ? ", cheese" : "") +
(pepperoni ? ", pepperoni" : ""));
}
}

Pizza p = new Pizza();


[Link]("Large").addCheese().addPepperoni().build();

Advantages:

• Clean, readable syntax


• Reduces intermediate variables
• Common in Builder pattern, Lombok, ORM frameworks, and Fluent APIs

Quick Comparison

Expression Meaning
[Link] Access current object's field
[Link]() Call another method in same object
this() Call another constructor in same class
return this; Return current object (for methodchaining)
Common Mistakes
Mistake Why it’s wrong
Using this() in non-constructors Only allowed in constructors
Forgetting to return this Breaks chaining
Recursive this() without exit StackOverflowError

Real-World Use Cases

• Builder pattern for constructing complex objects


• JDBC, JPA, Hibernate: method chaining in queries
• Lombok @Accessors(chain = true): auto-generates method chaining

Practice Exercises

1. Create a Book class with chained methods:


o setTitle(String)
o setAuthor(String)
o setPrice(double)
o printDetails()
2. Create a Rectangle class with:
o Multiple constructors using this()
o Method to calculate area using [Link] * [Link]

Summary
Concept Purpose
this() Constructor chaining to reuse logic
this. Call method or field of current object
return this Enable method chaining
Boxing and Unboxing
What is Boxing?

Boxing is converting a primitive into its wrapper object manually.

Manual Boxing (Pre-Java 5):


int x = 10;
Integer obj = new Integer(x); // Boxing

What is Autoboxing?

Autoboxing is when Java automatically converts a primitive to its wrapper class object.

Example:
int x = 20;
Integer obj = x; // Autoboxing — behind the scenes: [Link](x)

Java handles it automatically, so you don’t have to call new Integer(x).

What is Unboxing?

Unboxing is the reverse — converting a wrapper object into a primitive.

Manual Unboxing:
Integer obj = new Integer(50);
int y = [Link](); // Manual unboxing

What is Auto-unboxing?

Auto-unboxing is when Java automatically converts an object to a primitive.

Example:
Integer obj = 100;
int x = obj; // Auto-unboxing — behind the scenes: [Link]()

Real-Life Analogy

Imagine primitive values as raw materials (nuts, bolts).


To send them via a shipping API (collections), you need to box them first.

Collections like ArrayList<Integer> can’t store int directly — but autoboxing does the wrapping for you.
Common Use Cases
Using with Collections:
List<Integer> numbers = new ArrayList<>();
[Link](10); // Autoboxing
int num = [Link](0); // Unboxing
In Generics:
Map<Integer, String> map = new HashMap<>();
[Link](1, "One"); // int → Integer (autoboxing)

Gotchas & Pitfalls


NullPointerException during unboxing:
Integer obj = null;
int x = obj; // Throws NullPointerException

Why? Because Java tries [Link]() and obj is null.

Always check for null before unboxing.

Memory Behavior

• Primitive types are stored on the stack


• Wrapper objects are stored on the heap

This affects performance — boxing/unboxing adds overhead.

Performance Note

• Use primitives for performance-sensitive code (like loops).


• Use wrappers only when object behavior is needed (e.g., collections, null values).
Practice Exercise
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
[Link](i); // Autoboxing
}

int sum = 0;
for (Integer n : list) {
sum += n; // Unboxing
}

[Link]("Sum = " + sum);

Try manually converting to remove autoboxing/unboxing and see how verbose the code gets!

Summary
Concept Description
Boxing Manual conversion: int → new Integer(int)
Autoboxing Automatic: int → Integer
Unboxing Manual: Integer → int via .intValue()
Auto-unboxing Automatic: Integer → int
Use Case Collections, Generics, APIs that need Objects
Autoboxing – more detail :

Integer a = 10; // int automatically boxed to Integer


int b = a; // Integer automatically unboxed to int, less verbose and more readable

The compiler translates these into:

Integer a = [Link](10); // behind the scenes


int b = [Link]();

Operation What Happens Internally


Autoboxing int → Integer → Java calls [Link](int)
Unboxing Integer → int → Java calls [Link]()

Autoboxing in Memory
Code:
int x = 10;
Integer obj = x; // Autoboxing

What Happens:

1. Java calls [Link](10)


2. valueOf() checks the Integer Cache (range -128 to 127)
3. If within range, returns cached object from heap
4. obj now points to an object on the heap

Memory Layout:
Stack Heap
x = 10 Integer@0x123: value = 10
obj → 0x123 Cached or new Integer object

Efficient for small numbers (via caching)

Java caches Integer values from -128 to 127 by default:

Integer a = 100;
Integer b = 100;
[Link](a == b); // ✅ true (same object)

But:

Integer a = 1000;
Integer b = 1000;
[Link](a == b); // ❌ false (different objects)
All the wrapper classes in Java are immutable.

• Java is always pass-by-value (even for objects)


• Integer is an immutable object
• So when you "change" the Integer, you're just reassigning a new object reference, not
modifying the original.

Example:
public class Test {
public static void main(String[] args) {
Integer num = 10;
modify(num);
[Link]("Outside: " + num); // Output? ➜ 10
}

static void modify(Integer n) {


n = n + 5; // autoboxing: creates a new Integer object
[Link]("Inside: " + n); // ➜ 15
}
}

Output:
Inside: 15
Outside: 10

In memory:

• num holds a reference to an Integer object with value 10


• When passed to modify(n), a copy of that reference is passed
• When you do n = n + 5, Java:
o Unboxes n to int
o Adds 5 → becomes 15
o Boxes result back into a new Integer
o n now points to new object — original num is untouched
The static Keyword in Java

What is static?

The static keyword means:


“This belongs to the class itself, not to a specific object.”

When applied to:


Keyword Context Meaning
static variable Shared by all objects of the class (only one copy exists)
static method Can be called without creating an object
static block Runs once when class is loaded (initialization logic)
static class Applies to nested classes only — top-level classes can't be static

Static Data Member vs Instance Data Member


Instance Variable:

• Belongs to each object


• Separate copy for each object

Static Variable:

• Belongs to the class itself


• Only one copy, shared across all instances

Example:
class Counter {
static int count = 0; // static variable
int id; // instance variable

Counter() {
count++;
id = count;
}
}

Counter c1 = new Counter(); // id = 1


Counter c2 = new Counter(); // id = 2
[Link]([Link]); // 2 (shared across all)

// Every object has its own id, but they all share a single count.
Memory Mapping: Static vs Instance
Variable Type Memory Location
Static Method Area (class level)
Instance Heap (per object)

Static Methods
Properties of Static Methods:

• Belong to the class


• Can be called without an object
• Cannot access instance variables or methods directly
• Cannot use this or super keywords

Example:
class MathUtil {
static int square(int x) {
return x * x;
}
}
[Link]([Link](5)); // 25

Common Misunderstanding:
static void print() {
[Link](this); // ❌ Compile error: Cannot use 'this' in static context
}

Because there is no object context in a static method — this refers to "current object", which doesn’t
exist here.

Accessing Static Members Using Class Name


Best Practice:
[Link]([Link]); // Math is a class, PI is static
[Link](Integer.MAX_VALUE); // Integer is a class, MAX_VALUE is static

You can also access them through objects, but that’s discouraged:

MathUtil m = new MathUtil();


[Link]([Link](5)); // works, but not recommended
Why main() is static?
public static void main(String[] args)
Reason:

• JVM needs to call main() without creating an object


• When the class is loaded, no object exists yet
• So main() must be static, so JVM can call:
[Link](args);

Why this is NOT Allowed in Static Context


this refers to the current object.

But in a static context:

• No object exists.
• The method/variable belongs to the class, not any object.

Example:
public class Demo {
static void show() {
[Link](this); // Compile-time error
}
}

Summary Table
Feature Static Instance
Belongs to Class Object
Stored in Method Area Heap
Accessed using [Link] [Link]
Can use this? No Yes
Memory usage Low (one copy shared) Higher (each object has its copy)
Called before object? Yes No

Practice Task

Create a class BankAccount with:

• Static bankName
• Instance accountHolderName
• Static method printBankInfo()
• Instance method printAccountInfo()

Test:

• How many times is bankName shared?


• Can you access instance variables in a static method?
Scenarios — Static vs Non-Static Interactions

Learning Objectives

By the end of this section, learners will:

• Understand the valid and invalid interactions between static and non-static members
• Grasp why static can’t directly access non-static members
• Be able to write error-free object-oriented code with mixed static/non-static methods

Recap of static vs non-static


Feature Static Non-static
Belongs to Class Object
Accessed by Class name (or object) Object only
Object required? No Yes
Stored in Method Area Heap

Scenario 1: Static Calling Static


Is this valid? Yes

Why? Because both members belong to the class, no object is required.

Example:
class Demo {
static void methodA() {
[Link]("Inside static methodA");
methodB(); // ✅ Valid
}

static void methodB() {


[Link]("Inside static methodB");
}

public static void main(String[] args) {


methodA(); // ✅ Valid
}
}
Output:
Inside static methodA
Inside static methodB

Static methods are often utility-style methods and can call each other freely.
Scenario 2: Non-static Calling Static
Is this valid? Yes
Why?
Because:

• Static methods belong to the class


• Objects can see the class-level stuff

Example:
class Demo {
static void greet() {
[Link]("Hello from static");
}

void sayHi() {
greet(); // ✅ Valid
}

public static void main(String[] args) {


Demo d = new Demo();
[Link](); // ✅
}
}

Output:
Hello from static

You can call static from non-static without class name, but using the class name is clearer.

[Link](); // Recommended
Scenario 3: Non-static Calling Non-static
Is this valid? Yes
Why? Because both methods require an object and they belong to the same object. So [Link]()
works just fine.

Example:
class Demo {
void methodA() {
[Link]("In A");
methodB(); // ✅
}

void methodB() {
[Link]("In B");
}

public static void main(String[] args) {


new Demo().methodA(); // ✅
}
}

Output:
In A
In B

This is the most common case in OOP.

Scenario 4: Static Calling Non-static


Is this valid? No — you’ll get a compile-time error.

Why? Because static context does not have an object, and non-static methods require an object.

Example:
class Demo {
void instanceMethod() {
[Link]("I'm non-static");
}

static void staticMethod() {


instanceMethod(); // ❌ Error
}

public static void main(String[] args) {


staticMethod();
}
}
Compile Error: non-static method instanceMethod() cannot be referenced from a static context
Fix: Create an object
static void staticMethod() {
Demo d = new Demo();
[Link](); // Now it works
}

Summary Table
Scenario Allowed? Why?
Static calling static Yes Both belong to class; no object needed
Non-static calling static Yes Instance has access to class-level members
Non-static calling non-static Yes Both tied to the object; uses this internally
Static calling non-static No No object in static context; can't use this

Key Rule to Remember:

You need an object to access non-static members.

Real-Life Analogy

Think of:

• Static methods as school rules — everyone can read them.


• Non-static methods as student records — you need a specific student (object) to see their
data.

Practice Exercise

Create a class Library with:

o A static method getLibraryName()


o A non-static method getBookCount()
o A method printInfo() that tries to call both — try from static and non-static context.

Bonus Quiz: Will it compile?


class A {
static int x = 10;
int y = 20;

static void show() {


[Link](x);
[Link](y); // ❓
}
}

Error: Cannot make a static reference to the non-static field y


toString() Method in Java
Learning Objectives

By the end of this topic, learners will:

• Understand what the toString() method is and where it comes from


• Know how and why to override toString() in user-defined classes
• See what the default implementation returns and why it's not useful
• Learn best practices for overriding toString() for debugging and logging

What is toString()?

The toString() method is defined in the Object class (root class of all Java classes), and it is meant to
return a string representation of an object.

public String toString() {


return getClass().getName() + "@" + [Link](hashCode());
}

Example (Without Overriding):

class Person {
String name;
int age;

Person(String name, int age) {


[Link] = name;
[Link] = age;
}
}

public class Main {


public static void main(String[] args) {
Person p = new Person("Alice", 25);
[Link](p); // Output: Person@1a2b3c4
}
}

The default output isn’t human-readable — it prints class name + hashcode, which is rarely useful.

Overriding toString() — The Right Way

You can override the method in your class to print meaningful object info:

@Override

public String toString() {

return "Person{name='" + name + "', age=" + age + "}";


}
Result:

Person p = new Person("Alice", 25);


[Link](p);
// Output: Person{name='Alice', age=25}

Much cleaner, readable, and helpful during debugging or logging

Why Override toString()?

Reason Description
Debugging Easily inspect object state in logs/prints
Logging Write meaningful info into log files
Testing Helpful for assertions or printing test data
IDE & Console Inspection Most IDEs use toString() to show values
Readable output No need to manually access every field

IDE Example:

In IntelliJ / Eclipse, when you hover or print a variable, toString() is auto-used:

[Link](user); // calls [Link]()

Best Practices:

1. Always override in any class with meaningful state (e.g., DTOs, Models)
2. Use StringBuilder for better performance (if needed)
3. Consider using IDE auto-generate or Lombok’s @ToString
4. Avoid sensitive data in toString() (e.g., passwords)
5. Be consistent in format if used in logs

Bonus: Auto-generate toString() in IntelliJ

• Right-click → Generate → toString()


• Select fields → Done

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", rollNo=" + rollNo +
'}';
}
Summary Table

Aspect Default toString() Overridden toString()


Output Format ClassName@hexHashCode Custom, human-readable
Usefulness Minimal Very helpful for devs/logging
Automatically called? Yes in [Link](obj) Yes

Practice Task

Create a class Book with fields: title, author, price.

• Print object without overriding toString(), then override and compare outputs.
• Add a discountedPrice() method and show how you can combine it in toString() if needed.

You might also like