DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Java String: A Complete Guide With Examples
  • The Two-Pointers Technique
  • Speeding Up Large Collections Processing in Java
  • Mule 3 DataWeave(1.x) Script To Resolve Wildcard Dynamically

Trending

  • Building Reliable LLM-Powered Microservices With Kubernetes on AWS
  • AI-Driven Root Cause Analysis in SRE: Enhancing Incident Resolution
  • Go 1.24+ Native FIPS Support for Easier Compliance
  • Manual Sharding in PostgreSQL: A Step-by-Step Implementation Guide
  1. DZone
  2. Coding
  3. Java
  4. Generics in Java and Their Implementation

Generics in Java and Their Implementation

In Java programming language, generics are introduced in J2SE 5 for dealing with type-safe objects.

By 
Bikash Jain user avatar
Bikash Jain
·
Apr. 24, 23 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
11.2K Views

Join the DZone community and get the full member experience.

Join For Free

Generics in Java

In Java programming, language generics are introduced in J2SE 5 for dealing with type-safe objects. It detects bugs at the compile time by which code is made stable. Any object type is allowed to be stored in the collection before the generic introduction. Now after the generic introduction in the Java programming language, programmers are forced to store particular object types.

Advantages of Java Generics

Three main advantages of using generics are given below:

1. Type-Safety

Generics allow to store of only a single object type. Therefore, different object types are not allowed to be stored in generics.

Any type of object is allowed to be stored without generics.

Java
 
// declaring a list with the name dataList

List dataList= new ArrayList();    

// adding integer into the dataList 

dataList.add(10);  

// adding string data into the dataList 

dataList.add("10"); 


With generics, we need to tell the object type we want to store.

  • Declaring a list with the name dataList:

List<Integer> dataList= new ArrayList();   

  • Adding integer into the dataList

dataList.add(10);  

  • Adding string data into the dataList

dataList.add("10"); // but this statement gives compile-time error  

2. No Need for Type Casting 

Object type casting is not required with generics.

It is required to do casting before a generic introduction.

Java
 
declaring a list with the name dataList

List dataList= new ArrayList();    

adding an element to the dataList 

dataList.add("hello");    

typecasting    

String s = (String) dataList.get(0);


There is no need for object type casting after generics.

Java
 
// declaring a list with the name dataList

List<String> dataList= new ArrayList<String>();    

// adding an element to the dataList 

dataList.add("hello");   

//typecasting is not required 

String s = dataList.get(0);


3. Checking at Compile Time

Issues will not occur at run time as it is checked at the compile time. And according to good programming strategies, problem handling done at compile time is far better than handling done at run time. 

Java
 
// declaring a list with the name dataList

List<String> dataList = new ArrayList<String>();    

// adding an element into the dataList 

dataList .add("hello");    

// try to add an integer in the dataList but this statement will give compile-time error

dataList .add(32);


Syntax:

Java
 
Generic collection can be used as :

ClassOrInterface<Type>    

Example:

An example of how generics are used in java is given below:

ArrayList<String>  


Example Program of Java Generics

The ArrayList class is used in this example. But in place of the ArrayList class, any class of collection framework can be used, like Comparator, HashMap, TreeSet, HashSet, LinkedList, ArrayList, etc.

Java
 
// importing packages 

import java.util.*;

// creating a class with the name GenericsExample

class GenericsExample {

    // main method

    public static void main(String args[]) {

        // declaring a list with the name dataList to store String elements

        ArrayList < String > dataList = new ArrayList < String > ();

        // adding an element into the dataList 

        dataList.add("hina");

        // adding an element into the dataList 

        dataList.add("rina");

        // if we try to add an integer into the dataList then it will give a compile-time error

        //dataList.add(32); //compile time error  

        // accessing element from dataList 

        String s = dataList.get(1); //no need of type casting

        // printing an element of the list

        System.out.println("element is: " + s);

        // for iterating over the dataList elements

        Iterator < String > itr = dataList.iterator();

        // iterating and printing the elements of the list

        while (itr.hasNext()) {

            System.out.println(itr.next());

        }

    }

}


Output:

Java
 
element is: rina

hina

rina


Java Generics Example Using Map

In this, we are using a map to demonstrate the generic example. The map allows the data storage in the form of key-value pairs. 

Java
 
// importing packages 

import java.util.*;

// creating a class with the name GenericsExample

class GenericsExample {

    // main method

    public static void main(String args[]) {

        // declaring a map for storing keys of Integer type with String values

        Map < Integer, String > dataMap = new HashMap < Integer, String > ();

        // adding some key value into the dataMap

        dataMap.put(3, "seema");

        dataMap.put(1, "hina");

        dataMap.put(4, "rina");

        // using dataMap.entrySet() 

        Set < Map.Entry < Integer, String >> set = dataMap.entrySet();

        // creating an iterator for iterating over the dataMap

        Iterator < Map.Entry < Integer, String >> itr = set.iterator();

        // iterating for printing every key-value pair of map

        while (itr.hasNext()) {

            // type casting is not required

            Map.Entry e = itr.next();

            System.out.println(e.getKey() + " " + e.getValue());

        }



    }

}


Output:

Java
 
1 hina

3 seema

4 rina


Generic Class

A generic class is a class that can refer to any type. And here, for creating a particular type of generic class, we are using the parameter of T type. 

The declaration of a generic class is much similar to the declaration of a non-generic class, except that the type parameter section is written after the name of the class. Parameters of one or more than one type are allowed in the type parameter section. 

A generic class declaration looks like a non-generic class declaration, except that the class name is followed by a type parameter section. As one or more parameters are accepted, so Parameterized types or parameterized classes are some other names for it. 

And the example is given below to demonstrate the use and creation of generic classes.

Generic Class Creation

Java
 
class GenericClassExample < T > {

    T object;

    void addElement(T object) {

        this.object = object;

    }

    T get() {

        return object;

    }

}


Here T type represents that it can refer to any type, such as Employee, String, and Integer. The type specified by you for the class is used for data storage and retrieval. 

Generic Class Implementation

Java
 
Let us see an example for a better understanding of generic class usage

// creating a class with the name GenericExample

class GenericExample {

    // main method

    public static void main(String args[]) {

        // using the generic class created in the above example with the Integer type

        GenericClassExample < Integer > m = new GenericClassExample < Integer > ();

        // calling addElement for the m

        m.addElement(6);

        // if we try to call addElement with the string type element then it will give a compile-time error

        //m.addElement("hina"); //Compile time error  

        System.out.println(m.get());

    }

}


Output:

Java
 
6


Generic Method

Similar to the generic class, generic methods can also be created. And any type of argument can be accepted by the generic method. The declaration of the generic method is just similar to that of the generic type, but the scope of the type parameter is limited to the method where its declaration has been done. Generic methods are allowed to be both static and non-static. 

Let us understand the generic method of Java with an example. Here is an example of printing the elements of an array. Here E is used for representing elements.

Java
 
// creating a class with the name GenericExample

public class GenericExample {

    // creating a generic method for printing the elements of an array

    public static < E > void printElements(E[] elements) {

        // iterating over elements for printing elements of an array

        for (E curElement: elements) {

            System.out.println(curElement);

        }

        System.out.println();

    }

    // main method

    public static void main(String args[]) {

        // declaring an array having Integer type elements

        Integer[] arrayOfIntegerElements = {

            10,

            20,

            30,

            40,

            50

        };

        // declaring an array having character-type elements


        Character[] arrayOfCharacterElements = {

            'J',

            'A',

            'V',

            'A',

            'T',

            'P',

            'O',

            'I',

            'N',

            'T'

        };


        System.out.println("Printing an elements of an Integer Array");

        // calling generic method printElements for integer array 

        printElements(arrayOfIntegerElements);

        System.out.println("Printing an elements of an Character Array");


        // calling generic method printElements for character array 

        printElements(arrayOfCharacterElements);

    }

}


Output:

Java
 
Printing an elements of an Integer Array

10

20

30

40

50



Printing an elements of an Character Array

J

A

V

A

T

P

O

I

N

T


Wildcard in Java Generics

Wildcard elements in generics are represented by the question mark (?) symbol. And any type is represented by it. If <? extends Number> is written by us, then this means any Number such as (double, float, and Integer) child class. Now the number class method can be called from any of the child classes. Wildcards can be used as a type of local variable, return type, field, or Parameter. But the wildcards can not be used as type arguments for the invocation of the generic method or the creation of an instance of generic.

Let us understand the wildcards in Java generics with the help of the example below given:

Java
 
// importing packages

import java.util.*;

// creating an abstract class with the name Animal

abstract class Animal {

    // creating an abstract method with the name eat

    abstract void eat();

}

// creating a class with the name Cat which inherits the Animal class

class Cat extends Animal {

    void eat() {

        System.out.println("Cat can eat");

    }

}

// creating a class with the name Dog which inherits the Animal class

class Dog extends Animal {

    void eat() {

        System.out.println("Dog can eat");

    }

}

// creating a class for testing the wildcards of java generics

class GenericsExample {

    //creating a method by which only Animal child classes are accepted 

    public static void animalEat(List << ? extends Animal > lists) {

        for (Animal a: lists) {

            //Animal class method calling by the instance of the child class

            a.eat();

        }

    }

    // main method

    public static void main(String args[]) {

        // creating a list of type Cat

        List < Cat > list = new ArrayList < Cat > ();

        list.add(new Cat());

        list.add(new Cat());

        list.add(new Cat());

        // creating a list of type Dog

        List < Dog > list1 = new ArrayList < Dog > ();

        list1.add(new Dog());

        list1.add(new Dog());

        // calling animalEat for list

        animalEat(list);

        // calling animalEat for list1

        animalEat(list1);

    }

}


Output:

Java
 
Cat can eat

Cat can eat

Cat can eat

Dog can eat

Dog can eat


Upper Bounded Wildcards

The main objective of using upper-bounded wildcards is to reduce the variable restrictions. An unknown type is restricted by it to be a particular type or subtype of a particular type. Upper Bounded Wildcards are used by writing a question mark symbol, then extending the keyword if there is a class and implementing a keyword for the interface, and then the upper bound is written.

Syntax of Upper Bound Wildcard

 ? extends Type. 

Example of Upper Bound Wildcard

Let us understand the Upper Bound Wildcard with an example. Here upper bound wildcards are used by us for List<Double> and List<Integer> method writing.

Java
 
// importing packages

import java.util.ArrayList;

// creating a class with the name UpperBoundWildcardExample 

public class UpperBoundWildcardExample {

    // creating a method by using upper bounded wildcards

    private static Double sum(ArrayList << ? extends Number > list) {



        double add = 0.0;



        for (Number n: list) {

            add = add + n.doubleValue();

        }



        return add;

    }

    // main method

    public static void main(String[] args) {

        // creating a list of integer type

        ArrayList < Integer > list1 = new ArrayList < Integer > ();

        // adding elements to the list1

        list1.add(30);

        list1.add(40);

        // calling sum method for printing sum

        System.out.println("Sum is= " + sum(list1));

        // creating a list of double type

        ArrayList < Double > list2 = new ArrayList < Double > ();

        list2.add(10.0);

        list2.add(20.0);

        // calling sum method for printing sum

        System.out.println("Sum is= " + sum(list2));





    }



}


Output:

Java
 
Sum is= 70.0

Sum is= 30.0


Unbounded Wildcards

Unknown type list is specified by the unbounded wildcards like List<?>.

Example of Unbounded Wildcards

Java
 
// importing packages

import java.util.Arrays;

import java.util.List;

// creating a class with the name UnboundedWildcardExample 

public class UnboundedWildcardExample {

    // creating a method displayElements by using Unbounded Wildcard

    public static void displayElements(List << ? > list) {



        for (Object n: list) {

            System.out.println(n);

        }



    }



    // main method

    public static void main(String[] args) {

        // creating a list of type integer

        List < Integer > list1 = Arrays.asList(6, 7, 8);

        System.out.println("printing the values of integer list");

        // calling displayElements for list1  

        displayElements(list1);

        // creating a list of type string

        List < String > list2 = Arrays.asList("six", "seven", "eight");

        System.out.println("printing the values of string list");

        // calling displayElements for list2

        displayElements(list2);

    }

}


Output:

Java
 
printing the values of integer list

6

7

8

printing the values of string list

six

seven

eight


Lower Bounded Wildcards

Lower Bounded Wildcards are used to restrict the unknown type to be a particular type or the supertype of the particular type. Lower Bounded Wildcards are used by writing a question mark symbol followed by the keyword super, then writing the lower bound.

Syntax of Lower Bound Wildcard

 ? super Type. 

Example of Lower Bound Wildcard

Java
 
// importing packages

import java.util.*;

// creating a class with the name LowerBoundWildcardExample 

public class LowerBoundWildcardExample {

    // creating a method by using upper bounded wildcards

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



        for (Object n: list) {

            System.out.println(n);

        }

    }



    // main method

    public static void main(String[] args) {

        // creating a list of type integer

        List < Integer > list1 = Arrays.asList(6, 7, 8);

        System.out.println("printing the values of integer list");

        // calling displayElements for list1  

        displayElements(list1);

        // creating a list of type string

        List < Number > list2 = Arrays.asList(8.0, 9.8, 7.6);

        System.out.println("printing the values of string list");

        // calling displayElements for list2

        displayElements(list2);

    }

}


Output: 

Java
 
printing the values of integer list

6

7

8

printing the values of string list

8.0

9.8

7.6


Conclusion

  • After the generic introduction in the Java programming language, programmers are forced to store particular object types.
  • Type safety, No need for type casting, and Checking at compile time are Three main advantages of using generics.
  • A generic class is a class that can refer to any type.
  • Similar to the generic class, generic methods can also be created. And any type of argument can be accepted by the generic method. 
  • Wildcard elements in generics are represented by the question mark (?) symbol.
  • Upper Bounded, Lower Bounded, and Unbounded are three types of wildcards in Java generic.
Data structure Implementation Java (programming language) Object (computer science) Strings Data Types

Opinions expressed by DZone contributors are their own.

Related

  • Java String: A Complete Guide With Examples
  • The Two-Pointers Technique
  • Speeding Up Large Collections Processing in Java
  • Mule 3 DataWeave(1.x) Script To Resolve Wildcard Dynamically

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!