Easy Tutorial
❮ Java Object Notifyall Java Hashmap Keyset ❯

Java Generics

Java Generics is a new feature introduced in JDK 5, which provides a type safety mechanism at compile time. This mechanism allows programmers to detect illegal types at compile time.

The essence of generics is parameterized types, meaning the data type being operated on is specified as a parameter.

>

Suppose we have a requirement: to write a sorting method that can sort integer arrays, string arrays, or arrays of any other type. How can this be achieved?

The answer is to use Java Generics.

Using the concept of Java Generics, we can write a generic method to sort an array of objects. Then, we can call this generic method to sort integer arrays, floating-point arrays, string arrays, etc.


Generic Methods

You can write a generic method that can receive parameters of different types when called. Based on the parameter types passed to the generic method, the compiler handles each method call appropriately.

Here are the rules for defining generic methods:

Generic Type Notations in Java:

Example

The following example demonstrates how to use a generic method to print elements of different types of arrays:

Example

public class GenericMethodTest
{
   // Generic method printArray                         
   public static <E> void printArray(E[] inputArray)
   {
      // Output array elements            
      for (E element : inputArray) {        
         System.out.printf("%s ", element);
      }
      System.out.println();
   }

   public static void main(String args[])
   {
      // Create arrays of different types: Integer, Double, and Character
      Integer[] intArray = { 1, 2, 3, 4, 5 };
      Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
      Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

      System.out.println("Array elements of type Integer:");
      printArray(intArray); // Pass an Integer array

      System.out.println("\nArray elements of type Double:");
      printArray(doubleArray); // Pass a Double array

      System.out.println("\nArray elements of type Character:");
      printArray(charArray); // Pass a Character array
   } 
}

Compiling and running the above code produces the following result:

Array elements of type Integer:
1 2 3 4 5 

Array elements of type Double:
1.1 2.2 3.3 4.4 

Array elements of type Character:
H E L L O

Bounded Type Parameters:

There may be times when you want to restrict the types that can be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is where bounded type parameters come in.

To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, and then its upper bound.

Example

The following example demonstrates how "extends" can be used in the general sense of "extends" (class) or "implements" (interface). This example's generic method returns the maximum of three comparable objects.

Example

public class MaximumTest
{
   // Compares three values and returns the maximum
   public static &lt;T extends Comparable<T>> T maximum(T x, T y, T z)
   {
      T max = x; // Assume x is initially the largest

      if (y.compareTo(max) > 0) {
         max = y; // y is the largest so far
      }

      if (z.compareTo(max) > 0) {
         max = z; // z is the largest now                 
      }
      return max; // Returns the largest object   
   }

   public static void main(String args[])
   {
      System.out.printf("Maximum of %d, %d, and %d is %d\n\n", 
         3, 4, 5, maximum(3, 4, 5));

      System.out.printf("Maximum of %.1f, %.1f, and %.1f is %.1f\n\n",
         6.6, 8.8, 7.7, maximum(6.6, 8.8, 7.7));

      System.out.printf("Maximum of %s, %s, and %s is %s\n","pear",
         "apple", "orange", maximum("pear", "apple", "orange"));
   }
}

Compiling and running the above code produces the following result:

Maximum of 3, 4, and 5 is 5

Maximum of 6.6, 8.8, and 7.7 is 8.8

Maximum of pear, apple, and orange is pear
public static &lt;T extends Comparable<T>> T maximum(T x, T y, T z) {
   T max = x; // Assume x is initially the largest
   if (y.compareTo(max) > 0) {
      max = y; // y is the larger
   }
   if (z.compareTo(max) > 0) {
      max = z; // Now z is the larger
   }
   return max; // Return the largest object
}

public static void main(String args[]) {
   System.out.printf("%d, %d, and %d中最的数为 %d\n\n",
                     3, 4, 5, maximum(3, 4, 5));

   System.out.printf("%.1f, %.1f, and %.1f中最的数为 %.1f\n\n",
                     6.6, 8.8, 7.7, maximum(6.6, 8.8, 7.7));

   System.out.printf("%s, %s, and %s中最的数为 %s\n", "pear",
                     "apple", "orange", maximum("pear", "apple", "orange"));
}

Compiling the above code and running the output is shown below:

3, 4, and 5中最的数为 5

6.6, 8.8, and 7.7中最的数为 8.8

pear, apple, and orange中最的数为 pear

Generic Class

The declaration of a generic class is similar to that of a non-generic class, except that the class name is followed by a type parameter section.

Like generic methods, the type parameter section of a generic class can contain one or more type parameters separated by commas. A generic parameter, also known as a type variable, is an identifier that specifies a generic type name. Since they accept one or more parameters, these classes are called parameterized classes or parameterized types.

Example

The following example illustrates how we can define a generic class:

Example

public class Box<T> {

   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }

   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();

      integerBox.add(new Integer(10));
      stringBox.add(new String("tutorialpro.org"));

      System.out.printf("Integer Value :%d\n\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

Compiling the above code and running the output is shown below:

Integer Value :10

String Value :tutorialpro.org

Type Wildcard

  1. The type wildcard is generally represented by ? instead of a specific type parameter. For example, List<?> is logically a superclass of List<String>, List<Integer>, etc., all List&lt;specific type argument> types.

Example

import java.util.*;

public class GenericTest {

    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();

        name.add("icon");
        age.add(18);
        number.add(314);

        getData(name);
        getData(age);
        getData(number);
    }

    public static void getData(List<?> data) {
        System.out.println("Data: " + data.get(0));
    }
}

Compiling the above code and running the output is shown below:

Data: icon
Data: 18
Data: 314
getData(number);

}

public static void getData(List<?> data) {
   System.out.println("data :" + data.get(0));
}
}

Output:

data :icon
data :18
data :314

Explanation: Since the getData() method takes a parameter of type List<?>, name, age, and number can all be actual arguments for this method, which is the role of the wildcard.

  1. The upper bound of the type wildcard is defined as List<? extends Number>, meaning the generic wildcard accepts only types that are subclasses of Number.

Example

import java.util.*;

public class GenericTest {

   public static void main(String[] args) {
       List<String> name = new ArrayList<String>();
       List<Integer> age = new ArrayList<Integer>();
       List<Number> number = new ArrayList<Number>();

       name.add("icon");
       age.add(18);
       number.add(314);

       //getUperNumber(name);//1
       getUperNumber(age);//2
       getUperNumber(number);//3

  }

  public static void getData(List<?> data) {
     System.out.println("data :" + data.get(0));
  }

  public static void getUperNumber(List<? extends Number> data) {
        System.out.println("data :" + data.get(0));
     }
}

Output:

data :18
data :314

Explanation: The error occurs at //1 because the parameter in the getUperNumber() method limits the generic type to Number. Therefore, a type of String is not within this range, causing an error.

  1. The lower bound of the type wildcard is defined as List<? super Number>, indicating that the type can only accept instances of Number and its superclass types, such as Object.
❮ Java Object Notifyall Java Hashmap Keyset ❯