0% found this document useful (0 votes)
4 views7 pages

Understanding Java Generics Essentials

javaaa notess

Uploaded by

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

Understanding Java Generics Essentials

javaaa notess

Uploaded by

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

Why Generics Are Needed

1. Java collections like List, Set, Map are based on generics.


2. Understanding generics is important to understand collections properly.

Demo 0 – Life Without Generics

 Book class: Simple POJO with id (int) and name (String).


 BookRecord class:
o Stores books in a fixed-size array (size = 10).
o Methods:
 addItem(Book book) → Adds a book to the first null position.
 getItem(int index) → Returns the book at the given index if valid;
else null.
 Laptop class: Similar to Book class but represents laptops.
 LaptopRecord class: Same logic as BookRecord but for laptops.

Problem identified:

 Code repetition: BookRecord and LaptopRecord are almost identical, except for type.

Demo 1 – Using Object Instead of Specific Type

 Created ObjectRecord:
o Stores Object[] items instead of specific type arrays.
o Methods: addItem(Object item), getItem(int index) → Returns
Object.
 Usage:
o Can store Books and Laptops in the same record.
o Issue: When retrieving, you need explicit type casting:
o Book book = (Book) [Link](0);
o Laptop laptop = (Laptop) [Link](0);
 Advantages:
o Single class can store any type of object.
 Disadvantages:
o Type casting is required, which can lead to runtime errors.
Generic Class in Java

 Definition: A generic class is a class defined with one or more type parameters,
allowing it to work with any data type.
 Purpose: Reuse the same class for multiple data types while maintaining type safety.

Syntax of Generic Class


class Record<E> {
private E[] items;

public void addItem(E item) { /*...*/ }


public E getItem(int index) { /*...*/ }
}

 E is a type parameter (can be any letter/word, conventionally single uppercase


letter).
 E is not a class; it just represents the element type.
 Benefits over Object:
1. Type safety – prevents adding wrong types.
2. No type casting required when retrieving items.

Key Points

 Can replace E with any letter or word, but single letters are preferred.
 Cannot create an array with new E[] directly → need type casting from Object[].
 Example of creating a specific generic instance:

Record<Book> bookRecord = new Record<>();


Record<Laptop> laptopRecord = new Record<>();

 Now bookRecord can only accept Book, laptopRecord can only accept Laptop.

Using Object with Generics

 If you create Record<Object>:


o Can store any object (Book, Laptop, String).
o Returns Object, so type casting may be needed when retrieving.
 Bad practice: Using generics with Object loses the type safety benefit.

Important Rules

1. Generics do not support inheritance:


o Record<Laptop> is not compatible with Record<Object> or Record<Book>.
2. From Java 7 onwards, you can use diamond operator (<>) on the right-hand side:

Record<Laptop> laptopRecord = new Record<>();


Wrapper Classes

Why Wrapper Classes?

 Generics in Java cannot use primitive types (like int, float) directly.
 Wrapper classes are object representations of primitives, allowing their use in
generics.

Primitive → Wrapper mapping:

Primitive Wrapper Class

boolean Boolean

char Character

byte Byte

short Short

int Integer

long Long

float Float

double Double

 Advantages: Objects can have methods, can be used in generics, and allow type
conversion.

Example:

Record<Integer> record = new Record<>(10); // Not int, use Integer


Record<Float> recordFloat = new Record<>(5.5f); // Not float, use Float

Generic Methods vs Generic Classes

Generic Class

 A class defined with a type parameter <E>.


 Can have:
o Generic methods (E add(E item))
o Non-generic methods
 Example:

class Box<E> {
private E item;

void addItem(E item) { [Link] = item; } // Non-generic method


E getItem() { return item; } // Generic method using
class type
}

Generic Method

 A method with its own type parameter. Can exist in generic or non-generic classes.
 Type parameter <T> is declared before the return type.
 Example:

class Utils {
public static <T> T findItem(T[] array, T item) {
for (T element : array) {
if ([Link](item)) return element;
}
return null;
}
}

Rules:

 Declare type parameter before return type: public static <T> T method(...)
 Can use multiple type parameters: <T, U, V>

Practical Example: Find Object

Problem

 Want a find method for Book and Laptop.


 Initially created two separate methods: findBook() and findLaptop().
 Duplicated logic → maintenance nightmare.

Attempt 1: Using Object


public static Object findObject(Object[] arr, Object obj) { ... }

 Works, but requires type casting:

Book foundBook = (Book) findObject(books, new Book(1));


Laptop foundLaptop = (Laptop) findObject(laptops, new Laptop(2));

 Risk: passing wrong type (book array with laptop) → returns null.

Solution: Generic Method


public static <E> E find(E[] array, E item) {
for (E element : array) {
if ([Link](item)) return element;
}
return null;
}

Benefits:
 Single method works for any type
 No type casting required
 Compile-time type safety (cannot pass a Laptop array to find a Book)

Important:

 Always override equals() (and hashCode()) for custom comparison (e.g., compare
by id).

Notes on Multiple Type Parameters

 If a method needs to handle multiple types:

public static <T, U> void process(T t, U u) { ... }

 Not mandatory in simple cases; <E> is sufficient for find() example.

Wildcards in Java Generics

Problem
When you try to pass a List<Integer> to a method that expects List<Number>, it fails.

Why?
Because generics don’t allow inheritance:

List<Integer> intList = [Link](1, 2, 3);


List<Number> numList = intList; // ❌ Not allowed

Even though Integer is a subclass of Number, List<Integer> is not a subclass of


List<Number>.

Simple method for a specific type


private static void printIntegers(List<Integer> list) {
[Link](list);
}

Works only for List<Integer>


Won’t work for List<Number> or List<Double>

Parent (superclass) flexibility using ? super T

If you want to accept a type and its parent(s), use:

private static void printIntegerAndParents(List<? super Integer> list) {


[Link](list);
}

 Accepts: List<Integer>, List<Number>, List<Object>


 Does not accept: List<Double> or List<String>

Think of ? super T as “T or any superclass of T”.

Child (subclass) flexibility using ? extends T

If you want to accept a type and its child(ren), use:

private static void printNumberAndChildren(List<? extends Number> list) {


[Link](list);
}

 Accepts: List<Integer>, List<Double>, List<Float>


 Does not accept: List<Object> or List<String>

Think of ? extends T as “T or any subclass of T”.

Anything (unbounded wildcard)

If you want to accept any type, use:


private static void printEverything(List<?> list) {
[Link](list);
}

 Accepts: List<Integer>, List<Double>, List<String>, etc.


 Most flexible, no type restriction.

Key Notes on Wildcards

Wildcard Type Meaning Example Accepts


? Any type Anything (Integer, String, etc.)
? extends T T or any subclass of T Integer & Double if T=Number
? super T T or any superclass of T Integer, Number, Object if T=Integer

Wildcards allow limited inheritance flexibility in generics


Makes code reusable for multiple related types without duplicating methods

Example Summary
List<Integer> ints = [Link](1, 2, 3);
List<Double> doubles = [Link](1.1, 2.2);
List<Number> numbers = [Link](10, 20.5);

printIntegerAndParents(ints); // ✅ Integer or parent


printIntegerAndParents(numbers); // ✅ Parent allowed
// printIntegerAndParents(doubles); // ❌ Not allowed

printNumberAndChildren(numbers); // ✅ Number or child


printNumberAndChildren(ints); // ✅ Child allowed
// printNumberAndChildren(doubles); // ✅ Child allowed
// printNumberAndChildren(strings); // ❌ Not allowed

printEverything(ints); // ✅ Any type


printEverything(doubles); // ✅ Any type
printEverything(numbers); // ✅ Any type

Tip

 Use ? super T → when writing to a collection (add elements)


 Use ? extends T → when reading from a collection (get elements)

This is sometimes called PECS rule:

Producer Extends, Consumer Super

You might also like