Core Java notes (nine) - Generics

Generics

Generics in Java, is in the design class, interface or method, without particular type of the operation target determined in advance, but it is specified as a parameter, referred to as a type parameter (type parameters), until the use of these classes, interfaces, methods, or only when a specific type of delivery. The benefit of using generics is that:

  • Reusability: realization of template code

  • Readability: no mandatory conversion

  • Security: find errors at compile time

First, the definition of generic

Defined in the class

Having one or more types of variables belong to a generic class type (generic class), a simple Pair class as an example:

public class Pair<T> {
    private T first;
    private T second;
    public Pair() {
        first = null;
        second = null;
    }
    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }
    public T getFirst() {
        return first;
    }
    public T getSecond() {
        return second;
    }
    public void setFirst(T value) {
        first = value; 
    }
    public void setSecond(T value) {
        second = value;
    }
}

Type variable use in <>, placed after the class name. There can be multiple types of variables, for the different fields in different types, such as:

public class Pair<T, U> {
    private T first;
    private U second;
    // ...
}

When used, the type of the variable substitution into specific types can be:

Pair<Integer> pair = new Pair<>;

Starting Java SE 7, the constructor may be omitted generic type (also called "diamond Syntax").

In the method definition

The method is defined with a parameter of type:

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

The same types of variables used in <>, placed behind modifiers, return to the previous type. Called particular type is placed in front of the method name <>, although, in the condition of self-compiler includes inferred when specific types may be omitted:

String middle = ArrayAlg.<String>getMiddle("hello", "here", "hero");
// String middle = ArrayAlg.getMiddle("hello", "here", "hero");

Defined type variable

Sometimes, a class or method is not applicable to any type, such as a method of calculating the minimum (large) value, a necessary requirement to implement the type of incoming Comparable interface, so they should be constraints on the type of the variable.

class ArrayAlg {
    public static <T extends Comparable> T getMin(T[] a) {
        if (a == null || a.length == 0) return null;
        T min = a[0];
        for (int i = 1; i < a.length; i++) {
            min = min.compareTo(a[i]) > 0 ? a[i] : min;
        }
        return min;
    }
}

This notation:

<T extends BoundingType>

It represents T should be a subtype of the type defined, and T class type may be defined, or may be an interface. Further, there may be a plurality of types is defined, separated by &:

<T extends Comparable & Serializable>

And inheritance limit as defined in at most one category type, and the first list (if any) must be defined.

Second, the generic code and virtual machine

Look at a simple code:

Pair<String> stringPair = new Pair(str1, str2);
Pair<Person> personPair = new Pair(person1, person2);
System.out.println(stringPair.getClass == personPair.getClass); // always true

Why does this happen?

The compiler detects the use of generics is correct, however, it will be the type of generic code erased (erased) at compile time, and then casts where necessary, just like you would if you did not, like the introduction of generics. From this perspective, Java is actually a "pseudo-generics", the basic level is implemented in the compiler, the bytecode file no longer contains generic information about. In the virtual machine level, the generic type of object does not exist, all the objects belong to the general category. Because of this, understanding type erasure become the most important prerequisite to understand the mechanism of Java generics.

Type erasure

Any primitive type a generic type has a corresponding (raw type), deleting the original type of the generic type name is the name of the type of parameters, such as List / List <T> , Pair / Pair <T> ... after the type parameter is erased, if the upper limit is not specified, it will replace Object, if a specified limit (e.g., <T the extends the Comparable> ) will be replaced with a first defined type (Comparable).

Generic class Pair <T> where T is an indefinite variables are replaced with a Objec:

public class Pair {  // not Pair<T>
    private Object first;
    private Object second;
    
    public Pair(Object first, Object second) {...}
    public Object getFirst() {...}
    public Object getSecond() {...}
    public void setFirst(Object value) {...}
    public void setSecond(Object value) {...}
}
The difference between C ++ template

Each instance of the C ++ template will produce different types, resulting in code bloat, and Java generics mechanism does not have this problem.

For the generic method is generally considered to be a complete family of methods:

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

After erasing the type, it is only one option:

public static Comparable min(Comparable[] a)

Generic expression translated type erasure

get method Pair Returns generic type:

Pair<Employee> buddies = ...;
Employee buddy = buddies.getFirst();

GetFirst compiler type erasure method, the return type to the Object, automatically inserts Employee casts, that will translate into two virtual machine instructions:

  • A call to the original method of

  • Object of the return type or the type defined in the context of the type of cast to desired

Polymorphic type erasure and conflict

Here's a generic class inherits instance:

class DateInterval extends Pair<LocalDate> {
    public void setSecond(LocalDate second) {
        if (second.compareTo(getFirst()) >= 0)  // ensure second >= first
            super.setSecond(second);
    }
}

In Pair <the LocalDate> Parameter type is the LocalDate setSecond method, so the above method of rewriting getSecond should be no problem, however, noted that an erased type:

class DateInterval extends Pair {
    public void setSecond(LocalDate second) {
        ...
    }
}

There is another inherited from Pair over setSecond method at this time:

public void setSecond(Object second)

As a result, setSecond methods defined in DateInterval in or rewriting (override) do? No, because different parameter list, they became overloaded (overload), look at the following method call:

DateInterval interval = new DateInterval(...);
Pair<LocalDate> pair = interval;
pair.setSecond(date);

pair references subclass object interval, polymorphism makes interval.setSecond (Object) is called, rather than what we want setSecond (LocalDate), now type erasure clashed with polymorphism.

Bridge method

For the above problem, the compiler generates a method bridge (bridge method) in DateInterval the name suggests, is to function as a coupling:

public void setSecond(Object second) {
    setSecond((LocalDate) second);
}

This method inherited from setSecond Pair (type erased) were rewritten its internal implementation simply calls the overloaded setSecond (LocalDate), establish links, to solve the conflict.

For getSecond overridden method will be a little bit different. For example, like this:

class DateInterval extends Pair<LocalDate> {
    ...
    public LocalDate getSecond() {
        return (LocalDate) super.getSecond().clone();
    }
}

After synthesis method axle compiler, DateInterval getSecond there will be two methods:

LocalDate getSecond()
Object getSecond()
Why does the compiler can only produce different types of return method?

This is because in a virtual machine, through the parameter types and return types to determine a common approach.

Finally on the bridge method is that it is not designed to handle generic problems, it is also used to achieve said previous chapters have covariant return type (a sub-class can be specified when the override inherited methods more stringent return type).

Third, restrictions on generics

  • Examples of the basic types can not use the type of parameter

  • The type of query (instanceof / getClass) runtime applies only to the original type

  • You can not be instantiated (but can be declared) parameterized types of arrays, such as new new Pair <String> [10]

  • Type can not be instantiated variables, such as new T (...)

  • Type parameter can not be used for static fields and static methods

  • Examples can not throw and catch a generic class

Four, Tsuhaifu

 

Finally, sharing a good article on generics ( Click here to visit the author frank909), in which the passage made me feel very interesting:

I will generic likened a gatekeeper at the beginning of the article, the reason is that he has good intentions, the guardian of our security code, and then written out on the house of the provisions, and "xxx prohibit access to" reminder. But those same guards in general we encounter daily, they weird paranoid, rigid conservative, based on the knowledge we can use the reflection type erasure, to bypass certain restrictions generics, in real life, there will always be naughty based on the law on who can guard their lifestyle selectively bypassing their monitors, or slipped out another way to sneak into the door, then sped away, leaving defenders a lonely figure.

Guess you like

Origin www.cnblogs.com/zzzt20/p/11580897.html