[Reading notes] Java core technology Volume # 6.Chapter8

8 generic programming

8.1 Why use generic programming

  • Type parameter (of the type the EParameters) ( T, , S...)
  • Wildcard type (wildcard of the type) ?( )

Note the use of both usefulness and different.

8.2 define simple generic class

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 newValue) { first = newValue; }
    public void setSecond(T newValue) { second = newValue; }
}

8.3 generic method

Type variable modifier on the back, return to the previous type.
Generic methods can be defined in the general category, it can also be defined in generic classes.
When you call a generic method, into a specific type of angle brackets in front of the method name.

8.4 defining types of variables

By setting the variable T is defined type (bound):

public static <T extends Comparable> T min(T[] a) {. . .}
  • Keyword is extends, T class and type may be defined, or may be an interface.
  • A variable type or wildcards may define a plurality of, for example: T extends Comparable & Serializable; type defined by '&' separated by commas to separate the variable type.
  • Defining most one class, and must be defined first in the list.

8.5 generic code and virtual machine

Virtual machine does generic type objects - all objects belong to the general category.

8.5.1 type erasure

Whenever you define a generic type, automatically provides a corresponding original type (raw type). Deleting the original type of the generic type name is the name of the type parameter. Erase (ERASED) type variable, and replaced defined type.

The first original type replaced with a variable type defined, if it is not replaced by defining the given Object. To improve efficiency, should the marker interface (i.e., interface with no methods) at the end of the boundary list.

public class Pair {
    private Object first;
    private Object second;

    public Pair() { first = null; second = null; }
    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; }
}

8.5.2 Translation generic expression

When a program calls a generic method, if the return type erase, the compiler inserts cast.

8.5.3 Translation generic method

If the polymorphic type erasure clashed, for example:

public class Datelnterval extends Pair<LocalDate> {
    @Override
    public void setSecond(LocalDate second) {
        if (second.compareTo(getFirst()) >= 0)
            super.setSecond(second);
    }
    ...
}

After type erasure, become:

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

But after the Pair type erasure method is

public void setSecond(Object second);

When the coating method parameters is inconsistent with this polymorphism had a conflict. Therefore, the compiler generates is Datelnterval 桥方法(Bridge Method,):

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

If the bridge generation method get method, so in Datelnterval class, there are two methods getSecond:

LocalDate getSecond() // defined in DateInterval 中定义的
Object getSecond() // 桥方法,覆盖 Pair 中的方法,调用第一个方法

Method signature (the return value does not include) the same two methods are not legal.
However, in a virtual machine, the type of parameter and return type determining method. Thus, the compiler may generate return only two different types of methods byte code, the virtual machine to handle the situation correctly.

The fifth chapter mentioned covariant return types also use the bridge method

In short, to remember facts about the conversion of Java generics:

  • Virtual machine without generics, only ordinary classes and methods.
  • All types of parameters are defined by their type of replacement.
  • Bridge methods are synthesized to keep the polymorphism.
  • In order to maintain the type of security, if necessary, insert cast.

8.5.4 call legacy code (abbreviated)

8.6 Restrictions and limitations

8.6.1 base type can not be used to instantiate type parameter

No Pair<double>, only Pair<Double>. Because after type erasure, Pair would Object domain, and Object can not be stored double.

8.6.2 runtime type queries only applies to the original type

Such as:

if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<String> p = (Pair<String>) a; // Warning--can only test that a is a Pair

In fact, only tests whether a is a Pair. When reminded of the risks, try to check whether an object belongs to a generic type, if using instanceof will get a compiler error, if the cast will get a warning. Similarly, the getClassmethod always returns the original type. Because the total virtual machine object has a specific non-generic types.

8.6.3 You can not create arrays of parameterized types

Such as:

Pair<String>[] table = new Pair<String>[10]; // Error
Object[] objarray = table;
objarray[0] = "Hello"; // Error--component type is Pair
objarray[0] = new Pair<Employee>(); // 可以通过数组存储检査

Therefore not allowed to create (new) parameterized type of array. But the statement is legitimate and can be initialized using the type conversion.

Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];

Of course it's safe. Only a safe and effective method: ArrayList<Pair<String>>.

8.6.4 Varargs warning

Method variable number of parameters:

public static <T> void addAll(Collection<T> coll, T... ts)
{
    for (t : ts) coll.add(t);
}
// 如下调用:
Collection<Pair<String>> table = . . .;
Pair<String> pair1 = . . .;
Pair<String> pair2 = . . .;
addAll(table, pair1, pair2);

To call this method the opportunity to create a virtual Pair<String>array. But this time will only get a warning rather than an error. Eliminate this warning can be annotated @SuppressWarnings("unchecked")or @SafeVarargs.

8.6.5 Examples of types becomes not opposed

You can not use new T(...)or T.classsuch expressions.

Want to create an instance of the caller can provide a constructor expression or provide class (then Class.newlnstance method).

// 1.构造器表达式
Pair<String> p = Pair.makePair(String::new);
public static <T> Pair<T> makePair(Supplier<T> constr)
{
    return new Pair<>(constr.get(), constr.get());
}
// 2. 提供class
Pair<String> p = Pair.makePair(String.class);
public static <T> Pair<T> makePair(Class<T> cl)
{
    try { return new Pair<>(cl.newInstance(), cl.newInstance()); }
    catch (Exception ex) { return null; }
}

8.6.6 can not be constructed generic array

Can not new T[...].

  • Expressions or a reflective configuration, see P324
  • ArrayList.toArrayExamples, see P324

8.6.7 Static context generic class type variable invalid

You can not reference type variable domain or in a static method.

public class Singleton<T> {
    private static T singleInstance; // Error
    public static T getSingleInstance() // Error
    {
        if (singleInstance == null) construct new instance of T
        return singleInstance;
    }
}

Statement Singleton<Random>and Singleton<JFileChooser>, but only after type erasure Singleton class, it has only one singleInstance domain.

8.6.8 can not throw or capture instance generic class

Neither throw nor capture a generic class object. In fact, even the generic class extends Throwable is illegal.

public class Problem<T> extends Exception { /* . . . */ } // Error--can't extend Throwable

catch clause can not use the type variable:

public static <T extends Throwable> void doWork(Class<T> t) {
    try {
        do work
    }
    catch (T e) { // Error--can't catch type variable
        Logger.global.info(...)
    }
}

However, the use of variable type specification exception is permitted.

public static <T extends Throwable> void doWork(T t) throws T { // OK
    try {
        do work
    }
    catch (Throwable realCause) {
        t.initCause(realCause);
        throw t;
    }
}

8.6.9 can eliminate the inspection of checked exception of

8.6.10 attention to post-conflict erased

8.7 generic types of inheritance rules

  • Whether S have any contact with the T, generally, Pair<S>with Pair<T>no connection.

  • You can always convert a parameterized type is a primitive type. But there are risks, such as:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair rawBuddies = managerBuddies; // OK
rawBuddies.setFirst(new File(". . .")); // only a compile-time warning
Manager one = rawBuddies.getFirst();    // 抛出 ClassCastException 异常 
  • Generic class can extend or implement other generic classes. , There is no difference between ordinary classes this regard.
    For example, ArrayList<T>class implements List<T>the interface. This means that a ArrayList<Manager>can be converted into one List<Manager>. However, as seen before, a ArrayList<Manager>is not a ArrayList<Employee>or List<Employee>.

8.8 wildcard type

8.8.1 Wildcard concept

Wildcard type, allowing the change type parameter. E.g:

Pair<? extends Employee>

It is the type parameter is any subclass of Employee Pair generic type.

Pair<Employee>And Pair<Manager>all Pair<? extends Employee>sub-types.

Use wildcard by Pair<? extends Employee>reference will not damage Pair<Manager>:

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK
wildcardBuddies.setFirst(lowlyEmployee); // compile-time error

Because Pair<? extends Employee>the method looks like this:

? extends Employee getFirst()
void setFirst(? extends Employee)

This will not be possible to call setFirst method. The compiler needs to know only one subtype of Employee, but do not know
specifically what type. It is transmitted to any particular type of refuse. After all, ?it can not be used for matching.
Use getFirst problem does not exist: the getFirst the return value is assigned to an Employee reference perfectly legal.

This is where there is limited wildcard key point: now there is a way to distinguish between a safe 访问器method and unsafe 更改器way to go.

8.8.2 wildcard defining supertype

通配符限定And 类型变量限定it is very similar, but it can also specify a type of super-limited (supertype bound).

For example, Pair<? super Manager>there are methods:

void setFirst(? super Manager)
? super Manager getFirst()

The compiler can not know the specific type setFirst method, and therefore can not accept the argument of type Employee or Object when calling this method. Object Manager can only pass type, or a sub-type of the object.
In addition, if you call getFirst, we can not guarantee the return type of the object, can only assign it to a Object.

Intuitively, wildcards with supertype may be written to define a generic object with wildcard subtype defined it can be read from the generic object.

8.8.3 indefinite wildcard

Such Pair<?>as: .

? getFirst()
void setFirst(?)

getFirst return value can only be assigned to an Object. setFirst method can not be called, even passing Object object (it can be called setFirst(null)). However, it may be passed into the original type Pair setFirst method of any Object object.

  • Use simple operations that readability stronger. The detection of a pair contains a null reference:
public static boolean hasNulls(Pair<?> p)
{
    return p.getFirst() == null || p.getSecond() == null;
}

8.8.4 Wildcard capture

public static void swap(Pair<?> p) { 
    swapHelper(p);
}

public static <T> void swapHelper(Pair<T> p) {
    T t = p.getFirst();
    p.setFirst(p.getSecond());
    p.setSecond(t);
}

Note: swapHelper is a generic method, swap rather than having a fixed Pair<?>type parameter.
In this case, swapHelper capture wildcard parameter T method. It is not known what type the wildcard representation, but it is a certain type.

8.9 reflection and generics

Class class is generic. For example, String.classin fact, an Class<String>object class (in fact, is the only object).

Erased classes still retained some generic information about their origin:
public static Comparable min(Comparable[] a)
is erased by a generic method:
public static <T extends Comparable<? super T>> T min(T[] a)
You can use the reflection API to determine:

  • The generic method has a type parameter called T's.
  • This parameter has a subtype of the type defined, which is itself a generic type. //Comparable<? super T>
  • This defines the type of parameter has a wildcard. //? super T
  • This parameter has a wildcard defining supertype.
  • The generic method has a generic array parameter. //T[] a

In other words, you can reconstruct all the information about generic classes and methods, as they realize that those statements. But you do not know the specific object or method call is how to deal with the type of the parameter.

To express the generic type declaration, using java.lang.reflectthe interface provided in the packet Type. This interface contains the following subtypes:

  • ClassClass, a specific type.
  • Type VariableInterface described type variable (e.g., T extends Comparable<? super T>).
  • WildcardTypeInterface described wildcards (e.g., ?super T).
  • ParameterizedTypeInterfaces, generic description of a class or interface type (e.g., Comparable<? super T>).
  • GenericArrayTypeInterfaces, generic description array (e.g., T[]).

Said section to see the truth behind the wild card and foggy. . . . .

Guess you like

Origin www.cnblogs.com/caophoenix/p/12557006.html