java generics full solution - absolutely the most detailed

background

For java generics I have been part of a smattering of the usual really not much use. Until reading the "Effect Java", to see a lot do not understand the common usage, people determined, the system needs to learn, and recorded.


1, a generic overview:

1.1 The origin of generics

According motivation "Java programming ideas" in the description of generics:

有很多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。
复制代码

Generics have long thought exist, such as C ++ templates (Templates). Spirit template: parameterized types

1.2 Basic Overview

  • The generic nature is "parameterized type." Mention of parameters, the most familiar is the definition of the method parameter when needed, call the method when you need to pass arguments. That "parameterized type" is the original specific types of parametric
  • Avoid the emergence of generics strong turn of operation, type of transformation is completed in the compiler, thus avoiding wrong operation.

1.3 The purpose of generics

  • Java generics is also a syntactic sugar, done at compile phase of the conversion type, to avoid run-time type coercion occurs ClassCastException, type conversion exception.

1.4 Examples

JDK 1.5 when added generics, easy to use on the set to a large extent.

  • Not using generics:
public static void main(String[] args) {
        List list = new ArrayList();
        list.add(11);
        list.add("ssss");
        for (int i = 0; i < list.size(); i++) {
            System.out.println((String)list.get(i));
        }
    }
复制代码

Because the list type is Object. Therefore int, String type of data is to be placed, but also can be taken out. But the above code, runtime type conversion will throw an exception, I believe that everyone can understand.

  • Using generics:
public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("hahah");
        list.add("ssss");
        for (int i = 0; i < list.size(); i++) {
            System.out.println((String)list.get(i));
        }
    }
复制代码

In the above example, we can only add String data type, or the compiler will complain.


2, the use of generics

Generic three different ways: generic class , generic methods , generic interface

2.1 generic class

  • SUMMARY generic classes: the generic class defined in the
  • Definition Format:
public class 类名 <泛型类型1,...> {
    
}
复制代码
  • Note: The generic type must be a reference type (non-basic data types)

2.2 generic method

  • Generic Method Overview: The generic method defined in
  • Definition Format:
public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
    
}
复制代码
  • Points to note:
    • Parameter declaration method defined in the method can only be used where the type parameter interface defined in the class declaration may be used throughout the interface class. When calling fun () method, according to the actual object passed, the compiler determines that the actual type represented by the type parameter T.
class Demo{  
  public <T> T fun(T t){   // 可以接收任意类型的数据  
   return t ;     // 直接把参数返回  
  }  
};  
public class GenericsDemo26{  
  public static void main(String args[]){  
    Demo d = new Demo() ; // 实例化Demo对象  
    String str = d.fun("汤姆") ; // 传递字符串  
    int i = d.fun(30) ;  // 传递数字,自动装箱  
    System.out.println(str) ; // 输出内容  
    System.out.println(i) ;  // 输出内容  
  }  
};
复制代码

2.3 Generic Interface

  • Generic Interface Overview: The generic definition of the interface
  • Definition Format:
public interface 接口名<泛型类型> {
    
}
复制代码
  • Example:
/**
 * 泛型接口的定义格式:        修饰符  interface 接口名<数据类型> {}
 */
public interface Inter<T> {
    public abstract void show(T t) ;
}

/**
 * 子类是泛型类
 */
public class InterImpl<E> implements Inter<E> {
    @Override
    public void show(E t) {
        System.out.println(t);
    }
}


Inter<String> inter = new InterImpl<String>() ;
inter.show("hello") ;
复制代码

2.4 generics source used, the following is the code snippet and the List interface ArrayList class.

//定义接口时指定了一个类型形参,该形参名为E
public interface List<E> extends Collection<E> {
   //在该接口里,E可以作为类型使用
   public E get(int index) {}
   public void add(E e) {} 
}

//定义类时指定了一个类型形参,该形参名为E
public class ArrayList<E> extends AbstractList<E> implements List<E> {
   //在该类里,E可以作为类型使用
   public void set(E e) {
   .......................
   }
}
复制代码

2.5 generic class subclass

Parent class when the subclass does not contain the type of the parameter, the specific needs of the type of afferent

  • Wrong way:

public class A extends Container<K, V> {}

  • Right way:

public class A extends Container<Integer, String> {}

  • May not specify a particular type, the system will K, V as a parameter of type Object Processing

public class A extends Container {}

2.6 Generic constructor

  • The constructor is also a way, it also produced the so-called generic constructor.
  • Like an ordinary method, and there is no difference A is a generic parameters specified, the other is implicitly inferred
public class Person {
    public <T> Person(T t) {
        System.out.println(t);
    }
    
}
复制代码

use:

public static void main(String[] args) {
    new Person(22);// 隐式
    new <String> Person("hello");//显示
}
复制代码
  • Special Instructions:

    • If the constructor is generic constructor, while the case of the class is a generic class of how to use the generic constructors: because generic constructor can explicitly specify your own type parameter (need to use diamond, in the constructor before device), and their generic class also need to specify the type arguments (on the diamond after the constructor), which also appeared in two of the diamond, which there will be some small problems, the specific use to sum up here. The representatives of the following examples
    public class Person<E> {
        public <T> Person(T t) {
            System.out.println(t);
        }
    }
    复制代码

    Correct usage:

    public static void main(String[] args) {
        Person<String> person = new Person("sss");
    }
    复制代码

    PS: The compiler will remind you how to do

2.7 Senior wildcard

2.7.1 Background:

On 2.7.2 <? Extends T> bounded wildcards

  • Upper bound wildcard name implies, <? Extends T> represents the upper bound of the type comprising [itself], so Wild parameterized type may be T or a subclass.

    • Because not determine what specific type, add approach is limited (you can add null, because null means any type), but can be assigned after obtaining element from the list to the parent type. As a first example of the figure above, the third add () action is limited, because a List List and List <? Extends Animal> subtype.
    它表示集合中的所有元素都是Animal类型或者其子类
     List<? extends Animal>
    复制代码
  • This is called the upper limit of a wildcard, and the keyword extends achieved, upon instantiation of the specified type only argument is a rear type subclass or extends itself.

    • E.g:
    • This will determine the type of elements in the collection, although the specific type of uncertainty, but at least know its parent. And other operations.
    //Cat是其子类
        List<? extends Animal> list = new ArrayList<Cat>();
    复制代码

2.7.3 <? Super T> lower bound wildcard

  • Lower bound wildcard <? Super T> represents the parameterized type is a supertype of T (including itself), the layers of first, until the Object

    • The compiler can not determine get () Returns what type of object is thus get () method is limited. May be made add () method, add () method and the type T can add subtype of type T, such as the second example of a first add Cat type object, the object is then added two types of Cat subclasses, which method is feasible, but if you add an object of type Animal, obviously the inheritance relationship backwards, is not feasible.
     它表示集合中的所有元素都是Cat类型或者其父类
     List <? super Cat>   
    复制代码
  • This is called the lower limit of wildcards, to achieve super keyword, when instantiated only specify the type argument extends itself or a subclass of the type

    • E.g
    //Animal是其父类
    List<? super Cat> list = new ArrayList<Animal>();
    复制代码

2.7.4 <?> Unbounded wildcard

  • Any type, if not explicitly, then that Object as well as any of the Java class
  • Unbounded wildcards with <?> Said? Represents any kind of type that can represent any type of only null (Object itself can be considered a type, but not on behalf of any type, so the meaning of List and List are different, the former type is Object, which is inherited the top of the tree, while the latter type is completely unknown)

3, generics erased

3.1 concept

Will be removed when the type information set compiler compiles the tape type described

3.2 Verify that the instance:

public class GenericTest {
    public static void main(String[] args) {
        new GenericTest().testType();
    }

    public void testType(){
        ArrayList<Integer> collection1 = new ArrayList<Integer>();
        ArrayList<String> collection2= new ArrayList<String>();
        
        System.out.println(collection1.getClass()==collection2.getClass());
        //两者class类型一样,即字节码一致
        
        System.out.println(collection2.getClass().getName());
        //class均为java.util.ArrayList,并无实际类型参数信息
    }
}
复制代码
  • Output:
true
java.util.ArrayList
复制代码
  • analysis:
    • This is because no matter what type of argument is a generic type parameter passed, For Java, they are still treated as the same type of processing, in memory only occupies a memory space. For the purposes of this concept proposed by Java generics view, the code is compiled only act on stage, during compilation, for the correct test result generics, generic information will be struck, that is to say, to successfully compile after the class file does not contain any generic information. Generics will not enter information to the runtime phase.
    • In the static method, a static initializer block or declaring and initializing variables are not allowed static type parameter. Since the system does not actually generate a generic class, generic class can not be used after the operator instanceof

4, the reflective generics

  • The generic variables as parameters of the method, the method using Method getGenericParameterTypes generic class to obtain the actual type arguments
  • example:
public class GenericTest {

    public static void main(String[] args) throws Exception {
        getParamType();
    }
    
     /*利用反射获取方法参数的实际参数类型*/
    public static void getParamType() throws NoSuchMethodException{
        Method method = GenericTest.class.getMethod("applyMap",Map.class);
        //获取方法的泛型参数的类型
        Type[] types = method.getGenericParameterTypes();
        System.out.println(types[0]);
        //参数化的类型
        ParameterizedType pType  = (ParameterizedType)types[0];
        //原始类型
        System.out.println(pType.getRawType());
        //实际类型参数
        System.out.println(pType.getActualTypeArguments()[0]);
        System.out.println(pType.getActualTypeArguments()[1]);
    }

    /*供测试参数类型的方法*/
    public static void applyMap(Map<Integer,String> map){

    }
}
复制代码
  • Output:
java.util.Map<java.lang.Integer, java.lang.String>
interface java.util.Map
class java.lang.Integer
class java.lang.String
复制代码
  • By bypassing the reflector compiler limit generic type
public static void main(String[] args) throws Exception {
		//定义一个包含int的链表
		ArrayList<Integer> al = new ArrayList<Integer>();
		al.add(1);
		al.add(2);
		//获取链表的add方法,注意这里是Object.class,如果写int.class会抛出NoSuchMethodException异常
		Method m = al.getClass().getMethod("add", Object.class);
		//调用反射中的add方法加入一个string类型的元素,因为add方法的实际参数是Object
		m.invoke(al, "hello");
		System.out.println(al.get(2));
	}

复制代码

5 generics limit

5.1 ambiguity error

  • For the generic class User <K, V>, the generic class declares two parameters. Overload show in the class type parameter according to different methods.
public class User<K, V> {
    
    public void show(K k) { // 报错信息:'show(K)' clashes with 'show(V)'; both methods have same erasure
        
    }
    public void show(V t) {

    }
}
复制代码

Because generics erased all Obejct type on both the nature. The method is the same, so the compiler will complain.

For a way:

public class User<K, V> {

    public void show(String k) {

    }
    public void show(V t) {

    }
}
复制代码

Use the results:

Normal use

5.2 Type parameter can not be instantiated

The compiler does not know the type of the object that is created

public class User<K, V> {

    private K key = new K(); // 报错:Type parameter 'K' cannot be instantiated directly

}
复制代码

5.3 restrictions on the static member

Static methods can not access the class definition of generic; type of uncertainty if the static method of operation, you want to be on the generic method definition.

If you want to use a generic static method, then the static method must be defined as a generic method .

public class User<T> {

    //错误
    private static T t;

    //错误
    public static T getT() {
        return t;
    }

    //正确
    public static <K> void test(K k) {

    }
}
复制代码

5.4 restrictions on generic array

  • Can not be instantiated element is an array type parameters, but an array of pointers may be compatible with the type of array references
public class User<T> {

    private T[] values;

    public User(T[] values) {
        //错误,不能实例化元素类型为类型参数的数组
        this.values = new T[5];
        //正确,可以将values 指向类型兼容的数组的引用
        this.values = values;
    }
}
复制代码

5.5 restrictions on generic anomalies

Generic class can not extend Throwable, it means you can not create an exception class generic answer link

reference:

Guess you like

Origin juejin.im/post/5d64d0f8f265da03a653264e