1. 程式人生 > >javaSE(九)之泛型(Generics)

javaSE(九)之泛型(Generics)

運行時 str nts super 也有 get 基本類型 簡介 pre

前言

這幾天分享了怎麽搭建集群,這一篇給大家介紹的是泛型,在我們的很多java底層的源代碼都是有很多復雜的泛型的!那什麽是泛型呢?

泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法

Java語言引入泛型的好處是安全簡單。在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求

開發者對實際參數類型可以預知的情況下進行的。對於強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。

泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,以提高代碼的重用率。那廢話不多說,我們進入正題:

一、泛型的簡介

1.1、泛型概述

  泛型是JDK 1.5的一項新特性,它的本質是參數化類型(Parameterized Type),也就是說所操作的數據類型被指定為一個參數,在用到的時候在指定具體的類型
  這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口和泛型方法。
  泛型的類型將來傳入是只能是引用類型的,不能是基本類型的

//編譯通過    List<String>    List<Action>    List<Integer>    List<Integer[]>    List<int[]>
 
//編譯報錯 List<int>

1.2、泛型特點

  java中的泛型只是在編輯期間起作用的,在運行時會把泛型信息擦除的

只是在編譯期間啟動類型安全檢查的作用,運行時不起作用

例如:List<String> list = new ArrayList<String>();

雖然指定了泛型為String,但是在運行時候依然是可以向該list中存放其他類型數據的。(比如使用反射的方法)

二、泛型類

一個泛型類就是具有一個或多個類型變量(把類型參數化)的類
定義一個泛型類十分簡單,只需要在類名後面加上<>,再在裏面加上類型參數.



註:類型變量使用大寫形式,且比較短,這是很常見的。在JDK中,使用變量E表示集合的元素類型,K和V分別表示關鍵字與值的類型。(需要時還可以用其他的字母,也可以是一個或多個字母)

舉例1:

這裏的T是根據將來用戶使用Point類的時候所傳的類型來定

public class Point<T> {
            private T x;
            private T y;
            public T getX() {
                return x;
            }
            public void setX(T x) {
                this.x = x;
            }
            public T getY() {
                return y;
            }
            public void setY(T y) {
                this.y = y;
            }
        }         

  當我們創建一個對象為:Point<Double> p = new Point<Double>(); ,這裏的T就代表的是double。

舉例2:

   這裏的T和S是根據將來用戶使用Point類的時候所傳的類型來定

public class Point<T,S> {
            private T x;
            private S y;
            public T getX() {
                return x;
            }
            public void setX(T x) {
                this.x = x;
            }
            public S getY() {
                return y;
            }
            public void setY(S y) {
                this.y = y;
            }
        } 

  當我們創建一個對象為:Point<String,Integer> p = new Point<String,Integer>(); ,這個的T是String,S是Integer類型的。

三、泛型接口

一個泛型接口就是具有一個或多個類型變量的接口

舉例: 

public interface Action<T,U>{  
            void doSomeThing(T t,U u);  
        }  

        public class ActionTest implements Action<String,Date>{  
            public void doSomeThing(String str,Date date) {  
                System.out.println(str);  
                System.out.println(date);  
            }  
        }            

四、泛型方法

泛型方法就是在方法上直接聲明泛型

public class Test{
            public <T> void run1(T t){
            
            }

            public <T> T run2(T t){
                return t;
            }

            public <T,S> void run3(T t,S s){
        
            }
        }

五、通配符

  泛型增加了java中類型的復雜性,例如List<String>、List<Integer>、List<Object>等這些都是不同的類型。

//編譯報錯
        //雖然 List list = new ArrayList(); 是正確的
        //雖然 Object是String的父類型
        //但是下面代碼編譯時報錯的,因為使用了泛型
        List<Object> list = new ArrayList<String>(); 

  泛型中?是通配符,它可以表示所有泛型的父類型,集合元素可以是任意類型,這種沒有意義,一般是方法中,只是為了說明用法。
  List<?> list = new ArrayList<任意>();

//這時list可以指向任何泛型的List類型集合對象
        public void test(List<?> list){
            //編譯報錯,因為我們並不知道?到底代表什麽類型
            list.add(1);
//編譯通過 for(Object o:list){ System.out.println(o); } }

   註:通配符?只能用在泛型變量聲明的時候

六、泛型中的extends和super關鍵字

在泛型中可以使用extends和super關鍵字來表示將來用戶所傳的泛型參數的上限和下限

6.1、extends關鍵字的使用

舉例1:在聲明泛型類和泛型接口時使用extends

public class Point<T extends Number> {
            private T x;
            private T y;
        }

        public class Point<T extends Number,S> {
            private T x;
            private S y;
        }

        public interface Action<T extends Person> {
            public void doSomeThing(T t);
        }
        
        例如:在聲明泛型方法時使用extends
        public <T extends Action> void run(T t){
        
        }         

  舉例2:在聲明泛型方法時使用extends

public <T extends Action> void run(T t){
        }        

  舉例3:在聲明泛型類型變量時使用extends

List<? extends Number> list = new ArrayList<Integer>();
        List<? extends Number> list = new ArrayList<Long>();
        List<? extends Number> list = new ArrayList<Double>();
        //編譯報錯
        List<? extends Number> list = new ArrayList<String>();
        
        例如:
        public void test(List<? extends Number> list){
        
        }     

6.2、super關鍵字的使用

  舉例1:   

//編譯報錯
        //聲明泛型類或泛型接口時不能使用super
        public class Point<T super Number> {
    
        }
        public interface Action<T super Number> {
    
        }

        //編譯報錯
        //聲明泛型方法時不能使用super
        public <T super Action> void run2(T t){
        
        }     

  舉例2:在聲明泛型類型變量時使用super

//編譯通過
        List<? super Number> list1 = new ArrayList<Object>();
        List<? super Student> list2 = new ArrayList<Object>();
        List<? super Student> list3 = new ArrayList<Person>();

        //編譯通過
        public void test(List<? super Number> list){
        
        }
        
        //編譯通過
        public void test(List<? super Student> list){
        
        }

總結:

  ArrayList<T> al=new ArrayList<T>();指定集合元素只能是T類型
  ArrayList<?> al=new ArrayList<?>();集合元素可以是任意類型,這種沒有意義,一般是方法中,只是為了說明用法
  ArrayList<? extends E> al=new ArrayList<? extends E>();
  泛型的限定:
    ? extends E:接收E類型或者E的子類型。
    ?super E:接收E類型或者E的父類型。

七、泛型中的&

使用&可以給泛型加多個限定  

    public class A{
    
        }
        public inerface B{
            
        }    
        //不管該限定是類還是接口,統一都使用關鍵字extends
        //可以使用&符號給出多個限定
        //如果限定既有接口也有類,那麽類必須只有一個,並且放在首位置
        public class Point<T extends A&B> {    
        }

        class Sub extends A implements B{}
        main:
            //編譯報錯
            Point<A> p = new Point<A>();
            Point<B> p = new Point<B>();
    
            //編譯通過
            Point<Sub> p = new Point<Sub>();    

總結:我們可以觀察API中的Map接口及其方法的聲明

public interface Map<K,V>{
			public V get(Object key);
			public Set<Map.Entry<K,V>> entrySet();
			public Set<K> keySet();
			public void putAll(Map<? extends K,? extends V> m);
			..
		}   

  

覺得不錯的點個“推薦”哦!

javaSE(九)之泛型(Generics)