Skip to main content

2

Wrapper Classes, Boxing, and Unboxing​

Wrapper Classes​

In Java, wrapper classes are used to convert primitive data types into objects. The wrapper classes are part of the java.lang package.

Primitive Data Types and Their Wrapper Classes​

Primitive TypeWrapper Class
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

Boxing and Autoboxing​

  • Boxing: The process of converting a primitive data type into its corresponding wrapper class object.
  • Autoboxing: When this conversion is done automatically by the Java compiler.

Unboxing and Auto-Unboxing​

  • Unboxing: The process of converting a wrapper class object into a primitive data type.
  • Auto-Unboxing: When this conversion happens automatically by the Java compiler.

Sorting of Objects in Java​

Sorting is a fundamental operation in Java used to arrange elements in a specific order. Java provides different ways to sort elements in collections.

Sorting Using TreeSet (Automatically Sorted in Ascending Order)​

import java.util.TreeSet;

public class TreeSetSortingExample {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(89);
ts.add(45);
ts.add(23);
ts.add(67);
ts.add(12);
System.out.println("TreeSet: " + ts); // Output: [12, 23, 45, 67, 89]
}
}

Sorting Using ArrayList​

import java.util.ArrayList;
import java.util.Collections;

public class ArrayListSortingExample {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
al.add(89);
al.add(45);
al.add(23);
al.add(67);
al.add(12);

Collections.sort(al); // Sorting the ArrayList
System.out.println("ArrayList: " + al); // Output: [12, 23, 45, 67, 89]
}
}

Sorting Using ArrayDeque (Indirect Method)​

ArrayDeque does not support sorting directly. However, we can convert it into an ArrayList, sort it, and then add back the sorted elements.

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;

public class ArrayDequeSortingExample {
public static void main(String[] args) {
ArrayDeque<Integer> ad = new ArrayDeque<>();
ad.add(89);
ad.add(45);
ad.add(23);
ad.add(67);
ad.add(12);

System.out.println("Original ArrayDeque: " + ad); // [89, 45, 23, 67, 12]

ArrayList<Integer> adList = new ArrayList<>(ad);
Collections.sort(adList); // Sorting the ArrayList

System.out.println("Sorted ArrayDeque (Converted to List): " + adList); // [12, 23, 45, 67, 89]

ad.clear(); // Clearing the ArrayDeque
ad.addAll(adList); // Adding sorted elements back to ArrayDeque

System.out.println("Sorted ArrayDeque after clearing: " + ad); // [12, 23, 45, 67, 89]
}
}

Sorting in Java Collections​

  1. TreeSet: Automatically sorts elements in ascending order.
  2. ArrayList & LinkedList: Can be sorted using Collections.sort(list).
  3. ArrayDeque: Does not support sorting directly, but can be sorted by converting to a list.

These methods help efficiently arrange elements in the desired order.

Notes on Storing Complex Objects in Java Collection Framework

1. Introduction​

  • Java's Collection Framework allows storing and managing complex objects efficiently.
  • Commonly used collections include ArrayList, HashSet, and HashMap.

2. Defining a Complex Object​

  • A complex object is a user-defined class with multiple attributes.
  • In this case, we define a Student class with attributes like roll number, name, age, gender, marks, and placement status.
class Student {
int rollNo;
String name;
int age;
char gender;
double marks;
boolean isPlaced;

// Parameterized constructor
Student(int rollNo, String name, int age, char gender, double marks, boolean isPlaced) {
this.rollNo = rollNo;
this.name = name;
this.age = age;
this.gender = gender;
this.marks = marks;
this.isPlaced = isPlaced;
}

// Overriding toString() method for better output representation
@Override
public String toString() {
return "Student{" +
"rollNo=" + rollNo +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", marks=" + marks +
", isPlaced=" + isPlaced +
'}';
}
}

3. Storing Objects in an ArrayList​

  • ArrayList is a dynamic array used to store multiple Student objects.
  • We create ArrayList<Student> and add objects using add() method.


//Sorting Complex Objects

import java.lang.reflect.Array;
import java.util.ArrayList;

class Student {
int rollNo;
String name;
int age;
char gender;
double marks;
boolean isPlaced;

//Parameterized constructor
Student(int rollNo, String name, int age, char gender, double marks, boolean isPlaced){

this.age = age;
this.gender = gender;
this.marks = marks;
this.isPlaced = isPlaced;
}

// Override toString method for better output representation
@Override
public String toString() {
return "Student{" +
"rollNo=" + rollNo +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", marks=" + marks +
", isPlaced=" + isPlaced +
'}';
}


}


public class Main {
public static void main(String[] args) {
Student s1 = new Student(1, "John", 20, 'M', 85.5, true);
Student s2 = new Student(2, "Jane", 22, 'F', 90.0, false);
Student s3 = new Student(3, "Mike", 21, 'M', 78.0, true);
Student s4 = new Student(4, "Sara", 23, 'F', 88.5, false);


ArrayList al = new ArrayList();
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);

System.out.println(al); // This will print the memory address of the object [Student@2f92e0f4, Student@28a418fc, Student@5305068a, Student@1f32e575]

System.out.println(al.toString()); //equivalent to System.out.println(al); // This will print the memory address of the object [Student@2f92e0f4, Student@28a418fc, Student@5305068a, Student@1f32e575]
// To print the values of the object, we need to override the toString() method in the Student class



}
}

4. Explanation​

  • Step 1: Define a class Student with attributes and a constructor.
  • Step 2: Override the toString() method to format object output.
  • Step 3: Create an ArrayList<Student> to store multiple student objects.
  • Step 4: Add Student objects to the list.
  • Step 5: Print the list, where toString() helps display values instead of memory references.

5. Output​

[Student{rollNo=1, name='John', age=20, gender=M, marks=85.5, isPlaced=true},
Student{rollNo=2, name='Jane', age=22, gender=F, marks=90.0, isPlaced=false},
Student{rollNo=3, name='Mike', age=21, gender=M, marks=78.0, isPlaced=true},
Student{rollNo=4, name='Sara', age=23, gender=F, marks=88.5, isPlaced=false}]

6. Benefits of Using Collection Framework​

  • Dynamic Sizing: ArrayList resizes dynamically.
  • Efficient Data Manipulation: Allows easy addition, removal, and searching of objects.
  • Easy Sorting and Filtering: Sorting can be done using Comparator or Comparable.
  • Code Maintainability: Makes handling object collections easier and cleaner.

7. Conclusion​

Using Java’s Collection Framework, we can efficiently store, retrieve, and manipulate complex objects like Student. ArrayList<Student> provides flexibility

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

// Laptop class representing a complex object
class Laptop {
int id;
String brand;
double cost;
String processor;
int memory;
char grade;

// Parameterized constructor
public Laptop(int id, String brand, double cost, String processor, int memory, char grade) {
this.id = id;
this.brand = brand;
this.cost = cost;
this.processor = processor;
this.memory = memory;
this.grade = grade;
}

// Override toString method for better output representation
@Override
public String toString() {
return "Laptop{" +
"ID=" + id +
", Brand='" + brand + '\'' +
", Cost=" + cost +
", Processor='" + processor + '\'' +
", Memory=" + memory + "GB" +
", Grade=" + grade +
'}';
}
}

// Main class to store and display laptop details
public class Main {
public static void main(String[] args) {
// Creating Laptop objects
Laptop l1 = new Laptop(101, "Dell", 75000.50, "Intel i7", 16, 'A');
Laptop l2 = new Laptop(102, "HP", 65000.75, "AMD Ryzen 5", 8, 'B');
Laptop l3 = new Laptop(103, "Apple", 125000.00, "M1", 16, 'A');

// Creating an ArrayList to store Laptop objects
List<Laptop> laptopList = new ArrayList<>();
laptopList.add(l1);
laptopList.add(l2);
laptopList.add(l3);

// Displaying the details of all Laptop objects using toString()
System.out.println(laptopList.toString());

// Collections.sort(laptopList); // cannot sort without implementing Comparable or Comparator

System.out.println(laptopList);
}
}

Notes on Storing and Sorting Complex Objects in Java Collection Framework

Storing Complex Objects in Collection Framework:​

  1. Defining a Class:

    • Create a class with multiple attributes (e.g., Laptop with ID, brand, cost, processor, memory, and grade).
    • Define a parameterized constructor to initialize objects.
    • Override the toString() method for meaningful output representation.
  2. Using Generic Collections:

    • Use ArrayList<Laptop> to store multiple objects of the Laptop class.
    • Generics ensure type safety, allowing only Laptop objects to be stored in the list.
  3. Adding Objects to the Collection:

    • Create instances of the Laptop class.
    • Add these instances to the ArrayList using the add() method.

Sorting Complex Objects:​

  1. Why Sorting is Not Automatic?

    • Collections.sort() works for primitive types and simple objects.
    • Complex objects require custom sorting logic as they contain multiple attributes.
  2. Sorting Approaches:

    • Using Comparable Interface: Implement the Comparable<T> interface and override the compareTo() method.
    • Using Comparator Interface: Pass a custom comparator to Collections.sort() for flexible sorting.
  3. Sorting by Cost (Example):

    • Use Collections.sort(list, Comparator.comparingDouble(l -> l.cost));
    • This sorts the list based on the cost attribute in ascending order.

Example Code Overview:​

  • Class Laptop defines attributes, constructor, and toString() method.
  • Main Class Main:
    • Creates and stores Laptop objects in an ArrayList.
    • Displays the list before sorting.
    • Sorts the list by cost using Comparator.comparingDouble.
    • Displays the sorted list.

This approach ensures efficient storage and sorting of complex objects in Java.

Notes on Sorting Complex Objects Using Comparable Interface

Understanding Comparable Interface:​

  1. Purpose:

    • The Comparable<T> interface is used to define the natural ordering of objects.
    • It contains a single method compareTo(T o) which determines the sorting logic.
  2. How It Works:

    • The compareTo() method compares the current object (this) with another object (o).
    • It returns:
      • 0 if both objects are equal.
      • A negative number if this should come before o.
      • A positive number if this should come after o.

Implementing Comparable in Student Class:​

  1. Define Attributes:

    • rollNo, name, age, gender, marks, isPlaced.
  2. Constructor and toString() Method:

    • Initializes attributes and provides meaningful string representation.
  3. Implement compareTo() Method:

    • Sorting by age in ascending order using return this.age - o.age;.
    • Alternative approach (commented in code) for sorting by marks in descending order.

Sorting Student Objects in ArrayList:​

  1. Creating and Adding Objects:

    • Instances of Student are created and added to an ArrayList<Student>.
  2. Sorting Using Collections.sort()

    • Calls compareTo() internally to sort objects.
    • Ensures consistent ordering of elements.

Example Code Overview:​

  • Class Student implements Comparable<Student>.
  • Main Class Main:
    • Creates and stores Student objects in an ArrayList.
    • Displays the list before sorting.
    • Sorts using Collections.sort() which invokes compareTo().
    • Displays the sorted list.

Key Takeaways:​

  • Implement Comparable<T> for natural ordering.
  • Use compareTo() to define sorting logic.
  • Sorting is automatic with Collections.sort() after implementing Comparable.
  • Modify compareTo() logic to sort by different attributes as needed.


//Sorting Complex Objects

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;

class Student implements Comparable<Student> {
int rollNo;
String name;
int age;
char gender;
double marks;
boolean isPlaced;

//Parameterized constructor
Student(int rollNo, String name, int age, char gender, double marks, boolean isPlaced){

this.age = age;
this.gender = gender;
this.marks = marks;
this.isPlaced = isPlaced;
}

// Override toString method for better output representation
@Override
public String toString() {
return "Student{" +
"rollNo=" + rollNo +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", marks=" + marks +
", isPlaced=" + isPlaced +
'}';
}

// @Override
// public int compareTo(Student o) {
// // Compare by marks in descending order
// if (this.marks < o.marks) {
// return 1;
// } else if (this.marks > o.marks) {
// return -1;
// } else {
// return 0;
// }
// }

@Override
public int compareTo(Student o) {
return this.age - o.age; // Compare by age in ascending order

}


}


public class Main {
public static void main(String[] args) {
Student s1 = new Student(1, "John", 20, 'M', 85.5, true);
Student s2 = new Student(2, "Jane", 22, 'F', 90.0, false);
Student s3 = new Student(3, "Mike", 21, 'M', 78.0, true);
Student s4 = new Student(4, "Sara", 23, 'F', 88.5, false);


ArrayList al = new ArrayList();
al.add(s1);
al.add(s2);
al.add(s3);
al.add(s4);

System.out.println("Before sorting: " + al);

Collections.sort(al); // Sort the list using the compareTo method
// internally it will call the compareTo method of each object in the list
// and sort the list based on the return value of the compareTo method
System.out.println("After sorting: " + al);



}
}


Comparable vs Comparator in Java

1. Choosing Between Comparable and Comparator​

  • Use Comparable when the target class is accessible for modification.
  • Use Comparator when the target class is not accessible for modification.

2. Key Differences​

FeatureComparableComparator
DefinitionUsed to define the natural ordering of objects.Used to define custom ordering of objects.
ImplementationImplemented inside the target class.Implemented as a separate class.
MethodcompareTo(T o)compare(T o1, T o2)
ParametersTakes one parameter.Takes two parameters.
ModifiabilityRequires modifying the target class.Does not require modifying the target class.
Used WithCollections.sort(list)Collections.sort(list, comparatorInstance)

3. Example Using Comparable (When Target Class is Modifiable)​

import java.util.*;

class Student implements Comparable<Student> {
int rollNo;
String name;
int age;

public Student(int rollNo, String name, int age) {
this.rollNo = rollNo;
this.name = name;
this.age = age;
}

@Override
public int compareTo(Student other) {
return this.age - other.age; // Sorting by age
}

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

public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(1, "John", 20));
students.add(new Student(2, "Jane", 22));
students.add(new Student(3, "Mike", 21));

System.out.println("Before Sorting: " + students);
Collections.sort(students);
System.out.println("After Sorting by Age: " + students);
}
}

4. Example Using Comparator (When Target Class is Not Modifiable)​

import java.util.*;

class Laptop {
int id;
String brand;
double price;

public Laptop(int id, String brand, double price) {
this.id = id;
this.brand = brand;
this.price = price;
}

@Override
public String toString() {
return "Laptop{" + "id=" + id + ", brand='" + brand + "', price=" + price + '}';
}
}

// Helper class implementing Comparator
class LaptopPriceComparator implements Comparator<Laptop> {
@Override
public int compare(Laptop l1, Laptop l2) {
return Double.compare(l1.price, l2.price); // Sorting by price
}
}

public class Main {
public static void main(String[] args) {
List<Laptop> laptops = new ArrayList<>();
laptops.add(new Laptop(101, "Dell", 75000));
laptops.add(new Laptop(102, "HP", 65000));
laptops.add(new Laptop(103, "Apple", 125000));

System.out.println("Before Sorting: " + laptops);
Collections.sort(laptops, new LaptopPriceComparator());
System.out.println("After Sorting by Price: " + laptops);
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Laptop {
int id;
String brand;
int price;

public Laptop(int id, String brand, int price) {
this.id = id;
this.brand = brand;
this.price = price;
}

@Override
public String toString() {
return "Laptop{" + "id=" + id + ", brand='" + brand + "', price=" + price + '}';
}
}

// Helper class implementing Comparator
class LaptopPriceComparator implements Comparator<Laptop> {
@Override
public int compare(Laptop l1, Laptop l2) {
return (l1.price - l2.price);
}
}

public class Main {
public static void main(String[] args) {
List<Laptop> laptops = new ArrayList<>();
laptops.add(new Laptop(101, "Dell", 75000));
laptops.add(new Laptop(102, "HP", 65000));
laptops.add(new Laptop(103, "Apple", 125000));

LaptopPriceComparator laptopPriceComparator = new LaptopPriceComparator();


System.out.println("Before Sorting: " + laptops);
Collections.sort(laptops, laptopPriceComparator);
System.out.println("After Sorting by Price: " + laptops);
}
}


5. Conclusion​

  • Use Comparable if the sorting logic is natural and should be within the class.
  • Use Comparator if sorting logic varies or if the class cannot be modified.
  • compareTo() is used in Comparable, whereas compare() is used in Comparator.
  • Collections.sort(list) is used with Comparable, while Collections.sort(list, comparator) is used with Comparator.

image