Java8 basics (x) generic constraints and limitations

Generic constraints and limitations

Since the generic type by erasure, and the bridge type conversion method forces to achieve, there are certain limitations (mostly from erasure).

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

Type parameters are based, use a wrapper type package can be substantially (due to the type as a post erase type parameter Objectclass type base value can not be stored). When the package can not accept replacement class type parameter may be used to separate classes and methods for processing.

Run-time type query applies only to the original type

As the virtual machine object has a specific primitive type, so the type of query only query primitive types.

// 只能测试a是否为某种Pair类型
if (a instanceof Pair<String>) {...}
if (a instanceof Pair<T>) {...}
Pair<String> p = (Pair<String>) a;

When code attempts to use instanceofwhen querying whether the object belongs to a generic type, the compiler will complain; if you use cast will get a warning.

Similarly, even if getClassthe method can only return to the original type.

You can not create arrays of parameterized types

Since the erasure type, the original type only, so if the parameter allows the creation of an array type, then it can be after the array upcast Object[]generic type definition object parameter other than the type of parameters are then provided to add . This type of violation of safety requirements.

Pair<String> table = new Pair<String>[10];
Object[] = objArray = table;
// objArray记住了table的原始类型Pair,因此存储String类会抛出ArrayStoreException异常
objArray[0] = "Hello";
// objArray只记住了Pair,因此添加Pair<Employee>也不会编译报错,但会导致类型错误
objArray[0] = new Pair<Employee>();

Note: Do not allow to create an array does not mean not permitted to declare an array variable, but can not be used newto initialize it.

Note 2: You can declare an array of wildcard type, and then initialize variables type conversion, but this is still not safe.

Tip: The only way to safely and effectively collect parameterized type objects is ArrayList:ArrayList<Pair<String>>.

Varargs warning

When passed generic type instance to a variable number of parameters method, in fact, the virtual machine must establish a parameterized type of the array as a parameter method, which violated the regulations do not allow create a parameterized type of the array. However, the compiler will issue a warning rather than an error.

Be able to determine when to call correctly, you can use annotations or @SafeVarargslabeling method to cancel the warning.

Type variable can not instantiate

You can not be instantiated Ttype, as it will be erased Objecttype.

The best solution is to allow the caller to provide a constructor expression, that is to design a method of receiving Supplier<T>function interface to obtain the Ttype of instance. At this point Tis a function of the incoming interface decisions, without fear of being erased.

// 向该方法传入构造器引用即可获取T类型的实例
public static <T> Pair<T> makePair(Supplier<T> constr) {
    return new Pair<>(constr.get(), constr.get());
}

We can not be constructed generic array

In the presence of restrictions on the type, the type of array results in the formation of erase always limit type.

If the generic array only as a private domain class instance, this may be declared as an array Object[], the type of conversion can be acquired when the element.

If the generic groups have the number of its use, reference should be provided constructor to generate an array of the correct type. Examples of the method is similar to the generic variables.

The generic class type variable static context is invalid

If the static method returns a generic domain of static design, the type of erasing method will lead to the return Objecttype of a static field. As the static field will be shared by all objects in the generic class, it may not be applied to an object.

// 擦除类型后静态变量为Object类型
public class Singleton<T> {
    private static T singleInstance;
    private static T getSingleInstance() {
        if (singleInstance == null) // construct new instance of T
        return singleInstance;
    }
}
// 无法确定返回类型
SingletonA = new Singleton<Integer>();
SingletonB = new Singleton<Boolean>();
Singleton.getSingleInstance();

Not throw or capture instance of a generic class

Generic classes prohibit the expansion Thorwableinterface. However, generic types Tcan be extended Throwableinterfaces, but can not be caught or thrown.

// 不合法
public static <T extends Throwable> void doWork(Class<T> t) {
    try {
		// doWork
    }catch (T e) {
        Logger.global.info(...);
    }
}
// 合法
public static <T extends Throwable> void doWork(T t) throws T {
    try {
		// doWork
    }catch (Throwable realCause) {
        t.initCause(realCause);
        // t被擦除为Throwable类,然后返回后被调用者强制转换为T类型
        throw t;
    }
}

You can eliminate the inspection of checked exception

The use of generics can provide all checked exception processor at the same time.

Consider a threaded program:

package tClass;

public abstract class Block {
    public abstract void body() throws Exception;

    public Thread toThread(){
        return new Thread() {
            // run方法声明不抛出异常
            public void run() {
                // 将所有异常转换为编译器认为的非受查异常
                try{
                    body();
                }catch (Throwable t) {
                    Block.<RuntimeException>throwAs(t);
                }
            }
        };
    }

    @SuppressWarnings("unchecked")
    public static <T extends Throwable> void throwAs(Throwable e) throws T {
        throw (T)e;
    }
}
package tClass;

import java.io.File;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        new Block() {
            // body方法打开不存在的文件,抛出受查异常FileNotFoundException
            public void body() throws Exception {
                Scanner in = new Scanner(new File("notExistedFile"), "UTF-8");
                while(in.hasNext())
                    System.out.println(in.next());
            }
        }.toThread().start();
    }
}

By the above method, do not capture rununchecked exception by the method, just to make the compiler think throws a non-checked exception. In runthe case where the method of generating a variety of abnormalities, avoid writing this technique to capture a plurality of non-abnormality and packaged under investigation cumbersome codes thrown exception.

Note that post-conflict erased

When the generic class overrides a superclass method, if the parameter type is overloaded T, it will be erased Object. This could lead to conflict.

public class Pair<T> {
    // 被擦除为eqauls(Object value)与从Object类继承的equals(Object)冲突
    public boolean equals(T value) {return first.equals(value) && second.eqauls(value);}
}

Generic specification principle: To support erasure of conversion, we need to impose restrictions on a class or type variable can not be the two types of interfaces subclass, while the two interfaces of different parameters of the same interface.

The reason is that the presence of these principles: to achieve bridge method interface parameters of the class will receive interface, if the implementation of two different parameters of the same interface, you will get exactly the same two signatures bridge approach lead to conflict.

Guess you like

Origin www.cnblogs.com/aries99c/p/12616634.html