[关闭]
@natsumi 2018-03-15T09:04:30.000000Z 字数 11405 阅读 1343

Android 面试题总结

信意涵得offer


参考 https://bbs.byr.cn/#!article/MobileTerminalAT/33010
原作:dss886
并扩充了一些内容~

1. 计算机网络

1.1 ICMP协议是什么

  1. ICMP协议全称Internet Control Message Protocol,即网际控制报文协议。
  2. 是TCP/IP协议的一个子族,网络层。
  3. 用于在计算机、路由器之间传递控制消息,如网络通不通、主机是否可达、路由是否可用等等。
  4. ping命令即基于ICMP协议。
  5. 路由跟踪的traceroute/tracert等命令也基于ICMP

traceroute可以用ICMP ECHO、TCP SYN、UDP、UDPLITE、DCCP Request实现,中间路由节点返回ICMP超时报文,终点主机返回ICMP终点不可达报文。

1.2 DNS协议是什么

  1. DNS全称Domain Name System,即域名系统,一个用于映射域名和IP地址的分布式系统。
  2. DNS请求使用UDP协议,但本身属于应用层协议。
  3. DNS区域传送(辅DNS服务器和主DNS服务器同步)时使用TCP【参考http://benbenxiongyuan.iteye.com/blog/1088085

区传送:DNS的规范规定了2种类型的DNS服务器,一个叫主DNS服务器,一个叫辅助DNS服务器。在一个区中主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息。当一个辅助DNS服务器启动时,它需要与主DNS服务器通信,并加载数据信息,这就叫做区传送(zone transfer)

1.3 TCP和UDP的区别

UDP用户数据报协议

  1. 无连接,尽最大努力交付,不可靠
  2. 面向报文,不拆分或合并
  3. 没有拥塞控制
  4. 支持一对一、一对多,多对一,多对多的交互通信
  5. 首部开销小,只有8字节

TCP传输控制协议

  1. 面向连接,可靠交付
  2. 面向字节流,根据对方给出的窗口值和当前网络的拥塞程度决定报文长度,可能会对报文进行拆分或者合并。
  3. 提供拥塞控制功能
  4. 每一条TCP连接都只能是端到端的。
  5. 首部开销较大,固定部分就有20字节,还有选项部分和填充。

1.4 TCP拥塞控制算法

【预备知识】

  • 传输轮次:时间上就是一个RTT往返时间,传输轮次更强调把拥塞窗口允许发送的报文都发出去并收到了对已发送的最后一个字节的确认

  • MSS最大报文长度,指TCP数据字段的最大长度,不含首部。默认536字节,也可在TCP首部的选项中定义。

  1. 慢开始:拥塞窗口cwnd一开始很小(一般为1×MSS)但是很快地(每轮次翻倍1,2,4,8...)增长上来,直到达到慢开始门限。
  2. 拥塞避免:达到慢开始门限后,拥塞窗口每传输轮次+1,发生拥塞后,重置门限为当前cwnd的一半,cwnd置为1,进入慢开始。
  3. 快重传:TCP利用3个相同的ACK来判定数据包丢失,开始快去重传,不必等待该报文的重传计时器。
  4. 快恢复:发生快重传时网络很有可能没有拥塞,门限折半后不再慢开始,cwnd置为门限值,直接开始拥塞避免算法。

1.5 TCP为什么断开连要三次握手和四次握手?

  1. TCP是全双工的,每一个方向都必须单独进行开关,所以需要四次握手。
  2. 四次握手后A需要等待2MSL(最大报文段寿命)时间
  3. 建立连接时发起者A的两个方向是默认打开的,B可以省去一个通知A打开的请求,所以只需要三次握手。
  4. A进行第三次握手,可以避免已失效的链接请求报文突然传送到了B,因而产生错误。

2. Java基础

2.1 HashMap和HashTable的区别

2.2 SoftReference和WeakReference的区别

2.3 HashMap冲突后的处理方法

2.4 equal()方法重写时要注意的点

2.5 String为什么要设计成不变的

  1. String a = "123";
  2. String b = "123";
  3. String c = new String("123");
  4. System.out.println(a == b);
  5. System.out.println(a == c);

输出为:true,false

2.6 Java优先级队列的实现原理

https://github.com/xietiantian/JCFInternals/blob/master/markdown/8-PriorityQueue.md

2.7 Java虚拟机GC的原理

Java GC的原理
http://www.cnblogs.com/meitian/p/4570621.html
聊聊JVM的年轻代
http://ifeve.com/jvm-yong-generation/

  • 标记清除算法缺点是效率比较低,容易出现内存碎片,一般很少用到。
  • 复制算法缺点是浪费内存多,不适用于大对象和存活时间长的对象,一般用于新生代对象的GC。
  • 标记整理算法克服了内存碎片,但缺点仍是效率不高,一般用于老年代对象的GC。

2.8 Java堆和栈的区别

【注】堆和栈在数据结构和编程语言实现里的意思不一样。

作为数据结构,栈是后入先出的线性结构;堆是一个树,父节点总是大于(或者总是小于)子节点,用于实现优先队列。

但在编程语言实现、运行时环境、虚拟机的语境下,栈(调用栈)是维护嵌套函数调用状态的结构,主要是保存局部变量的值和返回地址;堆是动态内存分配的空间,生存期超出函数的范围,结构根据具体的分配算法以及垃圾回收算法而不同。

2.9 面向对象三大特性

封装

  • 把属性和行为结合成一个独立的类
  • 尽可能隐蔽类(对象)的内部细节,只保留有限的对外接口使之与外部发生联系
  • 封装的特性使得类(对象)以外的部分不能随意存取类(对象)的内部数据(属性),保证了程序和数据不受外部干扰且不被误用

继承

  • 代码复用的重要手段
  • Java的继承具有单继承的特点
  • 父类和子类的关系,是一种一般和特殊的关系。就像是水果和苹果的关系。或者说子类和父类是is-a的关系
  • extends:扩展+继承。子类扩展父类,子类可以继承父类的部分属性和方法。

多态

  • 父类中定义方法被子类继承之后,可以表现出不同的行为。这使得同一个方法在父类及其各子类类中具有不同的含义。
  • Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就会出现所谓的多态。

2.10 Java的可变参数

  1. 适用于参数个数不确定,类型确定时。
  2. 只能出现在参数列表的最后。
  3. Java把可变参数当做数组处理。
  1. public static int add(int x,int ...args){
  2. int sum = x;
  3. for(int i = 0; i < args.length; i++){
  4. sum += args[i];
  5. }
  6. return sum;
  7. }

2.11 Java用擦除实现范型的原因

Java泛型(一)、泛型的基本介绍和使用【这个太基础,不用再看了】
http://blog.csdn.net/lonelyroamer/article/details/7864531

java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
http://blog.csdn.net/lonelyroamer/article/details/7868820

  1. 纯技术角度考虑,Java实现类似C++模板的范型是相当简单的,Java不仅在2014年的Poject Valhalla的Model1中实现过,在更早的1996年的实验语言Pizza中也实现过。
  2. Java强调二进制向后兼容性,即低版本编译器生成的class文件要能在高版本的JRE上运行。
  3. 要保持兼容性的情况下在没有范型的基础上实现范型有两种思路:一是需要范型的类型(主要是容器类Collections)原有的不变,然后平行地加一套范型版本;二是让所有需要范型的类型原地范型化。
  4. C#在1.1至1.2时选择了第一条路,Java在1.4至1.5时选择了第二条。
  5. 第一个原因是C#在1.1时代码并不多,整个体系都在微软的控制下,变更比较容易,而Java1.4时已经有大量生产代码用于生产环境,如果新功能需要做大量源码级的修改,会大大影响新功能的普及。
  6. 第二个原因是,Java1.1至1.2时推翻过一次容器类的设计(Vector、HashTable),如果再加一套范型化的容器类画面实在太美。

2.12 如何定义一个Annotation【TODO】

  1. public @interface CustomAnnotation{}
  2. 元注解Target、Retention、Documented、Inherited
  3. 域 public String name() dafault "xx";

2.13 volatile关键字的作用【TODO 没看完&没看懂】

Java 理论与实践: 正确使用 Volatile 变量
https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

  1. volatile只能用在域变量上,作用是保证变量的可见性和读写操作的有序性。
  2. Java执行“int x = new Object()”时有三个步骤:1在栈帧中给x变量分配空间;2在堆中初始化Object;3将x指向Object。JVM不能保证其中2、3步的执行顺序,在多线程并发情况下x不为null时这个对象不一定初始化完成了,而volatile关键字正是用来保证这一点的,即读操作一定在写操作完成之后。
  3. volatile不是被设计用来多线程同步的,最常用的场景是懒加载双重检查的单例模式。
  4. 在JVM的实现中,volatile要比synchronized轻量,消耗资源更少。

2.14 notify了一个锁,wait的线程一定会被唤醒继续执行吗?

看线程状态和线程调度的部分
https://www.zybuluo.com/natsumi/note/531068#2-%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E8%BD%AC%E6%8D%A2

2.15 类的初始化顺序

三条规则,优先级依次下降

根据上面三条规则,总结顺序:

父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器

2.16 内部类

http://www.cnblogs.com/dolphin0520/p/3811445.html

3. Android基础

3.1 触摸事件的分发

3.1.1 View的事件分发

http://blog.csdn.net/guolin_blog/article/details/9097463/

  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
  3. mOnTouchListener.onTouch(this, event)) {
  4. return true;
  5. }
  6. return onTouchEvent(event);
  7. }

上面是View类的dispatchTouchEvent方法

3.1.2 ViewGroup的事件分发

源码分析ViewGroup的事件分发
http://blog.csdn.net/guolin_blog/article/details/9153747/

图解Android事件分发
http://www.jianshu.com/p/e99b5e8bd67b

关于事件分发的11个结论看一看~
http://www.jianshu.com/p/39ec5a50c213

3.2 Handler原理

MessageQueue:它的内部存储了一组数据,以队列的形式向外提供了插入和删除的工作。但是它的内部实现并不是队列,而是单链表。

Looper:会不停检查是否有新的消息,如果有就调用最终消息中的Runnable或者Handler的handleMessage方法。对应提取并处理消息。Looper内部持有一个MessageQueue、线程、主线程、ThreadLocal<Looper>。主要的方法有:

  • prepare:为当前线程创建一个Looper。
  • quit:退出Looper,Looper退出后,Handler的send方法会返回false,在子线程手动创建的Looper最好在不需要的时候终止掉。
  • quitSafely:把消息队列中已有的消息处理完毕后退出。
  • getMainLooper:在任何地方获取主线程的Looper。
  • getLooper:获取当前线程的Looper。
  • loop:最重要的一个方法,只有调用了loop方法后,消息循环系统才能起作用。

Handler:Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现,不过最后都是通过send的一系列方法实现的。对应添加消息和处理线程。
Handler持有一个LooperMessageQueue(即Looper持有的那个消息队列)、Callback

Callback的优先级比Handler的handleMessage优先级高。

  1. /**
  2. * Handle system messages here.
  3. */
  4. public void dispatchMessage(Message msg) {
  5. if (msg.callback != null) {
  6. handleCallback(msg);
  7. } else {
  8. if (mCallback != null) {
  9. if (mCallback.handleMessage(msg)) {
  10. return;
  11. }
  12. }
  13. handleMessage(msg);
  14. }
  15. }

提供多种创建方法,默认的Handler()将使用当前线程的Looper,如果当前线程没有Looper会抛出异常,要先prepare。

  1. new Thread(){
  2. Handler handler = null;
  3. public void run(){
  4. Looper.prepare();
  5. handler = new Handler();
  6. Looper.loop();
  7. };
  8. }.start();

也可以通过传参指定Looper。sendMessage方法可以往消息队列添加消息。handleMessage方法在创建Handler的线程中或者指定的Looper持有的线程中处理消息。

ThreadLocal:一个线程内部的数据存储类,通过它可以在指定的线程中储存数据,而其它线程无法获取到。在Looper、AMS中都有使用。ThreadLocal的get和set方法操作的数据,在每个线程中是相互独立,互不干扰的。

一个Thread只能持有一个Looper。
一个Looper可以被多个Handler持有。

3.2.1 Handler.postDelay()精确延迟指定时间的原理

http://www.dss886.com/2016/08/16/01/

3.3 Fragment的生命周期

http://blog.csdn.net/forever_crying/article/details/8238863/

3.4 Serializable和Parcelable的区别

https://zybuluo.com/natsumi/note/697988

3.5 一个Activity启动另外一个Activity并返回的生命周期调用

A.onCreate()
A.onStart()
A.onResume()

A.onPause()
B.onCreate()
B.onStart()
B.onResume()
A.onStop()

B.onPause()
A.onRestart()
A.onStart()
A.onResume()
B.onStop()
B.onDestory()

3.6 startService和bindService的区别

  1. startService启动的Service在调用者自己退出而没有调用stopService时会继续在后台运行。
  2. bindService启动的Service生命周期会和调用者绑定,调用者退出时Service也会调用unBind()->onDestory()退出。
  3. 先调用startService再调用bindService时Service也只会走一遍生命周期。
  4. 除了startService和bindService,Service的生命周期只有三个方法:onCreate()、onStartCommand()、onDestoty()。

3.7 如何监听ListView的item被回收了?

  1. //ListView
  2. AbsListView.setRecyclerListener(RecyclerListener listener)
  3. RecyclerListener.onMovedToScrapHeap(View view)
  4. //RecyclerView
  5. RecyclerView.setRecyclerListener(RecyclerListener listener)
  6. RecyclerListener.onViewRecycled(ViewHolder holder)

3.8 什么是属性动画

  1. Android在3.0引入属性动画的原因是视图动画有两个无法克服的缺点:只能对View进行操作,只支持移动、缩放、旋转和淡入淡出。
  2. 属性动画不针对View来设计,实际上是一种不断地对值进行操作的机制。
  3. ValueAnimator是针对值来进行变更的动画,值可以是int或float或任意对象。如果是对象的话需要实现TypeEvaluator,int和float是可选的。
  4. ObjectAnimator继承ValueAnimator,可以对任意对象的任意属性执行变更动画,前提是属性有get和set方法。

3.9 Android系统是如何保证一个线程只有一个Looper的

Android如何保证一个线程最多只能有一个Looper?
http://blog.csdn.net/sun927/article/details/51031268

  1. Looper.prepare()使用了ThreadLocal来保证一个线程只有一个Looper。
  2. ThreadLocal是Java1.5中提供的多线程保持对象的方法和避免参数传递路径过长的解决方案(注意它并不是被设计用于多线程通信或同步的)

3.10 ListView的ViewType的限制

ListView优化之ViewType使用
http://www.cnblogs.com/avenwu/archive/2013/04/09/3010462.html

RecyclerView.Adapter中的viewType
http://blog.csdn.net/uestcyms/article/details/51087882

  1. 只能是数字
  2. 取值[0, getViewTypeCount() - 1]
  3. 见android.widget.Adapter类的getItemViewType()方法的注释

3.11 什么是ViewStub

ListView之ViewStub的懒加载!
http://blog.csdn.net/joychine/article/details/43271291

  1. ViewStub是一个轻量级的View,用于延迟加载布局和视图
  2. 它不可见时不占布局位置、所占资源非常少。当可见时或调用ViewStub.inflate时它所指向的布局才会初始化
  3. ViewStub只能被inflate一次,一旦构建后就变成view了。
  4. ViewStub只能用来inflate一个布局,不能inflate一个具体的View

3.12 SurfaceView的特点【TODO】

  1. SurfaceView拥有独立的绘图表面,即它的UI可以在独立线程中绘制
  2. Android系统的UI由SurfaceFlinger服务负责绘制,每一个窗口有一个Layer用于描述它的绘图表面,所以可以实现独立于主线程进行绘制

3.13 如何定义一个Gradle Task【TODO】

  1. 定义Task类型:class HelloWorldTask extends DefaultTask{}
  2. @TaskAction用来标记这个task被执行时调用的方法:@TaskAction def hello {println "Hello World"}
  3. @Optional用来标记可选变量:@Optional String message = "m";
  4. 定义Task时即可指定Task类型,同时也可定义可选变量(如果有的话):
  5. task hello(type: HelloWorldTask)
  6. task hello(type: HelloWorldTask){message = "message"}

3.14 Gson的原理

Google的JSON解析库进阶使用
http://www.dss886.com/2016/01/19/01/
Json转化Java对象工具对比
https://www.zhihu.com/question/27242003/answer/58874167

  1. 如果使用默认的new Gson()对象,则采用反射来进行json的解析。
  2. 如果使用GsonBuilder来创建,并使用自定义的TypeAdapter,则会用自定义的TypeAdapter来解析json字符串。

3.15 如何调试ANR

  1. DDMS输出的LOG可以判断ANR发生在哪个类,但无法确定在类中哪个位置
  2. 在/data/anr/traces.txt文件中保存了ANR发生时的代码调用栈,可以跟踪到发生ANR的所有代码段
  3. adb pull 来pull traces文件到电脑上

3.16 Android程序方法数上限65535是怎么来的?【TODO】

  1. 方法数超限后的错误发生在构建期
  2. Dex的文件定义中方法数的索引长度为32位(2^32=65536×65536),所以不是Dex文件格式的限制
  3. Dalvik虚拟机的指令集中,B类查询参数(@BBBB)的长度为16位,所以支持的最大方法数是65535
  4. 不仅包括方法数,还包括field数和class数,所以dx(class转dex的)工具会对其进行检查,超限就会报错
  5. ART虚拟机在安装应用时会自动将多个dex文件编译成一个.ota文件用于执行,所以理论上不存在方法数超限的问题
  6. 但是由于目前apk标准中仍然使用.dex作为可执行文件的格式,为保证向下兼容Dalvik,dx工具在构建时仍然会对方法数进行检查,与实际运行环境是Dalvik还是ART无关

3.17 ListView的复用

ListView复用和优化详解
http://blog.csdn.net/u011692041/article/details/53099584

recyclerView
http://www.open-open.com/lib/view/open1482736519587.html

3.18 View的事件体系和工作原理

http://www.jianshu.com/p/39ec5a50c213

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注