面试干货

1.java中equals和==的区别

基本数据类型==比较的是值,非基本数据类型==比较的是内存地址

equals比较的是内存地址

2.String、StringBuffer、StringBuilder的区别(运行速度:StringBuilder>StringBuffer>String)

String:字符串常量, 每次修改都相当于生成一个新的对象,所以不适合经常变更值的场景

StringBuffer:字符串变量,线程安全适用于多线程

StringBuilder:字符串变量,线程不安全适用于单线程,效率略快于StringBuffer

速度上面String不断的复制和更改是创建不同的对象来进行操作,这里涉及到GC垃圾回收机制,会影响速度;而StringBuffer和StringBuilder则处理同一个对象不存在JVM的GC回收。

线程安全与否:如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,不能同步的问题。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

3.java8新特性有哪些?

Lamabda表达式
接口的默认方法和静态方法
重复注解
方法引用
更好的类型推断
拓宽注解的应用场景
访问局部变量
Filter过滤
Stream接口
sort排序
Map映射
DataApi等等
4.说说你对JVM的理解

5.Handler机制的原理与RXJava有什么区别?

当时问到我的时候我还真不知道怎么回答,我只知道相同点:都是为了线程间通信。

区别:

1.RxJava线程切换更方便(直接可以切换子线程和UI线程),Handler需要在子线程去发送消息,在主线程去接受消息然后才能改变UI。

2.RxJava是观察者模式,Handler是消息队列用的是双向链表。

6.广播有几种创建方式,有什么区别?

两种,动态创建和静态创建(Android8.0以后不能静态注册广播,官方说法是为了省电),区别:

1.动态注册的广播永远要快于静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低。

2.动态注册广播不是常驻型广播 ,也就是说广播跟随activity的生命周期。注意: 在activity调用ondestory(),移除广播接收器。静态注册是常驻型 (不能自动销毁),也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

3.在同一个优先级下,谁先启动的快,谁将先接收到广播。

7.Android的数据存储方式有哪些?

1.Sharedpreferences(适合轻量级数据存储,采用XML键值对的形式存储到本地,只能运用于一个App内)

2.文件存储

3.SQLite数据库存储

4.ContentProvider

5.网络存储

8.服务的启动方式和对应的生命周期以及区别?

1.startService(onCreate-onStartCommand-onDestory)

服务与启动者没有必然联系,启动者销毁,服务也可以存在;除非主动调用StopService方法来停止服务。

2.bindService(onCreate-onBind-onUnbind-onDestory)

服务与启动者相互关联,启动者销毁,那么服务也会跟着销毁;比如activityA中bind服务,然后activityB中也在使用该服务,一旦activityA销毁那么服务也会销毁,这个时候activityB中服务也就没用了,除非再bind一次。

3.startService之后再bindService这样避免宿主死亡之后service跟着被销毁。

9.线程间通信有哪些方式?

接口
Handler
观察者模式(EventBus)
Android使用RunonUiThread可以切换到主线程
AsyncTask
BroadCast
SharedPreferences
10.进程间通信有哪些方式?

Intent,访问其他程序的Activity或者调用系统电话、短信
Content Provider,多个App共享数据
AIDL(Android Interface Define Language)服务,客户端定义接口暴露给服务端使用
BroadCast
Socket
11.描述一下ANR错误,哪些情况会发生,如何避免?

activity 按键或触摸事件在5s无响应,broadcastreceiver 10s内无法做出回应,service20s内无法处理完成;都会导致应用无响应。(在主线程做耗时操作都会导致ANR)。

避免:

1.不要在主线程做耗时操作(数据库查询,网络操作,大量数据存储,图片的切割等)。

2.不要在广播内做耗时操作,如果非要,那么请通过Service新起线程来进行耗时操作。

12.横竖屏切换activity生命周期?

1、AndroidManifest.xml不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,

切横屏时会执行一次,切竖屏时会执行两次。生命周期如下:

onSaveInstanceState-onPause-onStop-onDestory-onCreate-onStart-onRestoreInstanceState-onResume

2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调

用各个生命周期,切横、竖屏时只会执行一次。生命周期如下:

onSaveInstanceState-onPause-onStop-onDestory-onCreate-onStart-onRestoreInstanceState-onResume

3、设置Activity的android:configChanges="orientation|keyboardHidden"时,

切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。

13.你对设计模式的理解,简单说几种?

一共23种,随便说几种就行,然后一般会问一些互相之间的区别啊,使用它们的好处之类的。

Builder模式(方便维护,使用者可以不用清楚内部构成情况就能直接调用方法;比如系统弹窗)
观察者模式(被观察者与观察者,只要有订阅关系,当被观察者发生改变时,就能通知观察者们;比如Event )
单例模式(一个进程/项目中只存在1个实例,为了节约内存资源)
工厂模式
14.Android动画有几类,它们的特点和区别是什么?

Android3.0之前2种动画,3.0之后3种动画

帧动画(Frame Animation):类似于一帧帧图片组成的电影,xml中多张图片组成,在UI线程中播放这个xml形成的动画。

补间动画(Tweened Animation):补间动画分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。补间动画的实现,一般会采用xml 文件的形式;当然也可以用Java代码直接实现。

属性动画(Property Animation):这是3.0之后加入的动画,为了弥补前面两种动画的不足。属性动画可以实现很多数学函数的路径动画。属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

15.平时开发中设计到哪些性能优化,你是从哪些地方来优化,你是通过什么工具来分析的?

笼统的说:就是让App反应更快,使用更稳,流量、电量更省,apk更小。

具体的说:省电优化、内存优化、网络优化、图片优化、UI优化。

更快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。

UI优化:

分析工具:Systrace

(1)减少层级,合理使用 RelativeLayout 和 LinerLayout,合理使用Merge,Include。

(2)提高显示速度,使用 ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。

(3)布局复用,可以通过标签来提高复用。

(4)尽可能少用wrap_content,wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。

(5)删除控件中无用的属性。

更稳:减低 Crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。

(1)增加相应的判断,以及异常处理。

(2)避免在主线程做耗时操作。

更省:节省流量和耗电,节约内存,减少用户使用成本,避免使用时导致手机发烫。

耗电分析工具:Battery Historian

(1)避免浮点运算。

(2)根据客户端图片的大小要求叫UI做相应大小的图提供给服务器,避免过大消耗更多流量和电量。

(3)不用的广播,服务记得及时关闭。

内存分析工具:Memory Monitor

(1)对象引用:强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。

(2)减少不必要的内存开销:注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。

(3)使用最优的数据类型:比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等。

(4)图片内存优化:点9图减少图片大小以及可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等。

更小:安装包小可以降低用户的安装成本。

(1)做混淆优化代码。

(2)删除无用的代码及图片相应的本地库。

(3)Lint优化。

(4)zip压缩。

16.你对主件开发,模块开发了解多少?模块之间怎么进行通讯,数据传输?

17.简单描述一下你对Gradle的理解

Gradle理解点击查看

18.MVC与MVP的区别?

MVC:Model(数据模型)、View(视图)、(Controller)控制器(activity或者fragment),View将操作反馈给Activity,Activitiy去获取数据,数据通过观察者模式刷新给View。循环依赖

1.Activity(Fragment)重,很难单元测试。

2.View和Model耦合严重。

MVP:Model(模型层)、View、Presenter(接口,Model和View交互的桥梁),View将操作给Presenter,Presenter去获取数据,数据获取好了返回给Presenter,Presenter去刷新View。PV,PM双向依赖

1.如果功能复杂,Presenter接口爆炸(界面的操作更新UI都必须配合Presenter的接口来操作)。

2.Activity需要重写很多接口方法来更新UI。

3.Model和View不直接进行交互,达到解耦效果。

19.使用RXjava时,你是如何对它进行生命周期管理?

20.Lru算法的原理?

LRU(Least Recently Used)最近最少使用,LRU使用的是LinkedHashMap,如果链表中存在一个数则将其置顶,如果没有则直接在顶部加入这个数并将其底部的数移除。大致可以这样理解,具体可以再搜索一下LRU算法。

21.冒泡、选择、快排有没有相似之处?简单说一下他们的原理?

冒泡:(原理看水桶里面的泡泡,从下到上冒泡,每次确定一个最大的泡到最上面)

/**  * 冒泡排序 从小到大     * 每次冒泡出相对最大的数到相对最后面    
public static void bubbleSort(int[] data){  
         if(data == null) throw new IllegalArgumentException("data can't be null");        
         if(data.length<2) return;     
//外层循环data.length-1次    
for(int i=0 ;idata[j+1]){              
                   int temp = data[j]; 
                      data[j] = data[j+1];
                      data[j+1]=temp;          }           
                    }  
   }       
/*for(int i:data)           
System.out.print(i+" ");*/  
      System.out.println(Arrays.toString(data));   }

选择: (选择第i个数依次与后面的数进行比较得到相对最小的数来替换第i个数)

/**     * 选择排序 从小到大     * 每次选出一个相对较小的排前面     */  
  public static void selectSort(int[] data){      
  if(data == null) throw new IllegalArgumentException("data can't be null");      
  if(data.length<2){return;}      
  //循环次数data.length-1       
 for(int i=0;i< data.length -1 ;i++){       
    int index = i;      
    //每次选择第i个数依次和后面的数进行比较,谁小谁变成第i个数;循环次数也是data.length-i-1       
    for(int j=i;jdata[j]){               
                        index = j;          
                }       
        }           
     if(i != index){            
            int temp = data[index];     
             data[index] = data[i];     
             data[i] = temp;        
                    }    
       }    
    /*for(int i:data)           System.out.print(i+" ");*/   

     System.out.println(Arrays.toString(data));    }

快排 :几个字说不清楚,给个链接https://blog.csdn.net/crazy_rain/article/details/1572080

22.自定义View需要用到哪些方法,各自的作用?

onMeasure 测量,onLayout 计算位置(布局),onDraw 绘制

具体推荐一篇博客:https://www.jianshu.com/p/146e5cec4863

23.JVM和DVM有什么区别,以及ART垃圾回收机制?

1.基于不同位置

Dalvik:基于寄存器,编译和运行都会快一些

JVM: 基于栈, 编译和运行都会慢些

2.字节码的区别

Dalvik: 执行.dex格式的字节码,是对.class文件进行压缩后产生的,文件变小

JVM: 执行.class格式的字节码

3.运行环境的区别

Dalvik : 一个应用启动都运行一个单独的虚拟机运行在一个单独的进程中

JVM: 只能运行一个实例, 也就是所有应用都运行在同一个JVM中

但是在Android4.4引入了ART,也是 Android 5.0 及更高版本的默认 Android 运行时。目前google已经不再维护和发布dalvik(DVM)。

1.ART GC 与 Dalvik 的主要区别在于 ART GC 引入了移动垃圾回收器。使用移动 GC 的目的在于通过堆压缩来减少后台应用使用的内存。目前,触发堆压缩的事件是 ActivityManager 进程状态的改变。当应用转到后台运行时,它会通知 ART 已进入不再“感知”卡顿的进程状态。此时 ART 会进行一些操作(例如,压缩和监视器压缩),从而导致应用线程长时间暂停。目前正在使用的两个移动 GC 是同构空间压缩和半空间压缩。

2.与 Dalvik 相比,暂停次数从 2 次减少到 1 次。Dalvik 的第一次暂停主要是为了进行根标记,而这个动作在 ART中已经是让线程自己去标记,然后马上恢复运行,这样就减少了一次暂停。

3.与 Dalvik 类似,ART GC 在清除过程开始之前也会暂停 1 次。两者在这方面的主要差异在于:在此暂停期间,某些 Dalvik 环节在 ART 中并发进行。这些环节包括 java.lang.ref.Reference 处理、系统弱清除(例如,jni 弱全局等)、重新标记非线程根和卡片预清理。在 ART 暂停期间仍进行的阶段包括扫描脏卡片以及重新标记线程根,这些操作有助于缩短暂停时间。

4.相对于 Dalvik,ART GC 改进的最后一个方面是粘性 CMS 回收器增加了 GC 吞吐量。不同于普通的分代 GC,粘性 CMS 不移动。系统会将年轻对象保存在一个分配堆栈(基本上是 java.lang.Object 数组)中,而非为其设置一个专属区域。这样可以避免移动所需的对象以维持低暂停次数,但缺点是容易在堆栈中加入大量复杂对象图像而使堆栈变长

最后说一下回收机制:

  1. 先回收与其他Activity 或Service/Intent Receiver 无关的进程(即优先回收独立的Activity)因此建议,我们的一些(耗时)后台操作,最好是作成Service的形式

2.不可见(处于Stopped状态的)Activity

3.Service进程(除非真的没有内存可用时会被销毁)

4.非活动的可见的(Paused状态的)Activity

5.当前正在运行(Active/Running状态的)Activity

  1. OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象语言)基本原理

25.IntentService和Service有什么区别?

Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程(比喻成没有界面的activity),也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。

IntentService是Service的子类,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。通过Handler looper message的方式实现了一个多线程的操作,同时耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。

26.事件分发机制的原理(点击上层如何传递给下层)?

https://www.jianshu.com/p/e99b5e8bd67b

27.当调用摄像机的时候怎么保存当前activity的状态?

为了防止在调用相机的时候,当前activity被系统kill(比如内存不够时,系统会自动销毁非可见的处于onPause或onStop状态的activity),我们需要 覆写 onSaveInstanceState方法,保存当前activity的状态变量值。

28.Service和线程的区别,我们为什么不用service代替线程,相应在什么情况下使用?

Service:service是android的一种机制,对应的service是运行在主线程上的,它是由系统进程托管。他们之间的通信类似于client和server,是一种轻量级的ipc通信,这种通信的载体是binder,它是在linux层交换信息的一种ipc。

线程:线程是程序执行的最小单元,它是分配CPU的基本单位。可以用线程来执行一些异步的操作。

区别:Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制;而Service则可以被多个activity共用(当然你也可以说我可以在服务里面新起线程这样不就可以被多个activity共用了,其实这样的本质还是共用的服务而不是线程)。

我们不用服务替代线程是因为:服务(子类IntentService则是在内部添加了子线程)也是运行在主线程上面,而不是子线程,相当于你还是需要新起线程来完成相应的操作,这又是何苦啦;并且一个类里面需要多线程操作的情况,服务是不是显得很无力。各有各的优点,下面来看使用情况。

使用情况:

1.在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。

同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,不需要长时间运行的情况下使用线程。

2.如果任务占用CPU时间多,资源大的情况下,要使用线程。

3.一般我们做下载任务都是在服务里面新起线程做异步任务来操作,或者直接使用IntentService。

29.Activity与Fragment之间通信

Handler
广播
接口
EventBus
以上是我最近面试遇到的常见问题,希望对大家有帮助;一般hr还有聊一些职业规划之类等等。

下面我推荐几篇总结比较全面的面试题:

https://www.jianshu.com/p/0f82b0650909

https://www.jianshu.com/p/4115bcf9f92e

你可能感兴趣的:(面试干货)