Java generics

Java generics is a new feature introduced in JDK 5. Generics provide a compile-time type security detection mechanism that allows programmers to detect illegal types at compile time.
The essence of generics is the parameterized type, which means that the type of data being manipulated is specified as a parameter.
Suppose we have a need to write a sort method that can sort integer arrays, arrays of strings, or even any other type of array. How do we do this?
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, call this generic method to sort integer arrays, floating-point arrays, string arrays, and so on.

Generic methods

You can write a generic method that can receive different types of parameters when invoked. Depending on the parameter type 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) that declares the section before the method return type (<E> in the following example).
  • Each type parameter declaration section contains one or more type parameters, separated by commas. A generic parameter, also called a type variable, is an identifier that specifies a generic type name.
  • The type parameter can be used to declare the return value type and be a placeholder for the actual parameter type that is available as a generic method.
  • The declaration of a generic method body is the same as other methods. Note that type parameters can only represent reference types, not primitive types (like int, double, char, etc.).

Examples

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

Examples

public class GenericMethodTest
{ // Generic method printArray public static < E > void printArray( E[] inputArray ) { // Output array element 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( "Integer array element:" ); printArray( intArray ); //Pass an array of integer type System.out.println( "\ndouble array elements are:" ); printArray( doubleArray ); // pass a double array System.out.println( "\ncharacter array elements:" ); printArray( charArray ); // send a character array } }
Compile the above code, the results of the operation are as follows:
The integer array element is:
1 2 3 4 5 1 2 3 4 5     

Double array elements are:Double array elements are:
1.1 2.2 3.3 4.4 1.1 2.2 3.3 4.4    

Character array elements are:Character array elements are:
HELLO 
Bounded type parameters:
There may be times when you want to limit the types 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 the bounded type parameter.
To declare a bounded type parameter, first list the name of the type parameter followed by the extends keyword, followed by its upper bound.

Examples

The following example shows how "extends" uses "extends" or "implements" in a generic sense. The generic method in this example returns the maximum of three comparable objects.

Examples

public class MaximumTest
{ // compare three values ​​and return the maximum value 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 bigger } 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( "The largest of %d, %d and %d is %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "The largest 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( "The largest of %s, %s and %s is %s\n","pear",
"apple", "orange", maximum( "pear", "apple", "orange" ) ); } }
Compile the above code, the results of the operation are as follows:
The largest of 3, 4 and 5 is 5

The largest of 6.6, 8.8 and 7.7 is 8.8

The largest 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 a type parameter declaration section is added after the class name.
As with 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 called a type variable, is an identifier that specifies a generic type name. Because they accept one or more arguments, these classes are called parameterized classes or parameterized types.

Examples

The following example demonstrates how we define a generic class:

Examples

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("rookie tutorial"));
System.out.printf("Integer value: :%d\n\n", integerBox.get()); System.out.printf("The string is:%s\n", stringBox.get()); } }
Compile the above code, the results of the operation are as follows:
Integer value: :10

The string is:rookie tutorial

Type wildcard

1. Type wildcards are generally used instead of specific type parameters. For example, List<?> is logically the parent of List<String>, List<Integer>, and all List< concrete type arguments>.

Examples

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)); } }
The output is:

data :icon
data :18
data :314
Analysis: Because the getData() method's argument is of type List , name, age, and number can all be used as the arguments of this method. This is the role of wildcards.
2, the type wildcard limit is defined by the form such as List , so the definition is the wildcard character generic value accepts Number and its underlying subclass type.

Examples

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 results:

data :18
data :314
Analysis: There will be an error at (//1), because the parameters in the getUperNumber() method have already limited the parameter generic type limit to Number, so the generic type is String is not in this range, so it will report an error
3, the lower limit of the type wildcard is defined by the form such as List<? superNumber > , indicating that the type can only accept Number and its three parent types, such as the Objec type instance.

Comments