泛型Generics

Type safety means that the compiler will validate types while compiling, and throw an error if you try to assign the wrong type to a variable.
Java is Type safety.
在這裏插入圖片描述

一、Why Use Generics?

  • Stronger type checks at compile time.
  • Elimination of casts.
  • Enabling programmers to implement generic algorithms.
       List<String> list = new ArrayList<>();
       List list1 = new ArrayList();
        /*
         1.在編譯時會報異常:add (java.lang.String) in List cannot be applied to (java.lang.Integer)
         無需等到運行時,運行時報錯可能比較難找錯誤位置
          */
        list.add(1);

        //2.
        //它會將list1中所有元素當成Object,向下轉換要顯式轉換
        String str= (String)list1.get(0);
        
        String str=list.get(0);
        //3.自定義特定類型的集合
        List<Student> list=new ArrayList<>();

二、generic type

A generic type is a generic class or interface that is parameterized over types.

//格式:
class name<T1, T2, ..., Tn> { /* ... */ }

//例子
public class Box<T> {
    private T t;
    //構造方法
    public Box(T t)
    {
        this.t=t;
    }
    public void set(T t){
        this.t=t;
    }

    public T get(){
        return t;
    }
}

//調用 invokation 初始化有兩種方式
Box<String> mybox=new Box<>("str1");
Box<String> mybox1=new Box<String>("str2");

Type Parameter and Type Argument
When coding, one provides type arguments in order to create a parameterized type.
<T> in Box<T> 是Type Parameter;<String> in Box<String>是Type Argument

注意:Type Argument是non-primitive也就是class、interface、array
An invocation of a generic type is generally known as a parameterized type.

三、Generic Method

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter’s scope is limited to the method where it is declared.
也就是說:generic type的type parameter範圍是整個類或接口;generic method的type parameter範圍是該方法。

public class Test {
   //Generic Method 要將type parameter寫在返回類型前面
    public static <T> boolean compareTo(Box<T> t1,Box<T> t2)
    {
        return t1==t2;
    }

    public static  void main(String[] args) {
       Box<String> mybox=new Box<>("str1");
       Box<String> mybox1=new Box<String>("str2");
       
       System.out.println(compareTo(mybox,mybox1));
    }
}

四、Bounded Type Parameters

There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

語法:
type Parameters extends upper bound

//只能接受Number及子類型 
    public <U extends Number> void inspect(U u){
        System.out.println(u.getClass().getName());
    }
    //測試:
       Test t=new Test();
        t.inspect(new Integer(1));
        t.inspect(new Double(1.0));

extends is used in a general sense to mean either “extends” (as in classes) or “implements” (as in interfaces).

1.Generics, Inheritance, and Subtypes

在上面的inspect例子中,能夠使用Integer、Double等的原因是他們均爲Number子類型(subtype),也就是"is a"的關係。
subtype:
考慮如下場景:

 public  void inspect1(Box<Number> b){
        System.out.println(b.getClass().getName());
    }

並不能接受Box<Integer>或Box<Double>,因爲它們不是Box<Number>的子類。
在這裏插入圖片描述
也就是說給定具體類型A、B(比如Number、integer),MyClass<A>與MyClass<B>是沒有關係的。不管A、B是否有關係。Class<A>與Class<B>的父類是Object(也就是萬物即爲對象)

2.Generic Classes and Subtyping

You can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.
在這裏插入圖片描述
ArrayList<E> implements List<E>,List<E> extends Collection<E>。So ArrayList<String>是List<String>的subtype.

五、Type Inference

Type inference is a Java compiler’s ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.

t.inspect(new Integer(1));//不用再寫t.<Integer>inspect(new Integer(1));
Map<String, List<String>> myMap = new HashMap<>();

六、Wildcards

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific). The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.

爲什麼需要Wildcards?

generic type讓類型更靈活,但是也存在Box<Numer>只能接受Number、不能接收父Object、子Double等問題,爲了解決這些存在繼承關係的問題,從而需要用Wildcards.

//B is A's subtype
class A { /* ... */ }
class B extends A { /* ... */ }

//可行:
B b = new B();
A a = b;

//不可行 List<B> is not List<A>'s subtype
List<B> lb = new ArrayList<>();// ArrayList is List's subtype
List<A> la = lb;   // compile-time error 

1.Upper Bounded Wildcards

You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.

an upper bounded wildcard restricts the unknown type to be a specific type or a subtype of that type and is represented using the extends keyword.
upper bounded wildcard將未知類型限制爲特定類型或該類型的子類型,並使用extends關鍵字表示。

extends is used in a general sense to mean either “extends” (as in classes) or “implements” (as in interfaces).

//語法:upper bounded wildcard: <? extends upper_bound>
public static void process(List<? extends Number> list) { /* ... */ }

//調用
process(new ArrayList<Integer>());
//傳參:List<? extends Number>  list=new ArrayList<Integer>();
①ArrayList 是 List的 subtype ②Numer是Integer的upper_bound.

To write the method that works on lists of Number and the subtypes of Number, such as Integer, Double, and Float, you would specify List<? extends Number>. The term List<Number> is more restrictive than List<? extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses.
List<Number>限制比List<? extends Number>更嚴格。

2.Lower Bounded Wildcards

a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.

//語法:lower bounded wildcard: <? super lower_bound>
public static void process(List<? super Integer> list) { /* ... */ }

//調用
process(new ArrayList<Integer>());
//傳參:List<? super Number>  list=new ArrayList<Integer>();
①ArrayList 是 List的 subtype ②Integer是Number的lower_bound.

To write the method that works on lists of Integer and the supertypes of Integer, such as Integer, Number, and Object, you would specify List<? super Integer>. The term List<Integer> is more restrictive than List<? super Integer> because the former matches a list of type Integer only, whereas the latter matches a list of any type that is a supertype of Integer.

3.Unbounded Wildcards

  • If you are writing a method that can be implemented using functionality provided in the Object class.(如果您正在編寫方法,它使用Object類中提供的方法)
    If we want to have it accept all type,we can have it extends Object,which every class in Java inherits from.
    But instead of using <? extends Object>,we can simplify this to <?>
  • When the code is using methods in the generic class that don’t depend on the type parameter. For example, List.size or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> do not depend on T.
public static void printList(List<?> list) {
    for (Object elem: list)//elem只能用Object類的方法 若
        System.out.print(elem + " ");
    System.out.println();
}
//調用
printList(new ArrayList<Integer>());
//傳參:List<? super Number>  list=new ArrayList<Integer>();
①ArrayList 是 List的 subtype ②?可接受任何類型

It’s important to note that List<Object> and List<?> are not the same. You can insert an Object only,not List

七、API舉例

  1. ArrayList<E>中的一個構造函數:ArrayList(Collection<? extends E> c)
 //沿用B extends A
 Collection<B> ls=new ArrayList<>();// Arraylist is Collection's subtype
 (參考四中Collection-List-ArrayList關係圖片)
 
 List<A> ls1=new ArrayList<>(ls);//ls中元素爲B extends A √

2.ArrayList<E> :add(E e)

     A al=new A();
     ls1.add(al);
     B b3=new B();
     ls1.add(b3);//B is A's subtype 

3.TreeSet<E>構造函數:TreeSet(Comparator<? super E> comparator) 也就是比較器是E或父類型

public class A {
    private  int a;
    
    public A(int a) {
        this.a = a;
    }
    //省略getter/setter
}

public class B extends A{
    public B(int a) {
        super(a);
    }
}
//用A做比較器
public class MyComparator implements Comparator<A> {
    @Override
    public int compare(A o1, A o2) {
        return o1.getA()-o2.getA();
    }
}

測試:

        Comparator<A> comparator=new MyComparator();
        //E是B  比較器是B的父類A
        TreeSet<B> ts=new TreeSet<>(new MyComparator());
        ts.add(new B(1));
        ts.add(new B(2));

參考:https://docs.oracle.com/javase/tutorial/java/generics/types.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章