1. Overview of Java Generics
1.1 Object realizes parameter arbitrariness
-
Consider implementing a container class yourself, which can support the addition, deletion, modification, and checking of different types of data.
-
Before JDK 1.5, because generics were not supported, it was necessary to use
Object
create arrays as containers. When getting the item, you need to explicitly cast the type.class MyList { public static final int LENGTH = 10; private Object[] list = new Object[LENGTH]; private int size = 0; public void add(Object object) { list[size++] = object; } public Object get(int index) { return list[index]; } public int size() { return size; } } // 使用方式 String str = (String) list.get(1);
-
For the above code, java does not check for illegal coercion when compiling, and will report errors at runtime.
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at ObjectGeneric.main(ObjectGeneric.java:8)
-
to sum up:
Object
The arbitrariness of parameters is realized by using , and the disadvantage is that it needs to be explicitly cast.- In the case of type conversion errors, the compiler will not prompt an error, and will throw it at runtime
ClassCastException
. - Therefore,
Object
the arbitrariness of the implementation parameters has potential safety risks.
1.2 The introduction of generics
- In the JDK source code, we often see similar code, they use capital letters to limit their parameter types. This is generic!
public interface List<E> extends Collection<E>
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
-
Generics mean generic types (parameterized types), that is, the type of data to be operated on can be specified in the form of parameters.
class Printer<T>{ private T item; public Printer(T item){ this.item=item; } public void print(){ System.out.println(item.getClass().getName()); } }
-
Java generics (generics) is a new feature introduced in JDK 5:
- Generics provide a compile-time type safety detection mechanism, which allows developers to detect illegal type conversions at compile time and improve the robustness of the code.
- Generics will implicitly and automatically force type conversion, which can improve code utilization.
- Reference document link:
Generic and application scenarios of Java learning
2. Generic types
2.1 Generic class
- Syntax of generic types:
class ClassName<泛型通配符identify>{
// 泛型通配符可以是A-Z的任意大写字母以及'?'
private identify item; // 使用泛型通配符定义成员变量
public identify getItem(){
// 返回泛型值的方法,并非是泛型方法
return item;
}
...
}
-
Generic classes are the most common in Java containers (
Collection
andMap
). The arbitrariness of data types is realized through generics, which is flexible, safe, and easy to maintain. -
A simple example of a generic class:
class MyGeneric<T> { private T item; public void setItem(T item) { this.item = item; } public T getItem() { return item; } } // 使用泛型类 public static void main(String[] args) { // 创建泛型类对象时不指定类型,使用时与Object定义的类一样,需要进行显式转换 MyGeneric generic1 = new MyGeneric(); generic1.setItem(new Double(12.5)); Double number = (Double) generic1.getItem(); System.out.println("number: " + number); // 创建泛型类对象是指定类型,可以充分利用泛型的优势 MyGeneric<Integer> generic2=new MyGeneric<>(); // generic2.setItem(12.3); // 编译无法通过,提示double类型无法转换成Integer类型 generic2.setItem(12); if (generic2.getItem() instanceof Integer){ System.out.println("Item is Integer"); } }
2.2 Generic methods
-
Generic method: Adding a generic wildcard between the permission modifier and the return value makes the ordinary method a generic method.
// 有参数的泛型方法 public <E> void printInfo(E input){ System.out.println(input); } // 调用泛型方法 obj.printInfo("sunrise"); // 无参数的泛型方法 public <E> List<E> createList(){ return new ArrayList<>(); } // 调用泛型方法 List<String> list = obj.createList(); // 创建的是String类型的list
-
note:
- Generic methods and generic classes are independent of each other:
① Generic classes are usedT
as wildcards, and generic methods are also usedT
. In actual use, the incoming type of the generic class isString
, and the generic method can be any type, without being restricted by the generic class.
② Generic methods can be defined in generic classes or ordinary classes; generic classes do not necessarily contain generic methods. - In a generic class, methods that use generic members are not generic methods. Generic methods must have separate declarations.
- Generic methods and variable parameters
-
In Java methods, it is usually used
...
to define variable-length parameters.public void printNames(String... names) { for (String name : names) { System.out.print(name + " "); } } // 传入任意数量的参数 generic.printNames("lucy", "grace", "john", "张三");
-
Generic parameters will be transformed into an array by the compiler, so it can be traversed as an ordinary array.
public void printNames(String... names) { for (int i=0;i<names.length;i++){ System.out.print(names[i] + " "); } }
-
Variable parameters stipulate that the types of parameters passed in must be consistent. Generic methods can be combined with variable parameters to pass in different types of parameters.
public <T> void printNumbers(T... args) { for (T arg : args) { System.out.print(arg + " "); } } // 方法的调用 generic.printNumbers("12.3", 24, 24.5, 2.4f);
2.3 Generic interface
-
The definition of generic interface is basically the same as that of generic
//定义一个泛型接口 public interface Generator<T> { public T next(); }
-
How to implement a generic interface?
-
When a generic class implements a generic interface, it does not pass in generic arguments to the generic interface. When defining a generic class, you need to add a generic declaration for the class.
class GenericClass2<T> implements GenericInterface<T>{ @Override public T next() { return null; } }
-
When a generic class implements a generic interface, it passes generic arguments to the generic interface. When defining a generic class, there is no need to add a generic declaration for the class.
class GenericClass1 implements GenericInterface<String>{ @Override public String next() { return null; } }
3. Generic wildcards
3.1 Overview of generic wildcards
-
A-Z
Any character that a generic wildcard can use does not affect the effect of generics, but it will affect understanding.class GenericClass2<A> implements GenericInterface<A>{ @Override public A next() { return null; } }
-
Wildcard commonly used include
T
,K
,V
,E
and?
, they have some common meanings:
?
Represents an uncertain Java type.T
(type) represents a specific Java typeK
AndV
that the key, value, represents the health and value of key Java.E
(element) represents
3.2 Unbounded wildcard?
- When the incoming type is uncertain, you can use unbounded wildcards
?
, which can receive all unknown types of genericspublic void printList(List<?> list){ list.add("2845"); // 编译报错 list.add(null); // 运行时错误,java.lang.UnsupportedOperationException String j = list.get(0); //编译期报错 for (Object obj:list){ System.out.print(obj+" "); } }
?
Precautions for use:
- It can only be
List<?>
added to usenull
, but an error will be reported during runtime. - Since
List<?>
the specific type of the element is not known , it can only be read, and the read element should be operated as anObject
object.
3.3 Upper bound wildcard<? extends T>
-
<? extends T>
Used to indicate that the incoming generic parameters must be class T or a subclass of class T/implementation class of interface T or T.
-
For example,
<? extends Number>
the parameter passed in must be ofNumber
its subclass.List<Integer> list1=Arrays.asList(1,2,3,4); List<String> list2=Arrays.asList("sunrise","john","grace"); getList(list1); getList(list2); // 编译报错,类型不兼容 public static List getList(List<? extends Number> list){ return list; }
-
PESC principle: upper bound wildcard, generally used in reading scenarios.
- The type specified for a generic can only be a
T
type or its subclasses. - Can only be added to its list
null
. - The value obtained by the get method can only be assigned to the
T
class or its superclass.
3.4 Nether wildcard<? super T>
<? super T>
Indicates that the passed-in generic parameter must be the parent class of class T or class T.
- For example, the
List<? super Integer>
incoming parameter must beInteger
or its parent class.List<Number> list=Arrays.asList(12,13,45); getSuperList(list); List<String> list2=Arrays.asList("sunrise","john","grace"); getSuperList(list2); // 编译报错 public static List getSuperList(List<? super Integer> list){ return list; }
- PECS principle: lower bound wildcard, generally used in writing scenarios.
- The type specified for a generic must be
T
, or its superclass. - You can add any
T
type to its list , or its subcategories. - The type obtained by the get method can only be assigned to the Object type.
- Summary: PECS principles
- The upper bound
<? extends T>
cannot be stored in, but can only be taken out. It is suitable for scenarios where content is frequently read outside. - The lower bound
<? super T>
does not affect the saving in, but the outgoing can only be placed in the Object object, which is suitable for scenarios where data is often inserted into it.
Follow-up learning:
- The erasure principle of generics: an in-depth understanding of Java generics
?
AndT
the difference between: Wildcard chat -JAVA generics T, E, K, V ,?- JAVA generic wildcard T, E, K, V difference, T and the difference between Class, Class