1.2019 Android基础面试题总结

1.为什么普通内部类会持有外部类的引用?
  1. 因为内部类的产生依赖于外部类,持有的引用是类名.this
  2. 编译器会将内部类和外部类分别编译成各自的class文件
  3. 编译器自动为内部类添加一个成员变量,这个成员变量就是指向外部类对象的引用
  4. 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型
  5. 调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。
    因此,内部类就持有了外部类的引用,可以访问外部类的变量和方法
2.Java中try catch finally的执行顺序

最一般的情况下,先try 发生异常执行catch,最后一定执行finally

3.return语句对try catch finally返回值的影响
  1. 发如果try catch中都有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、全局变量)。
  2. 尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生
//修改基本数据类型
public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            System.out.println("try block, i = "+i);
            return i;
        }catch(Exception e){
            i ++;
            System.out.println("catch block i = "+i);
            return i;
        }finally{
            i = 10;
            System.out.println("finally block i = "+i);
        }
}
输出结果
try block, i = 2
finally block i = 10
main test i = 2

//修改引用数据类型
public static  List testWrap(){
        List list = new ArrayList<>();
        try{
            list.add("try");
            System.out.println("try block");
            return list;
        }catch(Exception e){
            list.add("catch");
            System.out.println("catch block");
            return list;
        }finally{
            list.add("finally");
            System.out.println("finally block ");
        }
}
输出结果
try block
finally block
main test i = [try, finally]
 
 
3.equals与==的区别

==判断内存空间的地址,equals判断所指向内存空间的值

4.垃圾回收算法如何确定某个对象是垃圾

引用计数法:通过引用计数来判断一个对象是否可以被回收。如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象。(给对象增加一个计数器的功能,当存在引用使用功能对象是,计数器值加一,当引用失效时计数器值减1,任何时候计数器值为0时的对象是无法被使用的。)这种方式的特点是实现简单,而且效率较高,但是它无法解决循环引用(两个对象相互引用,导致两个对象都不能被回收)的问题,因此在Java中并没有采用这种方式(Python采用的是引用计数法)
可达性分析法:通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。

可作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象。
4.介绍垃圾回收机制

标记-清除算法:标记可回收的对象,清除被标记的对象
还有一种说法是标记可到达的对象,清除不可到达的对象,原理是一样的
缺点是标记和清除的效率不高,容易产生大量内存碎片,处罚更多的垃圾回收

标记-压缩算法:在标记清除算法上增加一步,将所有存活的对象压缩到内存的一端,然后对另一端的对象进行清除,减少了内存碎片,提高了内存利用率,广泛应用于老年代

复制算法:把内存分成两部分,每次只使用其中一个区域,gc时,遍历当前区域,将存活的对象复制到另一个区域,清除当前区域对象

没有内存碎片的问题,但是使用的内存减少为一半,效率和存活对象的数量有关系,存活的数量越高,效率越低,所以复制算法多应用于新生代中,新生代对象生命周期短,可以保证在同一时间段中存活数量不会很高

分代收集算法:前面提到了新生代和老年代,所以就产生了分代收集算法,根据对象生命周期长短将其分成两个或者多个域,如年轻代和老年代,新生代生命周期短,会很快被回收,因此在新生代采用效率比较高的算法,当一个对象经过几次回收后依然存活,此对象就会被放入老年代的内存空间,采用标记-压缩算法清理

5.数据结构中用于存储数据的有哪些

数组:内存空间连续,空间复杂度大,但二分查找时间复杂度小为O(1),特点是查找效率高,增删效率低
链表:存储区间分散,占用内存宽松,空间复杂度小,但时间复杂度大,O(N),特点是,查找效率低,增删效率高

6 HashMap实现原理

数组+单链表
当我们往HashMap中put元素时,会根据key值的hashCode重新计算hash值,根据这个值得到该元素在数组中的位置,如果这个位置上已经有元素,那么在这个位置上的元素及那个以单链表的形式存在,新加入的放在头部,如果该位置上没有元素,直接将该元素放在该位置上

7 ArrayList,LinkedList的区别

ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

8 ArrayList和Vector的主要区别

ArrayList 和Vector底层是采用数组方式存储数据Vector:线程同步当Vector中的元素超过它的初始大小时,Vector会将它的容量翻倍,ArrayList:线程不同步,但性能很好当ArrayList中的元素超过它的初始大小时,ArrayList只增加50%的大小

9 wait()和sleep()的区别

1.sleep来自Thread类,wait来自Object类
2.调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁
3.sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU
4.sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒,wait需要被唤醒

10 Android 线程间通信有哪几种方式(重要)

共享内存(变量);
文件,数据库;
Handler;
Java 里的 wait(),notify(),notifyAll()

11 TCP三次握手与四次挥手

第一次握手:发送请求报文,建立连接,等待服务器确认
第二次握手:服务器收到请求报文,进行确认发送响应报文给客户端
第三次握手:客户端收到服务器的报文段,向服务端发送确认,完成三次握手

第一次挥手:客户端发送报文告诉服务器没有数据要发送了
第二次挥手:服务端收到,再发送给客户端告诉它我收到了
第三次挥手:服务端向客户端发送报文,请求关闭连接
第四次挥手:客户端收到关闭连接的请求,向服务端发送报文,服务端关闭连接

为什么TCP是可靠的,UDP早不可靠的?为什么UDP比TCP快?

TCP/IP协议拥有三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。
UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。
但是就速度来说,还是UDP协议更高,毕竟其无需重复返回验证,只是一次性的

12 请介绍下 AsyncTask的内部实现,适用的场景是

AsyncTask内部是通过handler和线程池实现的,默认情况下所有任务串行执行,所以不适合高并发的场景

12 http协议了解多少,说说里面的协议头部有哪些字段

http协议是一个基于请求与响应模式的无连接,无状态,应用层的协议,支持c/s模式,简单快速,灵活
简单快速:协议简单,通信速度快
灵活:允许传输任意类型的数据对象,由Content-Type标记
无连接:每次处理一个请求,处理完成后既断开
无状态:对事务处理没有记忆能力

http有两种报文:请求报文和响应报文
请求报文由请求行,请求报头,和请求数据组成
请求行:抓包第一行,包括请求方法,url和http版本
请求报头:指的就是题目中“里面的协议头部”
请求数据:指post方式提交的表单数据

响应报文由状态行,响应报头,响应正文组成
状态行:状态码
响应报头:同请求报头
响应正文:服务器返回的资源数据

接下来是http头部,既请求报头和响应报头,统称消息报头,消息报头可以分为通用报头,请求报头,响应报头,实体报头等

通用报头和实体报头既可以出现在请求报头中,也可以出现在响应报头中,通用报头包含的字段如:Date Connection Cache-Control,实体报头中有Content-Type Content-Length Content-Language Content-Encoding.
请求报头中包含的字段有:
Host,User-Agent,Accept-Encoding,Accept-Language,Connection
响应报头包含的字段:
Location,Server

13 https了解多少

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL

14.Fragment 如何实现类似 Activity 栈的压栈和出栈效果的?

Fragment 的事物管理器内部维持了一个双向链表结构,该结构可以记录我们每次 add 的Fragment 和 replace 的 Fragment,然后当我们点击 back 按钮的时候会自动帮我们实现退栈操作。
Activity和Fragment生命周期有哪些?

15 Activity和Fragment生命周期有哪些?

Activity(6个):onCreate onStart onResume onPause onStop onDestroy
Fragment(11个):onAttach onCreate onCreateView onActivityCreated onStart onResume onPause onStop onDestoryView onDestroy onDetach

16 启动service的两种方法?有什么区别?

一种是startService(),另一种是bindService()。这两者的区别是第一种方式调用者开启了服务,即会与服务失去联系,两者没有关联。即使访问者退出了,服务仍在运行。如需解除服务必须显式的调用stopService方法。主要用于调用者与服务没有交互的情况下,也就是调用者不需要获取服务里的业务方法。比如电话录音。而后者调用者与服务绑定在一起的。当调用者退出的时候,服务也随之退出。用于需要与服务交互。

19.Dalvik虚拟机与JVM有什么区别

Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。
Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码。

DVM的进程和linux的进程关系(曾经是一个选择题)

DVM指dalvik的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念.

21.据自己的理解描述下Android数字签名。

a: Android所有的应用程序必须要有数字证书签名,Android系统不会安装一个没有数字证书签名的程序。
b: Android系统中,系统app使用的是平台证书签名,而第三方app一般使用开发者的自签名证书。
c: Release版本的第三方app(例如淘宝、支付宝、微信),必须使用一个合适私钥生成的数字证书来给程序进行签名,并且保证每次的迭代新版本都是使用相同的证书进行数字签名。不然的话,新版本和旧版本的数字证书不一致,Android系统会认为这是两个不同的app,导致更新等操作失败。
d: 数字证书是存在有效期的,这也决定了app的预计生命周期,如果数字证书超期失效,则应用无法安装或者无法正常升级。
e: Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。以同一个证书对多个应用程序进行签名,利用基于签名的权限检查,你就可以在应用程序间以安全的方式共享代码和数据了

22.Dalvik基于JVM的改进

a:几个class变为一个dex,constant pool,省内存
b:Zygote,copy-on-write shared,省内存,省cpu,省电
c:基于寄存器的bytecode,省指令,省cpu,省电
d:Trace-based JIT,省cpu,省电,省内存

23.ARGB_8888占用内存大小

是4byte,即ARGB各占用8个比特来描述。

24.apk安装卸载的原理

安装过程:
a.将apk复制到data/app目录下面,会放到data/app/包名/目录下面,同时apk中的so文件也会拷贝到此目录下的lib文件目录中。
b.解压apk,把其中的classes.dex 拷贝到data/dalvik-cache, 其命名规则是 apk路径+classes.dex
c.在data/data/目录下创建对应的包名目录,data/data/包名/,并在该目录下创建存储应用数据的相关目录,例如cache, database、lib、shared_perfs等
卸载过程:
删除安装过程中在上述三个目录下创建的文件及目录。

23.隐式启动Activity的匹配规则(IntentFilter的匹配规则)

IntentFilter中的过滤信息有action category data,假设一个IntentFilter中包含了这三个规则,那么需要这三个同时匹配才能正确的启动Activity,另外一个Activity可能设置多个IntentFilter,只要能完全匹配其中一个就可以了
a.action匹配规则
action的匹配要求Intent中的action必须存在且必须和过滤规中的其中一个action相同,也就是说可能存在多个action,只要和其中一个相同就可以了
b.category的匹配规则:
Intent中可以不定义category(系统默认定义一个Default),但是如果一旦定义了,不管定义几个,每一个都要和IntentFilter中的任何一个相同。这就说明一般IntentFilter中只会定义一个category

intent.addcategory("com.xxx");

c.data的匹配规则:
data由两部分组成,mineType和URI,如果IntentFilter中没有指定URI,那么默认值就是content和file,这就要求Intent中URI必须指定为content或file才行.注意不能先调用setData再调用setType,这两个方法会相互清空

//file是URI,image/png是mineType
intent.setDataAndType(Uri.parse("file://abc"),"image/png");

对应的IntentFilter中配置为


    

隐式启动Activity的时候,为了不发生异常,做一个判断采用PackageManager的resolveActivity方法或者Intent.resolveActivity,如果找不到匹配的Activity就会返回null

24.Serializable和Parcelable的区别

1.Serializable是Java中的序列化接口,使用简单但是开销很大,序列化和反序列化过程会设计大量IO操作
2.Parcelable是Android中的序列化方式,更适合在Android平台使用,缺点是使用麻烦但是效率很高,
3.Parcelable主要用在内存序列化上,通过它将对象序列化到存储设备中或者将对象序列化后通过网络传输也是可以的,但是这个过程会比较复杂,所以这两种情况推荐使用Serializable,

TCP 采用三次握手的原因

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认

webview怎么优化加载速度

1.开启离线缓存
在缓存可获取并且没有过期的情况下加载缓存,否则通过网络获取资源。这样的话可以减少页面的网络请求次数。
离线的情况下,设置缓存策略为setCacheMode(WebSettings.LOAD_CACHE_ONLY) 不使用网络,只加载缓存。
针对资源无法及时更新的问题,WebSettings.LOAD_DEFAULT中的页面中的缓存版本好像不是很起作用,我们需要自己做一个缓存版本控制。这个缓存版本控制可以放在APP版本更新中,在版本更改时清空webview缓存
2.预加载
将页面加载的大量资源打包进APK里面,然后当页面加载这些资源的时候让它从本地获取,这样可以提升加载速度也能减少服务器压力
3.H5优化
Android的OnPageFinished事件会在Javascript脚本执行完成之后才会触发。iPhone是显示完页面才会触发脚本的执行。所以我们这边的解决方案延迟JS脚本的载入,这个方面的问题是需要Web前端工程师帮忙优化的,网上应该有比较多LazyLoad插件
4.加载时先加载文本,后加载图片调用方式如下:

public void onProgressChanged(WebView view, int newProgress) { 
if (newProgress == 100) { 
    // 网页加载完成 
    settings.setBlockNetworkImage(false); 
} else { 
    // 网页加载中
 } 
webview内存泄漏的原因

webview引起的内存泄漏主要是因为org.chromium.android_webview.AwContents 类中注册了component callbacks,但是未正常反注册而导致的。
org.chromium.android_webview.AwContents 类中有这两个方法 onAttachedToWindow 和 onDetachedFromWindow;系统会在attach和detach处进行注册和反注册component callback;
在onDetachedFromWindow() 方法的第一行中:
if (isDestroyed()) return;,

如果 isDestroyed() 返回 true 的话,那么后续的逻辑就不能正常走到,所以就不会执行unregister的操作;我们的activity退出的时候,都会主动调用 WebView.destroy() 方法,这会导致 isDestroyed() 返回 true;destroy()的执行时间又在onDetachedFromWindow之前,所以就会导致不能正常进行unregister()。
然后解决方法就是:让onDetachedFromWindow先走,在主动调用destroy()之前,把webview从它的parent上面移除掉。
ViewParent parent = mWebView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(mWebView);
}

mWebView.destroy();

完整的activity的onDestroy()方法:

@Override
protected void onDestroy() {
    if( mWebView!=null) {

        // 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再
        // destory()
        ViewParent parent = mWebView.getParent();
        if (parent != null) {
            ((ViewGroup) parent).removeView(mWebView);
        }

        mWebView.stopLoading();
        // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
        mWebView.getSettings().setJavaScriptEnabled(false);
        mWebView.clearHistory();
        mWebView.clearView();
        mWebView.removeAllViews();
        mWebView.destroy();

    }
    super.on Destroy();
}
一个Activity中加载两个fragment,通过fragment的show和hide方法控制它的显示和隐藏,那么当我每次调用show的时候都会执行fragment的onResume方法吗?

不会,fragment的onResume方法和Activity的onResume方法是绑定在一起的,Activity的onResume执行的时候,fragment的onResume会执行,但是show方法调用的时候不会执行,如果调用的是replace方法,那么每次fragment的生命周期会再走一次,这种情况下onResume会执行

你可能感兴趣的:(1.2019 Android基础面试题总结)