Java Generics explained with simple definition and examples

The topic of Generics in Java is not an easy concept to understand. Unfortunately, it is the most neglected topic by students and software engineers who have just started their carrier.

This article tries to define it in a simple way with the analogy of fruits and vegetables.

Generics in Java

Generics Dictionary Definition

How is Genetics helpful?


Explained With Examples:

Say we have a parent class Fruit and its sub-classes as Apple, Orange, and Banana.

public class Fruit {
    private String name;
    private String color;

    public Fruit(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public String getColor() {
        return color;
    }
}
public class Apple extends Fruit {
    public Apple(String color) {
        super("Apple", color);
    }
}
public class Orange extends Fruit {
    public Orange(String color) {
        super("Orange", color);
    }
}
public class Banana extends Fruit {
    public Banana(String color) {
        super("Banana", color);
    }
}

We also have a class Potato which is a sub-class of Vegetable.

public class Vegetable {
    private String name;
    private String color;

    public Vegetable(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public String getColor() {
        return color;
    }
}
public class Potato extends Vegetable {
    public Potato(String color) {
        super("Potato", color);
    }
}

Now let's create a generic type that consists of a list of fruits:

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

public class FruitList<T extends Fruit> {
    private List<T> fruits;

    public FruitList() {
        fruits = new ArrayList<>();
    }

    public void addFruit(T fruit) {
        fruits.add(fruit);
    }

    public List<T> getFruits() {
        return fruits;
    }
}

Now, if you try to create a list of fruits with potatoes, you will get a compilation error.

FruitList<Apple> appleFruitList = new FruitList<>();
FruitList<Banana> bananaFruitList = new FruitList<>();
FruitList<Orange> orangeFruitList = new FruitList<>();

FruitList<Potato> potatoFruitList = new FruitList<>(); //Compliation Error

You can clearly see, generics make the program type safe and bring up issues during compile time to avoid runtime issues.


Example with Java Collection API

//Example 1
LinkedList listWithoutGenerics = new LinkedList();
listWithoutGenerics.add("A");
listWithoutGenerics.add(1);
String s1 = (String) listWithoutGenerics.get(1); //Need Cast Expression with String
String s2 = (String) listWithoutGenerics.get(2); //Need Cast Expression with String

//Example 2
LinkedList<String> listWithGenerics = new LinkedList();
listWithGenerics.add("A");
listWithGenerics.add(1); //Compilation Error - Required String - Provided int
String s3 = listWithGenerics.get(1); //ClassCastException

In example 1, we created a LinkedList without the use of Generics, though we were able to add elements without a problem, we need to cast the type when trying to fetch elements from the list, and it's not a safe thing to do as we see for string s2 where we get a ClassCastException as an Integer is required and not a String type.

In example 2, we made use of generics, hence if you try to add any other type of element to the list we get a Compilation Exception, this adds type-safety and avoids the need for casting.

Comments & Discussion

Facing issues? Have questions? Post them here! We're happy to help!