北邮人论坛DSS886安卓面试总结

虽然是面向Android开发,但也有一部分计算机基础和Java语言的内容

第一部分:计算机基础

一、ICMP协议是什么

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

二、DNS协议是什么

  1. DNS全称Domain Name System,即域名系统,一个用于映射域名和IP地址的分布式系统。
  2. DNS请求使用UDP协议,但本身属于应用层协议。

三、堆和栈的区别

  1. 栈空间由操作系统分配和释放,堆由程序分配和释放。
  2. 栈空间需要提前申请大小,申请完后大小不可变,速度较快;堆空间可动态申请,速度较慢。
  3. 数据结构不同,栈是先进后出的线性数据结构,堆的结构是树。

四、TCP和UDP的区别

  1. TCP是传输控制协议,面向字节流,提供拥塞控制功能;UDP是用户数据报协议,面向报文,尽最大努力交付数据;
  2. TCP是面向连接的协议,UDP是面向非连接的协议。
  3. TCP是传输可靠型协议,UDP是传输不可靠型协议。
  4. TCP的速度较慢,UDP的速度较快。

五、TCP拥塞控制逻辑

  1. 主要由拥塞窗口cwnd实现,具体逻辑主要包括慢启动、快速重传和快速恢复等。
  2. 慢启动:窗口一开始很小(一般为1)但是很快地(指数级)增长上来,直到达到慢启动门限。
  3. 快速重传:TCP利用3个相同的ACK来判定数据包丢失,开始快去重传
  4. 快速启动:重传后的慢启动

六、TCP为什么断开连接要四次握手?

  1. TCP是全双工的,每一个方向都必须单独进行开关,所以需要四次握手。而建立连接时发起者A的两个方向是默认打开的,B可以省去一个通知A打开的请求,所以只需要三次握手。

第二部分:Java基础

一、HashMap和HashTable的区别

  1. HashMap是线程不安全的,HashTable是线程安全的,所以HashTable通常要比HashMap慢。
  2. HashMap的迭代器是fast-fail的,即当迭代时HashMap的结构被改变了,会抛出ConcurrentModificationException,而HashTable则不会。
  3. HashMap不保证随着时间的推移Map中元素的次序是不变的。
  4. HashMap的主键可以为null

二、SoftReference和WeakReference的区别

  1. SoftReference只有当JVM即将OutOfMemory时才会被回收。
  2. WeakReference只要GC就会被回收。

三、HashMap冲突后的处理方法

  1. 开放地址法:又称再散列法,如果散列值p1冲突了,则基于p1再生成另一个地址p2,以此类推;常用再散列函数如线性探测、二次探测和伪随机数序列等。
  2. 链地址法:Java8中一个链长度超过8会转化为红黑树,减少查找时间。

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

  1. 判断对象非空
  2. 自反性、对称性、传递性、一致性

五、new String()

1
2
3
4
5
6
String a = "123";
String b = "123";
String c = new Sting("123");

System.out.println("a == b" + (a == b));
System.out.println("a == c" + (a == c));
  1. 输出为:true,false
  2. String是final类,编译期指定的字符串会指向字符串池中的对象。
  3. 运行时生成的String类会先在heap中建立一个对象,同时去字符串池中寻找这个字符串,如果没有则创建一个。

六、Java优先级队列的实现原理

  1. PriorityQueue使用优先级堆实现
  2. 使用堆排序算法进行快速调整

七、Java虚拟机GC的原理

  1. JVM的GC采用根搜索算法。
  2. GC Roots一般有四种:栈帧的本地变量表中引用的对象,方法区中的静态成员,方法区中的常量引用的对象(final全局变量),本地方法栈JNI方法引用的对象。
  3. 现代GC回收算法主要有三种:标记-清除算法,复制算法和标记-整理算法。
  4. 标记清除算法缺点是效率比较低,容易出现内存碎片,一般很少用到。
  5. 复制算法缺点是浪费内存多,不适用于大对象和存活时间长的对象,一般用于新生代对象的GC。
  6. 标记整理算法克服了内存碎片,但缺点仍是效率不高,一般用于老年代对象的GC。
  7. HotSpot虚拟机默认Eden和Survivor的比例是8比1,老年代使用标记整理算法,新生代使用复制算法。
  8. Survivor空间不够时大对象会直接进入老年代。
  9. 当一个对象不可达时会调用finalize()方法,但是仅调用一次。

八、Java堆和栈的区别

img

  1. 所有对象实例都是在Java堆上分配内存
  2. 方法区用于存放ClassLoader加载的类的相关信息,包括类、静态变量和常量,String常量池也在方法区内。
  3. Java栈存放方法调用时的局部变量、方法操作、方法出口与方法执行的相关信息,无限递归调用会撑爆Java栈。

九、Java三大特性

  1. 封装,继承,多态

十、Java的可变参数

  1. 适用于参数个数不确定,类型确定时。
  2. 只能出现在参数列表的最后。
  3. Java把可变参数当做数组处理。

十一、String为什么要设计成不变的

  1. 字符串不变时,字符串池才有可能实现,运行时能节约很多堆空间。
  2. 字符串不变,就不用考虑多线程同步问题,是线程安全的。
  3. 类加载器要用到字符串,字符串不变性提供了安全性,保证正确的类被加载。
  4. 字符串不变hashcode就能被缓存,作为HashMap的键要比其他对象速度快。

十二、如何理解String的不变性

  1. 所有在编译期间确定的字符串都会在常量池中。
  2. new String(“xxx”)会在堆中创建对象。
  3. string.intern()会根据字符串内容去常量池中寻找并返回相同内容的字符串,如果没有则先创建。

十二、Java用擦除实现范型的原因

  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),如果再加一套范型化的容器类画面实在太美。

十三、如何定义一个Annotation

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

十四、volatile关键字的作用

  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轻量,消耗资源更少。

十五、notify了一个锁,wait的地方一定会被唤醒继续执行吗?

  1. 如果只有一个线程在wait,那么是的。
  2. 如果有多个线程在同时wait同一个锁,那么唤醒哪一个线程与JVM的实现有关,不能保证某个线程一定会被唤醒。

第三部分:Android基础

一、触摸事件的分发

  1. 触摸事件的处理涉及三个方法:dispatchTouchEvent()onInterceptEvent()onTouchEvent()
  2. 从Activity的dispatch开始传递,如果没有拦截,则一直传递到子view。
  3. 如果子View没有消费事件,事件会向上传递,这时父Group才可以消费事件。
  4. 如果子View没有消费DOWN事件(没有返回 true),后续事件都不会再传递进来,直到下一次DOWN。
  5. OnTouchListener的处理优先级高于onTouchEvent()

二、Handler.postDelay()的原理

  1. Handler.postDelayed()精确延迟指定时间的原理

三、Fragment的生命周期

img

四、Gson的原理

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

五、Serializable和Parcelable的区别

  1. S是Java的序列化方案,P是Android的
  2. S在序列化的时候会产生大量的临时变量,导致频繁GC,P则不会。因此在内存中使用时(如网络中传递或进程间传递)推荐使用P。
  3. P被设计为IPC通信数据序列化方案,不适用于保存在磁盘上,此时应用S。
  4. S只需要继承Serializable接口即可,P则需要重写writeToParcel方法、重写describeContents方法、实例化Parcelable.Creator。

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

1. A.onCreate()
2. A.onStart()
3. A.onResume()
4. 启动B
5. A.onPause()
6. B.onCreate()
7. B.onStart()
8. B.onResume()
9. A.onStop()
10. 返回A
11. B.onPause()
12. A.onRestart()
13. A.onStart()
14. A.onResume()
15. B.onStop()
16. B.onDestory()

七、startService和bindService的区别

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

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

1. AbsListView.setRecyclerListener()
2. #onMovedToScrapHeap(View view)
3. RecyclerView.setRecyclerListener()
4. #onViewRecycled(ViewHolder holder)

九、什么是属性动画

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

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

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

十一、如何定义一个Gradle Task

  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"}

十二、ListView的ViewType的限制

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

十三、什么是ViewStub

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

十四、SurfaceView的特点

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

十五、如何调试ANR

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

十六、Android程序方法数上限65535是怎么来的?

  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无关
文章目录
  1. 1. 第一部分:计算机基础
    1. 1.1. 一、ICMP协议是什么
    2. 1.2. 二、DNS协议是什么
    3. 1.3. 三、堆和栈的区别
    4. 1.4. 四、TCP和UDP的区别
    5. 1.5. 五、TCP拥塞控制逻辑
    6. 1.6. 六、TCP为什么断开连接要四次握手?
  2. 2. 第二部分:Java基础
    1. 2.1. 一、HashMap和HashTable的区别
    2. 2.2. 二、SoftReference和WeakReference的区别
    3. 2.3. 三、HashMap冲突后的处理方法
    4. 2.4. 四、equal()方法重写时要注意的点
    5. 2.5. 五、new String()
    6. 2.6. 六、Java优先级队列的实现原理
    7. 2.7. 七、Java虚拟机GC的原理
    8. 2.8. 八、Java堆和栈的区别
    9. 2.9. 九、Java三大特性
    10. 2.10. 十、Java的可变参数
    11. 2.11. 十一、String为什么要设计成不变的
    12. 2.12. 十二、如何理解String的不变性
    13. 2.13. 十二、Java用擦除实现范型的原因
    14. 2.14. 十三、如何定义一个Annotation
    15. 2.15. 十四、volatile关键字的作用
    16. 2.16. 十五、notify了一个锁,wait的地方一定会被唤醒继续执行吗?
  3. 3. 第三部分:Android基础
    1. 3.1. 一、触摸事件的分发
    2. 3.2. 二、Handler.postDelay()的原理
    3. 3.3. 三、Fragment的生命周期
    4. 3.4. 四、Gson的原理
    5. 3.5. 五、Serializable和Parcelable的区别
    6. 3.6. 六、一个Activity启动另外一个Activity并返回的生命周期调用
    7. 3.7. 七、startService和bindService的区别
    8. 3.8. 八、如何监听ListView的item被回收了?
    9. 3.9. 九、什么是属性动画
    10. 3.10. 十、Android系统是如何保证一个线程只有一个Looper的
    11. 3.11. 十一、如何定义一个Gradle Task
    12. 3.12. 十二、ListView的ViewType的限制
    13. 3.13. 十三、什么是ViewStub
    14. 3.14. 十四、SurfaceView的特点
    15. 3.15. 十五、如何调试ANR
    16. 3.16. 十六、Android程序方法数上限65535是怎么来的?