Basics of Java Generics

background

In the absence of generics, once an object is thrown into the collection, the collection will forget the type of the object, all the objects are treated as Object type. When the program objects removed from the collection on the need for cast, this conversion can easily cause a ClassCastException.

definition

Program specifies the type of collection element in the creation of the collection. Increase the collection of the generic support, you can remember the type of elements in the collection, and you can check the type of elements in a set at compile time, if you try to add an object type does not meet the requirements to the collection, the compiler will report an error.

Examples

Use generic collections

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DiamondTest {
    public static void main(String[] args) {
        List<String> books = new ArrayList<>();
        books.add("learn");
        books.add("java");
        books.forEach(book -> System.out.println(book.length()));

        Map<String, List<String>> schoolsInfo = new HashMap<>();
        List<String> schools = new ArrayList<>();
        schools.add("i");
        schools.add("love");
        schoolsInfo.put("java", schools);
        schoolsInfo.forEach((key, value) -> System.out.println(key + "--->" + value));
    }
}

Classes, generic interface

public class Apple<T> {
    private T info;
    public Apple() {}
    public Apple(T info) {
        this.info = info;
    }
    public void setInfo(T info) {
        this.info = info;
    }
    public T getinfo() {
        return this.info;
    }
    public static void main(String[] args) {
        Apple<String> a1 = new Apple<>("Apple");
        System.out.println(a1.getinfo());
        Apple<Double> a2 = new Apple<>(5.67);
        System.out.println(a2.getinfo());
    }
}

Wildcard type

demand analysis

public void test(List<Object> c) {
    for (int i = 0; i < c.size(); i++) {
        System.out.prinln(c.get(i));
    }
}

This method declarations without any problems, but the method is called the actual parameter values ​​passed, may be wrong. Consider the following code:

List<String> strList = new ArrayList<>();
test(strList); // 编译出错,表明 List<String> 对象不能被当成 List<Object> 对象使用,也就是说 List<String> 并不是 List<Object> 的子类。

problem solved

To represent the various generic List parent class, the type of wildcards can be used. List<?>It represents an element of unknown type List. This number is known as a wildcard, it can match any type. The above code is changed to the following form:

public void test(List<?> c) {
    for (int i = 0; i < c.size(); i++) {
        System.out.prinln(c.get(i));
    }
}

Now any type of pass List, the program can be printed in the normal elements of the collection c.

However, the type of elements in the collection are treated as Object type.

The upper limit of the type of wildcards

demand analysis

When using List<?>, it indicates that it can be any generic List parent. If we only want it to represent a generic List class parent, java provides a generic wildcard is limited.

Look at the following code:

public abstract class Shape {
    public abstract void draw(Canvas c);
}
public class Circle extends Shape {
    @Override
    public void draw(Canvas c) {
        System.out.println("在画布上" + c + "上画一个圆");
    }
}
public class Rectangle extends Shape {
    @Override
    public void draw(Canvas c) {
        System.out.println("把一个矩形画在画布" + c + "上");
    }
}
import java.util.List;

public class Canvas {
    public void drawAll(List<Shape> shapes) {
        for (Shape s : shapes) {
            s.draw(this);
        }
    }
}

The following code will compile-time error, because List<Circle>not List<Shape>sub-type, it is not the List<Circle>subject as a List<Shape>class with.

// 错误示范
List<Circle> circleList = new ArrayList<>();
Canvas c = new Canvas();
c.drawAll(circleList); 

problem solved

Method one: solved by the type of wildcards that List<?>way.

Need to be cast, because List<?>the default element type Object

import java.util.List;

public class Canvas {
    public void drawAll(List<?> shapes) {
        for (Object obj : shapes) {
            Shape s = (Shape)obj // 但是需要进行强制类型转换,因为前面提到过 List<?> 中元素默认为 Object 类型
            s.draw(this);
        }
    }
}

Method two: the use of generic wildcard is restricted

List<? extends Shape>It can be expressed List<Circle>and List<Rectangle>parent. As long as the angle brackets in the List type is a subclass of Shape can be.

import java.util.List;

public class Canvas {
    public void drawAll(List<? extends Shape> shapes) { // 使用被限制的泛型通配符
        for (Shape s : shapes) {
            s.draw(this);
        }
    }
}

Application of parameter types

Setting an upper limit when defining the types of wildcards type parameter. In order to represent the actual type is passed to the type parameter must be an upper limit or a subclass type.

public class Apple<T extends Number> {
    T col;
    public static void main(String[] args) {
        Apple<Integer> ai = new Apple<>();
        Apple<Double> ad = new Apple<>();
        Apple<String> as = new Apple<>(); // 编译出错,试图将 String 类型传给 T 形参,但是 String 不是 Number 的子类型
    }
}

Generic method

definition

Generic method is to define one or more parameters in a type declaration method. Types separated by commas plurality of parameters.

修饰符 <T, S> 返回值类型 方法名(形参列表) {方法体}

demand analysis

Generic method to solve the problem?

static void fromArrayToCollection(Object[] a, Collection<Object> c) {
    for (Object o : a) {
        c.add(o)
    }
}

The method as defined above, without any problems, the key is in the c-parameter method, its data type Collection<Object>. Suppose incoming actual parameter type Collection<String>, because Collection<String>not Collection<Object>subclass, the function of this method is very limited, it is only the Object [] elements of the array are copied to the element type Object (Object not a subclass) of Collection collection.

If you use wildcards Collection<?>to work? Obviously does not work, Collection offers a collection of add () method has a type parameter E, but if you use a wildcard type, so that the program can not determine the type of element c in the collection, it is not correct to call the add method.

problem solved

Generic method.

import java.util.ArrayList;
import java.util.Collection;

public class GenericMethodTest {
    // 声明一个泛型方法
    static <T> void fromArryToCollection(T[] a, Collection<T> c) {
        for (T o : a) {
            c.add(o);
        }
    }
    public static void main(String[] args) {
        Object [] oa = new Object[100];
        Collection<Object> co = new ArrayList<>();
        fromArryToCollection(oa, co);

        String[] sa = new String[100];
        Collection<String> cs = new ArrayList<>();
        fromArryToCollection(sa, cs);
    }
}

Further transformation, as follows

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class RightTest {
    static <T> void test(Collection<? extends T> from, Collection<T> to) {
        for (T ele : from) {
            to.add(ele);
        }
    }
    public static void main(String[] args) {
        List<String> as = new ArrayList<>();
        List<Object> ao = new ArrayList<>();
        test(as, ao);
    }
}

Generic constructors

And similar generic methods, Java also allows the declaration of a type parameter in the constructor signature, which produced the so-called generic constructor

public class Foo {
    // 泛型构造器
    public <T> Foo(T t) {
        System.out.println(t);
    }
}

public class GenericConstructor {
    public static void main(String[] args) {
        new <String> Foo("crazy");
        new Foo("crazy"); // 与上面等价
        new <Sting> Foo(12.3) // 出错
    }
}

Wildcard type limit

demand analysis

Implement a method to copy src to dest elements of the collection of the collection, and the function returns the last copied elements.

Because src dest collection can save the collection of all the elements, so dest collection element type of src should be a collection element type parent.

To show two types of dependencies between parameters, while considering the use of the previously introduced a wildcard, generic parameters to achieve the method, as follows:

public static <T> T copy(Collection<T> dest, Collection<? extends T> src) {
    T last = null;
    for (T ele : src) {
        last = ele;
        dest.add(ele);
    }
    return last;
}

List<Number> ln = new ArrayList<>();
List<Integer> li = new ArrayList<>();
// 下面代码会引起编译错误
Integer last = copy(ln, li);

The above code has a problem, ln is the type List<Number>, the actual type is T Number, i.e., the return value is the last type of type Number. But in fact the type of the last element of a copy must be Integer. In other words, in the process of copying the program element in the collection, the missing collection element type src.

problem solved

To solve this problem, the introduction of a wildcard lower limit <? super Type>. Type must be represented itself or Type parent. Complete code rewritten as follows:

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class MyUtils {
    // 使用通配符下限
    public static <T> T copy(Collection<? super T> dest, Collection<T> src) {
        T last = null;
        for (T ele : src) {
            last = ele;
            dest.add(ele);
        }
        return last;
    }
    public static void main(String[] args) {
        List<Number> ln = new ArrayList<>();
        List<Integer> li = new ArrayList<>();
        li.add(5);
        // 此时可以准确知道最后一个被复制的元素是 Integer 类型,而不是笼统的 Number 类型
        Integer last = copy(ln, li);
        System.out.println(last);
        System.out.println(ln);
    }
}

Generic erased

Generics are basically the compiler to achieve this level. In the generated Java byte code is not included in the generic type of information. When combined with the use of the generic type parameter, it is removed the compiler at compile time. This process is called generics erased. As defined in the code List<Object>and List<String>other types, will become List after compilation, the JVM see List only, the generic type of additional information is not visible to the JVM.

I welcome the attention of the public number

Guess you like

Origin www.cnblogs.com/Tianny/p/11620384.html