參考文章
http://loveshisong.cn/%E7%BC%96%E7%A8%8B%E6%8A%80%E6%9C%AF/2016-02-16-Type%E8%AF%A6%E8%A7%A3.html
http://blog.csdn.net/gdutxiaoxu/article/details/68926515
話說學(xué)過java一直不知道Type這個(gè)東東,基礎(chǔ)還是不扎實(shí)呀~
為什么要學(xué)習(xí)這個(gè)東東呢朵诫?話說某一天小弟看到這么段代碼
public abstract class BaseActivity<T extends BasePresenter, E extends BaseModel> extends AppCompatActivity {
public T mPresenter;
public E mModel;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = TUtil.getT(this, 0);
mModel=TUtil.getT(this,1);
...
可以看到基類中定義了2個(gè)泛型一也,上限分別是BasePresenter,BaseModel
public class TUtil {
private static Type genericSuperclass;
public static <T> T getT(Object o, int i) {
try {
return ((Class<T>) ((ParameterizedType) (o.getClass()
.getGenericSuperclass())).getActualTypeArguments()[i])
.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (ClassCastException e) {
}
return null;
}
基類中生成T 转唉、E 對(duì)象的話我們肯定是不能new泛型的,那么生成的方法我有二種
① 使用注解依賴生成
② Java提供了運(yùn)行時(shí)期拿到類或者接口type信息的方法,這就需要了解Type和Class相關(guān)知識(shí)了
首先我們來一步步分析
mPresenter = TUtil.getT(this, 0); 中的this就是BaseActivity子類 ,調(diào)用getClass()獲取到子類對(duì)象的Class對(duì)象劝堪,然后調(diào)getGenericSuperclass()方法拿到BaseActivity的Type
我們看看api解釋
public Type getGenericSuperclass()
返回表示此Class
所表示的實(shí)體(類贬墩、接口呀闻、基本類型或 void)的直接超類的Type
。
如果超類是參數(shù)化類型秤涩,則返回的Type
對(duì)象必須準(zhǔn)確反映源代碼中所使用的實(shí)際類型參數(shù)帜乞。如果以前未曾創(chuàng)建表示超類的參數(shù)化類型,則創(chuàng)建這個(gè)類型筐眷。有關(guān)參數(shù)化類型創(chuàng)建過程的語義黎烈,請參閱 ParameterizedType
聲明。如果此Class
表示Object
類匀谣、接口照棋、基本類型或 void,則返回
null武翎。如果此對(duì)象表示一個(gè)數(shù)組類烈炭,則返回表示Object類的Class對(duì)象。
這里我們要明白Type是什么
public interface TypeType 是 Java 編程語言中所有類型的公共高級(jí)接口宝恶。它們包括原始類型梳庆、參數(shù)化類型、數(shù)組類型卑惜、類型變量和基本類型。
簡單說Type就是所有類型的原始接口,Type接口有幾個(gè)子接口
所有已知子接口:
GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType
ParameterizedType 表示參數(shù)化類型驻售,如 Collection<String>
類似這種參數(shù)泛型的對(duì)象得到的Type都是ParameterizedType
Type getGenericSuperclass()
返回表示此 Class 所表示的實(shí)體(類露久、接口、基本類型或 void)的直接超類的 Type欺栗。
拿到這個(gè)對(duì)象的所有參數(shù)類型的一個(gè)數(shù)組毫痕,比如Map<String,Person> map 這個(gè) ParameterizedType 返回的是 String 類,Person 類的全限定類名的 Type Array。
并且這個(gè)方法返回的是當(dāng)前類對(duì)象的直接父類的Type
比如上面案例代碼中獲得的Type就是直接父類的Type迟几,但是具體參數(shù)類型是子類申明的消请!這點(diǎn)需要注意
com.jaydenxiao.common.base.BaseActivity<com.jaydenxiao.androidfire.ui.news.presenter.NewsDetailPresenter, com.jaydenxiao.androidfire.ui.news.model.NewsDetailModel>
而拿到Type后就可以調(diào)用
Type[] getActualTypeArguments() 獲取此類型實(shí)際類型參數(shù)的 Type 對(duì)象的數(shù)組。
然后index 0就是申明的第一個(gè)類型參數(shù)com.jaydenxiao.androidfire.ui.news.presenter.NewsDetailPresenter
index1就是申明的第二個(gè)參數(shù)
com.jaydenxiao.androidfire.ui.news.model.NewsDetailModel
Type拿到了就可以強(qiáng)轉(zhuǎn)成Class對(duì)象調(diào)然后生成指定泛型類型的對(duì)象了
getRawType() 返回的就是getGenericSuperclass()
TypeVariable<D extends GenericDeclaration>:
api解釋----->各種類型變量的公共高級(jí)接口
這個(gè)就是我們聲明的成員變量的類型,<D extends GenericDeclaration>
GenericDeclaration這個(gè)是什么呢类腮?
舉個(gè)例子如果我在類中這樣申明泛型
class Demo<T extends Serializable & Comparable,V>
T t;
V v;
那么t的Type就是TypeVariable類型, 拿到TypeVariable對(duì)象后可以通過
getBounds()獲取到Type[]數(shù)組,由于這里我們指定t的類型為T并且這里通過&進(jìn)行上限符連接,所以getBounds拿到的都是一個(gè)數(shù)組,里面分別是Serializable,Comparable具體類型Class
同理v的TypeVariable的getBounds()拿到的就是V的具體類型的Class
D getGenericDeclaration()
這個(gè)方法獲取的是一個(gè)GenericDeclaration或者繼承GenericDeclaration的對(duì)象,拿到這個(gè)對(duì)象后調(diào)用getTypeParameters()方法可以拿到一個(gè)
TypeVariable<?>[]數(shù)組
而每個(gè)元素都可以通過getBounds()拿到Type[]數(shù)組然后得到每一個(gè)Class
GenericArrayType: 數(shù)組參數(shù)化類型
它就是由ParameterizedType或者TypeVariable<D>組成的數(shù)組
比如這種類型
T [] t 臊泰、 Collection<String> [] collections 這些都是GenericArrayType類型
一般我們在方法中申明這種參數(shù)類型時(shí),通過反射可以拿到方法中的參數(shù)類型
WildcardType 通配符類型
首先通配符 蚜枢? 這個(gè)概念可能很多童鞋會(huì)模糊缸逃,它跟前面申明的泛型T针饥、K啊什么的什么區(qū)別呢?
其實(shí)需频?就是一個(gè) 不確定的類型,如果我們簡單這樣申明一個(gè)Class類比如
class Simple <E>{
}
我們這樣創(chuàng)建Simple simple=new Simple(); 代表什么都不申明那么編譯時(shí)E就會(huì)被抹除,而用到E的地方都會(huì)被替換成Object,如果我們這樣申明Simple<String>simple=new Simple(); 那么E就會(huì)申明為String類型丁眼,編譯時(shí)都會(huì)被替換為String類型, 那如果這樣申明Simple<?>simple=new Simple(); 跟前面我們什么都不申明效果是一樣的,那么?與(E昭殉、T)區(qū)別是我總結(jié)了幾點(diǎn):
- 苞七?不能直接申明在類上,比如上面的這樣申明就會(huì)編譯報(bào)錯(cuò), 原因在2.
class Simple <挪丢?>{
}
- 類中申明的(E蹂风、T)是可以直接操作的,比如可以e=new E(),但是你沒法也不能? d=new ?();這樣這也是上面為什么沒法申明? 因?yàn)闆]意義
class Simple <E>{
E e;
}
- 那么你要疑問?有什么用,我們一般用作在方法中參數(shù)類的申明限定符,比如List中的
boolean addAll(Collection<? extends E> var1);
addAll參數(shù)是是一個(gè)Collection<? extends E> 吃靠,這樣申明我們就只能添加申明E子類類型的Collection硫眨,List <Object> object 這種addAll List <String> string沒事,但是反過來就會(huì)編譯錯(cuò)誤,
我們?nèi)绻@么申明一個(gè)變量 List <? extends View> list;
那么getGenericType()拿到的是ParameterizedType類型Type因?yàn)樗€是變量類型,然后調(diào)用getActualTypeArguments()就可以拿到<>里面的類型數(shù)組,因?yàn)榭赡苡?amp;符號(hào)連接形成多個(gè)類型,
那么類型數(shù)組里就是WildcardType 類型,而這個(gè)類型有二個(gè)方法
getLowerBounds() :顧名思義這個(gè)是獲取下邊界類型,List <? super View> list這樣獲取到的下邊界就是View
getUpperBounds() : 獲取上邊界類型巢块,比如上面申明獲取到的上邊界就是View
List <?> list;如果我們單獨(dú)就這么申明的話那么只能通過getUpperBounds() 獲取到Object