The source of the original text is : absfree

1. Why —— The reason for introducing generic mechanism

If we want to achieve a String Array , And it needs to be able to change the size dynamically , At this time, we all think of using ArrayList To aggregate String object . However , After a while , We want to achieve a size that can be changed Date An array of objects , At this time, of course, we hope to be able to reuse the previously written one for String Object's ArrayList Realization .

stay Java 5 Before ,ArrayList The implementation of this method is as follows :

1
2
3
4
5
6
public class ArrayList {
     public Object get( int i) { ... }
     public void add(Object o) { ... }
     ...
     private Object[] elementData;
}

From the above code, we can see that , Used to direct to ArrayList The add Function receives a Object The parameters of type , from ArrayList Gets the... Of the specified element get Method also returns a Object Object of type ,Object An array of objects elementData Store this ArrayList Objects in the , in other words , No matter what you say to ArrayList What type of type to put in , Inside it , It's all one Object object .

Inheritance based generic implementations pose two problems : The first question is about get Methodical , Every time we call get Method will return a Object object , Force the type conversion to the type we need every time , It's going to be cumbersome ; The second question is about add Methodical , If we get together String Object's ArrayList Add a File object , The compiler does not generate any error prompts , And this is not what we want .

therefore , from Java 5 Start ,ArrayList You can add a Type parameter (type parameter), This type parameter is used to indicate ArrayList Element types in . The introduction of type parameters solves the two problems mentioned above , As shown in the following code :

1
2
3
4
5
ArrayList<String> s = new ArrayList<String>();
s.add( "abc" );
String s = s.get( 0 ); // No cast required
s.add( 123 );  // Compile error , You can only add String object
...

In the above code , compiler “ Informed ”ArrayList Type parameter of String after , It will do the work of type casting and type checking for us .

2. Generic classes

     Generic classes (generic class) A class with one or more type parameters . for example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Pair<T, U> {
     private T first;
     private U second;
 
     public Pair(T first, U second) {
         this .first = first;
         this .second = second;
     }
 
     public T getFirst() {
         return first;
     }
 
     public U getSecond() {
         return second;
     }
 
     public void setFirst(T newValue) {
         first = newValue;
     }
 
     public void setSecond(U newValue) {
         second = newValue;
     }
}

We can see in the code above , Generic classes Pair The type parameter of is T、U, In angle brackets after the class name . there T namely Type The first letter of , It means type , There are also E(element)、K(key)、V(value) etc. . Of course, it's OK not to use these letters to refer to type parameters .

When instantiating generic classes , We just need to change the type parameter to a specific type , For example, instantiate a Pair<T, U> Class we can do this :

1
Pair<String, Integer> pair = new Pair<String, Integer>();

3. Generic methods

So called generic methods , Methods with type parameters , It can be defined in a generic class , It can also be defined in ordinary classes . for example :

1
2
3
4
5
public class ArrayAlg {
     public static <T> T getMiddle(T[] a) {
         return a[a.length / 2 ];
     }
}

In the above code getMiddle Method is a generic method , The format of the definition is that the type variable is placed after the modifier 、 Returns the front of the type . We can see , The above generic methods can be called for various types of arrays , When the types of these arrays are known and bounded , Although it can also be implemented with overload , But coding is much less efficient . The example code for calling the above generic method is as follows :

1
2
String[] strings = { "aa" , "bb" , "cc" };
String middle = ArrayAlg.getMiddle(names);

4. Limitation of type variables

In some cases , Generic classes or methods want to further restrict their own type parameters . such as , We want to limit type parameters to subclasses of a class or to classes that implement an interface . The related syntax is as follows :

<T extends BoundingType>(BoundingType It's a class or interface ). Among them BoundingType It can be more than 1 individual , use “&” Connect to .

5. Understand the implementation of generics in depth

actually , From a virtual machine point of view , non-existent “ Generic ” Concept . For example, the generic class we defined above Pair, In the eyes of virtual machines ( That is, after compiling into bytecode ), It looks like this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Pair {
     private Object first;
     private Object second;
 
     public Pair(Object first, Object second) {
         this .first = first;
         this .second = second;
     }
 
     public Object getFirst() {
         return first;
     }
 
     public Object getSecond() {
         return second;
     }
 
     public void setFirst(Object newValue) {
         first = newValue;
     }
 
     public void setSecond(Object newValue) {
         second = newValue;
     }
}

The above class is through Type Erasure Got , yes Pair Generic classes correspond to The original type (raw type). Type erasure is to replace all type parameters with BoundingType( If not limited, replace with Object).

We can simply verify , compile Pair.java after , type “javap -c -s Pair” available :

The picture above shows “descriptor” Is the signature of the corresponding method , For example, we can see from the fourth line that Pair After type erasure, the two formal parameters of the construction method have become Object.

Because in virtual machines, generic classes Pair Become its raw type, thus getFirst Method returns a Object object , And from the compiler's point of view , This method returns the object of the type parameter specified when we instantiate the class . actually , It's the compiler that helps us with the casts . That is to say, the compiler will put Pair In a generic class getFirst Method into two virtual machine instructions :

The first is right raw type Method getFirst Call to , This method returns a Object object ; The second command returns Object Object casts the type to the type parameter type we specified at the beginning .

Let's intuitively feel it through the following code :

1
2
3
4
5
6
7
8
9
10
public class Pair<T, U> {
     // See the code posted above
 
     public static void main(String[] args) {
         String first = "first" , second = "second" ;
         Pair<String, String> p = new Pair<String, String>(first, second);
         String result = p.getFirst();
     }
 
}

After compiling, we pass javap Look at the generated bytecode :

Let's focus on the next one, which is marked with ”17:” Of course , According to the following notes , We know it's right getFirst Method call , You can see that his return type is really Object.

Let's see the subscript again “20:” Of course , It's a checkcast Instructions , Literally, we can see that the meaning of this instruction is to check whether the type conversion is successful , Look at the notes later , We do have one here to String Cast of .

Type erasure also occurs in generic methods , Such as the following generic methods :

1
public static <T extends Comparable> T min(T[] a)

After compilation, after type erasure, it will be like this :

1
public static Comparable min(Comparable[] a)

There are some problems with type erasure of methods , Consider the following code :

1
2
3
4
5
6
7
8
9
10
11
12
public class DateInterval extends Pair<Date, Date> {
     public DateInterval(Date first, Date second) {
         super (first, second);
     }
 
     public void setSecond(Date second) {
         if (second.compareTo(getFirst()) >= 0 ) {
             super .setSecond(second);
         }
     }
 
}

After type erasure of the above code , Turn into :

1
2
3
4
5
6
7
8
9
10
public class DateInterval extends Pair {
 
     ...
     public void setSecond(Date second) {
         if (second.compareTo(getFirst()) >= 0 ) {
             super .setSecond(second);
         }
     }
 
}

And in the DateInterval There is also a class from Pair Class setSecond Methods ( After type erasure ) as follows :

1
public void setSecond(Object second)

Now we can see , This method is associated with DateInterval Rewrite the setSecond Methods have different method signatures ( The shape parameters are different ), So there are two different approaches , But these two methods used to be override The relationship between . Consider the following code :

1
2
3
4
DateInterval interval = new DateInterval(...);
Pair<Date, Date> pair = interval;
Date aDate = new Date(...);
pair.setSecond(aDate);

From the above code we can see ,pair The actual quotation is DateInterval object , So you should call DateInterval Of setSecond Method , The problem here is Type erasure conflicts with polymorphism .

Let's sort out why this problem happened :pair Previously declared as a type Pair<Date, Date>, There is only one class in the view of virtual machine “setSecond(Object)” Method . So at run time , Virtual machine discovery pair The actual quotation is DateInterval After the object , Going to call DateInterval Of “setSecond(Object)”, However DateInterval In class, only ”setSecond(Date)” Method .

The way to solve this problem is by the compiler in DateInterval Generate a Bridge method

1
2
3
public void setSecond(Object second) {
     setSecond((Date) second);
}

Let's go through javap Come and feel it :

We can see , stay DateInterval There are two setSecond Method , first setSecond Method ( That's what we define setSecond Method ) The formal parameter of is Date, the second setSecond The parameter of the method is Object, The second method is the bridge method that the compiler generates for us . We can see in the second method that Date Cast of , And called the first setSecond Method .

Above all , We know that the implementation of generic mechanism is actually the compiler's share of some troublesome work . On the one hand, by using type parameters , You can tell the compiler to do type checking at compile time ; On the other hand , The compiler also does the work of casts that we need to do .

6. matters needing attention

(1) Type parameter cannot be instantiated with base type

in other words , The following statement is illegal :

1
Pair< int , int > pair = new Pair< int , int >();

But we can use the corresponding packing type instead of .

(2) You can't throw or catch generic class instances

Generic class extensions Throwable It's illegal , Therefore, generic class instances cannot be thrown or caught . But it's legal to use type parameters in exception declarations :

1
2
3
4
5
6
7
8
public static <T extends Throwable> void doWork(T t) throws T {
     try {
         ...
     } catch (Throwable realCause) {
         t.initCause(realCause);
         throw t;
     }
}

(3) Illegal array of parameterized type

stay Java in ,Object[] An array can be the parent of any array ( Because any array can be transformed upward into an array of the parent class of the element type it specifies when defining ). Consider the following code :

1
2
3
String[] strs = new String[ 10 ];
Object[] objs = strs;
obj[ 0 ] = new Date(...);

In the above code , We assign array elements to satisfy the parent class (Object) type , But different from the original type (Pair) The object of , At compile time, you can pass , And at run time it throws ArrayStoreException abnormal .

For the above reasons , hypothesis Java Allows us to declare and initialize a generic array by :

1
Pair<String, String>[] pairs = new Pair<String, String>[ 10 ];

After type erasure of virtual machine , actually pairs Become Pair[] Array , We can turn it up into Object[] Array . Now if we add Pair<Date, Date> object , Can pass compile time checks and run time checks , And our intention is just to let this array store Pair<String, String> object , This can lead to inaccessible errors . therefore ,Java We are not allowed to declare and initialize a generic array in the form of the above statement .

You can declare and initialize a generic array with the following statement :

1
Pair<String, String>[] pairs = (Pair<String, String>[]) new Pair[ 10 ];

(4) Type variables cannot be instantiated

You can't do it in terms of “new T(…)”, “new T[...]“, “T.class” Use type variables in the form of .Java The reason why we are forbidden to do so is simple , Because there is type erasure , So it's like ”new T(…)” Such a statement would become ”new Object(…)”, And that's usually not what we mean . We can substitute the following sentence for “new T[...]“ Call to :

1
arrays = (T[]) new Object[N];

(5) Generic classes Type variables cannot be used in the static context of

Be careful , Here we emphasize generic classes . Because static generic methods can be defined in ordinary classes , As we mentioned above ArrayAlg Class getMiddle Method . About why there is such a rule , Consider the following code :

1
2
3
4
5
6
public class People<T> {
     public static T name;
     public static T getName() {
         ...
     }
}

We know , At the same time , There may be more than one... In memory People<T> Class instance . Let's say there's a... In memory right now People<String> Objects and People<Integer> object , The static variables and methods of a class are shared by all class instances . So here comes the question ,name Is it String Type or Integer Type? ? For this reason ,Java Type variables are not allowed in the static context of generic classes in .

7. Type wildcard

Before introducing type wildcards , Let's start with two points :

(1) hypothesis Student yes People Subclasses of ,Pair<Student, Student> But not Pair<People, People> Subclasses of , There's no one between them ”is-a” Relationship .

(2)Pair<T, T> With its original type Pair between ”is-a” Relationship ,Pair<T, T> In any case, it can be converted to Pair type .

Now consider such an approach :

1
2
3
4
public static void printName(Pair<People, People> p) {
     People p1 = p.getFirst();
     System.out.println(p1.getName()); // hypothesis People Class definition getName Example method
}

In the above method , We want to be able to pass in at the same time Pair<Student, Student> and Pair<People, People> Parameters of type , However, there is no relationship between the two ”is-a” Relationship . under these circumstances ,Java Provide us with such a solution : Use Pair<? extends People> As a type of formal parameter . in other words ,Pair<Student, Student> and Pair<People, People> Can be seen as Pair<? extends People> Subclasses of .

Form like ”<? extends BoundingType>” The code is called Subtype qualification of wildcards . There is also Super type restriction of wildcard , This is the format :<? super BoundingType>.

Now let's consider the following code :

1
2
3
Pair<Student> students = new Pair<Student>(student1, student2);
Pair<? extends People> wildchards = students;
wildchards.setFirst(people1);

The third line of the above code will report an error , because wildchards It's a Pair<? extends People> object , its setFirst Methods and getFirst Here's how it works :

1
2
void setFirst(? extends People)
? extends People getFirst()

about setFirst methods , It makes the compiler not know what type the formal parameter is ( I just know it's People Subclasses of ), And we're trying to pass in a People object , The compiler cannot determine People And whether the parameter type is ”is-a” The relationship between , So call setFirst The method will report an error . And call wildchards Of getFirst The method is legal , Because we know it will return a People Subclasses of , and People Subclasses of “always is a People”.( You can always convert a child object to a parent object )

In the case of super type restriction of wildcards , call getter The method is illegal , And call setter The method is legal .

Except for subtype qualification and supertype qualification , There is also a wild card called Indefinite wildcards , It looks like this :<?>. When will we use this ? Consider this scenario , We call one and return one getPairs Method , This method returns a set of Pair<T, T> object . There is Pair<Student, Student>,   also Pair<Teacher, Teacher> object .(Student Classes and Teacher Class has no inheritance relationship ) obviously , In this case , Both subtype qualification and supertype qualification cannot be used . At this point, we can do it with such a statement :

1
Pair<?>[] pairs = getPairs(...);

For indefinite wildcards , call getter Methods and setter The methods are illegal .

In depth understanding of Java More articles on generics of

  1. How do you understand java Generic of ?

    answer : stay Java SE 1.5 Before , Without generics , By type Object To implement the parameters “ Arbitrariness ”,“ Arbitrariness ” The disadvantage is to do explicit cast , This kind of conversion requires developers to know the actual parameter types ...

  2. In depth understanding of the long essay java The set in - attach PDF download

    Catalog 1. Preface 2. List 2.1 fail-safe fail-fast Know how much 2.1.1 Fail-fast Iterator 2.1.2 Fail-fast Principle 2.1.3 Fail- ...

  3. turn : understand Java Generic

    JDK 5.0 Generic types added in , yes Java An important improvement of type safety in languages . however , For first-time users of generic types , Some aspects of generics may not seem easy to understand , Even very strange . In this month's “Java Theory and practice ” in ...

  4. Tamp Java Foundation Series 13: In depth understanding of Java The generics in

    Catalog Generic overview A chestnut characteristic How to use generics Generic classes Generic interface Generic wildcard Generic methods Basic usage of generic methods Generic methods in classes Generic methods and variable parameters Static methods and generics Generic method summary The upper and lower bounds of generics Generic common interview ...

  5. Java Deep understanding of dry goods Java Generic

    General classes and methods , Only specific types can be used , Or the basic type , Either a custom class . If you want to write code that can apply multiple types , This kind of rigid restriction will greatly restrict the code . ---<Thinking in Java> ...

  6. How to understand Java Generic

    One . The role and definition of generics 1.1 The role of generics Using generics can write more flexible and general code. The design of generics mainly refers to C++ The template of , It's designed to make writing more general , More flexible code . Templates / Generic code , It's like a template for sculpture , With templates , need ...

  7. 《 In depth understanding of Java virtual machine 》 Class file structure

    Review of the last section In the last section , It mainly introduces some of its own tuning or troubleshooting experience in its own working environment . The so-called variety is inseparable from its origin , This case is our way to solve the problem . This section focuses on In the previous chapters , We have a macro view of virtual machines ...

  8. In depth understanding of Java 8 Lambda( Language ——lambda, Method reference , Target types and default methods )

    author :Lucida Microblogging :@peng_gong douban :@figure9 Link to the original text :http://zh.lucida.me/blog/java-8-lambdas-insideout-language- ...

  9. How to understand Java Medium &lt;T extends Comparable&lt;? super T&gt;&gt;

    Java It's similar to <T extends Comparable<? super T>> Such type parameters (Type Parameter) stay JDK You can often see it in tools and methods . ...

Random recommendation

  1. vim Use notes

    vim Command notes a Insert insert Insert :%!xxd With 16 Edit in decimal mode :%!xxd -r from 16 Binary restore

  2. Your pain

    Your pain is the breaking of the shell that encloses your understanding. Your pain is the rupture of your shell of knowledge .

  3. vim Future generations , Copy all , Delete all

    Future generations ( Highlight ): Press esc after , then ggvG perhaps ggVG Copy all : Press esc after , then ggyG Delete all : Press esc after , then dG analysis : gg: Is to move the cursor to the first line , stay vim It works ,vi Invalid in v : Is to enter V ...

  4. Oracle 11gR2 Database and Active Data Guard Migration cases

    The customer's core system consists of a Oracle Database 11.2.0.3.4 Single machine and one Active Data Guard form , It's running on two different machines PC Server ,Oracle Linux 5.8 x86_64b ...

  5. modify phpmyadmin Upload file size limit

    When you want to SQL sentence , Import phpmyadmin when , self-discovering sql Statement text size Greater than phpmyadmin The size of the text uploaded by the class . Default phpmyadmin The size of the uploaded file is 2M, If you want to phpmyadmin ...

  6. Python Yanghui triangle

    RT Show me the Code def triangles(): b = [1] while(True): yield b b = [1] + [b[i] + b[i+1] for i in ...

  7. System V IPC Shared memory

    IPC Is interprocess communication (Interprocess Communication) Abbreviation , It usually refers to a set of mechanisms that allow a user mode process to perform a series of operations : Synchronize with other processes through semaphores Send messages to or receive messages from other processes ...

  8. pyqt5-----postgresql Database usage

    The previous chapter solved the problem of not being able to load postgresql Database problem 1. Open the data from PyQt5 import QtWidgets,QtSql,QtCoreimport sys app =QtCore.QCor ...

  9. Ubuntu16.04 System installation Sogou input method detailed tutorial ( Reprint )

    1. Download the installation package of Sogou input method Download at :http://pinyin.sogou.com/linux/ , Here's the picture , To select an installation package that matches the number of digits in your system , My system is 64 position , So I download 64 Bit installation package 2. Key C ...

  10. webGL And three.js introduction 1

    Opening remarks Recently began to learn front end , I watched the front end teaching video of geek College , In fact, there are C++ perhaps java Basic people are still very fast in preschool . however html The label and CSS There are still more styles code To be proficient in , Practice makes perfect , Put this to use . Still watching js, Because there is ...