The so-called generics: It allows you to specify type parameters when defining classes and interfaces. This type parameter will be determined when declaring variables and creating objects (that is, passing in actual type parameters, which can also be called type arguments)
Generic class or interface
The "diamond" syntax copy code is as follows:
//definition
public interface List<E> extends Collection<E>
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
//use
List<String> list = new ArrayList();
//After Java 7, you can omit the type parameter of the angle brackets behind it.
List<String> list = new ArrayList<>();
Derive a subclass from a generic class
Copy the code code as follows:
//Method 1
public class App extends GenericType<String>
//Method 2
public class App<T> extends GenericType<T>
//Method 3
public class App extends GenericType
Pseudo generics
There is no real generic class. Generic classes are transparent to the Java virtual machine. The JVM does not know the existence of generic classes. In other words, the JVM processes generic classes no differently from ordinary classes. Therefore, Type parameters are not allowed in static methods, static initialization blocks, and static variables.
- The following methods are all wrong. The copy code code is as follows:
private static T data;
static{
T f;
}
public static void func(){
T name = 1;
}
The following example can verify from the side that there is no generic class. Copy the code. The code is as follows:
public static void main(String[] args){
List<String> a1 = new ArrayList<>();
List<Integer> a2 = new ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
The output copy code is as follows:
true
class java.util.ArrayList
class java.util.ArrayList
Type wildcard
First of all, it must be clear that if Foo is the parent class of Bar, but List<Foo> is not the parent class of List<Bar>. In order to represent various generic parent classes, Java uses "?" to represent generic wildcards. That is, List<?> represents the parent class of various generic Lists. With this kind of wildcard, List generics cannot set (set) elements, but can only get (get) elements. Because the program cannot determine the types in the List, it cannot add objects. But the object obtained must be of type Object.
The following methods will compile with errors:
Copy the code code as follows:
List<?> list = new ArrayList<>();
list.add(new Object());
Some ideas:
1. List<String> objects cannot be used as List<Object> objects, that is to say: List<String> class is not a subclass of List<Object> class.
2. Arrays are different from generics: assuming Foo is a subtype (subclass or subinterface) of Bar, then Foo[] is still a subtype of Bar[]; but G<Foo> is not G<Bar> subtype.
3. In order to represent the parent class of various generic Lists, we need to use type wildcards. The type wildcard is a question mark (?). Pass a question mark as a type argument to the List collection, written: List<?> (meaning unknown List of type elements). This question mark (?) is called a wildcard character, and its element type can match any type.
Wildcard upper limit
List<? extends SuperType> represents the parent class or itself of all SuperType generic Lists. Generics with wildcard upper limits cannot have set methods, only get methods.
Setting the upper limit of wildcards can solve the following problems: Dog is a subclass of Animal, and there is a getSize method to get the number of incoming Lists. The code is as follows. Copy the code as follows:
abstract class Animal {
public abstract void run();
}
class Dog extends Animal {
public void run() {
System.out.println("Dog run");
}
}
public class App {
public static void getSize(List<Animal> list) {
System.out.println(list.size());
}
public static void main(String[] args) {
List<Dog> list = new ArrayList<>();
getSize(list); // Compilation error here
}
}
The reason for the programming error here is that List<Animal> is not the parent class of List<Dog>. The first solution is to change the formal parameter List<Animal> in the getSize method to List<?>, but in this case, forced type conversion is required every time the object is obtained, which is more troublesome. Using the wildcard upper limit solves this problem very well. You can change List<Animal> to List<? extends Animal>, and there will be no errors in compilation, and no type conversion is required.
Lower bound for wildcards
List<? super SubType> represents the lower limit of the SubType generic List. Generics with wildcard upper limits cannot have get methods, only set methods.
Generic methods
If you define classes and interfaces without using type parameters, but want to define type parameters yourself when defining methods, this is also possible. JDK1.5 also provides support for generic methods. The method signature of a generic method has more type parameter declarations than the method signature of an ordinary method. The type parameter declarations are enclosed in angle brackets. Multiple type parameters are separated by commas (,). All type parameter declarations are placed Between method modifiers and method return value types. The syntax format is as follows:
Copy the code code as follows:
Modifier return value type method name (type list) {
//method body
}
Generic methods allow type parameters to be used to express type dependencies between one or more parameters of a method, or between method return values and parameters. If there is no such type dependency, generic methods should not be used. The copy method of Collections uses generic methods:
Copy the code code as follows:
public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
This method requires that the src type must be a subclass of the dest type or itself.
Erase and convert
In strict generic code, classes with generic declarations should always have type parameters. However, in order to be consistent with old Java code, it is also allowed to use classes with generic declarations without specifying type parameters. If no type parameter is specified for this generic class, the type parameter is called a raw type and defaults to the first upper limit type specified when the parameter was declared.
When an object with generic information is assigned to another variable without generic information, all type information between the angle brackets is thrown away. For example, if a List<String> type is converted to List, the type check of the collection elements of the List becomes the upper limit of the type variable (that is, Object). This situation is called erasure.
The sample copy code is as follows:
class Apple<T extends Number>
{
T size;
publicApple()
{
}
public Apple(T size)
{
this.size = size;
}
public void setSize(T size)
{
this.size = size;
}
public T getSize()
{
return this.size;
}
}
public class ErasureTest
{
public static void main(String[] args)
{
Apple<Integer> a = new Apple<>(6); // ①
// The getSize method of a returns an Integer object
Integer as = a.getSize();
// Assign the a object to the Apple variable, losing the type information in the angle brackets
Apple b = a; // ②
// b only knows that the type of size is Number
Number size1 = b.getSize();
//The following code causes a compilation error
Integer size2 = b.getSize(); // ③
}
}