Java generics

Java generics

If we only write a sort method, we can sort integer arrays, string arrays, and even any type of array that supports sorting, which would be great.

Java generic methods and generic classes allow programmers to use a method to specify a set of related methods, or use a class to specify a set of related types.

Java generics (generics) is a new feature introduced in JDK 5. Generics provide a compile-time type safety detection mechanism, which allows programmers to detect illegal types at compile time.

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

Generic method

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

Here are the rules for defining generic methods:

  • All generic method declarations have a type parameter declaration section (separated by angle brackets), the type parameter declaration section before the method return type (<E> in the example below).
  • Each type parameter declaration part contains one or more type parameters, separated by commas. A generic parameter, also known as a type variable, is an identifier used to specify the name of a generic type.
  • Type parameters can be used to declare the return value type, and can be used as placeholders for the actual parameter types obtained by a generic method.
  • The declaration of the method body of a generic method is the same as other methods. Note that type parameters can only represent reference types, not primitive types (like int, double, char, etc.).

Instance

The following example demonstrates how to use generic methods to print elements of different strings:

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 different types of arrays: 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 integerArray contains:" );
        printArray( intArray );//Pass an integer array

        System.out.println( "\nArray doubleArray contains:" );
        printArray( doubleArray );//Pass a double array

        System.out.println( "\nArray characterArray contains:" );
        printArray( charArray );//Pass a character type array
    } 
}

Compile the above code, the running result is as follows:

Array integerArray contains: 1 2 3 4 5 6 Array doubleArray contains: 1.1 2.2 3.3 4.4 Array characterArray contains: HELLO

Bounded type parameters:

Sometimes, you may want to limit the range of types that are allowed to be passed to a type parameter. For example, a method that manipulates numbers may only want to accept instances of Number or Number subclasses. This is the purpose of bounded type parameters.

To declare a bounded type parameter, first list the name of the type parameter, followed by the extends keyword, and finally its upper bound.

Instance

The following example demonstrates how "extends" can be used to mean "extends" (classes) or "implements" (interfaces) in the general sense. The generic method in this example returns the maximum of three comparable objects.

public class MaximumTest
{
  //Compare three values ​​and return the maximum
   public static <T extends Comparable<T>> T maximum(T x, T y, T z)
   {                     
      T max = x;//Assuming x is the initial maximum
      if (y.compareTo( max)> 0 ){
         max = y;//y is greater
      }
      if (z.compareTo( max)> 0 ){
         max = z;//now z is bigger           
      }
      return max;//return the largest object
   }
   public static void main( String args[])
   {
      System.out.printf( "Max of %d, %d and %d is %d\n\n",
                   3, 4, 5, maximum( 3, 4, 5) );
 
      System.out.printf( "Maxm 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( "Max of %s, %s and %s is %s\n","pear",
         "apple", "orange", maximum( "pear", "apple", "orange") );
   }
}

Compile the above code, the running result is as follows:

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

Generic class

The declaration of a generic class is similar to the declaration of a non-generic class, except that the type parameter declaration part is added after the class name.

Like generic methods, the type parameter declaration part of a generic class also contains one or more type parameters, separated by commas. A generic parameter, also known as a type variable, is an identifier used to specify the name of a generic type. Because they accept one or more parameters, these classes are called parameterized classes or parameterized types.

Instance

The following example demonstrates how we define a generic class:

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("Hello World"));
 
     System.out.printf("Integer Value :%d\n\n", integerBox.get());
     System.out.printf("String Value :%s\n", stringBox.get());
  }
}

Compile the above code, the running result is as follows:

Integer Value :10
 
String Value :Hello World