字节跳动正式启动 2021 届秋季校招!这份字节跳动历年校招 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
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:在线程池无法执行新任务时进行调度
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
以强引用的方式存储外界的缓存对象,并提供get
和put
方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。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(),但此时并不代表该回收对象一定会“死亡”,还有机会“逃脱”
评论