On the Java type erasure

This blog introduces the Java type erasure definition, describes in detail the type of scene that appears erased in Java.

1. What is type erasure

To give you a quick impression of a type erasure, first give a very simple and very classic example.

// 指定泛型为String
List<String> list1 = new ArrayList<>();
// 指定泛型为Integer
List<Integer> list2 = new ArrayList<>();

System.out.println(list1.getClass() == list2.getClass()); // true
复制代码

The above judgment result true. Was introduced to represent the two different generic List eventually compiled into ArrayList, become the same type, the original generic parameters String and Integer are erased a. This is a typical example of the type of erasure.

And if we talk about the type erasure Why is there, we have to understand generics.

2. Generic

2.1. The generic definition of

With the September 30, 2004, the project code-named Tiger JDK 1.5 release, from generics to meet with you. JDK 1.5 has made great improvements in ease of use Java syntax. In addition to the generic, with the release added as well as automatic packing, dynamic annotation, enumeration, variable-length parameters, foreach loop, and so on.

In versions prior to 1.5, in order to make Java class versatile, parameter types and return types are usually set to Object, visible, if not of the type required, it is necessary in the appropriate place, its cast, program can operate normally, very troublesome, little attention will be wrong.

Parameterized type is essentially generic. That is, the data type is specified as a parameter. The introduction of generics what good is it?

Generics can be wrong before JDK 1.5 at runtime can be found in advance to compile. In other words, generic detection mechanism provides a type-safe compile time. For example, a variable of type Integer originally, became the String we set in code, without the use of generics only when the code runs to this, and will report an error.

And this problem does not occur after the introduction of generics. This is because you can know the type specified by the generic parameter, then at compile time, determine its type for compliance type.

There are three generic use, it is used in the classes, interfaces and methods.

3. The use of generic

3.1 generic class

3.1.1 the definition of a generic class

Simple generic class can be defined as follows.

public class Generic<T> {
    T data;
    
    public Generic(T data) {
        setData(data);
    }
    
    public T getData() {
        return data;
    }
    
    public void setData(T data) {
        this.data = data;
    }
}
复制代码

Where T represents the parameter type, represents any type. Of course, not have to write T, it's just everyone convention habit. With the above generic class then we can be like the following way use.

3.1.2 Using generic class

// 假设有这样一个具体的类
public class Hello {
    private Integer id;

    private String name;

    private Integer age;

    private String email;
}

// 使用泛型类
Hello hello = new Hello();
Generic<Hello> result = new Generic<>();
resule.setData(hello);

// 通过泛型类获取数据
Hello data = result.getData();
复制代码

Of course, if the generic class does not pass the specified type, then type the generic class method or field can be defined as any type, if the print result.getClass(), it will get Generic.

3.2. Generic methods

3.2.1 generic method definition

First we look at the generic method with no return value can be defined as a structure.

// 定义不带返回值的泛型方法
public <T> void genericMethod(T field) {
    System.out.println(field.getClass().toString());
}

// 定义带返回值的泛型方法
private <T> T genericWithReturnMethod(T field) {
    System.out.println(field.getClass().toString());
    return field;
}
复制代码

3.2.2 calling a generic method

// 调用不带返回值泛型方法
genericMethod("This is string"); // class java.lang.String
genericMethod(56L); // class java.lang.Long

// 调用带返回值的泛型方法
String test = genericWithReturnMethod("TEST"); // TEST class java.lang.String
复制代码

The method of the return value, T is the return type of the current function.

3.3. Generic Interface

Generic interface is defined as follows

public interface genericInterface<T> {
}
复制代码

Method similar to the generic class, not repeat them here.

4. generics wildcards

What is a generic wildcard? The official explanation is that

Type of unknown.

That is indefinite wildcard can represent any type. There are also three usage, <?>, <? Extends T> and <? Super T>.

Now that you have a wildcard to represent any type of such T, why do we need such an indefinite wildcard do? Because the main problem is caused by inherited generic problems.

4.1. Generics inheritance

First look at an example

List<Integer> integerList = new ArrayList<>();
List<Number> numberList = integerList;
复制代码

We know that Integeris inherited from the Numberclass.

public final class Integer extends Number implements Comparable { .... }

Then the above code can compile it? Definitely not work. Integer Number does not mean that there are inherited from the inheritance relationship between List and the List. What wildcard scenarios is it?

4.2. Wildcard application scenarios

In other functions, such as JavaScript, the parameters of a function may be of any type, without the need for any type of conversion, so this function in some application scenarios, it will highly versatile.

In this strongly typed Java language, a function of the parameter type is fixed. So, if you want to achieve similar generic functions such as JavaScript in Java how to do it? This is why we need generics wildcards.

Suppose we have a lot of animals like, for example, Dog, Pig and Cat three classes, we need to have a common function to calculate the total number of animals in the list of all the animal's legs, if in Java, how to do it?

Some people would argue with generics ah, generic solution to this problem is not it? Generics must specify a specific type. Generics can not solve ... because the official was proposed generics wildcards.

4.3. Unbounded wildcards

Unbounded wildcard is ?. You may ask to see it, it's not like T do? Why did they have put forward ?. Their main difference is that, T is mainly used to declare a generic class or method? Mainly for use generic classes and generic methods. The following give a simple example.

// 定义打印任何类型列表的函数
public static void printList(List<?> list) {
    for (Object elem: list) {
        System.out.print(elem + " ");
    }
}

// 调用上述函数
List<Integer> intList = Arrays.asList(1, 2, 3);
List<String> stringList = Arrays.asList("one", "two", "three");
printList(li);// 1 2 3 
printList(ls);// one two three
复制代码

Above object function it is to print any type of list. You can see inside the function, did not care about the List generic type of what is in the end, you can <?> Understanding provides a read-only function only, which removes the ability to add specific elements, leaving only the independent of the specific type of functionality. As can be seen from the above example, the number of elements and their only concern is empty, except do not care about anything.

Then the other hand a T, we also lists how to define a generic method and a generic method is called. Internal generic method is going to care about the specific type, not just the number of empty and not so simple.

4.4. The upper bound wildcard <? Extends T>

Since it ?can represent any type, then extends and is doing it?

Assuming that there is such a demand, we only allow a certain type can call our function (for example, all the Animal class and its derived classes), but now the use of ?all types can call the function, can not meet our needs.

private int countLength(List< ? extends Animal> list) {...}
复制代码

After using the upper bound wildcard to complete the public function, you can call it using the following method.

List<Pig> pigs = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();
List<Cat> cats = new ArrayList<>();

// 假装写入了数据
int sum = 0;
sum += countLength(pigs);
sum += countLength(dogs);
sum += countLength(cats);
复制代码

After reading an example, we can draw a simple conclusion. It is a wildcard upper bound to any specific type and can handle the particular type of wildcard derived class.

Some may look a bit ignorant force, I combined the above example, then a simple human words to explain: the upper bound of a wild card is what the animal can put a box.

4.5. The lower bound wildcard <? Super Animal>

We chatted above the upper bound wildcard, it's unknown type restrictions (a subclass of all animals, and animals that is discussed above) is a specific type or subtype of that particular type. And the lower bound wildcard will limited to a particular type of an unknown type or the particular type supertype, i.e. the base class or superclass.

In the upper bound wildcard, we gave an example. Write a function that can handle any kind of animal, and the animal is a derived class of the class. And now we want to write a function to handle any function of the superclass is Integer Integer and is the.

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}
复制代码

The type erasure

After a brief understanding of generics several simple to use, we return to the subject of this blog is up - type erasure. While there are some generic benefits listed above, but the generic life cycle is limited to compilation phase.

Sample the beginning of this article is to give a typical example. We will take measures to generified After compilation, compiled during the erase operation after detection of the generic results will be generic information. Like most examples of the article mentioned at the beginning, we use the above defined Generic generic class to give a simple example.

Generic<String> generic = new Generic<>("Hello");
Field[] fs = generic.getClass().getDeclaredFields();
for (Field f : fs) {
    System.out.println("type: " + f.getType().getName()); // type: java.lang.Object
}
复制代码

getDeclaredFieldsReflection method can obtain the various fields of the current class has been declared, including public, protected, and private.

We can see the incoming String generics have been erased and replaced by Object. Where generic information before that String and Integer go of it? Maybe this time you will flash, that's not all will become generic Object is erased after it? Do not worry, read on.

When we use the generic top upper bound wildcard in the future, what will happen? We Generic class into the following form.

public class Generic<T extends String> {
    T data;

    public Generic(T data) {
        setData(data);
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
复制代码

Then use the reflection to see again after erasing the generic type. The console output type: java.lang.String. You can see, it will be replaced after the upper limit of the type if we set an upper limit to the generic class, generic erased. If not specified, it will be replaced by a unified Object. Accordingly, a method of the generic type defined in the class as well.

6. Written in the last

If you find that the article in question, welcome to the wing, I will promptly correct.

reference:

  1. Java language type erasure
  2. Lower bound through Hythe
  3. The difference between List <?> And List of

Guess you like

Origin juejin.im/post/5ceba1a2f265da1b95703558