Java generic study notes (not updated)

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

  1. ObjectThe arbitrariness of parameters is realized by using , and the disadvantage is that it needs to be explicitly cast.
  2. In the case of type conversion errors, the compiler will not prompt an error, and will throw it at runtime ClassCastException.
  3. Therefore, Objectthe 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:

  1. 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.
  2. Generics will implicitly and automatically force type conversion, which can improve code utilization.

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 ( Collectionand Map). 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:

  1. Generic methods and generic classes are independent of each other:
    ① Generic classes are used Tas wildcards, and generic methods are also used T. In actual use, the incoming type of the generic class is String, 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.
  2. In a generic class, methods that use generic members are not generic methods. Generic methods must have separate declarations.
  • Generic methods and variable parameters
  1. 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", "张三");
    
  2. 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] + " ");
        }
    }
    
  3. 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?

  1. 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;
        }
    }
    
  2. 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-ZAny 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, Eand ?, they have some common meanings:

  1. ?Represents an uncertain Java type.
  2. T (type) represents a specific Java type
  3. KAnd Vthat the key, value, represents the health and value of key Java.
  4. 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 generics
    public 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:
  1. It can only be List<?>added to use null, but an error will be reported during runtime.
  2. Since List<?>the specific type of the element is not known , it can only be read, and the read element should be operated as an Objectobject.
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.
    Insert picture description here

  • For example, <? extends Number>the parameter passed in must be of Numberits 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.

  1. The type specified for a generic can only be a Ttype or its subclasses.
  2. Can only be added to its list null.
  3. The value obtained by the get method can only be assigned to the Tclass 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.
    Insert picture description here
  • For example, the List<? super Integer>incoming parameter must be Integeror 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.
  1. The type specified for a generic must be T, or its superclass.
  2. You can add any Ttype to its list , or its subcategories.
  3. The type obtained by the get method can only be assigned to the Object type.
  1. 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.
  2. 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:

Guess you like

Origin blog.csdn.net/u014454538/article/details/108196646