Implementing Complex Data Types with Java Classes


Classes and Objects

Classes

  • A class is a blueprint for creating objects. It defines the data members (attributes) and methods (functions) that the objects created from the class will have.
  • In Java, classes are defined using the class keyword. The general syntax is:
class ClassName {
    // Data members (attributes)
    // Methods (functions)
}

Objects

  • An object is an instance of a class. It contains state (data) and behavior (methods).
  • The process of creating an object is called instantiation.
  • Objects are created using the new keyword, which allocates memory for the object. For example:
Rectangle r1 = new Rectangle(); // Creates an object of Rectangle class

Example Program: Classes and Objects

Here’s a breakdown of the example provided in the text:

package classesandobjectsproject;
import java.util.*;

class Rectangle {
private int len, brd; // Data members (attributes)

// Method to get data from the user
public void getData() {
Scanner scn = new Scanner(System.in);
System.out.println("Enter length and breadth:");
len = scn.nextInt();
brd = scn.nextInt();
}

// Method to set data directly
public void setData(int l, int b) {
len = l;
brd = b;
}

// Method to display data
public void displayData() {
System.out.println("Length = " + len);
System.out.println("Breadth = " + brd);
}

// Method to calculate area and perimeter
public void areaPeri() {
int area = len * brd;
int perimeter = 2 * (len + brd);
System.out.println("Area = " + area);
System.out.println("Perimeter = " + perimeter);
}
}

public class ClassesAndObjectsProject {
public static void main(String[] args) {
Rectangle r1, r2, r3; // Define three reference variables
r1 = new Rectangle(); // Create first object
r2 = new Rectangle(); // Create second object
r3 = new Rectangle(); // Create third object

r1.setData(10, 20); // Set data for r1
r1.displayData(); // Display r1's data
r1.areaPeri(); // Calculate and print area and perimeter for r1

r2.setData(5, 8); // Set data for r2
r2.displayData(); // Display r2's data
r2.areaPeri(); // Calculate and print area and perimeter for r2

r3.getData(); // Receive data from keyboard for r3
r3.displayData(); // Display r3's data
r3.areaPeri(); // Calculate and print area and perimeter for r3
}
}

Program Explanation

  • Data Members: The class Rectangle has two private data members, len (length) and brd (breadth). Making them private restricts direct access from outside the class, protecting the integrity of the data.
  • Methods:
    • getData(): A method that prompts the user to enter the length and breadth.
    • setData(int l, int b): A method to set the length and breadth directly using parameters.
    • displayData(): Displays the current values of length and breadth.
    • areaPeri(): Calculates and displays the area and perimeter based on the current values of length and breadth.
  • Main Class: The ClassesAndObjectsProject class contains the main() method, which is the entry point of the program.
    • Three Rectangle objects (r1, r2, r3) are created.
    • Data is set for r1 and r2 using setData(), and results are displayed.
    • For r3, data is obtained from user input through the getData() method.

Access Modifiers

  • Private: Data members (len and brd) are declared private, which means they cannot be accessed directly outside the class.
  • Public: The methods (getData(), setData(), displayData(), areaPeri()) are public, allowing other classes to access them. This provides controlled access to the private data members.

Constructors

What is a Constructor?

  • A constructor is a special method that is called when an object is instantiated. It has the same name as the class and does not have a return type.
  • Constructors are used to initialize objects, often setting initial values for the data members.

Types of Constructors

  1. Zero-Argument Constructor: A constructor that does not take any parameters. It initializes data members to default values (e.g., 0, null).
  2. Parameterized Constructor: A constructor that takes parameters to initialize data members with specific values at the time of object creation.

Example Program: Constructors

Here’s another example demonstrating constructors:

package constructorsproject;
import java.util.*;

class Number {
private int i;

// Zero-argument constructor
public Number() {
}

// One-argument constructor
public Number(int j) {
i = j;
}

public void setData(int j) {
i = j;
}

public void getData() {
Scanner scn = new Scanner(System.in);
System.out.println("Enter any integer:");
i = scn.nextInt();
}

public void displayData() {
System.out.println("Value of i = " + i);
}
}

public class ConstructorsProject {
public static void main(String[] args) {
Number n1, n2, n3;
n1 = new Number(); // Calls zero-argument constructor
n1.displayData(); // Displays default value (0)
n1.setData(200); // Sets value using setData()
n1.displayData(); // Displays updated value

n2 = new Number(); // Calls zero-argument constructor
n2.displayData(); // Displays default value (0)
n2.getData(); // Gets input from the user
n2.displayData(); // Displays user-input value

n3 = new Number(100); // Calls one-argument constructor
n3.displayData(); // Displays value (100)
}
}

Constructor Explanation

  • In this example, the Number class has both a zero-argument constructor and a one-argument constructor.
  • When n1 and n2 are created using the zero-argument constructor, the default value of i is 0.
  • The value of i can later be set using the setData() method or obtained through user input via getData().
  • n3 is instantiated with the one-argument constructor, which initializes i directly to 100.

Object Lifecycle and Memory Management

Memory Allocation

  • When an object is created using the new operator, memory is allocated for that object on the heap.
  • The reference variable (like r1, n1, etc.) is stored on the stack, holding the memory address of the object.

Garbage Collection

  • Java has an automatic Garbage Collector that manages memory. It periodically checks for objects that are no longer referenced and reclaims memory, preventing memory leaks.
  • This is different from languages like C++, where the programmer must manually manage memory (allocating and freeing it).

Finalize Method

  • The finalize() method is defined in the Object class and can be overridden to perform cleanup operations (like closing files or releasing resources) before an object is destroyed by the garbage collector.
  • It is called by the garbage collector, but there’s no guarantee when it will be called.

Example Program: Finalize Method

Here’s an example of how the finalize() method works:

package objectdestructionproject;

class Example {
private int data;

public Example() { // Constructor
System.out.println("Inside the constructor");
}

protected void finalize() throws Throwable {
System.out.println("Inside finalize method");
super.finalize(); // Call to superclass finalize
}
}

public class ObjectDestructionProject {
public static void main(String[] args) {
Example e = new Example(); // Object creation
e = null; // Nullifying reference
System.gc(); // Suggest garbage collection
}
}

Finalization Explanation

  • In this example, when the Example object is no longer referenced (by setting e to null), the garbage collector is suggested to run using System.gc().
  • Before the object’s memory is reclaimed, the finalize() method is called, allowing for any necessary cleanup.

Complex Class Implementation

Class Definition: The Complex class is designed to represent complex numbers with a real and imaginary part.

class Complex {
    private float real, imag;
    ...
}

Constructors:

  • A default constructor initializes a Complex object without setting its values.An overloaded constructor initializes a Complex object with specified real and imaginary parts.

public Complex() {
}

public Complex(float r, float i) {
    real = r;
    imag = i;
}

Data Input Methods:

  • getData() method prompts the user to enter the real and imaginary parts of the complex number.setData(float r, float i) allows setting values for the complex number.

public void getData() {
    ...
}

public void setData(float r, float i) {
    real = r;
    imag = i;
}

Display Method: displayData() prints the real and imaginary parts of the complex number.

public void displayData() {
    System.out.println("real = " + real);
    System.out.println("imaginary = " + imag);
}

Arithmetic Operations:

  • addComplex(Complex y) adds two complex numbers and returns the result as a new Complex object.mulComplex(Complex y) multiplies two complex numbers and returns the result.

public Complex addComplex(Complex y) {
    Complex t = new Complex();
    t.real = real + y.real;
    t.imag = imag + y.imag;
    return t;
}

public Complex mulComplex(Complex y) {
    Complex t = new Complex();
    t.real = real * y.real - imag * y.imag;
    t.imag = real * y.imag + y.real * imag;
    return t;
}

Main Class for Testing

Creating Complex Numbers: The main method creates instances of Complex and performs addition and multiplication on them.

public class ComplexNumbersProject {
    public static void main(String[] args) {
        Complex c1 = new Complex();
        c1.setData(2.0f, 2.0f);
        Complex c2 = new Complex();
        Complex c3 = c1.addComplex(c2);
        ...
    }
}

Chaining Method Calls: The program demonstrates the ability to chain method calls, such as adding the result of a multiplication directly to another complex number.

c7 = c1.addComplex(c2.mulComplex(c3));

The this Reference

  • The this keyword is used to refer to the current object instance. It helps distinguish between instance variables and parameters with the same name, particularly when they are set within methods.
public void setData(int i) {
    this.i = i; // Uses 'this' to refer to the instance variable
}

Static Members

  • Static members (both variables and methods) belong to the class rather than instances. They are shared among all instances of the class, which is useful for maintaining shared data, like a count of how many objects have been created
class Ex {
    private static int count = 0;
    ...
    public static void showCount() {
        System.out.println(count);
    }
}

Passing Objects to Functions

  • Objects are passed by reference, meaning if you modify an object’s data within a method, the changes will reflect outside the method as well.
static void fun(Ex p) {
    p.setData(3, 8.5f);
}