introduction

Generics are Java A very important knowledge point in , stay Java Generics are widely used in set class framework . Java The introduction of generics is mainly to solve two problems :1. Type replacement exception for collection type element at runtime , Add compile time type checking ,2.
Solve duplicate code writing , Be able to reuse algorithms .

Generic basis  

Generic class

Let's first define a simple Box class :

1

2

3

4

5

public class Box {

    private String boxname;

    public void set(String boxname) { this.boxname = boxname; }

    public String get() { return boxname; }

}

This is the most common practice , One of the disadvantages of this is that Box It can only be loaded now String Elements of type , In the future, if we need to load Integer And other types of elements , You have to rewrite another one Box, Code is not reused , Using generics can solve this problem well .

1

2

3

4

5

6

public class Box<T> {

    // T stands for "Type"

    private T t;

    public void set(T t) { this.t = t; }

    public T get() { return t; }

}

So our Box Class can be reused , We can T Replace it with whatever type we want :

1

2

3

Box<Integer> integerBox = new Box<Integer>();

Box<Double> doubleBox = new Box<Double>();

Box<String> stringBox = new Box<String>();

generic method

I've finished looking at generic classes , Let's take a look at generic methods . It's easy to declare a generic method , Just precede the return type with a similar <K, V> That's fine :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class Util {

    public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {

        return p1.getKey().equals(p2.getKey()) &&

               p1.getValue().equals(p2.getValue());

    }

}

public class Pair<K, V> {

    private K key;

    private V value;

    public Pair(K key, V value) {

        this.key = key;

        this.value = value;

    }

    public void setKey(K key) { this.key = key; }

    public void setValue(V value) { this.value = value; }

    public K getKey()   { return key; }

    public V getValue() { return value; }

}

We can call generic methods as follows :

1

2

3

Pair<Integer, String> p1 = new Pair<>(1, "apple");

Pair<Integer, String> p2 = new Pair<>(2, "pear");

boolean same = Util.<Integer, String>compare(p1, p2);

Or in the Java1.7/1.8 utilize type inference, Give Way Java Automatically derive the corresponding type parameters :

1

2

3

Pair<Integer, String> p1 = new Pair<>(1, "apple");

Pair<Integer, String> p2 = new Pair<>(2, "pear");

boolean same = Util.compare(p1, p2);

Boundary character

Now we want to implement such a function , Finds the number of elements in a generic array that are greater than a specific element , We can do this :

1

2

3

4

5

6

7

public static <T> int countGreaterThan(T[] anArray, T elem) {

    int count = 0;

    for (T e : anArray)

        if (e > elem)  // compiler error

            ++count;

    return count;

}

But this is obviously wrong , Because apart from short, int, double, long, float, byte, char And so on , Other classes do not necessarily use operators
>, So the compiler reported an error , How to solve this problem ? The answer is to use a boundary character .

1

2

3

public interface Comparable<T> {

    public int compareTo(T o);

}

Make a statement like this , This is equivalent to telling the compiler the type parameter T All of them are realized Comparable The class of the interface , This tells the compiler that they are at least implemented compareTo
method . By definition T extends Comparable
indicate ,T Yes, it is Comparable The type of the interface for , So it's done compareTo method , Therefore, there is no compile time error .

1

2

3

4

5

6

7

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T
elem) {

    int count = 0;

    for (T e : anArray)

        if (e.compareTo(elem) > 0)

            ++count;

    return count;

}

We can use more than one type & To segment , And limited keywords can only be used extends. At the same time, when both the interface and the type exist , Class can only be placed in the first , And there can only be one , As shown below :

1

<T extends Object&Comparable&Serializable>

wildcard

Before you learn about wildcards , We must first clarify a concept , Or borrow our definition above Box class , Suppose we add a method like this :

1

public void boxTest(Box<Number> n) { /* ... */ }

So now Box<Number> n What types of parameters are allowed ? Can we pass in Box<Integer> perhaps Box<Double>
What about ? The answer is No , although Integer and Double yes Number Subclasses of , But in generics Box<Integer> perhaps Box<Double> And Box<Number>
There is no relationship between them . This is very important , Let's take a complete example to deepen our understanding .

First, let's define a few simple classes , We'll use it next :

1

2

3

class Fruit {}

class Apple extends Fruit {}

class Orange extends Fruit {}

In this example , We created a generic class Reader, And then in the f1() When we try Fruit f = fruitReader.readExact(apples);
The compiler will report an error , because List<Fruit> And List<Apple> There is no relationship between them .

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class GenericReading {

    static List<Apple> apples = Arrays.asList(new Apple());

    static List<Fruit> fruit = Arrays.asList(new Fruit());

    static class Reader<T> {

        T readExact(List<T> list) {

            return list.get(0);

        }

    }

    static void f1() {

        Reader<Fruit> fruitReader = new Reader<Fruit>();

        // Errors: List<Fruit> cannot be applied to List<Apple>.

        // Fruit f = fruitReader.readExact(apples);

    }

    public static void main(String[] args) {

        f1();

    }

}

But according to our usual habits of thinking ,Apple and Fruit There must be a connection between them , However, the compiler does not recognize it , So how to solve this problem in generic code ? We can solve this problem by using wildcards :

1

2

3

4

5

6

7

8

9

10

11

12

13

static class CovariantReader<T> {

    T readCovariant(List<? extends T> list) {

        return list.get(0);

    }

}

static void f2() {

    CovariantReader<Fruit> fruitReader = new CovariantReader<Fruit>();

    Fruit f = fruitReader.readCovariant(fruit);

    Fruit a = fruitReader.readCovariant(apples);

}

public static void main(String[] args) {

    f2();

}

This is equivalent to telling the compiler ,
fruitReader Of readCovariant Method accepts as long as the parameters are satisfied Fruit Just subclasses of ( include Fruit oneself ), In this way, the relationship between the child class and the parent class is related .

PECS principle

We see something like that above <? extends T> Usage of , We can use it from list inside get element , So can we go list inside add What about the elements ? Let's try it :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class GenericsAndCovariance {

    public static void main(String[] args) {

        // Wildcards allow covariance:

        List<? extends Fruit> flist = new ArrayList<Apple>();

        // Compile Error: can't add any type of object:

        // flist.add(new Apple())

        // flist.add(new Orange())

        // flist.add(new Fruit())

        // flist.add(new Object())

        flist.add(null); // Legal but uninteresting

        // We Know that it returns at least Fruit:

        Fruit f = flist.get(0);

    }

}

The answer is No ,Java The compiler doesn't allow us to do this , Why? ? For this problem, we might as well consider it from the compiler's point of view . because List<? extends Fruit> flist
It can have many meanings in itself :

1

2

3

List<? extends Fruit> flist = new ArrayList<Fruit>();

List<? extends Fruit> flist = new ArrayList<Apple>();

List<? extends Fruit> flist = new ArrayList<Orange>();

* When we try add One Apple When ,flist May point to new ArrayList<Orange>();
* When we try add One Orange When ,flist May point to new ArrayList<Apple>();
* When we try add One Fruit When , this Fruit It can be any type Fruit, and flist Maybe just want a certain type Fruit, The compiler does not recognize it, so it will report an error .
So for the implementation <? extends T> The collection class of can only treat it as Producer Provide to the outside world (get) element , It can't be done Consumer To obtain from abroad (add) element .

If we want to add What should elements do ? have access to <? super T>:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class GenericWriting {

    static List<Apple> apples = new ArrayList<Apple>();

    static List<Fruit> fruit = new ArrayList<Fruit>();

    static <T> void writeExact(List<T> list, T item) {

        list.add(item);

    }

    static void f1() {

        writeExact(apples, new Apple());

        writeExact(fruit, new Apple());

    }

    static <T> void writeWithWildcard(List<? super T> list, T item) {

        list.add(item)

    }

    static void f2() {

        writeWithWildcard(apples, new Apple());

        writeWithWildcard(fruit, new Apple());

    }

    public static void main(String[] args) {

        f1(); f2();

    }

}

So we can add elements to the container , But using super The disadvantage is that we can't get The elements in the container , The reason is simple , We continue to think about this from the compiler's point of view , about List<?
super Apple> list, It can have the following meanings :

1

2

3

List<? super Apple> list = new ArrayList<Apple>();

List<? super Apple> list = new ArrayList<Fruit>();

List<? super Apple> list = new ArrayList<Object>();

When we try to pass list come get One Apple When , Maybe get Get one Fruit, this Fruit It can be Orange And other types of Fruit.

According to the example above , We can sum up a rule ,”Producer Extends, Consumer Super”:

* “Producer Extends” – If you need a read-only one List, Use it produce T, Then use ? extends T.
* “Consumer Super” – If you need a write only one List, Use it consume T, Then use ? super T.
* If you need to read and write at the same time , Then we can't use wildcards .
How to read some Java Source code of collection class , As you can see, we usually use both together , Like this :

1

2

3

4

5

6

public class Collections {

    public static <T> void copy(List<? super T> dest, List<? extends T> src) {

        for (int i=0; i<src.size(); i++)

            dest.set(i, src.get(i));

    }

}

Type Erasure

Type erasure means Java Generics can only be used for static type checking during compilation , The code generated by the compiler then erases the corresponding type information , So when it comes to runtime, it's actually JVM You know exactly what type generics represent . The purpose of this is because Java Generics are 1.5 It was introduced after that , To maintain downward compatibility , So you can only do type erasure to be compatible with previous non generic code .

* stay Java Creating generic arrays is not allowed in
* Cannot be used directly with generic code instanceof keyword
* Using type parameters to create instances does not pass the compiler :

1

2

3

4

public static <E> void append(List<E> list) {

    E elem = new E();  // compile-time error

    list.add(elem);

}

If there are scenarios where we want to create instances with type parameters , Reflection can be used to solve this problem :

1

2

3

4

public static <E> void append(List<E> list, Class<E> cls) throws Exception {

    E elem = cls.newInstance();   // OK

    list.add(elem);

}

 

 

Technology
©2019-2020 Toolsou All rights reserved,
Final review of database : Summary of comprehensive application questions Laplance operator ( Second derivative ) Simple learning of computer composition principle pyqt Button call python program _PyQt: Link button to function in program How much can you go up once you change jobs ? Today, I saw the ceiling of job hopping python in str Function usage _python in str Usage Summary of built-in functions MySQL trigger web The server nginx---linux Installation and deployment C++ Chapter V polymorphism exercises :( It's coming to an end )python Check built-in functions , How to check python Built in function