面试的话, 一天面完3面, 效率很高, 三天之后就发了offer
字节邮件里面也说了不能泄露面试题, 那我就把我秋招参与美团,字节,腾讯,阿里面试被问到的全部问题总结着写出来了, 这其实是我每一轮面试完之后我都会总结哪里答对了, 哪里没有答对, 总结了一大堆问题出来. 答案未必正确, 我只是给自己写了个简单的一句话概括, 可能不够完善, 建议看官自行回答一下这些问题
二本非科班, 暑假在字节实习过, 不过不是tiktok部门, 因此秋招就没啥时间准备面试了, 只投了几个大厂, 顺便也在字节跨部门转正, 被问到了很多问题, 面试体验最好的是字节, 最烂的是阿里, 阿里总给我一种高高在上问我的感觉, 而字节面试更像是在聊天.
其实因为是校招嘛, 问的也都不是特别难, 因为懂一点字节码插桩以及热修复技术, 还了解一点点性能优化, 就和面试官聊的非常开心, 也就过的很顺利
进程和线程? 线程的轻量级的体现在哪里?
: 一个进程可以有多个线程, 线程是CPU调度的最小单位, 进程是资源分配的最小单位. 轻量级的话, 进程是静态的只用来分配资源的, 线程是动态的用来执行指令的.线程crash进程会不会crash
: 在Java语言的话, 线程crash并不会导致进程crash, 不过进程内不同线程之间的内存是共享的, 一个线程的crash可能导致其他线程用到的内存访问到不正确的数据, 然后导致其他线程出现crash死锁了解吗? 说一下死锁产生的四个必要条件?有什么算法能避免死锁吗
(银行家算法): 四个必要条件: 互斥(一个资源一次只能分配给一个线程使用), 不可剥夺(一个线程不能强行占有其他线程已经占有的), 请求和保持(一个线程在等待其他进程释放资源的同时,继续占有已经拥有的资源), 循环等待条件(A等B等C等A)操作系统中cpu调度算法有哪些? 你觉得其中最好的一种是?
: 首先是分为抢占和非抢占, 具体有:先进先执行FCFS/最短优先SJF/优先权***转法(隔一段时间被迫交出CPU)...操作系统IO模型
: 同步阻塞/同步非阻塞(轮询:隔一会儿瞄一眼进度条/IO多路复用:poll&epoll机制:Handler?)/异步非阻塞(回调式)/异步阻塞(Kotlin协程suspend底层原理利用了Continuation实现了CPS转换,回调地狱应该算异步阻塞)
进程通信方式
: 管道(只能在有亲缘关系进程间单向流动), 有名管道(允许无亲缘关系进程间单向流动), 消息队列, 共享内存, 信号量(控制多个进程对共享资源的访问,常用于文件锁), 套接字(可用于网络), 信号(通知进程某个事件已经发生)解释性语言
: Java编译成class, 在不同平台使用不同虚拟机解释执行. 编译型语言: c语言编译成二进制文件, 不同平台可执行的二进制文件不同.架构? MVVM/MVP 区别
:(MVC: View触发事件传递给Controller通知Model数据变化刷新View. MVP: MV彻底解耦, Presenter持有两者的接口进行操作. MVVM: MV彻底解耦, VM实现数据双向绑定, 比如Google的Databinding, 这时我们其实还需要写BindAdapter)https与http的区别, 数字签名?
: 多了一层 TLS/SSL, 数字签名将服务器发来的密文用签发机构的公钥解密, 然后和服务器的信息的hash值进行对比DNS解析怎么做的? DNS劫持如何避免
: DNS解析就是根据指定的域名, 记录类型(A,AAAA,CNAME,MX,NS), 记录值找到指定的服务器或跳转到其他域名. 避免DNS劫持可以在OkHttpClient中自定义自己的dnshttp状态码
: 100/102continue, 206分段内容, 301永久/301临时重定向/304 NotModified, 401未授权/403Forbidden服务器拒绝请求/404NotFound, 500服务器内部错误/502网关错误/503服务暂时不可用http2多路复用
: 基于二进制分帧层, HTTP消息被分解为独立的帧并行发送出去, 最后在另一端根据流ID重新组合http几个版本的不同
: 1.1: 多条连接承载多个请求, 2.0: 单条连接多路复用, 3.0: 基于QUIC实现快速可靠的UDP连接get与post请求的区别? get与post携带数据的区别
: get往往使用FormUrlEncoded这种方式将请求参数编码在url中, post往往会在body中包含数据. 且get请求一般带有缓存, post没有. get发送一次, post会先发送一次header, 服务端响应100 continue, 然后再发送真实数据, 响应 200浏览器输入url发生了什么
: 构建请求/DNS解析/发起TCP连接/发送HTTP请求/服务端响应HTTP请求/客户端处理请求TCP原理
, 如何实现可靠传输, 除了三次握手和四次挥手还有哪些机制?
: ACK(服务端返回收到的最后一次正确的seq+1), 流量控制, 拥塞控制为什么要三次握手/四次挥手
:
tcp长连接和http长连接区别
: HTTP header(Connection: keep-alive), 指的是一个连接会保持一段时间, 而不是传输完数据就直接断开. TCP长连接指的是TCP保活计时器, HTTP的长连接本质上是TCP的长连接, TCP的长连接通过心跳包建立.UDP如何实现可靠传输
: QUIC: 基于UDP,减少了握手时间/避免队头阻塞的多路复用怎么优化首页加载速度(从数据传输方面)
:(使用http3.0, 加入缓存机制, protobuf, 预加载机制, 服务端优化查询策略, dns解析存储ip, 跳过查找过程服务端进行压缩, 数据分页传递...)说一下你熟悉的设计模式?
: Factory/Builder/Adapter/Observer/Proxy/Singleton...设计模式六大原则
:开闭(扩展开放,修改关闭), 里氏代换(基类可以出现的地方,子类一定可以替换), 依赖反转(面向切面编程而不是具体的实现), 接口隔离(使用多个隔离接口解耦), 最少知道(尽可能少的与其他实体相互作用,系统功能模块相对独立), 合成复用(使用组合而不是继承)多态能解决什么问题, 多态的底层原理
: invokespecial(init及私有方法)/invokevirtual(虚方***检查父类)泛型是什么
(在同一份代码上操作多种类型), 泛型上界下界?
(上:extends,out/下:super,in) 如何反射获取泛型类型
: Field.genericTypeJava内部类和静态内部类的区别
: 是否可以访问外部类的属性接口和抽象类的区别?抽象类和接口的使用侧重点知道吗?
: 抽象类是对整个类的抽象, 接口是对局部行为的抽象.容器类了解哪些?说说copyonwrite容器的应用场景
: set,map,list,deque. copyonwrite:并发读多写少的场景ArrayList扩容机制
: 默认10, 每次扩1.5倍(oldCap+oldCap>>1)HashMap底层数据结构
:数组+链表(+红黑树 1.8), 不线程安全, 扩容:乘2, 负载因子:默认0.75...其余八股略Hashmap的Concurrentmodification异常怎么产生的
: HashMap迭代时添加或删除元素HashMap put时的流程是怎么样的
: 高低16位异或得到hash, 空间不够的话进行resize, 之后通过hash&(容量-1)异或得到储存位置, 如果当前位置没元素或者keyObject相同, 那么直接新建或者修改他们的value, 如果hash冲突那么就使用链表查找或者添加, 如果hash冲突严重就会使用红黑树进行查找或者添加.红黑树如何自平衡? 为什么树化的阈值为8?
(泊松分布命中概率太低了)为什么hashmap的长度必须是2的指数?
因为长度是2的指数的时候hash&(n-1)=hash%n, hashmap中的tabSizeFor方法也会找到刚刚比需要容量大的2的n次方的容量LinkedHashMap底层
: 在hashmap的node的基础上给它增加了当前元素的前节点和后节点.ConcurrentHashMap底层
三个关键字什么区别
: final
(对象关键字,代表不可变. 类关键字)、finally
(异常处理,不管有无异常均执行)与finalize
(对象被回收时回调,但并不能确保,建议使用PhantomReference)死锁
(写一个) 悲观锁
乐观锁
volatile与synchronized都是什么? 他们的区别
: volatile保证了内存的可见性, 对变量的读写会直接刷新到主存. synchronized既可以保证可见也可以保证原子synchronized代码块原理:
我们在字节码里面可以看到, 是在语句之前插入了一个monitorenter, 如果线程进入数为0就将进入数设为1, 如果当前线程已经持有了monitor, 那么就继续+1(可重入), 语句之后插入了一个monitorexit, 每次会将进入数-1, 进入数为0可以理解为释放掉了锁.wait 和 sleep 的区别
: wait是让出对象锁, sleep就是阻塞线程一段时间后继续执行java开启一个线程的方式
: 线程池, new ThreadThread.start()与直接调用run()的区别
: start是启动新线程执行内部的runnable, run方法是Thread继承Runnable, 实现了run方法, 直接执行runnable#runthreadlocal原理
: 每个线程都拥有一个属于它们的ThreadLocalMap, 相当于一个精简的Hashmap, ThreadLocal的get就是从这些map中获取指定的键值对Java默认提供了几种线程池
, 有哪些参数ThreadPoolExecutor(核心线程数corePoolSize, 最大并发数maximumPoolSize, 空闲回收超时keepAliveTime, 阻塞队列 workQueue, threadFactory, 超出maxPoolSize+queue大小时, 任务交给RejectedExecutionHandler处理)有哪些常用线程池?
:newFixed(指定线程池大小,全部是核心线程,空闲立即回收,阻塞队列无限), newCached(无核心线程,默认60s回收,无空间阻塞队列), newSingle/Scheduled...线程池4种拒绝策略:
丢弃,抛出异常/丢弃,不抛出异常/丢弃最早的任务,重新提交新的/由调用线程处理这个任务synchronized与reentrantlock内部实现方式的区别
(性能? synchronized具体做了哪些优化): synchronized是在JVM层面, 不能主动释放锁, 非公平锁. reentrantlock是Java代码层面, 可以主动释放锁, 也可以是公平锁.synchronized是什么锁?
偏向锁向轻量CAS到重量锁的过程java注解用法
: 比如说可以通过动态代理反射读取一些注解进行一些操作, 还可以用apt, 还有字节码插桩kotlin扩展函数原理
JVM运行时内存区
: 数据(方法区:类信息,字段信息,常量池/堆内存), 指令(程序计数器/虚拟机栈:基本数据类型,对象引用/Native栈)如何判断什么样的对象需要回收?GC ROOTS有哪些
: 主要有虚拟机栈以及Native方法区中引用的对象Python如何实现的断开循环引用
分代收集使用不同算法的原因
方法执行之前发生了什么
: 首先加载class文件, 验证准备解析, 然后执行父类构造, 子类构造, 成员变量初始化, 然后执行方法System.out.println(“a”)将字符输出到屏幕发生了什么
: 一个Synchronized的方法将字符串输出到System.out.textOut中然后flushBuffer成员变量与局部变量的区别? 局部变量的值一定是存放在堆中吗
AQS原理
jvm类加载的时机
: 调用静态方法/new对象/反射调用/.class根类加载器加载什么类
:jre包下的类rt.jar(BootstrapClassLoader)jvm类加载过程
: 加载/验证准备解析/初始化使用卸载双亲委托机制是什么
双亲委托机制什么时候会被破坏
: 通过Thread#setContextClassLoader给线程设置一个自定义ClassLoader/ClassLoader.getSystemClassLoader().getParent()得到AppClassLoader的父类, 然后加载我们需要的ClassClass.forName和ClassLoader.loadclass的区别
: Class.forName会进行初始化, loadclass在完成解析之后便会结束遇到过的异常有哪些?
空指针,数组越界,文件未找到,IOException,NosuchMethod,OOMError,StackOverflowErrorCAS
, 自旋锁
四种引用
handler原理
: handler的post实际上最终是向MessageQueue中通过enqueueMessage插入了Message, 并会通过when参数保证消息的顺序, 同时在插入完成后会通过nativeWake唤醒等待的消息队列. Looper中的loop是阻塞的, 会阻塞在message的next方法中, 这个阻塞是通过nativePollOnce实现的, 并会传递超时时间, 若超时或者被nativeWake唤醒则继续消息队列的循环.handler的内存泄露了解吗?如何避免?
: handler.removeCallbacksAndMessages/静态内部类持有外部activity的弱引用, 不过当消息队列为空自然会释放, 但是, 比如说activity的window已经detach了还去操作布局就会出现问题, 建议使用生命周期感知刷新界面(livedata?)postDelay源码
两个Message相隔5秒, 这5秒内线程会一直阻塞吗
view绘制流程, 怎样优化
include, viewStub, merge 的使用和区别
怎么获取view的宽高, 如何确定值是准确的
: onWindowFocusChanged/view.post()/viewTreeObserver.OnGlobalLayoutListenerview.post和handler.post的区别?
: View.post如果还没有attach到window上面会先把消息插入到Queue,在ViewRootImpl#performTraversal后执行requestLayout 和 invalidate 的区别
: 重新调用onMeasure,onLayout/重新onDraw知道消息是怎么插入到消息队列的吗?
广播注册有哪些方式?
: 启动流程
、绘制流程
、事件分发
遇到过滑动冲突吗?滑动冲突的解决方法
: 父View是否intercept,是则父View#onTouch,否则子View#dispatch自定义View如何特殊处理wrap_content, padding的实现
: 给子View也传AT_MOST过去让子View都测量一遍,然后计算出我这个View实际尺寸.属性动画和补间动画的区别
: 属性动画反射setter方法调用,真实改变view的属性,可以作用于任意对象,不只是View,且而补间动画可能只会改变view的translationXY,只能作用与View.点击桌面上的 App 启动发生了什么
: Launcher通过Intent启动Activity,这里会调用AT(task)MS,之后通知AMS创建应用进程,之后ActivityThread.main(),之后创建出第一个Activity,执行各种生命周期,onCreate#setContentView的方***让activity创建的PhoneWindow创建ViewRootImpl,里面会有一个decroView,decroView中的content就是activity的布局Android四大组件
Service优先级
: 前台进程, 可见进程, 服务进程, 后台进程, 空进程Service使用场景, 如何绑定服务
: startService/startForegroundService/bindService不使用startForegroundService可以启动前台服务吗
Service的两种启动方式和生命周期
: create->(un)bind/onStartCommand->destory,onStartCommand在每次startService都会调用, onBind只在第一次bindService调用广播分类
: 普通广播(sendBroadcast)、有序广播(sendOrderedBroadcast)、异步(粘性)广播(已经弃用,发出广播会一直等待Receiver). 重写BroadcastReceiver#onReceiveActivity的启动模式及其应用场景
: standard(打开后可以返回原app)/singleTop(创建Activity加入栈顶,如已有则拿到栈顶onNewIntent)/singleTask/singleInstance(调用支付宝支付)onSaveInstance 调用的场景
: 语言字号, 屏幕尺寸方向发生改变Activity taskAffinity了解吗
横竖屏转换发生了什么
, onNewIntent有什么用
Activity生命周期, 每个生命周期事件代表了什么样的含义
: create正在被创建/restart重新启动/onstart即将启动/onResume用户可交互/onPause/onDestory销毁启动一个活动A, 接着在A中启动活动B, 各自的生命周期变化?如果B活动是透明的呢?如果此时再启动第三个活动C, 三个活动的生命周期变化?
fragment的生命周期了解吗?
: onAttach:与Activity建立关联,onCreateView:创建视图时使用,onViewCreated,onDestroyView,onDetachRecyclerView和ListView区别, RecyclerView缓存机制
: RecyclerView四级缓存:mAttachedScrap(预布局时储存不变的VH)+mChangedScrap(变了的VH,用来执行动画)/mCacheViews(默认缓存两个)/mViewCacheExtension/RecycledViewPool(SparseArray,不同itemType使用不同缓存ListIPC有哪些? ContentProvider细讲?
Binder 的原理, 共享内存原理?
AIDL有了解过吗
: 服务端onBind实现AIDL接口Stub对象,客户端.Stub.asInterface(iBinder)如何自己做ANR监测, 设计一下
如何做crash检测
为什么会发生OOM?
: 图片视频,循环中创建大量对象(包括onDraw),内存泄漏(Handler?)Android热修复有哪几种方案?
: tinker/robust, andfix不太行(SharedPreference commit和apply方法的区别以及它们的缓存机制?
SharedPreference要多进程怎么办
为什么不用 SharedPreference? 为什么数据库性能会更好?
怎么去创建一个数据库, 有哪些东西是必要的?
Parcelable轻量的原理是什么
适配浏览器跳转到 APP
, intent-filiterSparseArray
Dagger原理
ViewModel怎么实现保存恢复数据, 如何创建一个viewModel
: 在横竖屏切换时会调用onRetainNonConfigurationInstance(onSaveInstanceState之后), ComponentActivity重写了这个东西, 在其中ViewModelStore用来保存了状态, 恢复数据的话, 就从getLastNonConfigurationInstance里面看看有没有上次保存的配置. 至于这个保存在ActivityClientRecord里面, 储存在Activity#mActivities:ArrayMapLiveData的onChanged回调时机
: setValue(postValue实际也调)时通知每个观察者onChanged, 每次set版本号++, 因此即使set值相同也回调.LiveData与RxJava的区别
LiveData生命周期感知如何实现, LiveData原理
:setValue时会分发(dispatchValue), 考虑通知(considerNotify)这里就会根据ObserverWrapper(LifecycleBoundObserver) 根据生命周期决定是否分发.介绍RxJava
内存泄漏是什么
: 有内存无法回收内存泄漏的场景
: 静态对象(比如静态集合), 单例模式, 数据库/网络/文件IO等连接不释放, 内部类持有外部类引用内存泄漏检测的工具
LeakCanary原理, 用了个什么队列
: 通过ActivityLifecycleCallbacks绑定生命周期, 在Activity销毁后触发就去检查, 检查就是构建了一个WeakReference并向其提供了一个ReferenceQueue, 之后触发gc, 然后看看引用队列里面有没有元素.OkHttp底层, 对网络请求做了啥优化
:RetryAndFollowUpInterceptor:请求,出错重试,重定向, BridgeInterceptor加各种header(cookie), CacheInterceptor:通过Cache/有无网络综合判断是否使用缓存, ConnectInterceptor:打开连接,也会通过连接池复用healthConnection,创建okio IO流, CallServerInterceptor:发起真正的请求,从IO流读取内容.OkHttp异步流程中准备队列的进入条件
: 是一个ThreadPoolExecutor,maxRequests:64,maxRequestsPerHost:5Retrofit原理
Retrofit返回的是什么数据类型
: CallNavigation的优缺点
如何实现的自定义navigate方法切换fragment, 如何让被覆盖的fragment感知到生命周期
图片框架就是使用Glide吗, 有自己思考吗
: with创建RequestManager, 创建fragment绑定生命周期(Retriever), 如果传入application就全局生命周期. load使用RequestManager构建RequestBuilder, 指定asBitmap/Drawable/Gif什么的, into到一个target, ImageView会变成一个ViewTarget, 然后engine.load依次从三个缓存里面查找, 找不到就网络请求.Glide缓存有什么优化?
: 内存缓存(ResourceWeakReference,LRUCache), 磁盘缓存(DATA/NONE/RESOURCE/ALL/AUTOMATIC). with传入Activity/Fragment什么的,用来创建空Fragment绑定生命周期对于算法, 如果你问题答得很好, 那么给你来一道easy, 如果问题答得一般, 就给你来一个hard
LC: 力扣
JZ: LC剑指offer
NC: 牛客
分享不易,如果你觉得文章还不错,你的转发、分享、点赞、关注、留言就是对我最大的鼓励。感谢您的阅读!