泛型

本文轉載自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.htmlhtml

1 泛型概念的提出(爲何須要泛型?)
java

1.1 首先,咱們看下下面這段簡短的代碼:ide

public class GenericTest {

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("qqyumidi");
        list.add("corn");
        list.add(100);

        for (int i = 0; i < list.size(); i++) {
            String name = (String) list.get(i); // 1
            System.out.println("name:" + name);
        }
    }
}
View Code

  定義了一個List類型的集合,先向其中加入了兩個字符串類型的值,隨後加入一個Integer類型的值。這是徹底容許的,由於此時list默認的類型爲Object類型。在以後的循環中,因爲忘記了以前在list中也加入了Integer類型的值或其餘編碼緣由,很容易出現相似於//1中的錯誤。由於編譯階段正常,而運行時會出現「java.lang.ClassCastException」異常。所以,致使此類錯誤編碼過程當中不易發現。函數

1.2 在上述編碼過程當中,主要存在兩個問題:this

  • 當咱們將一個對象放入相似的raw Type中,集合並無記錄對象的具體類型,都看成object類型處理,該對象編譯時按照object處理,但其運行時仍然爲自己初始類型
  • 所以//1處取出的對象,須要強制轉換到具體的目標類型,進行處理。但容易出現「java.lang.ClassCastException」異常。

1.3 此問題解決方法:編碼

  • 利用instanceof來判斷類型
import java.util.*;

public class GenericTesst {

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("qqyumidi");
        list.add("corn");
        list.add(100);

        for (int i = 0; i < list.size(); i++) {
            if(list.get(i) instanceof Integer){
                String name = ((Integer) list.get(i)).toString(); // 1
                 System.out.println("name:" + name);
            }else if(list.get(i) instanceof String){
                String  name = (String) list.get(i); // 1
                 System.out.println("name:" + name);
            }
           
        }
    }
}
View Code
  • 利用getClass()
import java.util.*;

public class GenericTesst {

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("qqyumidi");
        list.add("corn");
        list.add(100);
        
        for (int i = 0; i < list.size(); i++) {
            if(list.get(i).getClass().equals(Integer.class)){
                String name = ((Integer) list.get(i)).toString(); // 1
                 System.out.println("name:" + name);
            }else if(list.get(i).getClass().equals(String.class)){
                String  name = (String) list.get(i); // 1
                 System.out.println("name:" + name);
            }
           
        }
    }
}
View Code
  • 利用泛型

2 泛型定義(什麼是泛型?)spa

泛型,即參數化類型,相似於函數的形參與實參;在類型定義時將類型定義爲類型形參,而在類型使用時利用類型實參來進行使用。3d

2.1 從源碼中看看List接口是如何定義的code

public interface List<E> extends Collection<E> {

    int size();

    boolean isEmpty();

    boolean contains(Object o);

    Iterator<E> iterator();

    Object[] toArray();

    <T> T[] toArray(T[] a);

    boolean add(E e);

    boolean remove(Object o);

    boolean containsAll(Collection<?> c);

    boolean addAll(Collection<? extends E> c);

    boolean addAll(int index, Collection<? extends E> c);

    boolean removeAll(Collection<?> c);

    boolean retainAll(Collection<?> c);

    void clear();

    boolean equals(Object o);

    int hashCode();

    E get(int index);

    E set(int index, E element);

    void add(int index, E element);

    E remove(int index);

    int indexOf(Object o);

    int lastIndexOf(Object o);

    ListIterator<E> listIterator();

    ListIterator<E> listIterator(int index);

    List<E> subList(int fromIndex, int toIndex);
}
View Code

咱們能夠看到,在List接口中採用泛型化定義以後,<E>中的E表示類型形參,能夠接收具體的類型實參,而且此接口定義中,凡是出現E的地方均表示相同的接受自外部的類型實參。htm

2.2 利用泛型重寫上述代碼

public class GenericTest {

    public static void main(String[] args) {
        /*
        List list = new ArrayList();
        list.add("qqyumidi");
        list.add("corn");
        list.add(100);
        */

        List<String> list = new ArrayList<String>();
        list.add("qqyumidi");
        list.add("corn");
        //list.add(100);   // 1  提示編譯錯誤

        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i); // 2
            System.out.println("name:" + name);
        }
    }
}
View Code

利用泛型可以使List記錄添加對象的具體類型,從而保證編譯與運行時的一致

3 自定義泛型接口、泛型類及泛型方法

3.1 自定義泛型接口

//定義接口
interface Operatable<T>{
     <T> T add(T t1, T t2);
}
View Code

3.2 自定義泛型類型

//類型的定義,該類型中能夠裝入多種類型的對象
class Box<T>{

    private T data ;
    
    public Box() {

    }
    
    public Box(T data) {
        setData(data);
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
View Code

3.3 自定義泛型方法

 static  <T> T getData(T t1){
        return t1;
}
View Code

3.3 對於不一樣傳入的類型實參,生成的相應對象實例類型是否是同樣呢?

public class GenericTest {

    public static void main(String[] args) {

        Box<String> name = new Box<String>("corn");
        Box<Integer> age = new Box<Integer>(712);

        System.out.println("name class:" + name.getClass());      // com.qqyumidi.Box
        System.out.println("age class:" + age.getClass());        // com.qqyumidi.Box
        System.out.println(name.getClass() == age.getClass());    // true

    }

}
View Code

由此,說明不一樣傳入的類型實參,並無生成不一樣的類型,傳入不一樣泛型實參的泛型類在內存上只有一個,即仍是原來的最基本的類型。

究其緣由,在於Java中的泛型這一律念提出的目的,致使其只是做用於代碼編譯階段,在編譯過程當中,對於正確檢驗泛型結果後,會將泛型的相關信息擦出,也就是說,成功編譯事後的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

對此總結成一句話:泛型類型在邏輯上看以當作是多個不一樣的類型,實際上都是相同的基本類型。

4 類型通配符

4.1 邏輯上Box<Number>不能視爲Box<Integer>的父類

  接着上面的結論,咱們知道,Box<Number>和Box<Integer>實際上都是Box類型,如今須要繼續探討一個問題,那麼在邏輯上,相似於Box<Number>和Box<Integer>是否能夠當作具備父子關係的泛型類型呢?

public class GenericTesst {

    public static void main(String[] args) {

        Box<Integer> a = new Box<Integer>(712);
        Box<Number> b = a;  // 1
        Box<Float> f = new Box<Float>(3.14f);
        getData(f);        // 2

    }

    public static void getData(Box<Number> data) {
        System.out.println("data :" + data.getData());
    }

}

class Box<T> {

    private T data;

    public Box() {

    }

    public Box(T data) {
        setData(data);
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}
View Code

這個例子中,顯然//1和//2處確定會出現錯誤提示的。由此咱們可使用反證法來講明:在邏輯上Box<Number>不能視爲Box<Integer>的父類。

4.2 類型通配符

  類型通配符通常是使用 ? 代替具體的類型形參。注意了,此處是類型形參,而不是類型實參!且Box<?>在邏輯上是Box<Integer>、Box<Number>...等全部Box<具體類型實參>的父類。由此,咱們依然能夠定義泛型方法,來完成此類需求。

public class GenericTest {

    public static void main(String[] args) {

        Box<String> name = new Box<String>("corn");
        Box<Integer> age = new Box<Integer>(712);
        Box<Number> number = new Box<Number>(314);

        getData(name);
        getData(age);
        getData(number);
        
        //getUpperNumberData(name); // 1
        getUpperNumberData(age);    // 2
        getUpperNumberData(number); // 3
    }

    public static void getData(Box<?> data) {
        System.out.println("data :" + data.getData());
    }
    
    public static void getUpperNumberData(Box<? extends Number> data){
        System.out.println("data :" + data.getData());
    }

}
View Code

類型通配符上限經過形如Box<? extends Number>形式定義,相對應的,類型通配符下限爲Box<? super Number>形式,其含義與類型通配符上限正好相反,

相關文章
相關標籤/搜索