久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java 泛型在實(shí)際開(kāi)發(fā)中的應(yīng)用

 流曲頻陽(yáng) 2017-07-11

一:泛型出現(xiàn)的背景

在java代碼里,,你會(huì)經(jīng)常發(fā)現(xiàn)類似下邊的代碼:

復(fù)制代碼

public class Test {    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("hah");        //list.add(new Test());       // list.add(1);
        for (Object object : list) {
            String s1 = (String)object;            //.....如果是你你該如何拿出list的值,如果list中放著上邊的不同類型的東西,。無(wú)解        }
    }
}

復(fù)制代碼

  編碼的時(shí)候,,不加泛型是可以的,但是 你從容器中拿出來(lái)的時(shí)候必須強(qiáng)制類型轉(zhuǎn)換,,第一是多敲很多代碼,,第二極容易發(fā)生類型轉(zhuǎn)換錯(cuò)誤,這個(gè)運(yùn)行時(shí)異常 比如你把上邊

注釋的代碼放開(kāi),,程序在獲取容器的地方就會(huì)報(bào)運(yùn)行時(shí)異常 ClassCasrException

Java語(yǔ)言的設(shè)計(jì)者引入了泛型,,暫時(shí)先不追究它內(nèi)在是怎么實(shí)現(xiàn)的。只需要知道,,如果我們像下邊這么寫,,我們就不需要強(qiáng)制類型轉(zhuǎn)換。我們也不需要擔(dān)心運(yùn)行是異常了,。

List<String> newList = new ArrayList<String>();
newList.add("hhe");
newList.add("123");
String s1 = newList.get(0);//不需要強(qiáng)制類型轉(zhuǎn)換,,因?yàn)槲壹恿朔盒停揖驼J(rèn)為它里邊一定都是String

二: 泛型的語(yǔ)法使用

1:使用具體的泛型類型: 尖括號(hào)內(nèi)帶有具體的類型,??梢韵薅ㄟ@個(gè)Map的key和value只能是字符串

Map<String, String> map = new HashMap<String, String>();
map.put("key","value");
String value = map.get("key")

從面向?qū)ο蟮慕嵌瓤矗褂脤?duì)象的時(shí)候,,泛型內(nèi)傳入的具體的類型,。聲明的時(shí)候采用尖括號(hào)內(nèi)加占位符的形式,比如這是HashMap的源碼

復(fù)制代碼

public class HashMap<K,V>    extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable{
    ...   public HashMap(Map<? extends K, ? extends V> m) {        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY),     DEFAULT_LOAD_FACTOR);
        putAllForCreate(m);
    }  
    ...      public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);        return (e == null ? null : e.value);
    }   
}

復(fù)制代碼

 2:方法聲明的時(shí)候 : public  <T> T getValue(){...}

  在上邊的代碼中,,我們可以看到在類上如何定義泛型,也看到了類上定義的占位符在類的普通方法上可以直接使用,。但是如果想在靜態(tài)方法上定義泛型,,這需要單獨(dú)的處理  。下面我們單獨(dú)對(duì)方法上如何定義

和使用泛型進(jìn)行介紹(注意:方法上是否定義泛型和類上是否定義沒(méi)有必然的聯(lián)系)

比如Web項(xiàng)目中,泛型是修飾類型的,,在方法上,,一般就是返回值和參數(shù)列表

  •   返回值類型:可以定義為L(zhǎng)ist<String>等形式,但是實(shí)際開(kāi)發(fā)中,,一般都是不知道具體類型,,定義形式如下  <T> List<T> test(T t){...} ,前邊的<T>可以理解為泛型的聲明,,你只有聲明了T,你才可以在              方法中用到T,這一具體的類型,, List<T>是具體的返回值類型。

  •   方法傳參: 可以用占位符限定的容器 比如 List<T>,,或者直接是占位符 T  

復(fù)制代碼

public class BaseServiceImpl implements BaseService {    protected <T> List<T> calcPage(String hql, PageContext pageContext,
            Object... params) {        int total = getDataTotalNum(hql, params);
        pageContext.setTotal(total);
        List<T> list = (List<T>) getPageDataByHQL(hql, pageContext.getRows(),
                pageContext.getPage(), pageContext.getTotal(), params);        return list;
    }
    @Override
    @Sync    public void deleteBatchVO(final List<?> dataList) throws ServiceException {
        baseDAO.deleteBatchVO(dataList);
    }
    @Override    public List<?> getPageDataByHQL(final String hql,            final Map<String, Object> filter) throws ServiceException {        return baseDAO.getPageDataByHQL(hql, filter);
    }
}

復(fù)制代碼

簡(jiǎn)單的例子:

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

 方法定義的時(shí)候,,泛型是這樣設(shè)計(jì),在使用的時(shí)候,,代碼如下:

List<TaclUserinfo> list = calcPage(hqluser1.toString(), pageContext,
                taclRole.getRoleid(), taclRole.getTenantId());//返回值類型 是<T>List<T>的,,j接收的時(shí)候,我直接用List<具體類>

3 :類或者接口使用泛型  interface Collection<V> {..}

  上邊的HashMap代碼中,,也看到了在類上使用泛型的具體例子,。在真正的項(xiàng)目上,一些基礎(chǔ)的公共類經(jīng)常定義泛型,,如下:

復(fù)制代碼

 1 public interface GenericDao<T, ID extends Serializable> { 2  3     public abstract void saveOrUpdate(T t) throws DataAccessException; 4  5     public abstract T get(ID id) throws DataAccessException; 6  7     public abstract List<T> query(String queryString) throws DataAccessException; 8  9     public abstract Serializable save(T t) throws DataAccessException;10 11     public abstract void saveOrUpdateAll(Collection<T> entities) throws DataAccessException;12 13     public abstract List<T> loadAll() throws DataAccessException;14 15     public abstract void merge(T t) throws DataAccessException;16 17 }

復(fù)制代碼

接口的實(shí)現(xiàn)類: 傳入?yún)?shù)為T,,實(shí)現(xiàn)類中也可以繼續(xù)用T,返回為T也可以用T;實(shí)現(xiàn)的時(shí)候 可以用 extends限定泛型的邊界。

復(fù)制代碼

public abstract class GenericDaoImpl<T extends BaseEntity, ID extends Serializable> extends
        HibernateDaoSupport implements GenericDao<T, ID> {    
    public void merge(T t) throws DataAccessException {
        TenantInterceptor.setTenantInfoToEntity(t);
        getHibernateTemplate().merge(t);
    }    
         public T get(ID id) throws DataAccessException {        // getHibernateTemplate().setCacheQueries(true);
        T load = (T) getHibernateTemplate().get(getEntityClass(), id);        return load;
    }    
}

復(fù)制代碼

具體使用的時(shí)候:

public class UserDao extends GenericDaoImpl<User, Serializable> {
    ...//比如get() merge()這些方法不需要在單獨(dú)編寫,,直接調(diào)用}

4:  聲明帶邊界的泛型   class userDao<T extends BaseEntity>

  Java中泛型在運(yùn)行期是不可見(jiàn)的,,會(huì)被擦除為它的上級(jí)類型。如果你是無(wú)界的泛型參數(shù)類型,,就會(huì)被替換為Object. 

復(fù)制代碼

public class RedColored<T extends Color> {    public T t;    public void color(){
        t.getColor();//T的邊界是Color,所以可以調(diào)用getColor(),,否則會(huì)編譯報(bào)錯(cuò)    }
}abstract class Color{    abstract void getColor();
}

復(fù)制代碼

   類似這樣的定義形式:GenericDaoImpl<T extends BaseEntity, ID extends Serializable> ,java重載了extends,標(biāo)注T的邊界就是BaseEntity,。如果需求是繼承基類,,那么邊界定義在子類上

類似 

class Colored2<T extends Color> extends RedColor<T>

5:用于通配符  <?>

   參考于( Java 通配符解惑  )泛型類型的子類型的不相關(guān)性。比如 現(xiàn)在List<Cat>并不是List<Anilmal>是兩種不同的類型;且無(wú)繼承關(guān)系 ,。那么,,我們像想要傳入的參數(shù)既可能是List<Cat>

也有可能是List<Annimal>

復(fù)制代碼

public class AnimalTrainer {    public void act(List<? extends Animal> list) {//備注:如果用 List<Animal> 作為形參列表,是無(wú)法傳入List<Cat>for (Animal animal : list) {
            animal.eat();
        }
    }
}

復(fù)制代碼

  act(List<,? extends Animal> list),當(dāng)中“,?”就是通配符,而“,? extends Animal”則表示通配符“,?”的上界為Animal,,換句話說(shuō)就是,“,? extends Animal”可以代表Animal或其子類,,可代表不了Animal的父類(如Object),因?yàn)橥ㄅ浞纳辖缡茿nimal,。

所以,,泛型內(nèi)是不存在父子關(guān)系,但是利用通配符可以產(chǎn)生類似的效果:

假設(shè)給定的泛型類型為G,,(如List<E>中的List),兩個(gè)具體的泛型參數(shù)X,、Y,當(dāng)中Y是X的子類(如上的Animal和Cat))

  • G<? extends Y> 是 G<? extends X>的子類型(如List<? extends Cat> 是 List<? extends Animal>的子類型),。

  • G<X> 是 G<? extends X>的子類型(如List<Animal> 是 List<? extends Animal>的子類型)

  • G<?> 與 G<? extends Object>等同,,如List<?> 與List<? extends Objext>等同 

三: 泛型可以用到那些地方

    泛型可以用到容器,方法,,接口,,內(nèi)部類,抽象類

四: Java中泛型獨(dú)特之處

    泛型是Java1.5之后才引入的,,為了兼容,。Java采用了C++完全不同的實(shí)現(xiàn)思想。Java中的泛型更多的看起來(lái)像是編譯期用的,,比如我定義一個(gè)使用泛型的demo

我在查看它的class文件時(shí),,發(fā)現(xiàn)class文件并沒(méi)有任何泛型信息。

Java會(huì)在編輯期把泛型擦除掉

  在JAVA的虛擬機(jī)中并不存在泛型,,泛型只是為了完善java體系,,增加程序員編程的便捷性以及安全性而創(chuàng)建的一種機(jī)制,在JAVA虛擬機(jī)中對(duì)應(yīng)泛型的都是確定的類型,,在編寫泛型代碼后,,java虛擬中會(huì)把這些泛型參數(shù)類型都擦除,用相應(yīng)的確定類型來(lái)代替,,代替的這一動(dòng)作叫做類型擦除,,而用于替代的類型稱為原始類型,在類型擦除過(guò)程中,,一般使用第一個(gè)限定的類型來(lái)替換,,若無(wú)限定,則使用Object.

擦除的原理以及邊界

  關(guān)鍵在于從泛型類型中清除類型參數(shù)的相關(guān)信息,,并且再必要的時(shí)候添加類型檢查和類型轉(zhuǎn)換的方法,。

  可以參考Java泛型-類型擦除。 運(yùn)行期編譯期會(huì)去掉泛型信息,,轉(zhuǎn)換為左邊界,,在調(diào)用的地方添加類型轉(zhuǎn)換,。

泛型擦除肯可能導(dǎo)致的問(wèn)題

用泛型不可以區(qū)分方法簽名

復(fù)制代碼

public void test(List<String> ls){
                System.out.println("Sting");
            }            public void test(List<Integer> li){
                System.out.println("Integer");
            }//這回報(bào)錯(cuò),,編譯期無(wú)法區(qū)分這兩個(gè)方法

復(fù)制代碼

泛型類的靜態(tài)變量是共享

復(fù)制代碼

public class StaticTest{    public static void main(String[] args){
        GT<Integer> gti = new GT<Integer>();
        gti.var=1;
        GT<String> gts = new GT<String>();
        gts.var=2;
        System.out.println(gti.var);
    }
}class GT<T>{    public static int var=0;    public void nothing(T x){}
}

復(fù)制代碼

五: 泛型中特殊使用

   java中的泛型不只是上述說(shuō)的內(nèi)容,,還有一些特殊的地方,如果這些地方也用泛型該怎么設(shè)計(jì),。比如說(shuō)“動(dòng)態(tài)類型”,,“潛在類型”,“異?!?/p>

程序如果運(yùn)行時(shí)需要類型信息

  就在調(diào)用的地方傳入類型信息

異常中使用泛型

  不能拋出也不能捕獲泛型類的對(duì)象,。事實(shí)上,泛型類擴(kuò)展Throwable都不合法,,因?yàn)榉盒托畔?huì)被擦除,,相當(dāng)于catch兩個(gè)相同的異常,是不可以的

數(shù)組與泛型

  不能聲明參數(shù)化類型的數(shù)組,, 數(shù)組可以記住自己的元素類型,,不能建立一個(gè)泛型數(shù)組。(當(dāng)然 你如果用反射還是可以創(chuàng)建的,,用Array.newInstance,。這里說(shuō)不能建是不能用普通方法)

泛型的一些其他細(xì)節(jié):  

  1.基本類型無(wú)法作為類型參數(shù)即ArrayList<int>這樣的代碼是不允許的,如果為我們想要使用必須使用基本類型對(duì)應(yīng)的包裝器類型ArrayList<Integer>

  2.在泛型代碼內(nèi)部,,無(wú)法獲得任何有關(guān)泛型參數(shù)類型的信息換句話說(shuō),,如果傳入的類型參數(shù)為T,即你在泛型代碼內(nèi)部你不知道T有什么方法,,屬性,,關(guān)于T的一切信息都丟失了(類型信息,博文后續(xù)),。

  3.注,,在能夠使用泛型方法的時(shí)候,盡量避免使整個(gè)類泛化,。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多