写点什么

字节跳动正式启动 2021 届秋季校招!这份字节跳动历年校招 Android 面试真题解析,你确定不收藏

用户头像
Android架构
关注
发布于: 刚刚
  • 参考回答:View 动画改变的只是 View 的显示,而没有改变 View 的响应区域;而属性动画会通过反射技术来获取和执行属性的 get、set 方法,从而改变了对象位置的属性值。


Q:属性动画插值器和估值器的作用?


  • 技术点:属性动画

  • 参考回答:

  • 插值器(Interpolator):根据时间流逝的百分比计算出当前属性值改变的百分比。确定了动画效果变化的模式,如匀速变化、加速变化等等。View 动画和属性动画均可使用。常用的系统内置插值器:

  • 线性插值器(LinearInterpolator):匀速动画

  • 加速减速插值器(AccelerateDecelerateInterpolator):动画两头慢中间快

  • 减速插值器(DecelerateInterpolator):动画越来越慢

  • 类型估值器(TypeEvaluator):根据当前属性改变的百分比计算出改变后的属性值。针对于属性动画,View 动画不需要类型估值器。常用的系统内置的估值器:

  • 整形估值器(IntEvaluator)

  • 浮点型估值器(FloatEvaluator)

  • Color 属性估值器(ArgbEvaluator)



Q:Activity、View、Window三者之间的关系?


  • 技术点:Activity、View、Window 联系

  • 思路:围绕 Window 是 Activity 和 View 的桥梁展开

  • 参考回答:在 Activity 启动过程其中的 attach()方法中初始化了 PhoneWindow,而 PhoneWindow 是 Window 的唯一实现类,然后 Activity 通过 setContentView 将 View 设置到了 PhoneWindow 上,而 View 通过 WindowManager 的 addView()、removeView()、updateViewLayout()对 View 进行管理。


Q:Window有哪几种类型?


  • 技术点:Window 类型

  • 参考回答:Window 有三种类型:

  • 应用 Window:对应一个 Activity。

  • 子 Window:不能单独存在,需附属特定的父 Window。如 Dialog。

  • 系统 Window: 需申明权限才能创建。如 Toast。


Q:Activity创建和Dialog创建过程的异同?


  • 技术点:Window 创建

  • 参考回答:Dialog 的 Window 创建过程:

  • 创建 WindowDialog。和 Activity 类似,同样是通过 PolicyManager.makeNewWindow() 来实现。

  • 初始化 DecorView 并将 Dialog 的视图添加到 DecorView 中去。和 Activity 类似,同样是通过 Window.setContentView() 来实现。

  • 将 DecorView 添加到 Window 中显示。和 Activity 一样,都是在自身要出现在前台时才会将添加 Window。

  • Dialog.show() 方法:完成 DecorView 的显示。

  • WindowManager.remoteViewImmediate() 方法:当 Dialog 被 dismiss 时移除 DecorView。



Q:谈谈消息机制Hander?作用?有哪些要素?流程是怎样的?


  • 技术点:消息机制

  • 参考回答:

  • 作用:跨线程通信。当子线程中进行耗时操作后需要更新 UI 时,通过 Handler 将有关 UI 的操作切换到主线程中执行。

  • 四要素:

  • Message(消息):需要被传递的消息,其中包含了消息 ID,消息处理对象以及处理的数据等,由 MessageQueue 统一列队,最终由 Handler 处理。

  • MessageQueue(消息队列):用来存放 Handler 发送过来的消息,内部通过单链表的数据结构来维护消息列表,等待 Looper 的抽取。

  • Handler(处理者):负责 Message 的发送及处理。通过 Handler.sendMessage() 向消息池发送各种消息事件;通过 Handler.handleMessage() 处理相应的消息事件。

  • Looper(消息泵):通过 Looper.loop()不断地从 MessageQueue 中抽取 Message,按分发机制将消息分发给目标处理者。

  • 具体流程如图

![](https://up


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


load-images.jianshu.io/upload_images/23948686-90997e20d52cd2c3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


  • Handler.sendMessage()发送消息时,会通过MessageQueue.enqueueMessage()向 MessageQueue 中添加一条消息;

  • 通过Looper.loop()开启循环后,不断轮询调用MessageQueue.next()

  • 调用目标Handler.dispatchMessage()去传递消息,目标 Handler 收到消息后调用Handler.handlerMessage()处理消息。


Q:为什么系统不建议在子线程访问UI?


  • 技术点:UI 线程、子线程

  • 参考回答:系统不建议在子线程访问 UI 的原因是,UI 控件非线程安全,在多线程中并发访问可能会导致 UI 控件处于不可预期的状态。而不对 UI 控件的访问加上锁机制的原因有:

  • 上锁会让 UI 控件变得复杂和低效

  • 上锁后会阻塞某些进程的执行


Q:一个Thread可以有几个Looper?几个Handler?


  • 技术点:Looper、Handler

  • 参考回答:一个 Thread 只能有一个 Looper,可以有多个 Handler

  • 引申:更多数量关系:Looper 有一个 MessageQueue,可以处理来自多个 Handler 的 Message;MessageQueue 有一组待处理的 Message,这些 Message 可来自不同的 Handler;Message 中记录了负责发送和处理消息的 Handler;Handler 中有 Looper 和 MessageQueue;


Q:如何将一个Thread线程变成Looper线程?Looper线程有哪些特点?


  • 技术点:Looper

  • 参考回答:通过 Looper.prepare()可将一个 Thread 线程转换成 Looper 线程。Looper 线程和普通 Thread 不同,它通过 MessageQueue 来存放消息和事件、Looper.loop()进行消息轮询。


Q:可以在子线程直接new一个Handler吗?那该怎么做?


  • 技术点:Handler

  • 参考回答:不同于主线程直接 new 一个 Handler,由于子线程的 Looper 需要手动去创建,在创建 Handler 时需要多一些方法:


new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();//为子线程创建 Looper


new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);//子线程消息处理}};Looper.loop(); //开启消息轮询}}).start();


Q:Message可以如何创建?哪种效果更好,为什么?


  • 技术点:Message

  • 参考回答:创建 Message 对象的几种方式:

  • Message msg = new Message();

  • Message msg = Message.obtain();

  • Message msg = handler1.obtainMessage();后两种方法都是从整个 Messge 池中返回一个新的 Message 实例,能有效避免重复 Message 创建对象,因此更鼓励这种方式创建 Message


Q:这里的ThreadLocal有什么作用?


  • 技术点:ThreadLocal

  • 参考回答:ThreadLocal 类可实现线程本地存储的功能,把共享数据的可见范围限制在同一个线程之内,无须同步就能保证线程之间不出现数据争用的问题,这里可理解为 ThreadLocal 帮助 Handler 找到本线程的 Looper。

  • 底层数据结构:每个线程的 Thread 对象中都有一个 ThreadLocalMap 对象,它存储了一组以 ThreadLocal.threadLocalHashCode 为 key、以本地线程变量为 value 的键值对,而 ThreadLocal 对象就是当前线程的 ThreadLocalMap 的访问入口,也就包含了一个独一无二的 threadLocalHashCode 值,通过这个值就可以在线程键值值对中找回对应的本地线程变量。


Q:主线程中Looper的轮询死循环为何没有阻塞主线程?


  • 技术点:Looper

  • 参考回答:Android 是依靠事件驱动的,通过 Loop.loop()不断进行消息循环,可以说 Activity 的生命周期都是运行在 Looper.loop()的控制之下,一旦退出消息循环,应用也就退出了。而所谓的导致 ANR 多是因为某个事件在主线程中处理时间太耗时,因此只能说是对某个消息的处理阻塞了 Looper.loop(),反之则不然。


Q:使用Hanlder的postDealy()后消息队列会发生什么变化?


  • 技术点:Handler

  • 参考回答:post delay 的 Message 并不是先等待一定时间再放入到 MessageQueue 中,而是直接进入并阻塞当前线程,然后将其 delay 的时间和队头的进行比较,按照触发时间进行排序,如果触发时间更近则放入队头,保证队头的时间最小、队尾的时间最大。此时,如果队头的 Message 正是被 delay 的,则将当前线程堵塞一段时间,直到等待足够时间再唤醒执行该 Message,否则唤醒后直接执行。



Q:Android中还了解哪些方便线程切换的类?


  • 技术点:线程通信

  • 参考回答:对 Handler 进一步的封装的几个类:

  • AsyncTask:底层封装了线程池和 Handler,便于执行后台任务以及在子线程中进行 UI 操作。

  • HandlerThread:一种具有消息循环的线程,其内部可使用 Handler。

  • IntentService:是一种异步、会自动停止的服务,内部采用 HandlerThread。

  • 引申:更多是对消息机制的理解


Q:AsyncTask相比Handler有什么优点?不足呢?


  • 技术点:AsyncTask、Handler

  • 参考回答:

  • Handler 机制存在的问题:多任务同时执行时不易精确控制线程。

  • 引入 AsyncTask 的好处:创建异步任务更简单,直接继承它可方便实现后台异步任务的执行和进度的回调更新 UI,而无需编写任务线程和 Handler 实例就能完成相同的任务。


Q:使用AsyncTask需要注意什么?


  • 技术点:AsyncTask

  • 参考回答:

  • 不要直接调用 onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()和 onCancelled()方法

  • 一个异步对象只能调用一次 execute()方法

  • 引申:谈谈 AsyncTask 初始化、五个核心方法如何配合进而体现 Handler 的作用


Q:AsyncTask中使用的线程池大小?


  • 技术点:AsyncTask

  • 参考回答:在 AsyncTask 内部实现有两个线程池:

  • SerialExecutor:用于任务的排队,默认是串行的线程池,在 3.0 以前核心线程数为 5、线程池大小为 128,而 3.0 以后变为同一时间只能处理一个任务

  • THREAD_POOL_EXECUTOR:用于真正执行任务。

  • 引申:谈谈对线程池的理解


Q:HandlerThread有什么特点?


  • 技术点:HandlerThread

  • 参考回答:HandlerThread 是一个线程类,它继承自 Thread。与普通 Thread 不同,HandlerThread 具有消息循环的效果,这是因为它内部HandlerThread.run()方法中有 Looper,能通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。


Q:快速实现子线程使用Handler


  • 技术点:HandlerThread

  • 思路:不同于之前手动在子线程创建 Looper 再构建 Handler 的想法,这里从 HandlerThread 角度去快速实现在子线程使用 Handler

  • 参考回答:HandlerThread 实现方法

  • 实例化一个 HandlerThread 对象,参数是该线程的名称;

  • 通过 HandlerThread.start()开启线程;

  • 实例化一个 Handler 并传入 HandlerThread 中的 looper 对象,使得与 HandlerThread 绑定;

  • 利用 Handler 即可执行异步任务;

  • 当不需要 HandlerThread 时,通过 HandlerThread.quit()/quitSafely()方法来终止线程的执行。


Q:IntentService的特点?


  • 技术点:IntentService

  • 思路:和普通线程和普通 Service 比较突出其特点

  • 参考回答: 不同于线程,IntentService 是服务,优先级比线程高,更不容易被系统杀死,因此较适合执行一些高优先级的后台任务;不同于普通 Service,IntentService 可自动创建子线程来执行任务,且任务执行完毕后自动退出


Q:为何不用bindService方式创建IntentService?


  • 技术点:IntentService

  • 思路:从底层实现出发

  • 参考回答:IntentService 的工作原理是,在 IntentService 的 onCreate()里会创建一个 HandlerThread,并利用其内部的 Looper 实例化一个 ServiceHandler 对象;而这个 ServiceHandler 用于处理消息的 handleMessage()方法会去调用 IntentService 的 onHandleIntent(),这也是为什么可在该方法中处理后台任务的逻辑;当有 Intent 任务请求时会把 Intent 封装到 Message,然后 ServiceHandler 会把消息发送出,而发送消息是在 onStartCommand()完成的,只能通过 startService()才可走该生命周期方法,因此不能通过 bindService 创建 IntentService。


Q:线程池的好处、原理、类型?


  • 技术点:线程池

  • 参考回答:

  • (1)线程池的好处:

  • 重用线程池中的线程,避免线程的创建和销毁带来的性能消耗;

  • 有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致阻塞现象;

  • 进行线程管理,提供定时/循环间隔执行等功能

  • (2)线程池的分类:

  • FixThreadPool:线程数量固定的线程池,所有线程都是核心线程,当线程空闲时不会被回收;能快速响应外界请求。

  • CachedThreadPool:线程数量不定的线程池(最大线程数为 Integer.MAX_VALUE),只有非核心线程,空闲线程有超时机制,超时回收;适合于执行大量的耗时较少的任务

  • ScheduledThreadPool:核心线程数量固定,非核心线程数量不定;可进行定时任务和固定周期的任务。

  • SingleThreadExecutor:只有一个核心线程,可确保所有的任务都在同一个线程中按顺序执行;好处是无需处理线程同步问题。

  • (3)线程池的原理:实际上通过 ThreadPoolExecutor 并通过一系列参数来配置各种各样的线程池,具体的参数有:

  • corePoolSize 核心线程数:一般会在线程中一直存活

  • maximumPoolSize 最大线程数:当活动线程数达到这个数值后,后续的任务将会被阻塞

  • keepAliveTime 非核心线程超时时间:超过这个时长,闲置的非核心线程就会被回收

  • unit:用于指定 keepAliveTime 参数的时间单位

  • workQueue 任务队列:通过线程池的execute()方法提交的 Runnable 对象会存储在这个参数中。

  • threadFactory:线程工厂,可创建新线程

  • handler:在线程池无法执行新任务时进行调度

  • 引申:使用Executors各个方法创建线程池的弊端


Q:ThreadPoolExecutor的工作策略?


  • 技术点:线程池

  • 参考回答:ThreadPoolExecutor 的默认工作策略

  • 若程池中的线程数量未达到核心线程数,则会直接启动一个核心线程执行任务。

  • 若线程池中的线程数量已达到或者超过核心线程数量,则任务会被插入到任务列表等待执行。

  • 若任务无法插入到任务列表中,往往由于任务列表已满,此时如果

  • 线程数量未达到线程池最大线程数,则会启动一个非核心线程执行任务;

  • 线程数量已达到线程池规定的最大值,则拒绝执行此任务,ThreadPoolExecutor 会调用 RejectedExecutionHandler 的 rejectedExecution 方法来通知调用者。

  • 引申:ThreadPoolExecutor 的拒绝策略


Q:什么是ANR?什么情况会出现ANR?如何避免?在不看代码的情况下如何快速定位出现ANR问题所在?


  • 技术点:ANR

  • 思路:

  • 参考回答:

  • ANR(Application Not Responding,应用无响应):当操作在一段时间内系统无法处理时,会在系统层面会弹出 ANR 对话框

  • 产生 ANR 可能是因为 5s 内无响应用户输入事件、10s 内未结束 BroadcastReceiver、20s 内未结束 Service

  • 想要避免 ANR 就不要在主线程做耗时操作,而是通过开子线程,方法比如继承 Thread 或实现 Runnable 接口、使用 AsyncTask、IntentService、HandlerThread 等

  • 引申:快读定位 ANR 方法:使用命令导出 ANR 日志,并分析关键信息,详见ANR问题一般解决思路



Q:加载图片的时候需要注意什么?


  • 技术点:Bitmap 高效加载

  • 参考回答:

  • 直接加载大容量的高清 Bitmap 很容易出现显示不完整、内存溢出 OOM 的问题,所以最好按一定的采样率将图片缩小后再加载进来

  • 为减少流量消耗,可对图片采用内存缓存策略,又为了避免图片占用过多内存导致内存溢出,最好以软引用方式持有图片

  • 如果还需要网上下载图片,注意要开子线程去做下载的耗时操作


Q:LRU算法的原理?


  • 技术点:LRU 算法

  • 参考回答:为减少流量消耗,可采用缓存策略。常用的缓存算法是 LRU(Least Recently Used):

  • 核心思想:当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:

  • LruCache(内存缓存):LruCache 类是一个线程安全的泛型类:内部采用一个LinkedHashMap强引用的方式存储外界的缓存对象,并提供getput方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。

  • DiskLruCache(磁盘缓存): 通过将缓存对象写入文件系统从而实现缓存效果

  • 引申:感兴趣可了解具体实现算法



Q:项目中如何做性能优化的?


  • 技术点:性能优化实例

  • 思路:举例说明项目注意了哪些方面的性能优化,如布局优化、绘制优化、内存泄漏优化、 响应速度优化、列表优化、Bitmap 优化、 线程优化......


Q:了解哪些性能优化的工具?


  • 技术点:性能优化工具

  • 思路:做项目时是否使用过的系统自带的性能优化工具?公司是否有自己的性能优化工具?实现原理怎样的?


Q:布局上如何优化?


  • 技术点:布局优化

  • 参考回答:布局优化的核心就是尽量减少布局文件的层级,常见的方式有:

  • 多嵌套情况下可使用 RelativeLayout 减少嵌套。

  • 布局层级相同的情况下使用 LinearLayout,它比 RelativeLayout 更高效。

  • 使用<include>标签重用布局、<merge>标签减少层级、<ViewStub>标签懒加载。


Q:内存泄漏是什么?为什么会发生?常见哪些内存泄漏的例子?都是怎么解决的?


  • 技术点:内存泄漏

  • 参考回答:内存泄漏(Memory Leak)是指程序在申请内存后,无法释放已申请的内存空间。简单地说,发生内存泄漏是由于长周期对象持有对短周期对象的引用,使得短周期对象不能被及时回收。常见的几个例子和解决办法:

  • 单例模式导致的内存泄漏:单例传入参数 this 来自 Activity,使得持有对 Activity 的引用。

  • 解决办法:传参 context.getApplicationContext()

  • Handler 导致的内存泄漏:Message 持有对 Handler 的引用,而非静态内部类的 Handler 又隐式持有对外部类 Activity 的引用,使得引用关系会保持至消息得到处理,从而阻止了 Activity 的回收。

  • 解决办法:使用静态内部类+WeakReference 弱引用;当外部类结束生命周期时清空消息队列。

  • 线程导致的内存泄漏:AsyncTask/Runnable 以匿名内部类的方式存在,会隐式持有对所在 Activity 的引用。

  • 解决办法:将 AsyncTask 和 Runnable 设为静态内部类或独立出来;在线程内部采用弱引用保存 Context 引用

  • 资源未关闭导致的内存泄漏:未及时注销资源导致内存泄漏,如 BraodcastReceiver、File、Cursor、Stream、Bitmap 等。

  • 解决办法:在 Activity 销毁的时候要及时关闭或者注销。

  • BraodcastReceiver:调用unregisterReceiver()注销;

  • Cursor,Stream、File:调用close()关闭;

  • 动画:在Activity.onDestroy()中调用Animator.cancel()停止动画

  • 引申:谈谈项目中是如何注意内存泄漏的问题


Q:内存泄漏和内存溢出的区别


  • 技术点:内存泄漏、内存溢出

  • 参考回答:

  • 内存泄漏(Memory Leak)是指程序在申请内存后,无法释放已申请的内存空间。是造成应用程序 OOM 的主要原因之一。

  • 内存溢出(out of memory)是指程序在申请内存时,没有足够的内存空间供其使用。


Q:什么情况会导致内存溢出?


  • 技术点:内存溢出

  • 参考回答:内存泄漏是导致内存溢出的主要原因;直接加载大图片也易造成内存溢出

  • 引申:谈谈如何避免内存溢出(如何避免内存泄漏、避免直接加载大图片)


  • 开源框架(略)

  • 谷歌新动态


Q:是否了解和使用过谷歌推出的新技术?Q:有了解刚发布的Androidx.0的特性吗?Q:Kotlin对Java做了哪些优化?


  • 可能意图:了解候选者对谷歌 &安卓的关注度、共同探讨对新技术的看法、学习主动性、平时学习习惯

  • 思路:谷歌的安卓官方网站(中文版):https://developer.android.google.cn,了解最新动态


1.2 Java


  • 基础


Q:面向对象编程的四大特性及其含义?


  • 技术点:面向对象编程特点

  • 思路:分条简述每个特性的含义

  • 参考回答:

  • 抽象:对现实世界的事物进行概括,抽象为在计算机虚拟世界中有意义的实体

  • 封装:将某事物的属性和行为包装到对象中,构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,并且尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系

  • 继承:子类继承父类,不仅可以有父类原有的方法和属性,也可以增加自己的或者重写父类的方法及属性

  • 多态:允许不同类的对象对同一消息做出各自的响应


Q:String、StringBuffer和StringBuilder的区别?


  • 技术点:String

  • 参考回答:

  • String 是字符串常量,而 StringBuffer、StringBuilder 都是字符串变量,即 String 对象一创建后不可更改,而后两者的对象是可更改的:

  • StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,这是由于 StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁

  • String 更适用于少量的字符串操作的情况,StringBuilder 适用于单线程下在字符缓冲区进行大量操作的情况,StringBuffer 适用于多线程下在字符缓冲区进行大量操作的情况


Q:String a=""和String a=new String("")的的关系和异同?


  • 技术点:String

  • 参考回答:

  • 通过 String a=""直接赋值的方式得到的是一个字符串常量,存在于常量池;注意,相同内容的字符串在常量池中只有一个,即如果池已包含内容相等的字符串会返回池中的字符串,反之会将该字符串放入池中

  • 通过 new String("")创建的字符串不是常量是实例对象,会在堆内存开辟空间并存放数据,且每个实例对象都有自己的地址空间

  • 引申:对于用 String a=""和 String a=new String("")两种方式定义的字符串,判断使用 equals()、"=="比较结果是什么


Q:Object的equal()和==的区别?


  • 技术点:equal()、==

  • 参考回答:

  • equals():是 Object 的公有方法,具体含义取决于如何重写,比如 String 的 equals()比较的是两个字符串的内容是否相同

  • "==" :对于基本数据类型来说,比较的是两个变量值是够是否相等,对于引用类型来说,比较的是两个对象的内存地址是否相同

  • 引申:对于用 String a=""和 String a=new String("")两种方式定义的字符串,判断使用 equals()、"=="比较结果是什么


Q:装箱、拆箱什么含义?


  • 技术点:装箱、拆箱

  • 参考回答:装箱就是自动将基本数据类型转换为包装器类型,拆箱就是自动将包装器类型转换为基本数据类型


Q:int和Integer的区别?


  • 技术点:基本数据类型、引用类型

  • 参考回答:

  • Integer 是 int 的包装类,int 则是 java 的一种基本数据类型

  • Integer 变量必须实例化后才能使用,而 int 变量不需要

  • Integer 实际是对象的引用,当 new 一个 Integer 时,实际上是生成一个指针指向此对象;而 int 则是直接存储数据值

  • Integer 的默认值是 null,int 的默认值是 0


Q:遇见过哪些运行时异常?异常处理机制知道哪些?


  • 技术点:Java 异常机制

  • 思路:对 Throwable 异常进行分类说明每种异常的特点和常见问题,简述几种常见异常处理机制,详见Java基础之异常机制

  • 参考回答:

  • (1) Throwable 继承层次结构,可见分成两大类 Error 和 Exception:

  • Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题;发生于虚拟机自身、或者在虚拟机试图执行应用时,如 Virtual MachineError(Java 虚拟机运行错误)、NoClassDefFoundError(类定义错误);属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。

  • Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:

  • RuntimeException(运行时异常):由程序自身的问题导致产生的异常;如 NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常);属于不可查异常。

  • 非运行时异常:由程序外部的问题引起的异常;除了 RuntimeException 以外的异常,如 FileNotFoundException(文件不存在异常);属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。

  • (2)常见的异常处理机制有:

  • 捕捉异常:由系统自动抛出异常,即 try 捕获异常->catch 处理异常->finally 最终处理

  • 抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。配合 throws 声明抛出的异常和 throw 抛出异常

  • 自定义异常:继承 Execption 类或其子类


Q:什么是反射,有什么作用和应用?


  • 技术点:反射

  • 思路:简述反射的定义、功能和应用,详见Java基础之泛型&反射

  • 参考回答:

  • 含义:在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任何一个对象都能够调用它的任何一个方法和属性。

  • 功能:动态性,体现在:在运行时判断任意一个类所具有的属性和方法; 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时调用任意一个对象的方法;生成动态代理

  • 应用:反射 &泛型

  • 引申:是否在项目中使用过反射机制,有什么优缺点


Q:什么是内部类?有什么作用?静态内部类和非静态内部类的区别?


  • 技术点:内部类

  • 思路:

  • 参考回答:内部类就是定义在另外一个类里面的类。它隐藏在外部类中,封装性更强,不允许除外部类外的其他类访问它;但它可直接访问外部类的成员。静态内部类和非静态内部类的区别有:

  • 静态内部类是指被声明为 static 的内部类,可不依赖外部类实例化;而非静态内部类需要通过生成外部类来间接生成。

  • 静态内部类只能访问外部类的静态成员变量和静态方法,而非静态内部类由于持有对外部类的引用,可以访问外部类的所用成员

  • 引申:谈谈匿名内部类


Q:final、finally、finalize()分别表示什么含义


  • 技术点:final、finally、finalize()

  • 参考回答:

  • final 关键字表示不可更改,具体体现在:

  • final 修饰的变量必须要初始化,且赋初值后不能再重新赋值

  • final 修饰的方法不能被子类重写

  • final 修饰的类不能被继承

  • finally:和 try、catch 成套使用进行异常处理,无论是否捕获或处理异常,finally 块里的语句都会被执行,在以下 4 种特殊情况下,finally 块才不会被执行:

  • 在 finally 语句块中发生了异常

  • 在前面的代码中用了System.exit()退出程序

  • 程序所在的线程死亡

  • 关闭 CPU

  • finalize():是 Object 中的方法,当垃圾回收器将回收对象从内存中清除出去之前会调用 finalize(),但此时并不代表该回收对象一定会“死亡”,还有机会“逃脱”

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
字节跳动正式启动2021届秋季校招!这份字节跳动历年校招Android面试真题解析,你确定不收藏