Lab Manual III · CSE 202
Constructors, Overloading & Reference Passing
Give a Rectangle class default, parameterised and copy constructors chained with this(…), overload area() and describe(), and find out exactly what Java passes to a method.
← → move between slides · F full screen · M slide list
Before we start
Why this lab
You pass a rectangle to a method and it comes back twice as big. You pass a number and it comes back unchanged. Why the difference?
Java always passes a copy: a copy of the number, or a copy of the reference to the object. This lab proves it with a Rectangle class.
Lab 3 of 10
Lab at a glance
After this lab you can
- Define default, parameterised and copy constructors
- Chain constructors with
this(…)to avoid repeated code - Overload methods by changing the parameter list
- Explain how the compiler picks an overload
- Distinguish passing primitives from passing object references
- Explain why reassigning a parameter does not affect the caller
Before you start
- Lab 2: classes, objects, constructors, encapsulation
- Primitive vs reference types
Plan for the session
- Theory recap
- Walk through the program, section by section, and run it
- In-lab tasks, shown to the instructor
- Report exercises at home
Lab 3 of 10
Contents
Select a part to jump to it.
Theory 1 of 5
Default, parameterised and copy constructors
public Rectangle() // default: 1 x 1, White public Rectangle(double side) // square public Rectangle(double w, double h) // rectangle public Rectangle(double w, double h, String colour) public Rectangle(Rectangle other) // copy
- Java writes a no-argument constructor only if you write none yourself.
- A copy constructor builds a new, independent object with the same field values.
Theory 2 of 5
Constructor chaining with this(…)
- Simpler constructors delegate to the full one, so validation lives in one place.
Constructor chaining with this(…)
public Rectangle(double side) {
this(side, side, "White"); // must be the first statement
}
Theory 3 of 5
Method overloading
public double area() // own fields public double area(double scaleFactor) // scaled public static double area(double width, double height) // any size
- Same name, different parameter lists (number, type or order).
- Resolved by the compiler at compile time.
- A different return type or access modifier alone is not an overload — compile error.
Theory 4 of 5
Passing a primitive
- The method gets a copy of the value; changing the copy cannot touch the caller’s variable.
Passing a primitive
static void passPrimitive(double side) { side = side * 2; }
double side = 10.0;
passPrimitive(side); // side is still 10.0
Theory 5 of 5
Passing an object reference
- The method gets a copy of the reference: both point to the same object, so
r.scale(2.0)is visible to the caller. - Reassigning the parameter (
r = new Rectangle(…)) only moves the copy; the caller still sees the original. - So Java is always pass-by-value — for objects the value is a reference.
Implementation design
Program design
Implementation design
Execution flow
- Build rectangles with each of the five constructors
- Copy r3, change r3’s colour and show the copy is unchanged
- Call the three area() overloads and the two describe() overloads
- Pass a primitive: unchanged after the call
- Pass a reference and scale: the change is visible
- Reassign the parameter: the caller’s object is untouched
All constructors funnel into the full one, which validates width and height.
Code walkthrough 1 of 13 · Rectangle.java
Constructor chaining
public Rectangle() {
this(1.0, 1.0, "White");
}
public Rectangle(double side) {
this(side, side, "White");
}
public Rectangle(double width, double height) {
this(width, height, "White");
}- Each simple constructor passes defaults to the full one with
this(…).
Code walkthrough 2 of 13 · Rectangle.java
The full constructor validates
public Rectangle(double width, double height, String colour) {
if (width > 0) {
this.width = width;
} else {
this.width = 1.0;
}
if (height > 0) {
this.height = height;
} else {
this.height = 1.0;
}
this.colour = colour;
}- All checks live in one place, whichever constructor was called.
Code walkthrough 3 of 13 · Rectangle.java
The copy constructor
// Copy constructor
public Rectangle(Rectangle other) {
this(other.width, other.height, other.colour);
}- Builds a new object from another one’s values; it can read
other’s private fields because it is the same class.
Code walkthrough 4 of 13 · Rectangle.java
Three overloads of area()
public double area() {
return width * height;
}
public double area(double scaleFactor) {
return area() * scaleFactor;
}
public static double area(double width, double height) {
return width * height;
}- Same name, different parameters.
- The static one needs no object:
Rectangle.area(3, 8).
Code walkthrough 5 of 13 · Rectangle.java
describe() overloads and scale()
public String describe() {
return String.format("Rectangle[%.2f x %.2f, colour=%s, area=%.2f]",
width, height, colour, area());
}
public String describe(String prefix) {
return prefix + ": " + describe();
}
public void scale(double factor) {
Code walkthrough 5 of 13 · Rectangle.java
describe() overloads and scale() (cont.)
if (factor > 0) {
width = width * factor;
height = height * factor;
}
}describe(prefix)reusesdescribe().scale()changes the object itself.
Code walkthrough 6 of 13 · Lab3Demo.java
Passing a primitive
static void passPrimitive(double side) {
System.out.println("Inside passPrimitive: side before = " + side);
side = side * 2;
System.out.println("Inside passPrimitive: side after = " + side);
}sidehere is a copy; doubling it cannot change the caller’s variable.
Code walkthrough 7 of 13 · Lab3Demo.java
Passing a reference
static void passReference(Rectangle rectangle) {
System.out.println("Inside passReference before scaling: " + rectangle.describe());
rectangle.scale(2.0);
System.out.println("Inside passReference after scaling : " + rectangle.describe());
}- The parameter points to the caller’s object, so scaling is visible after the call.
Code walkthrough 8 of 13 · Lab3Demo.java
Reassigning the parameter
static void tryReassignReference(Rectangle rectangle) {
rectangle = new Rectangle(99.0, 99.0, "Invisible");
System.out.println("Inside tryReassignReference: " + rectangle.describe());
}- Only the local copy of the reference moves to the new object.
Code walkthrough 9 of 13 · Lab3Demo.java
Using every constructor
// 1. Constructor Variants
System.out.println("=== Constructor Variants ===");
Rectangle r0 = new Rectangle();
System.out.println("Default constructor : " + r0.describe());
Rectangle r1 = new Rectangle(5.0);
System.out.println("Square constructor : " + r1.describe());
Rectangle r2 = new Rectangle(4.0, 7.0);
System.out.println("Two-arg constructor : " + r2.describe());
Rectangle r3 = new Rectangle(3.0, 6.0, "Blue");
System.out.println("Full constructor : " + r3.describe());
Rectangle r4 = new Rectangle(r3);
System.out.println("Copy constructor : " + r4.describe());- The compiler picks a constructor by the arguments.
Code walkthrough 10 of 13 · Lab3Demo.java
Copies are independent
// 2. Copy Constructor Independence
System.out.println("\n=== Copy Constructor Independence ===");
r3.setColour("Green");
System.out.println("Original after change : " + r3.describe());
System.out.println("Copy remains unchanged : " + r4.describe());- Changing r3 does not affect r4.
Code walkthrough 11 of 13 · Lab3Demo.java
Calling the overloads
// 3. Method Overloading
System.out.println("\n=== Method Overloading: area() ===");
Rectangle rect = new Rectangle(6.0, 4.0, "Yellow");
System.out.printf("area() = %.2f%n", rect.area());
System.out.printf("area(1.5) = %.2f%n", rect.area(1.5));
System.out.printf("area(3.0, 8.0) = %.2f%n", Rectangle.area(3.0, 8.0));
System.out.println("\n=== Method Overloading: describe() ===");
System.out.println(rect.describe());
System.out.println(rect.describe("Main rectangle"));- Arguments decide which area() and describe() run.
Code walkthrough 12 of 13 · Lab3Demo.java
Pass-by-value: a primitive
// 4. Passing Primitive Value
System.out.println("\n=== Passing a Primitive Value ===");
double side = 10.0;
System.out.println("Before method call: side = " + side);
passPrimitive(side);
System.out.println("After method call : side = " + side);- side is still 10.0 after the call: the method doubled a copy.
Code walkthrough 13 of 13 · Lab3Demo.java
Pass-by-value: references
// 5. Passing Object Reference
System.out.println("\n=== Passing an Object Reference ===");
Rectangle ref = new Rectangle(5.0, 5.0, "Blue");
System.out.println("Before method call: " + ref.describe());
passReference(ref);
System.out.println("After method call : " + ref.describe());
// 6. Reassigning Reference Parameter
System.out.println("\n=== Reassigning Reference Parameter ===");
Rectangle original = new Rectangle(2.0, 3.0, "Pink");
System.out.println("Before method call: " + original.describe());
tryReassignReference(original);
System.out.println("After method call : " + original.describe());- Mutating through the reference: the change is visible.
- Reassigning the reference: the caller still sees the Pink 2 × 3 rectangle.
Step through the code · 1 of 3
Trace: constructor chaining with this(…)
The stack grows by one frame when one constructor hands over to another.
Step through the code · 1 of 3
Trace: constructor chaining with this(…) (cont.)
Step through the code · 2 of 3
Trace: pass-by-value, three ways
Before stepping, predict which call changes something the caller can see.
Step through the code · 2 of 3
Trace: pass-by-value, three ways (cont.)
Step through the code · 3 of 3
Trace: copy or alias?
r4 is a copy made by the copy constructor; r5 is just another reference. Which one changes when r3 does?
Step through the code · 3 of 3
Trace: copy or alias? (cont.)
For reference · 2 files
The complete program
public class Rectangle {
private double width;
private double height;
private String colour;
public Rectangle() {
this(1.0, 1.0, "White");
}
public Rectangle(double side) {
this(side, side, "White");
}
public Rectangle(double width, double height) {
this(width, height, "White");
}
public Rectangle(double width, double height, String colour) {
if (width > 0) {
this.width = width;
} else {
this.width = 1.0;
}
if (height > 0) {
this.height = height;
} else {
this.height = 1.0;
}
this.colour = colour;
}
// Copy constructor
public Rectangle(Rectangle other) {
this(other.width, other.height, other.colour);
}
public double area() {
return width * height;
}
public double area(double scaleFactor) {
return area() * scaleFactor;
}
public static double area(double width, double height) {
return width * height;
}
public String describe() {
return String.format("Rectangle[%.2f x %.2f, colour=%s, area=%.2f]",
width, height, colour, area());
}
public String describe(String prefix) {
return prefix + ": " + describe();
}
public void scale(double factor) {
if (factor > 0) {
width = width * factor;
height = height * factor;
}
}
public double getWidth() { return width; }
public double getHeight() { return height; }
public String getColour() { return colour; }
public void setColour(String colour) { this.colour = colour; }
@Override
public String toString() {
return describe();
}
}public class Lab3Demo {
static void passPrimitive(double side) {
System.out.println("Inside passPrimitive: side before = " + side);
side = side * 2;
System.out.println("Inside passPrimitive: side after = " + side);
}
static void passReference(Rectangle rectangle) {
System.out.println("Inside passReference before scaling: " + rectangle.describe());
rectangle.scale(2.0);
System.out.println("Inside passReference after scaling : " + rectangle.describe());
}
static void tryReassignReference(Rectangle rectangle) {
rectangle = new Rectangle(99.0, 99.0, "Invisible");
System.out.println("Inside tryReassignReference: " + rectangle.describe());
}
public static void main(String[] args) {
// 1. Constructor Variants
System.out.println("=== Constructor Variants ===");
Rectangle r0 = new Rectangle();
System.out.println("Default constructor : " + r0.describe());
Rectangle r1 = new Rectangle(5.0);
System.out.println("Square constructor : " + r1.describe());
Rectangle r2 = new Rectangle(4.0, 7.0);
System.out.println("Two-arg constructor : " + r2.describe());
Rectangle r3 = new Rectangle(3.0, 6.0, "Blue");
System.out.println("Full constructor : " + r3.describe());
Rectangle r4 = new Rectangle(r3);
System.out.println("Copy constructor : " + r4.describe());
// 2. Copy Constructor Independence
System.out.println("\n=== Copy Constructor Independence ===");
r3.setColour("Green");
System.out.println("Original after change : " + r3.describe());
System.out.println("Copy remains unchanged : " + r4.describe());
// 3. Method Overloading
System.out.println("\n=== Method Overloading: area() ===");
Rectangle rect = new Rectangle(6.0, 4.0, "Yellow");
System.out.printf("area() = %.2f%n", rect.area());
System.out.printf("area(1.5) = %.2f%n", rect.area(1.5));
System.out.printf("area(3.0, 8.0) = %.2f%n", Rectangle.area(3.0, 8.0));
System.out.println("\n=== Method Overloading: describe() ===");
System.out.println(rect.describe());
System.out.println(rect.describe("Main rectangle"));
// 4. Passing Primitive Value
System.out.println("\n=== Passing a Primitive Value ===");
double side = 10.0;
System.out.println("Before method call: side = " + side);
passPrimitive(side);
System.out.println("After method call : side = " + side);
// 5. Passing Object Reference
System.out.println("\n=== Passing an Object Reference ===");
Rectangle ref = new Rectangle(5.0, 5.0, "Blue");
System.out.println("Before method call: " + ref.describe());
passReference(ref);
System.out.println("After method call : " + ref.describe());
// 6. Reassigning Reference Parameter
System.out.println("\n=== Reassigning Reference Parameter ===");
Rectangle original = new Rectangle(2.0, 3.0, "Pink");
System.out.println("Before method call: " + original.describe());
tryReassignReference(original);
System.out.println("After method call : " + original.describe());
}
}Copy or download each file, save it under the same name, then compile and run: javac *.java → java Lab3Demo
Implementation
Expected output
=== Constructor Variants === Default constructor : Rectangle[1.00 x 1.00, colour=White, area=1.00] Square constructor : Rectangle[5.00 x 5.00, colour=White, area=25.00] Two-arg constructor : Rectangle[4.00 x 7.00, colour=White, area=28.00] Full constructor : Rectangle[3.00 x 6.00, colour=Blue, area=18.00] Copy constructor : Rectangle[3.00 x 6.00, colour=Blue, area=18.00] === Copy Constructor Independence === Original after change : Rectangle[3.00 x 6.00, colour=Green, area=18.00] Copy remains unchanged : Rectangle[3.00 x 6.00, colour=Blue, area=18.00] === Method Overloading: area() === area() = 24.00 area(1.5) = 36.00 area(3.0, 8.0) = 24.00 === Method Overloading: describe() === Rectangle[6.00 x 4.00, colour=Yellow, area=24.00] Main rectangle: Rectangle[6.00 x 4.00, colour=Yellow, area=24.00] === Passing a Primitive Value === Before method call: side = 10.0 Inside passPrimitive: side before = 10.0 Inside passPrimitive: side after = 20.0 After method call : side = 10.0 === Passing an Object Reference === Before method call: Rectangle[5.00 x 5.00, colour=Blue, area=25.00] Inside passReference before scaling: Rectangle[5.00 x 5.00, colour=Blue, area=25.00] Inside passReference after scaling : Rectangle[10.00 x 10.00, colour=Blue, area=100.00] After method call : Rectangle[10.00 x 10.00, colour=Blue, area=100.00] === Reassigning Reference Parameter === Before method call: Rectangle[2.00 x 3.00, colour=Pink, area=6.00] Inside tryReassignReference: Rectangle[99.00 x 99.00, colour=Invisible, area=9801.00] After method call : Rectangle[2.00 x 3.00, colour=Pink, area=6.00]
Compare the last three sections: the primitive is unchanged, the scaled object changed, the reassigned parameter left the original alone.
Interactive 1 of 1
Which overload does the compiler pick?
In-lab task 1 of 3
Task 1: Overloaded perimeter() methods
Show a hint
perimeter().In-lab task 2 of 3
Task 2: Copy constructor independence test
Show a hint
In-lab task 3 of 3
Task 3: Design a Circle class
Show a hint
Circle(double radius, String colour) and validate radius there.In-lab tasks
Show your work during the lab
For each task, show the instructor:
- the source code
- a successful compilation
- the running output
- a short explanation of the logic you used
Lab report · exercise 1 of 2
Geometric shape library
Triangle and Cylinder with a driver class.Lab report · exercise 2 of 2
Student record mutation study
StudentRecord with a double[] grades array, to study copying and mutation.Lab report
Writing the lab report
- Problem statement and your design (classes, fields, methods)
- Complete source code, formatted and commented
- Sample output or screenshots for normal and edge cases
- A short discussion: what each OOP concept did in your program
Academic integrity
Copying from the internet, classmates, seniors or any other unauthorized source is strictly prohibited. Full marks may be deducted if plagiarism, copied work or academic dishonesty is detected. Complete the tasks, implementation, output analysis and report yourself.
Discussion and analysis
Viva questions (1 of 2)
this(…) be the first statement in a constructor?Show the answer
Show the answer
calculate() would be ambiguous, so it is a compile error.Discussion and analysis
Viva questions (2 of 2)
Show the answer
Show the answer
Check yourself
Quiz
Summary
Summary
- Default, parameterised and copy constructors give flexible object creation.
- Chain constructors with this(…) so validation lives in one place.
- Overloads share a name but differ in parameters; the compiler chooses.
- Java passes copies: of values for primitives, of references for objects.
- Mutation through a reference is visible; reassigning the parameter is not.