推荐下载Android框架基础知识梳理.docx

上传人:b****4 文档编号:4243935 上传时间:2022-11-28 格式:DOCX 页数:19 大小:23.30KB
下载 相关 举报
推荐下载Android框架基础知识梳理.docx_第1页
第1页 / 共19页
推荐下载Android框架基础知识梳理.docx_第2页
第2页 / 共19页
推荐下载Android框架基础知识梳理.docx_第3页
第3页 / 共19页
推荐下载Android框架基础知识梳理.docx_第4页
第4页 / 共19页
推荐下载Android框架基础知识梳理.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

推荐下载Android框架基础知识梳理.docx

《推荐下载Android框架基础知识梳理.docx》由会员分享,可在线阅读,更多相关《推荐下载Android框架基础知识梳理.docx(19页珍藏版)》请在冰豆网上搜索。

推荐下载Android框架基础知识梳理.docx

推荐下载Android框架基础知识梳理

Android框架基础知识梳理

2017/02/220转载自大神谷歌小弟的博客

 经过几年的发展和沉淀,Android开发中涌现出许多优秀的框架,比如:

Retrofit、Afinal、OKHttp、ButterKnife、AndFix等等。

这些框架的出现极大地简化

了开发流程,提高了工作效率。

在项目开发的过程中我们主要是使用这些轮子完成

项目,很难有时间去顾及框架的内部实现。

在项目交付之后我们可能就要去看看这

些框架的源码了。

 这些主流框架的功能各不相同,但每当打开浩繁的源码时我们几乎都可以看到反

射,注解,泛型的广泛应用;也正是这些技术使得框架具有了高度的灵活性,优良

的扩展性和健壮的稳定性。

鉴于这些框架必备知识的重要性故在此对这部分内容做

一个全面的梳理和总结

 主要内容:

 ClassLoaderClassLoader的分析几种不同ClassLoader的介绍ClassLoader的应用泛

型泛型的由来自定义泛型泛型的擦除反射class常用反射技术Type以及

ParameterizedType反射与泛型的结合使用注解常用注解的介绍和使用元注解自定义

注解及其使用1.ClassLoader在程序运行时首先要将类加载到内存中,这个加载工作

就是由ClassLoader完成的,故在中文文档中将其翻译为“类加载器”

 那么我们代码中所用到的类有什么不同呢?

——它们的“来源”是不一样的

 有的类是属于系统提供的类,比如:

String、Date、Object等因此,在Android

系统启动时会自动创建一个Boot类型的ClassLoader,该ClassLoader用于加载一些

系统层级的类

 有的类属于我们自己写的类,比如:

User、Girl、Beauty等等因此,每个APP会

创建一个自己的ClassLoader实例,该ClassLoader用于加载dex

 privatevoidgetClassLoaders(){ClassLoaderclassLoader=getClassLoader();while

(null!

=classLoader){System.out.println(“----classLoader=“+classLoader);classLoader

=classLoader.getParent();}}

 此处一共展示了三个ClassLoader

 第一个ClassLoader,如下:

dalvik.system.PathClassLoader[DexPathList[[zip_file”/data/app/com.lizi.classloaderdemo-

1/base.apk”],nativeLibraryDirectories=[/data/app/com.lizi.classloaderdemo-1/lib/x86,

/vendor/lib,/system/lib]]]

 该PathClassLoader在应用启动时创建,用于加载/data/app/cc.testreflection-

2/base.apk中的类

 ClassLoader是一个抽象类,它有三个常用的子类:

PathClassLoader、

URLClassLoader、DexClassLoader

 PathClassLoader它只能加载已经安装的apk中的资源,比如dex文件

URLClassLoader它只能用于加载jar文件中的资源。

但是dalvik不能直接识别jar,

因此这个加载器极少使用。

DexClassLoader它用于从.jar和.apk类型的文件内部加

载classes.dex。

该类加载器常用来完成动态加载apk的需求第二个ClassLoader,我

不是很清楚,嘿嘿,欢迎指点。

 第三个ClassLoader,如下:

 java.lang.BootClassLoader@112e4ef该BootClassLoader在系统启动的时候创建,用

于加载系统层级的类

 看看解释的这两个类加载器的应用

 privatevoidtestClassLoader(){try{Classclazz=

Class.forName(“cc.testreflection.Girl”);ClassLoaderclassLoader=

clazz.getClassLoader();System.out.println(“----classLoader=“+classLoader);

classLoader=mContext.getClass().getClassLoader();InputStreaminputStream=

classLoader.getResourceAsStream(“assets/ic_launcher.png”);System.out.println(“----

classLoader=“+classLoader);clazz=Class.forName(“java.lang.String”);classLoader=

clazz.getClassLoader();System.out.println(“----classLoader=“+classLoader);}catch

(Exceptione){}}

 我们自己的类com.lizi.classloaderdemo和assets文件夹中的图片ic_launcher.png都

是由PathClassLoader加载的,而java.lang.String是由BootClassLoader加载的

 2.泛型2.1概念泛型始现于JDK1.5,从那以后大家在项目常常使用泛型,比

如:

 ArrayListGirlarrayList=newArrayListGirlfor(inti=0;i10;i++){Girlgirl=new

Girl();arrayList.add(girl);}在与此类似的场景中利用泛型限定了集合中的输入类型,

从而让编译器屏蔽了源程序中的非法数据输入,比如此时往ArrayList中add一个

Boy就无法通过编译器的编译

 泛型主要是给编译器看的;那么在编译完成之后生成的字节码里泛型会发生什么

变化呢?

来看个例子:

 privatevoidtestArraylistClass(){Classclazz1=newArrayListInteger().getClass();

Classclazz2=newArrayListString().getClass();booleanisEqual=(clazz1==clazz2);

System.out.println(“----isEqual=“+isEqual);}输出结果:

 —-isEqual=true带不同泛型的ArrayList在编译后生成的Class是相同的!

也就是

说,泛型在编译生成字节码文件时会被”擦除”;不管ArrayList带什么泛型,在编译

后都是ArrayList所对应的字节码文件

 privatevoidtestArraylistGeneric(){try{ArrayListIntegerarrayList=newArrayList

IntegerarrayList.add(9527);arrayList.add(9528);Method

method=arrayList.getClass().getMethod(“add”,Object.class);

method.invoke(arrayList,”hello,java”);for(inti=0;iarrayList.size();i++){

System.out.println(“----arrayList.get(“+i+”)=“+arrayList.get(i));}}catch(Exception

e){}}输出结果如下图所示:

 看到了吧,之因此能把一个字符串add到该ArrayList中,究其原因还是因为泛型

的擦除所致

 2.2自定义泛型方法publicstaticTTgenericMethod1(Tt){returnnull;}publicK,V

KgenericMethod2(Kk,Vv){returnnull;}publicK,VStringgenericMethod3(Kk,Vv)

{returnnull;}在自定义泛型方法时,请注意在方法的返回值之前声明一个泛型,比

如:

这就表示该方法使用到了泛型T。

在此之后,在方法的输入参数中和方法体中

均可以使用该泛型

 2.3自定义泛型接口publicinterfaceUserInfoT{publicvoidprintUserInfo(T

t);}privateclassUserInfoImplTimplementsUserInfoT{@Overridepublicvoid

printUserInfo(Tt){}}在自定义泛型接口时,请注意在接口名之后声明一个泛型,比

如:

这就表示该接口使用到了泛型T。

在此之后,在接口定义方法时就可以使用该

泛型了

 2.4自定义泛型类publicclassCollectionK,V{privateKkey;privateVvalue;

privateKgetValue(Kk){returnnull;}privatevoidprintValue(Vv){}}自定义泛型类

与自定义泛型接口非常类似,不再赘述

 3.反射我们知道Java代码会被编译成字节码文件,当需要用一个类创建其对象的

时候就会将其对应的字节码文件装载到内层,然后新建对象。

 也就是说,当一个类编译完成后,在生成的.class文件中会产生一个Class对象,

该对象用于表示这个类的信息,比如类的属性,字段,构造方法等等

 既然Class中包含了这么多有用的信息,那么我们可以用什么方式获取Class呢?

 3.1获取Class//第一种方式Classclazz=Girl.class;System.out.println(“----“+

clazz.getName());//第二种方式Girlgirl=newGirl();clazz=girl.getClass();

System.out.println(“----“+clazz.getName());//第三种方式clazz=

Class.forName(“com.lizi.classloaderdemo.Girl”);System.out.println(“----“+

clazz.getName());三种方式:

 1.利用类名.class获取2.利用对象.getClass()获取3.利用Class.forName(“类名”)获取

在获取到Class之后,就可以利用newInstance()方法生成一个对象

 Objectobject=clazz.newInstance();其实,在调用newInstance()方法时实际上是调

用了该类的无参构造方法。

 当然,我们的目的不仅仅是利用newInstance()生成一个对象,更重要的是要采用

反射技术结合Class获取到该类的构造方法,属性,方法等信息

 在该类中有一些简单的属性,比如年龄,姓名,国家,城市,腰围,胸围,臀

围。

还有一些简单的方法比如,构造方法Girl(Stringname,Integerage),获取电话号

码getMobile();看到这里获取大家可能发现了:

这些属性和方法有的是公有的,有

的是私有的。

访问属性的不同会带来哪些差异呢?

带着这个小疑问,我们来看看常

见的反射使用方法

 3.2获取构造方法/***利用反射获取类的构造器**1getConstructors()获取类

的构造器,但获取不到私有构造器*2getDeclaredConstructors()获取类的所有构造

器*3getDeclaredConstructor()获取指定的构造器*/privatevoidtestGetConstructor()

{try{Classclazz=Class.forName(“com.lizi.classloaderdemo.Girl”);Constructor[]

Constructors=clazz.getConstructors();for(Constructorconstructor:

Constructors){

System.out.println(“----constructor=“+constructor);}System.out.println(“-----------------

-----------”);Constructor[]declaredConstructors=clazz.getDeclaredConstructors();for

(ConstructordeclaredConstructor:

declaredConstructors){System.out.println(“----

declaredConstructor=“+declaredConstructor);}System.out.println(“-------------2----------

-----”);Constructorconstructor=clazz.getDeclaredConstructor(String.class,Integer.class);

constructor.setAccessible(true);Girlgirl=(Girl)constructor.newInstance(“liuyan”,

Integer.valueOf(22));System.out.println(“----girl=“+girl);}catch(Exceptione){

e.printStackTrace();}}获取类所有的构造器,这个没啥可说的。

那么怎么获取指定的

构造器呢?

一个类可能有多个重载的构造方法,它们的方法名都是一样的;因此此

时需要从构造器的输入参数入手,比如:

 clazz.getDeclaredConstructor(String.class,Integer.class);就可以获取到如下的构造方

法:

 privateGirl(Stringname,Integerage){}但是请注意该构造方法是private的,因此需

要将该方法的accessible标志设置为true表示取消语言访问检查。

即:

 constructor.setAccessible(true);在获取构造方法后即可利用newInstance()创建对

象,即:

 Girlgirl=(Girl)constructor.newInstance(“liuyan”,Integer.valueOf(22));3.3利用反射

获取字段/***利用反射操作类的字段*1getFields()获取类的字段,但是获取不到

私有字段*2getDeclaredFields()获取类的所有字段*3获取指定的字段及其type*

4获取指定对象的某个字段值*5设置指定对象的某个字段值*/privatevoid

testGetField(){try{Classclazz=Class.forName(“com.lizi.classloaderdemo.Girl”);

Field[]fields=clazz.getFields();for(Fieldfield:

fields){System.out.println(“----field=“

+field);}Field[]declaredFields=clazz.getDeclaredFields();for(FielddeclaredField:

declaredFields){System.out.println(“-----declaredField=“+declaredField);}//获取指定

的字段及其typeFieldfield=clazz.getDeclaredField(“name”);Classtype=

field.getType();System.out.println(“----field=“+field+“,type=“+type);

System.out.println(“-----------------------“);//获取指定对象的某个字段值Girlgirl=new

Girl(“lucy”,100,100,100,18);Fieldfield2=clazz.getDeclaredField(“name”);

field2.setAccessible(true);Stringname=(String)field2.get(girl);System.out.println(“----

name=“+name);//设置指定对象的某个字段值Fieldfield3=

clazz.getDeclaredField(“name”);field3.setAccessible(true);field3.set(girl,“hanmeimei”);

System.out.println(“----girl=“+girl);}catch(Exceptione){}}3.4利用反射获取类中

的方法/***利用反射获取类的方法*1getMethods()获取该类及其父类的方法,但

不能获取到私有方法*2getDeclaredMethods()获取该类本身所声明的所有方法*3

反射出类中的指定方法*/privatevoidtestGetMethod(){try{Classclazz=

Class.forName(“com.lizi.classloaderdemo.Girl”);Objectobject=clazz.newInstance();

Method[]methods=clazz.getMethods();for(Methodmethod:

methods){

System.out.println(“----method=“+method);}Method[]declaredMethods=

clazz.getDeclaredMethods();for(MethoddeclaredMethod:

declaredMethods){

System.out.println(“----declaredMethod=“+declaredMethod);}Methodmethod=

clazz.getDeclaredMethod(“getMobile”,String.class);ClassreturnType=

method.getReturnType();System.out.println(“----method=“+method+”,returnType=“+

returnType);method.setAccessible(true);Stringmobile=(String)method.invoke(object,

“678”);System.out.println(“----mobile=“+mobile);}catch(Exceptione){}}3.5利用

反射操作数组/***利用反射操作数组*1利用反射修改数组中的元素*2利用反

射获取数组中的每个元素*/privatevoidtestArrayClass(){int[]intArray=new

int[]{5,7,9};Array.set(intArray,0,9527);Classclazz=intArray.getClass();if

(clazz.isArray()){intlength=Array.getLength(intArray);for(inti=0;ilength;i++){

Objectobject=Array.get(intArray,i);StringclassName=object.getClass().getName();

System.out.println(“----object=“+object+”,className=“+className);}}}3.6利用反射

获取泛型的参数类型在许多框架中有这样的需求:

根据不同的泛型参数响应不同的

操作。

 一说到泛型参数类型,可能大家立马就想到了刚才说的泛型擦除,比如ArrayList

在编译后就变成了ArrayList,它原本的泛型被”擦除”了。

但是我们有时确实需要知

道泛型的参数类型,又该怎么来实现呢?

按照刚才的那些思路恐怕是走不通了,得

另辟蹊径了

 第一步:

 定义getGenericHelper()方法其输入参数为带泛型的参数,比如ArrayList

String,Integer

 第二步:

 利用反射获取到该getGenericHelper()方法,即:

Method

method=getClass().getDeclaredMethod(“getGenericHelper”,HashMap.class);

 第三步:

获取到该方法的带泛型的输入参数,即:

 Type[]genericParameterTypes=method.getGenericParameterTypes();注意

getGenericParameterTypes()方法返回的是一个数组,因为方法可能有多个参数,但

是依据我们的需求这个数组中是仅有一个元素的

 4.2ParameterizedTypeParameterizedType称为参数化类型,比如HashMapK,

Integer

 privateHashMapK,IntegerhashMap=null;publicvoidtestParameterizedType()

throwsE

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1