At some unknown azimuth has so called the island of Java, unique natural conditions make the country rich products, which is famous as rich in famous Java world, every year to attract a large number of visitors from all over the world to study tourism, sightseeing is understandable, study the method of how to understand, with this doubt we continue down further, beeping, Drive!

It is interesting that the Java language is used by the local people living in The Country of Java to communicate. This language, called Java, was created by the first king of the country of Java, and gradually improved and evolved into cultural characters and communication language, which has been passed down to this day. Language communication also makes information more timely, which is of great help to the country’s Java Bean production industry. Therefore, the export of coffee beans in this country has always been in great demand, which is why the flag of Java island is a cup of steaming coffee:

The advent of generics

The introduction of any thing is not perfect, the jade after the craftsman’s carving warm and smooth square, the roommate of the upper shop willfully resigned, went home to inherit the family property existing car has room, leaving me in place with emotion: senior players!

Back in JDK 1.4, when generics were not a concept, people used to talk about things like:

public static void main(String[] args) {
    List list = new ArrayList();
    list.add("https://www.talkmoney.cn/");
    list.add(5);
    String str = (String)list.get(0);
    Integer num = (Integer)list.get(1);
}
Copy the code

The first thing you can see is that you declare a collection and then put different data into the collection, and then you have to cast the data in the collection. In addition, you can also get a ClassCastException when you cast the data in the collection, and you can get a ClassCastException when you cast the data. It is as if processors unload different varieties of beans from trucks coming from plantations, resulting in roasted beans that are not what they need.

This situation did not change until the fifth Javanese monarch took office. The new monarch made great efforts and issued the rule of generics for this situation. General classes and methods can only use specific types: either basic types or custom classes. This constraint constrains the code very much if you want to write code that can be applied to multiple types. In fact, generics are designed to make code that can be reused by different types of objects, and thus the way people communicate with each other again:

public static void main(String[] args) {
    List<String> list = new ArrayList();
    list.add("https://www.talkmoney.cn/");
    list.add("Hello, I am Reed.");
    String url = list.get(0);
    String name = list.get(1);
}
Copy the code

When the set is created, String is assigned to it. This means that only String data can be stored into the set. Therefore, there is no need to cast data when fetching data, thus avoiding the risk of casting exceptions. In the Constitution of Java, “Thinking in Java”, generics appear because:

There are many reasons for generics, one of the most notable being the creation of container classes.

When you think about it, it seems that the Collection library and generics really do work together. Here’s an example of the Collection interface:

public interface Collection<E> extends 可迭代<E> {

    Iterator<E> iterator(a);

    Object[] toArray();

    <T> T[] toArray(T[] a);
    
    boolean add(E e);

    boolean remove(Object o);

    boolean containsAll(Collection
        c);

    boolean addAll(Collection<? extends E> c);

    boolean removeAll(Collection
        c);
}   
Copy the code

The use of generics

In order to write code that can be reused by different types of objects, you need to specify parameters for the data type of the operation. This parameter type can be used in classes, methods, collections, interfaces, and so on.

A generic class

Suppose we now need a class that can pass in different types of data, we can write it by using generics:

public class GenericClass<T> {
    private T item;
    
    public void setItem(T t) {
        this.item = t;
    }
    
    public void getItem(T t) {
        return this.item; }}Copy the code

At first glance, you can see that a generic class is similar to a normal class, except that the class name is followed by a list of type parameters. The T in Angle brackets is the specified type parameter. Class members, methods, and arguments can use this parameter type, and return the specified parameter type.

public static void main(String[] args) {
    GenericClass<String> name = new GenericClass<>(Reed Technology);
    GenericClass<Integer> age = new GenericClass<>(5);
}
Copy the code

Generic method

A generic method, as its name implies, is a method that uses generics. It has its own type parameters, which are also between Angle brackets and before the return value of the method. In addition, a generic method can exist in either a generic class or an ordinary class, as follows:

/ / a generic class
public class GenericClass<T> {
    private T item;
    
    public void setItem(T t) {
        this.item = t;
    }
    // Just use generics without declaring type parameters, so don't confuse this with a generic method
    public void getItem(T t) {
        return this.item;
    }
    
    // Generic methods
    public <T> void GenericMethod(T t) { System.out.println(t); }}Copy the code

It is important to note that type T in a generic method and type T in a generic class are two different things. Although they are both T, they do not affect each other, and there can be multiple type parameters.

A generic interface

The definition of a generic interface is basically the same as the definition of a generic class. The type parameters are written after the interface name as follows:

public interface GenericInterface<T> {
    public void doSomething(T t);
}
Copy the code

In use, the implementation class needs to pass in a specific parameter type to implement the generic interface, so that any subsequent use of the generic will be replaced by the parameter type passed in, as follows:

public class Generic implements GenericInterface<String> {
    @override
    public void doSomething(String s) {... }}Copy the code

Generic wildcard

In addition to generic classes, methods, etc., there are other applications of generics. For example, sometimes you want to pass in type parameters with a limited range, which is obviously expected by Java. The solution is generic wildcards.

  • The upper bound wildcard
  • The lower wildcard
  • Unbounded wildcard

Before we look at wildcards, we need to have a basic understanding of type information.

public class Coffee {}

// Cappuccino
public class Cappuccino extends Coffee {}

// The first creation method
Cappuccino cappuccino = new Cappuccino();
// The second creation method
Coffee cappuccino = new Cappuccino();
Copy the code

The Coffee class is the parent of the Cappuccino class. There are two ways to create a class object. The first is very common: create a Cappuccino object and point to it. This allows the TYPE information to be Cappuccino both at JVM compile time and at runtime. The second way is to use a Coffee variable to point to a Cappuccino object. This is called an upcast in Java syntax. In Java, you can assign a subclass object to a superclass object. Runtime type information allows us to discover and use type information at run time, and all conversions recognize the type of the object at run time, so at compile time the type is Coffee, and at run time the JVM finds it points to a Cappuccino object by initializing the object. So it’s of Cappuccino type at runtime.


The upper bound wildcard <? extends T>

Now that we’ve sorted out the type information, we’ve also mentioned that sometimes we want to pass in a type parameter that has a limited range, so we define a Cup class that can be used to load coffee:

public class Cup<T> {
    private List<T> list;
    public void add(T t) {list.add(t); }public T get(int index) {return list.get(index);}
}
Copy the code

The Cup class is a generic class, and it specifies the type parameter T, which means that we can pass in any type. If we need a Cup to hold coffee, we can use cappuccino, because cappuccino is also a type of coffee, right?

Cup<Coffee> cup = new Cup<Cappuccino>();	// compiler error
Copy the code

The Coffee and Cappuccino classes are known to inherit from each other, but this is not supported in generics. The solution is to use upper bound wildcards:

Cup<? extends Coffee> cup = new Cup<Cappuccino>();
Copy the code

Using extends in the type parameter list means that in the generic type it must be Coffee or a subclass of Coffee. Of course, there can be more than one parameter in the type parameter list, separated by commas. This problem is solved by using the upper bound wildcard, but using the upper bound wildcard makes it impossible to put any objects in it, but possible to pull objects out of it.

Cup<? extends Coffee> cup = new Cup<Cappuccino>();
cup.add(new Cappuccino()); 			  // compiler error
Coffee coffee = cup.get(0);		          // compiler success
Copy the code

The reason for this is that we know that a Cup<? A reference to extends Coffee> may refer to an object of the Coffee class or to a subclass of another Coffee class, so that the JVM does not know what type it is at compile time and just blitzed it out for safety reasons. Fetching data from it can eventually be referenced using Coffee type variables by upcasting. So, when we use the upper bound wildcard <? When extends T>, note that you can’t insert into it, but you can read;

The lower wildcard <? super T>

The lower wildcard
is exactly the same as the upper bound wildcard
extends T> extends T> extends T> extends T> extends T> extends T> extends T> extends T> extends T> extends T> extends T> extends T

Cup<? super Cappuccino> cup = new Cup<Coffee>();         // compiler success
Cup<? super Cappuccino> cup = new Cup<Object>(); 	 // compiler success
Object object = cup.get(0);
Copy the code

For CUP, the specific type it points to can be any parent of Cappuccino class. Although we don’t know which type it is, it can be converted to T, so we can insert T and its subclasses into it. On the read side, since it stores T and its base class, There is no way to cast to any type, only fetching data through the Object base class.

Unbounded wildcard <? >

This wildcard can hold any type if you’re not sure what type argument you’re actually operating on. It’s important to note that it’s easy to confuse and, for example, List and List look alike when they’re not. List is a List of unknown type, and List is a List of any type. We can assign List to List<? > < span style = “box-sizing: border-box; color: RGB (74, 74, 74);

List<Object> objectList = newArrayList<>(); List<? > anyTypeList; List<String> stringList =new ArrayList<>();

anyTypeList = stringList;	       // compiler success
objectList = (List<Object>)stringList; // compiler error
Copy the code

Wildcard summary

As we learned earlier, the unbounded wildcard <? > is used for scenarios where the scope is uncertain, while the upper bound wildcard <? Extends T> and the lower wildcard <? Super T> also knows where they can be used and restricted:

  • The upper bound wildcard
    Does not insert storage data but can read data.
  • The lower wildcard
    can insert T type and its subclass Object, and only through the Object variable to take out the data, suitable for the scene that requires content insertion;

In fact, this is also known as the PECS principle, which stands for Producer Extends Consumer Super. Producer Extends shows that when a Producer needs to obtain content resources to produce, the scene role is the Producer. The upper bound wildcard <? Extends T> better reads data; Consumer Super refers to when we need to insert content resources for consumption and the scene role is the Consumer, we can use the lower wildcard <? Super T> Better insert data. The specific choice can be flexibly selected based on your actual situation. When it comes to producers and consumers, the feeling goes back to the beginning of multithreading, time slips away quietly like this, and can not be caught.

The mystery of generics

About generics

In the world of all corners of the country that jin Yong Lao Don describes, inside have skill of martial arts and martial arts is called universe and earth move greatly, want to acquire this skill to be able to put to good use the other side martial arts and martial arts directly only, even if be to learn now to use now pass and not as good as, sound extensive model seems to be about the same also. So let’s start with an example:

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> a = new ArrayList<String>();
        ArrayList<Integer> b = newArrayList<Integer>(); System.out.println(a.getclass() == b.getclass()); }}// Result: true
Copy the code

Although they are two different types of collection array, when their class information and compare, this time between the two types should be the same, the reason this is Java generics erasure mechanism, the first thing you need to know is that generics are embodied in the compile time, after in the generated bytecode file and run time is not include generic information, So the type information is erased, leaving only the original type. This process is the mechanism for generic erasure. The reason for erasure is to make compatibility with the original code. In addition, primitive types are described below.

When a generic type is erased, only the primitive type remains.

/ / before erasing
public class GenericClass<T> {
    private T data;
    
    public T getData(a) {returndata; }... }/ / erased
public class GenericClass {
    private Object data;
    
    public Object getData(a) {returndata; }... }Copy the code

An unbounded type parameter is replaced by Object after being erased by the type, as opposed to an unbounded type parameter. As mentioned above, if no bounds are specified, the type parameter is replaced by Object. What if you want to restrict the type to a range?

/ / before erasing
public class GenericClass<T extends Serializable> {
  	private T data;
    public T getData(a) {returndata; }... }/ / erased
public class GenericClass {
    private Serializable data;
    public Serializable getData(a) {returndata; }... }Copy the code

If there are more than one boundary, the type parameter will only erase the first boundary. If there are more than one boundary, the type parameter will erase the first boundary.

The nature of generics

At this point, we might wonder, since generics are erased when the class is compiled, how do we make the insertion read type consistent at runtime? In other words, if the generic type argument is erased to Object, it should be possible to insert other types of data.

In fact, the JVM, while erasing type parameters when compiling a class, ensures that generic type parameters are used consistently. We know that the type parameters are still available when the class is being compiled, and the compiler can do type checking, for example, when an ArrayList is declared as an Integer, and it checks when it inserts data into the ArrayList. This ensures consistency of data types. When the type argument is erased, the JVM silently converts the type argument to the one we specified in order to make sure that the data we read from it is of the same type argument

Limitations of generics

Due to the Java generic erasure mechanism, specified type parameters are erased, so the following operations are not allowed:

  • Cannot use type parameters to create instances;
  • Instanceof cannot be used with type parameters;
public class GenericClass<T> {
    public static void method(Object obj) {
        if (obj instanceof T) { // compiler error. } T t =new T(); // compiler error}}Copy the code
  • The type parameter specified by a generic type cannot be a primitive type
ArrayList<int> list = new ArrayList<int> ();// compiler error
/** * Can use wrapper classes */ for basic data types
ArrayList<Integer> list = new ArrayList<Integer>(); // compiler success
Copy the code
  • Cannot create an array of type parameters
ArrayList<Integer>[] list = new ArrayList<Integer>(3);
Copy the code

conclusion

As you can see, the Java in order to let people to live and work in peace and contentment, and under some kind of hard, over the years as the “coffee market” in short supply, many people have joined in, also mentioned in the beginning of the article, every year to attract large Numbers of tourists to learn from all over the world, the future no one knows exactly how, just a lot of time is just like a castle, Some people come out, some people go in. In their words: “Alas, a poor man’s livelihood! “.

Here, this article has entered the end, on the one hand there are many failed to record in detail, I hope to play a role here, because my level is limited, please criticize.


Reference:

  • Thinking in Java

  • Java generics in detail


Push the information

  • We are recruiting partners, interested partners can send your resume to [email protected], note: from the nuggets community
  • For details, please click here –> Guangzhou Reed Information Technology