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 Type | Wrapper Class |
|---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
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
- TreeSet: Automatically sorts elements in ascending order.
- ArrayList & LinkedList: Can be sorted using
Collections.sort(list). - 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, andHashMap.
2. Defining a Complex Object
- A complex object is a user-defined class with multiple attributes.
- In this case, we define a
Studentclass 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
ArrayListis a dynamic array used to store multipleStudentobjects.- We create
ArrayList<Student>and add objects usingadd()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
Studentwith 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
Studentobjects 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:
ArrayListresizes dynamically. - Efficient Data Manipulation: Allows easy addition, removal, and searching of objects.
- Easy Sorting and Filtering: Sorting can be done using
ComparatororComparable. - 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:
-
Defining a Class:
- Create a class with multiple attributes (e.g.,
Laptopwith ID, brand, cost, processor, memory, and grade). - Define a parameterized constructor to initialize objects.
- Override the
toString()method for meaningful output representation.
- Create a class with multiple attributes (e.g.,
-
Using Generic Collections:
- Use
ArrayList<Laptop>to store multiple objects of theLaptopclass. - Generics ensure type safety, allowing only
Laptopobjects to be stored in the list.
- Use
-
Adding Objects to the Collection:
- Create instances of the
Laptopclass. - Add these instances to the
ArrayListusing theadd()method.
- Create instances of the
Sorting Complex Objects:
-
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.
-
Sorting Approaches:
- Using Comparable Interface: Implement the
Comparable<T>interface and override thecompareTo()method. - Using Comparator Interface: Pass a custom comparator to
Collections.sort()for flexible sorting.
- Using Comparable Interface: Implement the
-
Sorting by Cost (Example):
- Use
Collections.sort(list, Comparator.comparingDouble(l -> l.cost)); - This sorts the list based on the
costattribute in ascending order.
- Use
Example Code Overview:
- Class
Laptopdefines attributes, constructor, andtoString()method. - Main Class
Main:- Creates and stores
Laptopobjects in anArrayList. - Displays the list before sorting.
- Sorts the list by
costusingComparator.comparingDouble. - Displays the sorted list.
- Creates and stores
This approach ensures efficient storage and sorting of complex objects in Java.
Notes on Sorting Complex Objects Using Comparable Interface
Understanding Comparable Interface:
-
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.
- The
-
How It Works:
- The
compareTo()method compares the current object (this) with another object (o). - It returns:
0if both objects are equal.- A negative number if
thisshould come beforeo. - A positive number if
thisshould come aftero.
- The
Implementing Comparable in Student Class:
-
Define Attributes:
rollNo,name,age,gender,marks,isPlaced.
-
Constructor and
toString()Method:- Initializes attributes and provides meaningful string representation.
-
Implement
compareTo()Method:- Sorting by
agein ascending order usingreturn this.age - o.age;. - Alternative approach (commented in code) for sorting by
marksin descending order.
- Sorting by
Sorting Student Objects in ArrayList:
-
Creating and Adding Objects:
- Instances of
Studentare created and added to anArrayList<Student>.
- Instances of
-
Sorting Using
Collections.sort()- Calls
compareTo()internally to sort objects. - Ensures consistent ordering of elements.
- Calls
Example Code Overview:
- Class
StudentimplementsComparable<Student>. - Main Class
Main:- Creates and stores
Studentobjects in anArrayList. - Displays the list before sorting.
- Sorts using
Collections.sort()which invokescompareTo(). - Displays the sorted list.
- Creates and stores
Key Takeaways:
- Implement
Comparable<T>for natural ordering. - Use
compareTo()to define sorting logic. - Sorting is automatic with
Collections.sort()after implementingComparable. - 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
| Feature | Comparable | Comparator |
|---|---|---|
| Definition | Used to define the natural ordering of objects. | Used to define custom ordering of objects. |
| Implementation | Implemented inside the target class. | Implemented as a separate class. |
| Method | compareTo(T o) | compare(T o1, T o2) |
| Parameters | Takes one parameter. | Takes two parameters. |
| Modifiability | Requires modifying the target class. | Does not require modifying the target class. |
| Used With | Collections.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 inComparable, whereascompare()is used inComparator.Collections.sort(list)is used withComparable, whileCollections.sort(list, comparator)is used withComparator.