Java generics detailed _java

Source: Internet
Author: User
Tags comparable instance method object object throwable

1. Reasons for introducing generic mechanism in why--

If we want to implement a string array and ask it to change size dynamically, then we all think of using ArrayList to aggregate string objects. However, after a while, we want to implement an array of date objects that can vary in size, and then of course we want to be able to reuse the ArrayList implementation of the string object that was previously written.

Before Java 5, the implementation of ArrayList was roughly as follows:

public class ArrayList {public
  Object get (int i) {...}
  public void Add (Object o) {...}
  ...
  Private object[] Elementdata
}

As we can see from the code above, the Add function used to add an element to the ArrayList receives an object-type argument, and the Get method that gets the specified element from ArrayList also returns an objects of the object. An Object object array elementdata the objects in this ArrayList, that is, no matter what type of type you put into the ArrayList, the inside of it is an object.

A generic implementation based on inheritance can create two problems: The first question is about get methods, and every time we call the Get method, we return an object, forcing the type to be converted to the type we need, which is cumbersome; the second question is about the Add method, If we add a file object to the ArrayList that aggregates a string object, the compiler does not produce any error prompts, and this is not what we want.

So, starting with Java 5, ArrayList can be used with a type parameter (type parameter), which is used to indicate the element type in the ArrayList. The introduction of the type parameter solves the two problems mentioned above, as shown in the following code:

arraylist<string> s = new arraylist<string> ();
S.add ("abc");
String s = s.get (0); No cast
S.add (123);//Compile error, only String object can be added to ...

In the above code, the compiler "learns" the type parameter string of ArrayList, and then completes the coercion type conversion and type checking for us.

2. Generic type

The so-called generic class (generic Class) is a class that has one or more type parameters. For example:

public class Pair<t, u> {
  private T-i;
  Private U second;

  Public Pair (T-A, U second) {
    this.first = A;
    This.second = second;
  }

  Public T GetFirst () {return a
    .
  }

  Public U Getsecond () {return
    second;
  }

  public void Setfirst (T newvalue) {i
    = newvalue;
  }

  public void Setsecond (U newvalue) {
    second = newvalue;
  }
}

As we can see in the above code, the type parameter of the generic class pair is T, U, placed in the angle bracket after the class name. Here the T is the first letter of type, which means the meaning of types, and E (Element), K (key), V (value) are commonly used. Of course, it is perfectly OK to use these letters to refer to the type parameters.

When instantiating a generic class, we simply replace the type argument with a specific type, such as instantiating a pair<t, u> class We can do this:

pair<string, integer> Pair = new pair<string, integer> ();

3. Generic method

A generic method is a method with a type parameter that can be defined either in a generic class or in a normal class. For example:

public class Arrayalg {public
  static <T> T getmiddle (t[] a) {return
    A[A.LENGTH/2];
  }

The Getmiddle method in the preceding code is a generic method that is defined in a format where the type variable is placed behind the modifier and before the return type. As we can see, the above generic methods can be invoked for various types of arrays, which, while the types of these arrays are known to be tangent-constrained, can be implemented with overload, although coding is much less efficient. The sample code that invokes the above generic method is as follows:

String[] strings = {"AA", "BB", "CC"};
String middle = arrayalg.getmiddle (names);

4. Qualification of type variables

In some cases, a generic class or generic method would like to impose further restrictions on its own type parameters. For example, we want to qualify that a type parameter can only be a subclass of a class or a class that implements only one interface. The relevant syntax is as follows:

<t extends Boundingtype> (Boundingtype is a class or interface). The boundingtype can be more than 1, with the "&" connection can be.

5. Deep understanding of the implementation of generics

In fact, from the point of view of the virtual machine, there is no "generics" concept. For example, the generic class pair we defined above, in the view of the virtual machine (that is, after being compiled into bytecode), is the length of this:

public class Pair {
  private Object A;
  Private Object second;

  Public Pair (Object A, object second) {
    this.first = i;
    This.second = second;
  }

  Public Object GetFirst () {

  return a Public Object Getsecond () {return
    second;
  }

  public void Setfirst (Object newvalue) {i
    = newvalue;
  }

  public void Setsecond (Object newvalue) {
    second = newvalue;
  }
}

The above class is obtained by type Erasure and is the original type (raw type) corresponding to the pair generic class. Type erasure is the substitution of all type parameters with Boundingtype (replaced with object if not qualified).

We can simply verify that, after compiling Pair.java, type "javap-c-S Pair" to get:

The line with "descriptor" in the figure above is the signature of the corresponding method, for example, from line fourth we can see that the two parameters of the pair constructor have become object after the type erasure.

Because the generic class pair becomes its raw type in the virtual machine, the GetFirst method returns an Object object, and from the compiler's point of view, this method returns the objects of the type parameters that we specified when instantiating the class. In fact, the compiler helped us with the task of enforcing type conversions. That is, the compiler converts the call to the GetFirst method in the pair generic class to two virtual machine directives:

The first is a call to the raw type method GetFirst, which returns an Object object, and the second instruction converts the returned object coercion type to the type parameter type we specified.

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

public static <t extends comparable> T min (t[] a)
after compiling the type erase, it becomes the following:

public static comparable min (comparable[] a)
the type erasure of a method can cause problems, considering the following code:

Class DateInterval extends Pair<date, date> {public
  void Setsecond (Date second) {
    if Second.compareto ( GetFirst ()) >= 0) {
      super.setsecond (second);
    }
  }
  ...
}

After the type erase, the above code becomes:

Class DateInterval extends Pair {public
  void Setsecond (Date second) {...}
  ...
}

The DateInterval class also has a Setsecond method that inherits from the pair class (after type Erasure) as follows:

public void Setsecond (Object second)
Now we can see that this method has different method signatures (different parameters) than the DateInterval rewrite Setsecond method, so there are two different methods, however, the two methods should not be different methods (because they are override). Consider the following code:

DateInterval interval = new DateInterval (...);
Pair<date, date> Pair = interval;
Date adate = new Date (...);
Pair.setsecond (adate);

The above code shows that pair actually refers to the DateInterval object, so you should call the DateInterval Setsecond method, where the problem is that type erasure conflicts with polymorphism.

Let's comb the question of why this occurs: pair was previously declared as type Pair<date, Date>, and the class has only one "Setsecond" method in the virtual machine. Therefore, at runtime, the virtual machine discovers that pair is actually referencing the DateInterval object, and then invokes the DateInterval "Setsecond", whereas the DateInterval class has only "Setsecond" (Date) Method

The solution to this problem is for the compiler to generate a bridge method in DateInterval:

public void Setsecond (Object second) {
  Setsecond ((Date) second);


6. Matters needing attention

(1) cannot instantiate type parameter with base type

In other words, the following statement is illegal:

Pair<int, int> Pair = new Pair<int, int> ();
But we can use the corresponding packing type to replace.

(2) cannot throw or capture generic class instances

Generic class extension Throwable is illegal, so it is not possible to throw or capture generic class instances. However, it is legal to use type parameters in an exception declaration:

public static <t extends throwable> void doWork (T t) throws T {
  try {
    ...
  } catch (Throwable realcause) {
    t.initcause (realcause);
    throw t;
  }
}

(3) An array of parameterized types is not valid

In Java, a object[] array can be the parent of any array (because any array can be transformed upwards to an array of the parent classes that it specifies for the element type at the time of definition). Consider the following code:

string[] STRs = new STRING[10];
object[] Objs = STRs;
Obj[0] = new Date (...);

In the code above, we assign an array element to an object that satisfies the parent class (object) type, but differs from the original type (Pair), at compile time, and throws a Arraystoreexception exception at run time.

For the above reasons, suppose Java allows us to declare and initialize a generic array with the following statement:

Pair<string, string>[] pairs = new pair<string, string>[10];
So after the type erasure of the virtual machine, actually pairs became the pair[] array, and we can transition it up to the object[] array. When we add pair<date to it, date> objects, we can check at compile-time and run-time, and our intention is to just let this array store pair<string, string> objects, which can make it difficult to locate errors. Therefore, Java does not allow us to declare and initialize a generic array through the above statement form.

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

Pair<string, string>[] pairs = (pair<string, string>[]) new PAIR[10];

(4) Cannot instantiate type variable

You cannot use type arguments in the form of "new T (...)", "New t[...", "T.class". The reason that Java forbids us to do this is simple because there is type erasure, so it's similar to "New T (...)" Such statements become "New Object (...)", which is usually not our intention. We can use the following statement instead of "new t[...]" The call:

Arrays = (t[]) new Object[n];

(5) A type variable cannot be used in a static context of a generic class

Note that here we emphasize the generic class. Because a static generic method can be defined in a generic class, as the Getmiddle method in the Arrayalg class we mentioned above. Consider the following code regarding why this is the rule:

public class People<t> {public
  static T name;
  public static T GetName () {
    ...}}
}

We know that at the same time, there may be more than one People<t> class instance in memory. Suppose there is now a People<string> object and a People<integer> object in memory, and the static variable of the class is shared with the static method by all instances of the class. So the question is, is name the string or the integer type? For this reason, type variables are not allowed in Java in the static context of a generic class.

7. Type wildcard characters

Before introducing the type wildcard, first introduce two points:

(1) Assuming that Student is a subclass of people, Pair<student, student> is not pair<people, people> subclass, there is no "is-a" relationship between them.

(2) Pair<t, T> has a "is-a" relationship with its original type Pair, Pair<t, t> can be converted to the Pair type in any case.

Now consider such a method:

public static void Printname (Pair<people, people> p) {
  people p1 = P.getfirst ();
  System.out.println (P1.getname ()); Suppose the People class defines the GetName instance method
}

In the above approach, we want to be able to pass in Pair<student, student> and Pair<people, people> type parameters, but there is no "is-a" relationship between the two. In this case, Java provides us with such a solution: using Pair<? Extends people> as the type of the formal parameter. That is to say, Pair<student, student> and Pair<people, people> can be regarded as pair<. A subclass of the extends people>.

form as " Extends boundingtype> code is called a subtype of the wildcard character. and the corresponding wildcard character of the super type limit, the format is this: Super boundingtype>.

Now let's consider the following code:

pair<student> students = new pair<student> (student1, student2);
pair<? Extends people> wildchards = students;
Wildchards.setfirst (PEOPLE1); 

The third line of the above code error, because Wildchards is a pair<? Extends People> object, its Setfirst method and GetFirst method are as follows:

void Setfirst (? Extends people)
? Extends people GetFirst ()

For the Setfirst method, the compiler does not know what the formal parameter is (only the subclass of the people), and we try to pass in a people object, and the compiler cannot determine whether the people and formal parameter types are "is-a" relationships. So invoking the Setfirst method can cause an error. The GetFirst method of invoking Wildchards is legal because we know it will return a subclass of people, and the people subclass "always is a people". (Can always cast objects to the parent class object)

It is illegal to invoke the Getter method for the superclass of the wildcard character, and invoking the setter method is legal.

In addition to subtype qualification and superclass qualification, there is also a wildcard character called an unqualified wildcard, which is:<?>. When are we going to use this thing? Considering this scenario, we call one that returns a Getpairs method that returns a set of Pair<t, t> objects. Among them are pair<student, Student>, and Pair<teacher, teacher> objects. (There is no inheritance relationship between the student class and the teacher Class) Obviously, in this case, the subtype qualification and the superclass qualification are not available. Then we can use such a statement to fix it:

pair<?>[] pairs = getpairs (...);

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.