Home  >  Article  >  Java  >  Implementation principles of Java generics

Implementation principles of Java generics

高洛峰
高洛峰Original
2016-12-19 15:47:181414browse

1. Introduction to Java Generics

Generics are a new feature of Java 1.5. The essence of generics is a parameterized type, which means that the data type being operated is specified as a parameter. This parameter type can be used in the creation of classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods respectively.

The advantage of Java generics being introduced is safety and simplicity.

Before Java SE 1.5, in the absence of generics, the "arbitrary" parameter was realized by referencing the type Object. The disadvantage of "arbitrary" was that explicit forced type conversion was required, and This conversion requires developers to know the actual parameter types beforehand. For forced type conversion errors, the compiler may not prompt an error, and an exception will occur during runtime. This is a security risk.

The advantage of generics is that type safety is checked during compilation, and all casts are automatic and implicit, improving code reuse.

There are some rules and restrictions in the use of generics:

1. The type parameters of generics can only be class types (including custom classes), not simple types.

2. The same generic type can correspond to multiple versions (because the parameter type is uncertain), and different versions of generic class instances are incompatible.

3. Generics can have multiple type parameters.

4. Generic parameter types can use the extends statement, for example. Customarily become "bounded types".

5. Generic parameter types can also be wildcard types.

Class<?> classType = Class.forName(java.lang.String);

Generics also include interfaces, methods, etc. There is a lot of content, and it takes a lot of effort to understand and apply it skillfully.

2. Java generics implementation principle: type erasure

Java’s generics are pseudo-generics. During compilation, all generic information is erased. The first prerequisite for correctly understanding the concept of generics is to understand type erasure.

Generics in Java are basically implemented at the compiler level. The type information in generics is not included in the generated Java bytecode. Type parameters added when using generics will be removed by the compiler during compilation. This process is called type erasure.

Types such as List273238ce9338fbb04bee6997e5552b95 and Listf7e83be87db5cd2d9a8a0b8117b38cd4 defined in the code will be programmed into List after compilation. All the JVM sees is the List, and the type information attached by generics is invisible to the JVM. The Java compiler will try its best to find possible errors at compile time, but it still cannot avoid type conversion exceptions at runtime. Type erasure is also an important difference between Java's generic implementation method and C++ template mechanism implementation method (described later).

3. The original type retained after type erasure

The original type (raw type) is the real type of the type variable in the bytecode after the generic information has been erased. Whenever a generic type is defined, the corresponding primitive type is automatically provided. Type variables are erased (crased) and replaced with their qualified type (unqualified variables are Object).

class Pair<T> {    
  private T value;    
  public T getValue() {    
    return value;    
  }    
  public void setValue(T  value) {    
    this.value = value;    
  }    
}

The original type of Pair8742468051c85b06f0a0af9e3e506b5c is:

class Pair {    
  private Object value;    
  public Object getValue() {    
    return value;    
  }    
  public void setValue(Object  value) {    
    this.value = value;    
  }    
}

Because in Pair8742468051c85b06f0a0af9e3e506b5c, T is an undefined type variable, so it is replaced with Object. The result is a normal class, just as generics were implemented before Java was added to the language. The program can contain different types of Pair, such as Pairf7e83be87db5cd2d9a8a0b8117b38cd4 or Pairc0f559cc8d56b43654fcbe4aa9df7b4a. However, after erasing the type, they become the original Pair type, and the original types are all Object.

If the type variable is bounded, then the original type is replaced by the first bounding type variable.

For example, if Pair declares like this:

public class Pair<T extends Comparable& Serializable> {

Then the original type is Comparable

Note:

If Pair declares public class Pair072f492c1c614d437f856ffc9d1253f7 like this, then the original type will be replaced by Serializable, and the compiler will replace it when necessary When inserting a cast into Comparable. For efficiency, tagged interfaces (i.e. interfaces without methods) should be placed at the end of the bounds-qualified list.

To distinguish between primitive types and generic variable types

When calling a generic method, you can specify the generic type or not.

Without specifying a generic, the type of the generic variable is the lowest level of the same parent class of several types in the method, until Object.

When specifying a generic, several types in the method must be the generic instance type or its subclass.

public class Test{    
  public static void main(String[] args) {    
    /**不指定泛型的时候*/    
    int i=Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型    
    Number f=Test.add(1, 1.2);//这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Number    
    Object o=Test.add(1, "asd");//这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Object    
    
    /**指定泛型的时候*/    
    int a=Test.<Integer>add(1, 2);//指定了Integer,所以只能为Integer类型或者其子类    
    int b=Test.<Integer>add(1, 2.2);//编译错误,指定了Integer,不能为Float    
    Number c=Test.<Number>add(1, 2.2); //指定为Number,所以可以为Integer和Float    
  }    
  
  //这是一个简单的泛型方法    
  public static <T> T add(T x,T y){    
    return y;    
  }    
}

In fact, in a generic class, when generics are not specified, it is almost the same, except that the generic type at this time is Object, just like in ArrayList, if generics are not specified, then any type can be placed in this ArrayList Object.

4. C++ template implementation

Although I don’t understand C++, I also looked for the implementation of C++ on the Internet.

The phenomenon of generating different types for each template instantiation in C++ is called "template code bloat".

For example, vectorbd43222e33876353aff11e13a7dc75f6, vector424b5ca5994d08464738b3617afd1719, vector229a20c20174f89abe8fab2ad31639d8, a total of 3 different vector codes will be generated here.



For more articles related to the implementation principles of Java generics, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn