安卓面试题

1.Kotlin的伴生对象
Kotlin中,在类中定义的对象(object)声明,可使用companion修饰,这样此对象(object)就是伴生对象了

class NumberTest {
    companion object Obj {  
        var flag = false

        fun plus(num1: Int, num2: Int): Int {
            return num1 + num2
        }
    }
}

2.Kotlin的高阶函数
https://www.jianshu.com/p/27ed7e4e1259

3.安卓中Activity,Window,View之间的关系
Activity创建时通过attach()初始化了一个Window也就是PhoneWindow,一个 PhoneWindow 持有一个DecorView的实例,DecorView本身是一个 FrameLayout,继承于 View,Activty通过setContentView将xml 布局控件不断addView()添加到 View 中,最终显示到Window于我们交互
安卓面试题_第1张图片
4.跨进程通信的几种方式
1)Intent,比如拨打电话,唤起手机浏览器
2)ContentProvider数据库存储数据
3)Broadcast广播通信
4)AIDL通信,通过接口共享数据,跨应用,跨进程

5.wait和sleep的区别
1)wait是Object的方法,它是一个对象锁,通过锁定方法不让线程继续执行,但是当执行notify方法后则会继续执行
2)sleep是Thread的方法,它会使线程睡眠,从而让出cpu,结束该命令后线程会自动继续执行

6.String,StringBuffer,StringBuilder的区别
当字符赋值少使用String,字符赋值频繁使用StringBuilder,当多个线程同步操作数据,使用StringBuffer
1)String不可改变对象,一旦创建就不能修改

String str="aaa";
str="bbb";//代码虽然改变了str,但是执行过程是回收str,再把值赋给一个新的str

2)StringBuffer创建之后,可以去修改
3)StringBuilder也可修改,执行效率高于StringBuffer,但是不安全,容易造成丢失

7.View和SurfaceView的区别
1)View基于主线程刷新UI
2)SurfaceView子线程也可以刷新UI

8.View的绘制原理
View为所有图形控件的基类,View的绘制由3个函数完成
1)measure:计算视图的大小,返回绘制在手机上时候的宽高
在这里插入图片描述
MeasureSpec有三种测量模式:
安卓面试题_第2张图片

2)layout:返回视图要显示的位置,xy轴
3)draw:当一个activity加载出来的时候需要绘制会回调该方法

9.简述JNI
是java和c语言之间的桥梁,由于java是一种半解释语言,可以被反编译出来,一些重要的涉及安全的代码就使用了C编程,再者很多底层功能调用C语言都实现了Java没必要重复造轮子,所以定义了JNI接口的实现

10.简述TCP,UDP,Socket
1)TCP是经过3次握手,4次挥手完成一串数据的传送
2)UDP是无连接的,知道IP地址和端口号,向其发送数据即可,不管数据是否发送成功
3)Socket是让不同计算机能够实时连接,比如说传送文件,即时通讯

11.音视频相关类
1)视频录制方面,Camear摄像头录制视频类,MediaProjection屏幕录制视频类
2)编码方面,MediaCodec,MediaRecorder
3)预览方面,SurfaceView,GLSurfaceView,TextureView,VideoView

12.进程和线程的区别
进程包括多个线程,一个程序一个进程,多线程的优点可以提高执行效率,提高资源利用率
即Thread类和Runnable接口
常用方法有:
start()用于启动线程
run()调用线程对象中的run方法
join()合并插队到当前线程
sleep()睡眠释放cpu资源
setPriority()设置线程优先级

多线程的三种实现方式:
1,继承Thread类,
2,实现Runnable接口(推荐,方便的实现资源的共享)
3,通过Callable和Future创建线程

13.内存泄露如何查看和解决
概念:有些对象只有有限的生命周期,当他们的任务完成之后,它们将被垃圾回收,如果在对象的生命周期本该结束的时候,这个对象还被一系列的引用,着就会导致内存泄露。
解决方法:使用开源框架LeakCanary检测针对性解决
常见的内存泄露有:
单例造成的内存泄露,例如单例中的Context生命周期大于本身Context生命周期
线程使用Hander造成的内存泄露,当activity已经结束,线程依然在运行更新UI
非静态类使用静态变量导致无法回收释放造成泄露
WebView网页过多造成内存泄露
资源未关闭造成泄露,例如数据库使用完之后关闭连接

14.View的分发机制,滑动冲突
View的事件传递顺序有3个重要的方法,dispatchTouchEvent()是否消耗了本次事件,onInterceptTouchEvent()是否拦截了本次事件,onTouchEvent()是否处理本次事件,滑动冲突分为同方向滑动冲突,例如ScrollView和ListView,同方向滑动冲突,可以计算ListView高度而动态设置ListView的高度,ScrollView高度可变。例如ViewPager和ListView,不同方向滑动冲突,一个是横向滑动一个是竖直滑动,不同方向滑动可以判断滑动的x,y轴是横向还是竖直滑动,如果判断得到是横向滑动,就拦截ListView的事件,竖则反之。

15.RecyclerView和ListView的区别
前者缓存的是View+ViewHolder+flag,不用每次调用findViewById,后者则只是缓存View
刷新数据方面,前者提供了局部刷新,后者则全部刷新

16.RecyclerView嵌套卡顿解决如何解决
设置预加载的数量LinearLayoutManager.setInitialPrefetchItemCount(4),默认是预加载2个,
设置子项缓存,
设置自带滑动冲突解决属性rv.setHasFixedSize(true); rv.setNestedScrollingEnabled(false);
可以完美解决,不过Google不推荐RecyClerView嵌套使用,需要嵌套尽量找类似于ExpandableListView 第三方控件来解决

17.MVC ,MVP,MVVM
MVC:View是可以直接访问Model的。从而View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示及View。所以在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。
MVP:MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过Controller。
MVVM:数据双向绑定,通过数据驱动UI,M提供数据,V视图,VM即数据驱动层

18.Android性能优化
布局优化: 减少布局层级,使用ViewStub提高显示速度,布局服用,尽可能少使用warp_content,删除空间中无用的属性,避免过度绘制移除window默认背景,按需显示展位图,自定义View优化,使用canvas.clipRect()识别可见区域
启动速度:采用分布加载,异步加载,延期加载提高应用初始化速度,采用线程初始化数据等,合理的刷新机制
内存方面:防止内存泄露,使用一些第三方工具检测解决
代码优化:遵循Java生命周期
安装包优化:删除无用资源,优化图片,代码混淆,避免重复库存在,插件化

19.Hander原理
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作
一、Handler的定义:
  主要接受子线程发送的数据, 并用此数据配合主线程更新UI。
  解释:当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件, 进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 “强制关闭”。 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的, 也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。 这个时候,Handler就出现了。,来解决这个复杂的问题 ,由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
二、Handler一些特点
  handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:
  (1)安排消息或Runnable 在某个主线程中某个地方执行;
  (2)安排一个动作在不同的线程中执行。
三、Handler实例
  子类需要继承Hendler类,并重写handleMessage(Message msg) 方法, 用于接受线程数据。

20.SharedPreference跨进程使用会怎么样?如何保证跨进程使用安全?
在两个应用的manifest配置中好相同的shareUserId属性,A应用正常保存数据,B应用
createPackageContext(“com.netease.nim.demo”, CONTEXT_IGNORE_SECURITY)
获取context然后获取应用数据,为保证数据安全,使用加密存储

21.activity与fragment区别
生命周期:
fragment从创建到销毁整个生命周期依次为onAttach()→onCreate()→onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→onDestroy()→onDetach()
与activity不同的方法有
onAttach():当Fragment和Activity建立关联的时候调用;
onCreateView():当Fragment创建视图调用;
onActivityCreated:与Fragment相关联的Activity完成onCreate()之后调用;
onDestoryView():在Fragment中的布局被移除时调用;
onDetach():当Fragment和Activity解除关联时调用;
activity常用的生命周期只有以下几个;
onCreate(): 表示 Activity 正在被创建,常用来 初始化工作,比如调用 setContentView 加载界面布局资源,初始化 Activity 所需数据等;
onRestart():表示 Activity 正在重新启动,一般情况下,当前Acitivty 从不可见重新变为可见时,OnRestart就会被调用;
onStart(): 表示 Activity 正在被启动,此时 Activity 可见但不在前台,还处于后台,无法与用户交互;
onResume(): 表示 Activity 获得焦点,此时 Activity 可见且在前台并开始活动,这是与 onStart 的区别所在;
onPause(): 表示 Activity 正在停止,此时可做一些 存储数据、停止动画等工作,但是不能太耗时,因为这会影响到新 Activity的显示,onPause 必须先执行完,新 Activity 的 onResume 才会执行;
onStop(): 表示 Activity 即将停止,可以做一些稍微重量级的回收工作,比如注销广播接收器、关闭网络连接等,同样不能太耗时;
onDestroy(): 表示 Activity 即将被销毁,这是 Activity 生命周期中的最后一个回调,常做 回收工作、资源释放;
区别:
Fragment比Activity多出四个回调周期,控制操作上更灵活;
Fragment可以在xml文件中直接写入,也可以在Activity中动态添加;
Fragment可以使用show()/hide()或者replace()对Fragment进行切换,切换的时候不会出现明显的效果,Activity切换的时候会有明显的翻页或其他效果;

22.Fragment中add与replace的区别?
add不会重新初始化fragment,replace每次都会;
添加相同的fragment时,replace不会有任何变化,add会报IllegalStateException 异常;
replace 先 remove 掉相同 id 的所有 fragment,然后在add 当前的这个 fragment,而 add 是覆盖前一个fragment。所以如果使用 add 一般会伴随 hide()和show(),避免布局重叠;
使用 add,如果应用放在后台,或以其他方式被系统销毁,再打开时,hide()中引用的 fragment 会销毁,所以依然会出现布局重叠 bug,可以使用 replace 或使用add时,添加一个tag参数

23.FragmentPagerAdapter与FragmentStatePagerAdapter的区别与使用场景?
FragmentPagerAdapter 的每个 Fragment 会持久的保存在 FragmentManager 中,只要用户可以返回到页面中,它都不会被销毁。因此适用于那些数据 相对静态的页,Fragment 数量也比较少的那种;FragmentStatePagerAdapter 只保留当前页面,当页面不可见时,该 Fragment 就会被消除,释放其资源。因此适用于那些 数据动态性较大、 占用内存较多,多 Fragment 的情况

24.说下Activity 的四种启动模式、应用场景?
1)standard 标准模式: 每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在,此模式的 Activity 默认会进入启动它的Activity 所属的任务栈中;
2)singleTop 栈顶复用模式: 如果新Activity已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时会回调 onNewIntent方法,如果新Activity实例已经存在但不在栈顶,那么Activity 依然会被重新创建;
3)singleTask 栈内复用模式: 只要Activity在一个任务栈中存在,那么多次启动此 Activity 都不会重新创建实例,并回调onNewIntent 方法,此模式启动 Activity A,系统首先会寻找是否存在 A 想要的任务栈,如果不存在,就会重新创建一个任务栈,然后把创建好A的实例放到栈中;
4)singleInstance单实例模式: 这是一种加强的 singleTask 模式,具有此种模式的 Activity 只能单独地位于一个任务栈中,且此任务栈中只有唯一一个实例;

25.横竖屏切换的Activity生命周期变化?
不设置 Activity 的 android:configChanges 时,切屏会销毁当前Activity,然后重新加载调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;onPause()→onStop()→onDestory()→onCreate()→onStart()→onResume()
设置 Activity 的 android:configChanges=" orientation",经过机型测试
在 Android5.1(API23),切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
在 Android9(API28),切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

26.Android产生ANR时间
1)Service Timeout

// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000; // 前台

// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台

2)Broadcast Timeout

// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;  // 前台
static final int BROADCAST_BG_TIMEOUT = 60*1000;  // 后台

3)InputDispatching Timeout

// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;

4)ContentProvider Timeout

// How long we wait for an attached process to publish its content providers
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;

27.Android中volatile和synchronized的应用
1)synchronized
同步块通过 synchronized 来实现,所有加上synchronized和块语句,在多线程访问的时候,同一时刻只能有一个线程能够用
synchronized 修饰的方法或者代码块。

2)volatile
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。

28.invalidate()和postInvalidate() 的区别
Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程(工作者线程)中使用。

29.描述一下Android手机启动过程和App启动过程
Android手机启动过程 当我们开机时,首先是启动Linux内核,在Linux内核中首先启动的是init进程,这个进程会去读取配置文件system\core\rootdir\init.rc配置文件,这个文件中配置了Android系统中第一个进程Zygote进程。

启动Zygote进程 --> 创建AppRuntime(Android运行环境) --> 启动虚拟机 --> 在虚拟机中注册JNI方法 --> 初始化进程通信使用的Socket(用于接收AMS的请求) --> 启动系统服务进程 --> 初始化时区、键盘布局等通用信息 --> 启动Binder线程池 --> 初始化系统服务(包括PMS,AMS等等) --> 启动Launcher

App启动过程

应用的启动是从其他应用调用startActivity开始的。通过代理请求AMS启动Activity。
AMS创建进程,并进入ActivityThread的main入口。在main入口,主线程初始化,并loop起来。主线程初始化,主要是实例化ActivityThread和ApplicationThread,以及MainLooper的创建。ActivityThread和ApplicationThread实例用于与AMS进程通信。
应用进程将实例化的ApplicationThread,Binder传递给AMS,这样AMS就可以通过代理对应用进程进行访问。
AMS通过代理,请求启动Activity。ApplicationThread通知主线程执行该请求。然后,ActivityThread执行Activity的启动。
Activity的启动包括,Activity的实例化,Application的实例化,以及Activity的启动流程:create、start、resume。
可以看到入口Activity其实是先于Application实例化,只是onCreate之类的流程,先于Activity的流程。另外需要scheduleLaunchActivity,在ApplicationThreaad中,对应AMS管理Activity生命周期的方法都以scheduleXXXActivity,ApplicationThread在Binder线程中,它会向主线程发送消息,ActivityThread的Handler会调用相应的handleXXXActivity方法,然后会执行performXXXActivity方法,最终调用Activity的onXXX方法

30.ViewGroup事件分发
当一个点击事件产生后,它的传递过程将遵循如下顺序:
Activity -> Window -> View
事件总是会传递给Activity,之后Activity再传递给Window,最后Window再传递给顶级的View,顶级的View在接收到事件后就会按照事件分发机制去分发事件。如果一个View的onTouchEvent返回了FALSE,那么它的父容器的onTouchEvent将会被调用,依次类推,如果所有都不处理这个事件的话,那么Activity将会处理这个事件。
对于ViewGroup的事件分发过程,大概是这样的:如果顶级的ViewGroup拦截事件即onInterceptTouchEvent返回true的话,则事件会交给ViewGroup处理,如果ViewGroup的onTouchListener被设置的话,则onTouch将会被调用,否则的话onTouchEvent将会被调用,也就是说:两者都设置的话,onTouch将会屏蔽掉onTouchEvent,在onTouchEvent中,如果设置了onClickerListener的话,那么onClick将会被调用。如果顶级ViewGroup不拦截的话,那么事件将会被传递给它所在的点击事件的子view,这时候子view的dispatchTouchEvent将会被调用

31.堆和栈的主要区别
栈–主要存放引用和基本数据类型。
堆–用来存放 new 出来的对象实例和数组。

32.图片压缩
1)图片的质量压缩是指:会改变图片在磁盘中的大小(File文件的大小),不能改变图片在加载时,在内存中的大小。
2)图片的尺寸压缩是指:按照一定的倍数对图片减少单位尺寸的像素值,可以改变图片在内存中的大小,不改变图片在磁盘中的大小。

33.Intent传递的数据有大小限制吗?
Intent在传递数据时是有大小限制的。官方并未详细说明,不过可以估算出数据应该被限制在1MB之内(1024KB)可以试着传递一个超过1M的Bitmap,就可能导致程序闪退或停止运行。

34.两个对象互相引用,能被内存回收吗?
不能,只要对象、属性等存在被引用,GC都会过滤掉的,不会被回收

35.一个try块下面有多个catch块,其中一个catch块内又抛出了异常,能被下面的catch块捕获吗?
能,如果两个异常存在继承关系,应该把子类异常放在父类异常的前面来捕获

36.Android中Context类的继承体系
Context是维持Android程序中各组件能够正常工作的一个核心功能类
Context分为三种类型:Application、Activity、Service分别属于Context的一种,而他们的具体实现是由ContextImpl类去实现的

37.Android里面为什么要设计出Bundle而不是直接用HashMap结构?
1)Bundle内部是由ArrayMap实现的,ArrayMap的内部实现是两个数组,一个int数组是存储对象数据对应下标,一个对象数组保存key和value,内部使用二分法对key进行排序,所以在添加、删除、查找数据的时候,都会使用二分法查找,只适合于小数据量操作,如果在数据量比较大的情况下,那么它的性能将退化。而HashMap内部则是数组+链表结构,所以在数据量较少的时候,HashMap的Entry Array比ArrayMap占用更多的内存。因为使用Bundle的场景大多数为小数据量,我没见过在两个Activity之间传递10个以上数据的场景,所以相比之下,在这种情况下使用ArrayMap保存数据,在操作速度和内存占用上都具有优势,因此使用Bundle来传递数据,可以保证更快的速度和更少的内存占用。
2)另外一个原因,则是在Android中如果使用Intent来携带数据的话,需要数据是基本类型或者是可序列化类型,HashMap使用Serializable进行序列化,而Bundle则是使用Parcelable进行序列化。而在Android平台中,更推荐使用Parcelable实现序列化,虽然写法复杂,但是开销更小,所以为了更加快速的进行数据的序列化和反序列化,系统封装了Bundle类,方便我们进行数据的传输。

38.HashMap底层是如何实现的?
1)使用hash算法,基于数组+链表+红黑树来实现
2)内部数组的初始长度为16,能自动扩容

39.java常用的设计模式
1)单例模式
每个类只能创建一个实例对象,主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。 可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收
2)工厂模式(多态,一个接口实现多个回调方法)
将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,明确了职责。把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则,面向接口编程,而不是面向实现编程。
安卓面试题_第3张图片安卓面试题_第4张图片
3)观察者模式
观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。例如:GUI中的事件处理机制采用的就是观察者模式。
安卓面试题_第5张图片
安卓面试题_第6张图片
40.Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
不是主线程更新Ui,就要加Looper.getMainLooper(),如果你不带参数的实例化:Handler handler = new Handler();那么这个会默认用当前线程的looper
一般而言,如果你的Handler是要来刷新操作UI的,那么就需要在主线程下跑。
情况:
1.要刷新UI,handler要用到主线程的looper。那么在主线程 Handler handler = new Handler();,如果在其他线程,也要满足这个功能的话,要Handler handler = new Handler(Looper.getMainLooper());
2.不用刷新ui,只是处理消息。 当前线程如果是主线程的话,Handler handler = new Handler();不是主线程的话,Looper.prepare(); Handler handler = new Handler();Looper.loop();或者Handler handler = new Handler(Looper.getMainLooper());
若是实例化的时候用Looper.getMainLooper()就表示放到主UI线程去处理。
如果不是的话,因为只有UI线程默认Loop.prepare();Loop.loop();过,其他线程需要手动调用这两个,否则会报错。

41.Handler、Loop、Message
Loop中会构造一个message的对列,而没个message的中的target指向是handler。
而在一个Thread中调用Loop.prepare()会给此Thread创建一个loop对象,同时loop有会创建一个messageQueue,
当调用loop.loop()时,开始循环从messageQueue中获取消息,当messageQueue中没有消息的时候,进入堵塞状态。
当loop不在使用的时候可以调用loop.quit()释放资源
Handler的postDelayed底层的实现相当于一个wait的操作,当时间未到时等待,但不堵塞线程,非sleep类型

42.自定义View和ViewGroup区别
1)自定义 View
1.自定义属性,获取自定义属性(达到配置的效果)
2.onMeasure()方法用于测量自己宽高,前提是继承View。如果继承系统已经有的控件比如TextView,Button等等 则不需要重写,因为系统已经给你计算好了。
3.onDraw()方法用于绘制自己想实现的样式。
4.onTouch()用于用户和控件的交互处理。

2)自定义 ViewGroup
1.自定义属性,获取自定义属性(达到配置的效果)
2.onMeasure方法,for循环获取所有子view,然后根据子view的宽高来计算自己的宽高。
3.onDraw() 一般不需要,默认是不会调用的。如果需要绘制就要实现dispatchDraw()来进行绘制。
4.onLayout()用来摆放子view,前提view是可见
5.很多情况下不是不会继承ViewGroup的,一般都是继承系统控件。

43.View的onMeasure()、onSizeChanged()、onLayout()、onDraw()调用顺序
继承与View和继承与现有控件都是下面的顺序,但是控件的大小是生成之后就固定的,不会再次改变。
onMeasure()→onSizeChanged()→onLayout()→onMeasure()→onLayout()→onDraw()

44.LinkedeList和ArrayList的区别
1)数据结构不同
ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构。
2)效率不同
当随机访问List(get和set操作)时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
当对数据进行增加和删除的操作(add和remove操作)时,LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。
3)自由性不同
ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
4)主要控件开销不同
ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。

你可能感兴趣的:(安卓面试题)