APP下载
报价宝  ›  科技  › 

你不知道的android 网友回复:都是大公司啊

报价宝 来源:baojiabao.com 发布时间:2019-11-27 14:55:00 10月26日更新
报价宝综合消息你不知道的android 网友回复:都是大公司啊

写在最前

我兜兜转转从android到java又回到android,校招面了很多大公司,阿里、京东、小米、头条、知乎、腾讯、有赞,也收获了几个offer。感谢大家的关注,让我在简书上面也混到了一个简书程序员优秀作者的称号,所以为了回馈大家,一篇最完全的android面经诞生了。这是我集合了牛客网、百度、简书等网站的几十篇面经和我自己面试的经历的合集,希望大家喜欢。(ps:里面当然会有纰漏,如果有问题欢迎大家留言或者加我QQ讨论3-5年的java进阶架构师可以联络 QQ号: 2750253501, 交流qq群: 668041364)

1.android事件分发机制,请详细说下整个流程

事件分发(面试).png

2.android view绘制机制和载入过程,请详细说下整个流程

1.ViewRootImpl会呼叫performTraversals(),其内部会呼叫performMeasure()、performLayout、performDraw()。2.performMeasure()会呼叫最外层的ViewGroup的measure()-->onMeasure(),ViewGroup的onMeasure()是抽象方法,但其提供了measureChildren(),这之中会遍历子View然后循环呼叫measureChild()这之中会用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一起获取本View的MeasureSpec,然后呼叫子View的measure()到View的onMeasure()-->setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()预设返回measureSpec的测量数值,所以继承View进行自定义的wrap_content需要重写。3.performLayout()会呼叫最外层的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()设定本View的四个顶点位置。在onLayout(抽象方法)中确定子View的位置,如LinearLayout会遍历子View,循环呼叫setChildFrame()-->子View.layout()。4.performDraw()会呼叫最外层ViewGroup的draw():其中会先后呼叫background.draw()(绘制背景)、onDraw()(绘制自己)、dispatchDraw()(绘制子View)、onDrawScrollBars()(绘制装饰)。5.MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(对应精确值和match_parent)、AT_MOST(对应warp_content))和30位SpecSize组成一个int,DecorView的MeasureSpec由视窗大小和其LayoutParams决定,其他View由父View的MeasureSpec和本View的LayoutParams决定。ViewGroup中有getChildMeasureSpec()来获取子View的MeasureSpec。6.三种方式获取measure()后的宽高:1.Activity#onWindowFocusChange()中呼叫获取2.view.post(Runnable)将获取的程式码投递到讯息伫列的尾部。3.ViewTreeObservable.3.android四大元件的载入过程,请详细介绍下

1.android四大元件的载入过程:这是我总结的一篇部落格4.Activity的启动模式

1.standard:预设标准模式,每启动一个都会建立一个例项,2.singleTop:栈顶复用,如果在栈顶就呼叫onNewIntent复用,从onResume()开始3.singleTask:栈内复用,本栈内只要用该型别Activity就会将其顶部的activity出栈4.singleInstance:单例模式,除了3中特性,系统会单独给该Activity建立一个栈,5.A、B、C、D分别是四种Activity的启动模式,那么A->B->C->D->A->B->C->D分别启动,最后的activity栈是怎么样的

1.这个题目需要深入了解activity的启动模式2.最后的答案是:两个栈,前台栈是只有D,后台栈从底至上是A、B、C6.Activity快取方法

1.配置改变导致Activity被杀死,横屏变竖屏:在onStop之前会呼叫onSaveInstanceState()储存资料在重建Activity之后,会在onStart()之后呼叫onRestoreInstanceState(),并把储存下来的Bundle传给onCreate()和它会预设重建Activity当前的检视,我们可以在onCreate()中,回复自己的资料。2.内存不足杀掉Activity,优先级分别是:前台可见,可见非前台,后台。7.Service的生命周期,两种启动方法,有什么区别

1.context.startService() ->onCreate()- >onStart()->Service running-->(如果呼叫context.stopService() )->onDestroy() ->Service shut down1.如果Service还没有执行,则呼叫onCreate()然后呼叫onStart();2.如果Service已经执行,则只调用onStart(),所以一个Service的onStart方法可能会重复呼叫多次。3.呼叫stopService的时候直接onDestroy,4.如果是呼叫者自己直接退出而没有呼叫stopService的话,Service会一直在后台执行。该Service的呼叫者再启动起来后可以通过stopService关闭Service。2.context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop1.onBind将返回给客户端一个IBind界面例项,IBind允许客户端回拨服务的方法,比如得到Service执行的状态或其他操作。2.这个时候会把呼叫者和Service系结在一起,Context退出了,Service就会呼叫onUnbind->onDestroy相应退出。3.所以呼叫bindService的生命周期为:onCreate --> onBind(只一次,不可多次系结) --> onUnbind --> onDestory。8.怎么保证service不被杀死

1.提升service优先级2.提升service程序优先级3.onDestroy方法里重启service9.静态的Broadcast 和动态的有什么区别

1.动态的比静态的安全2.静态在app启动的时候就初始化了 动态使用程式码初始化3.静态需要配置 动态不需要4.生存期,静态广播的生存期可以比动态广播的长很多5.优先级动态广播的优先级比静态广播高10.Intent可以传递哪些资料型别

1.Serializable2.charsequence: 主要用来传递String,char等3.parcelable4.Bundle11.Json有什么优劣势、解析的原理

1.JSON的速度要远远快于XML2.JSON相对于XML来讲,资料的体积小3.JSON对资料的描述性比XML较差4.解析的基本原理是:词法分析12.一个语言的编译过程

1.词法分析:将一串文字按规则分割成最小的结构,关键字、识别符号、运算子、界符和常量等。一般实现方法是自动机和正则表示式2.语法分析:将一系列单词组合成语法树。一般实现方法有自顶向下和自底向上3.语义分析:对结构上正确的源程式进行上下文有关性质的审查4.目的码生成5.程式码优化:优化生成的目的码,13.动画有哪几类,各有什么特点

1.动画的基本原理:其实就是利用插值器和估值器,来计算出各个时刻View的属性,然后通过改变View的属性来,实现View的动画效果。2.View动画:只是影像变化,view的实际位置还在原来的地方。3.帧动画是在xml中定义好一系列图片之后,使用AnimationDrawable来播放的动画。4.View的属性动画:1.插值器:作用是根据时间的流逝的百分比来计算属性改变的百分比2.估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类14.Handler、Looper讯息伫列模型,各部分的作用

1.MessageQueue:读取会自动删除讯息,单链表维护,在插入和删除上有优势。在其next()中会无限循环,不断判断是否有讯息,有就返回这条讯息并移除。2.Looper:Looper建立的时候会建立一个MessageQueue,呼叫loop()方法的时候讯息循环开始,loop()也是一个死循环,会不断呼叫messageQueue的next(),当有讯息就处理,否则阻塞在messageQueue的next()中。当Looper的quit()被呼叫的时候会呼叫messageQueue的quit(),此时next()会返回null,然后loop()方法也跟着退出。3.Handler:在主执行绪构造一个Handler,然后在其他执行绪呼叫sendMessage(),此时主执行绪的MessageQueue中会插入一条message,然后被Looper使用。4.系统的主执行绪在ActivityThread的main()为入口开启主执行绪,其中定义了内部类Activity.H定义了一系列讯息型别,包含四大元件的启动停止。5.MessageQueue和Looper是一对一关系,Handler和Looper是多对一15.怎样退出终止App

1.自己设定一个Activity的栈,然后一个个finish()16.Android IPC:Binder原理

1.在Activity和Service进行通讯的时候,用到了Binder。1.当属于同个程序我们可以继承Binder然后在Activity中对Service进行操作2.当不属于同个程序,那么要用到AIDL让系统给我们建立一个Binder,然后在Activity中对远端的Service进行操作。2.系统给我们生成的Binder:1.Stub类中有:界面方法的id,有该Binder的标识,有asInterface(IBinder)(让我们在Activity中获取实现了Binder的界面,界面的实现在Service里,同进程时候返回Stub否则返回Proxy),有onTransact()这个方法是在不同程序的时候让Proxy在Activity进行远端呼叫实现Activity操作Service2.Proxy类是代理,在Activity端,其中有:IBinder mRemote(这就是远端的Binder),两个界面的实现方法不过是代理最终还是要在远端的onTransact()中进行实际操作。3.哪一端的Binder是副本,该端就可以被另一端进行操作,因为Binder本体在定义的时候可以操作本端的东西。所以可以在Activity端传入本端的Binder,让Service端对其进行操作称为Listener,可以用RemoteCallbackList这个容器来装Listener,防止Listener因为经历过序列化而产生的问题。4.当Activity端向远端进行呼叫的时候,当前执行绪会挂起,当方法处理完毕才会唤醒。5.如果一个AIDL就用一个Service太奢侈,所以可以使用Binder池的方式,建立一个AIDL其中的方法是返回IBinder,然后根据方法中传入的引数返回具体的AIDL。6.IPC的方式有:Bundle(在Intent启动的时候传入,不过是一次性的),档案共享(对于SharedPreference是特例,因为其在内存中会有快取),使用Messenger(其底层用的也是AIDL,同理要操作哪端,就在哪端定义Messenger),AIDL,ContentProvider(在本程序中继承实现一个ContentProvider,在增删改查方法中呼叫本程序的SQLite,在其他程序中查询),Socket17.描述一次跨程序通讯

1.client、proxy、serviceManager、BinderDriver、impl、service2.client发起一个请求service资讯的Binder请求到BinderDriver中,serviceManager发现BinderDiriver中有自己的请求 然后将clinet请求的service的资料返回给client这样完成了一次Binder通讯3.clinet获取的service资讯就是该service的proxy,此时呼叫proxy的方法,proxy将请求传送到BinderDriver中,此时service的 Binder执行绪池循环发现有自己的请求,然后用impl就处理这个请求最后返回,这样完成了第二次Binder通讯4.中间client可挂起,也可以不挂起,有一个关键字oneway可以解决这个18.android重要术语解释

1.ActivityManagerServices,简称AMS,服务端物件,负责系统中所有Activity的生命周期2.ActivityThread,App的真正入口。当开启App之后,会呼叫main()开始执行,开启讯息循环伫列,这就是传说中的UI执行绪或者叫主执行绪。与ActivityManagerServices配合,一起完成Activity的管理工作3.ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的互动。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理物件与ActivityThread通讯。4.ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通讯的。5.Instrumentation,每一个应用程序只有一个Instrumentation物件,每个Activity内都有一个对该物件的引用。Instrumentation可以理解为应用程序的管家,ActivityThread要建立或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作。6.ActivityStack,Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态资讯等。通过ActivityStack决定是否需要启动新的程序。7.ActivityRecord,ActivityStack的管理物件,每个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其他的管理资讯。其实就是服务器端的Activity物件的映像。8.TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。如果你清楚Activity的4种launchMode,那么对这个概念应该不陌生。19.理解Window和WindowManager

1.Window用于显示View和接收各种事件,Window有三种类型:应用Window(每个Activity对应一个Window)、子Window(不能单独存在,附属于特定Window)、系统window(Toast和状态列)2.Window分层级,应用Window在1-99、子Window在1000-1999、系统Window在2000-2999.WindowManager提供了增删改View三个功能。3.Window是个抽象概念:每一个Window对应着一个View和ViewRootImpl,Window通过ViewRootImpl来和View建立联络,View是Window存在的实体,只能通过WindowManager来访问Window。4.WindowManager的实现是WindowManagerImpl其再委托给WindowManagerGlobal来对Window进行操作,其中有四个List分别储存对应的View、ViewRootImpl、WindowManger.LayoutParams和正在被删除的View5.Window的实体是存在于远端的WindowMangerService中,所以增删改Window在本端是修改上面的几个List然后通过ViewRootImpl重绘View,通过WindowSession(每个应用一个)在远端修改Window。6.Activity建立Window:Activity会在attach()中建立Window并设定其回拨(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy类建立PhoneWindow实现的。然后通过Activity#setContentView()呼叫PhoneWindow的setContentView。20.Bitmap的处理

1.当使用ImageView的时候,可能图片的画素大于ImageView,此时就可以通过BitmapFactory.Option来对图片进行压缩,inSampleSize表示缩小2^(inSampleSize-1)倍。2.BitMap的快取:1.使用LruCache进行内存快取。2.使用DiskLruCache进行硬盘快取。3.实现一个ImageLoader的流程:同步异步载入、图片压缩、内存硬盘快取、网络拉取1.同步载入只建立一个执行绪然后按照顺序进行图片载入2.异步载入使用执行绪池,让存在的载入任务都处于不同执行绪3.为了不开启过多的异步任务,只在列表静止的时候开启图片载入21.如何实现一个网络框架(参考Volley)

1.快取伫列,以url为key快取内容可以参考Bitmap的处理方式,这里单独开启一个执行绪。2.网络请求伫列,使用执行绪池进行请求。3.提供各种不同型别的返回值的解析如String,Json,图片等等。22.ClassLoader的基础知识

1.双亲委托:一个ClassLoader类负责载入这个类所涉及的所有类,在载入的时候会判断该类是否已经被载入过,然后会递回去他父ClassLoader中找。2.可以动态载入Jar通过URLClassLoader3.ClassLoader 隔离问题 JVM识别一个类是由:ClassLoader id+PackageName+ClassName。4.载入不同Jar包中的公共类:1.让父ClassLoader载入公共的Jar,子ClassLoader载入包含公共Jar的Jar,此时子ClassLoader在载入公共Jar的时候会先去父ClassLoader中找。(只适用Java)2.重写载入包含公共Jar的Jar的ClassLoader,在loadClass中找到已经载入过公共Jar的ClassLoader,也就是把父ClassLoader替换掉。(只适用Java)3.在生成包含公共Jar的Jar时候把公共Jar去掉。23.外挂化框架描述:dynamicLoadApk为例子

1.可以通过DexClassLoader来对apk中的dex包进行载入访问2.如何载入资源是个很大的问题,因为宿主程式中并没有apk中的资源,所以呼叫R资源会报错,所以这里使用了Activity中的实现ContextImpl的getAssets()和getResources()再加上反射来实现。3.由于系统启动Activity有很多初始化动作要做,而我们手动反射很难完成,所以可以采用界面机制,将Activity的大部分生命周期提取成界面,然后通过代理Activity去呼叫外挂Activity的生命周期。同时如果像增加一个新生命周期方法的时候,只需要在界面中和代理中宣告一下就行。4.缺点:1.慎用this,因为在apk中使用this并不代表宿主中的activity,当然如果this只是表示自己的界面还是可以的。除此之外可以使用that代替this。2.不支援Service和静态注册的Broadcast3.不支援LaunchMode和Apk中Activity的隐式呼叫。24.热修复:Andfix为例子

1.大致原理:apkpatch将两个apk做一次对比,然后找出不同的部分。可以看到生成的apatch了档案,字尾改成zip再解压开,里面有一个dex档案。通过jadx检视一下源代码,里面就是被修复的程式码所在的类档案,这些更改过的类都加上了一个_CF的字尾,并且变动的方法都被加上了一个叫@MethodReplace的annotation,通过clazz和method指定了需要替换的方法。然后客户端sdk得到补丁档案后就会根据annotation来寻找需要替换的方法。最后由JNI层完成方法的替换。2.无法新增新类和新的字段、补丁档案很容易被反编译、加固平台可能会使热补丁功能失效25.执行绪同步的问题,常用的执行绪同步

1.sycn:保证了原子性、可见性、有序性2.锁:保证了原子性、可见性、有序性1.自旋锁:可以使执行绪在没有取得锁的时候,不被挂起,而转去执行一个空循环。1.优点:执行绪被挂起的概率减少,执行绪执行的连贯性加强。用于对于锁竞争不是很激烈,锁占用时间很短的并发执行绪。2.缺点:过多浪费CPU时间,有一个执行绪连续两次试图获得自旋锁引起死锁2.阻塞锁:没得到锁的执行绪等待或者挂起,Sycn、Lock3.可重入锁:一个执行绪可多次获取该锁,Sycn、Lock4.悲观锁:每次去拿资料的时候都认为别人会修改,所以会阻塞全部其他执行绪 Sycn、Lock5.乐观锁:每次去拿资料的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个资料,可以使用版本号等机制。cas6.显示锁和内建锁:显示锁用Lock来定义、内建锁用synchronized。7.读-写锁:为了提高效能,Java提供了读3.volatile1.只能保证可见性,不能保证原子性2.自增操作有三步,此时多执行绪写会出现问题4.cas1.操作:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false。2.解释:本地副本为A,共享内存为V,执行绪A要把V修改成B。某个时刻执行绪A要把V修改成B,如果A和V不同那么就表示有其他执行绪在修改V,此时就表示修改失败,否则表示没有其他执行绪修改,那么把V改成B。3.局限:如果V被修改成V1然后又被改成V,此时cas识别不出变化,还是认为没有其他执行绪在修改V,此时就会有问题4.局限解决:将V带上版本。5.执行绪不安全到底是怎么回事:1.一个执行绪写,多个执行绪读的时候,会造成写了一半就去读2.多执行绪写,会造成脏资料26.Asynctask和执行绪池,GC相关(怎么判断哪些内存该GC,GC算法)

1.Asynctask:异步任务类,单执行绪执行绪池+Handler2.执行绪池:1.ThreadPoolExecutor:通过Executors可以构造单执行绪池、固定数目执行绪池、不固定数目执行绪池。2.ScheduledThreadPoolExecutor:可以延时呼叫执行绪或者延时重复排程执行绪。3.GC相关:重要1.搜寻算法:1.引用计数2.图搜寻,可达性分析2.回收算法:1.标记清除复制:用于青年代2.标记整理:用于老年代3.堆分割槽:1.青年区eden 80%、survivor1 10%、survivor2 10%2.老年区4.虚拟机器栈分割槽:1.区域性变量表2.算子栈3.动态连结4.方法返回地址5.GC Roots:1.虚拟机器栈(栈桢中的本地变量表)中的引用的物件2.方法区中的类静态属性引用的物件3.方法区中的常量引用的物件4.本地方法栈中JNI的引用的物件27.网络

1.ARP协议:在IP以太网中,当一个上层协议要发包时,有了该节点的IP地址,ARP就能提供该节点的MAC地址。2.HTTP HTTPS的区别:1.HTTPS使用TLS(SSL)进行加密2.HTTPS预设工作在TCP协议443埠3.它的工作流程一般如以下方式:1.完成TCP三次同步握手2.客户端验证服务器数字证书,通过,进入步骤33.DH算法协商对称加密算法的金钥、hash算法的金钥4.SSL安全加密隧道协商完成5.网页以加密的方式传输,用协商的对称加密算法和金钥加密,保证资料机密性;用协商的hash算法进行资料完整性保护,保证资料不被篡改3.http请求包结构,http返回码的分类,400和500的区别1.包结构:1.请求:请求行、头部、资料2.返回:状态行、头部、资料2.http返回码分类:1到5分别是,讯息、成功、重定向、客户端错误、服务端错误4.Tcp1.可靠连线,三次握手,四次挥手1.三次握手:防止了服务器端的一直等待而浪费资源,例如只是两次握手,如果s确认之后c就掉线了,那么s就会浪费资源1.syn-c = x,表示这讯息是x序号2.ack-s = x + 1,表示syn-c这个讯息接收成功。syn-s = y,表示这讯息是y序号。3.ack-c = y + 1,表示syn-s这条讯息接收成功2.四次挥手:TCP是全双工模式1.fin-c = x , 表示现在需要关闭c到s了。ack-c = y,表示上一条s的讯息已经接收完毕2.ack-s = x + 1,表示需要关闭的fin-c讯息已经接收到了,同意关闭3.fin-s = y + 1,表示s已经准备好关闭了,就等c的最后一条命令4.ack-c = y + 1,表示c已经关闭,让s也关闭3.滑动视窗,停止等待、后退N、选择重传4.拥塞控制,慢启动、拥塞避免、加速递减、快重传快恢复28.数据库效能优化:索引和事务,需要找本专门的书大概了解一下

29.13.APK打包流程和其内容

1.流程1.aapt生成R档案2.aidl生成java档案3.将全部java档案编译成class档案4.将全部class档案和第三方包合并成dex档案5.将资源、so档案、dex档案整合成apk6.apk签名7.apk字节对齐2.内容:so、dex、asset、资原始档30.网络劫持的型别原理:可以百度一下了解一下具体概念

1.DNS劫持、欺骗、污染2.http劫持:重定向、注入js,http注入、报文扩充套件31.java类载入过程:

1.载入时机:建立例项、访问静态变数或方法、反射、载入子类之前2.验证:验证档案格式、元资料、字节码、符号引用的正确性3.载入:根据全类名获取档案字节流、将字节流转化为静态储存结构放入方法区、生成class物件4.准备:在堆上为静态变数划分内存5.解析:将常量池中的符号引用转换为直接引用6.初始化:初始化静态变数7.书籍推荐:深入理解java虚拟机器,部落格推荐:Java/Android阿里面试JVM部分理解32.retrofit的了解

1.动态代理建立一个界面的代理类2.通过反射解析每个界面的注解、入参构造http请求3.获取到返回的http请求,使用Adapter解析成需要的返回值。33.bundle的资料结构,如何储存

1.键值对储存2.传递的资料可以是boolean、byte、int、long、float、double、string等基本型别或它们对应的阵列,也可以是物件或物件阵列。3.当Bundle传递的是物件或物件阵列时,必须实现Serializable 或Parcelable界面34.listview内点选buttom并移动的事件流完整拦截过程:

1.点下按钮的时候:1.产生了一个down事件,activity-->phoneWindow-->ViewGroup-->ListView-->botton,中间如果有重写了拦截方法,则事件被该view拦截可能消耗。2.没拦截,事件到达了button,这个过程中建立了一条事件传递的view连结串列3.到button的dispatch方法-->onTouch-->view是否可用-->Touch代理2.移动点选按钮的时候:1.产生move事件,listView中会对move事件做拦截2.此时listView会将该滑动事件消费掉3.后续的滑动事件都会被listView消费掉3.手指抬起来时候:前面建立了一个view连结串列,listView的父view在获取事件的时候,会直接取连结串列中的listView让其进行事件消耗。35.service的意义:不需要界面,在后台执行的程式

36.android的IPC通讯方式,执行绪(程序间)通讯机制有哪些

1.ipc通讯方式:binder、contentprovider、socket2.操作系统程序通讯方式:共享内存、socket、管道37.操作系统程序和执行绪的区别

1.简而言之,一个程式至少有一个程序,一个程序至少有一个执行绪.2.执行绪的划分尺度小于程序,使得多执行绪程式的并发性高。3.另外,程序在执行过程中拥有独立的内存单元,而多个执行绪共享内存,从而极大地提高了程式的执行效率。4.多执行绪的意义在于一个应用程序中,有多个执行部分可以同时执行。有将多个执行绪看做多个独立的应用,来实现程序的排程和管理以及资源分配38.HashMap的实现过程:Capacity就是buckets的数目,Load factor就是buckets填满程度的最大比例。如果对迭代效能要求很高的话不要把capacity设定过大,也不要把load factor设定过小。

1.简单来说HashMap就是一个会自动扩容的阵列连结串列2.put过程1.对key的hashCode()做hash,然后再计算index;2.如果没碰撞直接放到bucket里;3.如果碰撞了,以连结串列的形式存在buckets后;4.如果碰撞导致连结串列过长(大于等于TREEIFY_THRESHOLD),就把连结串列转换成红黑树;5.如果节点已经存在就替换old value(保证key的唯一性)6.如果bucket满了(超过load factor*current capacity),就要resize。3.resize:当put时,如果发现目前的bucket占用程度已经超过了Load Factor所希望的比例,那么就会发生resize。在resize的过程,简单的说就是把bucket扩充为2倍,之后重新计算index,把节点再放到新的bucket中4.get过程1.根据key的hash算出阵列下表2.使用equals遍历连结串列进行比较39.mvc、mvp、mvvm:

1.mvc:资料、View、Activity,View将操作反馈给Activity,Activitiy去获取资料,资料通过观察者模式重新整理给View。循环依赖1.Activity重,很难单元测试2.View和Model耦合严重2.mvp:资料、View、Presenter,View将操作给Presenter,Presenter去获取资料,资料获取好了返回给Presenter,Presenter去重新整理View。PV,PM双向依赖1.界面爆炸2.Presenter很重3.mvvm:资料、View、ViewModel,View将操作给ViewModel,ViewModel去获取资料,资料和界面绑定了,资料更新界面更新。1.viewModel的业务逻辑可以单独拿来测试2.一个view 对应一个 viewModel 业务逻辑可以分离,不会出现全能类3.资料和界面绑定了,不用写垃圾程式码,但是复用起来不舒服40.java的执行绪如何实现

1.Thread继承2.Runnale3.Future4.执行绪池41.ArrayList 如何删除重复的元素或者指定的元素;

1.删除重复:Set2.删除指定:迭代器42.如何设计在 UDP 上层保证 UDP 的可靠性传输;

1.简单来讲,要使用UDP来构建可靠的面向连线的资料传输,就要实现类似于TCP协议的超时重传,有序接受,应答确认,滑动视窗流量控制等机制,等于说要在传输层的上一层(或者直接在应用层)实现TCP协议的可靠资料传输机制。2.比如使用UDP资料包+序列号,UDP资料包+时间戳等方法,在服务器端进行应答确认机制,这样就会保证不可靠的UDP协议进行可靠的资料传输。3.基于udp的可靠传输协议有:RUDP、RTP、UDT43.Java 中内部类为什么可以访问外部类

1.因为内部类建立的时候,需要外部类的物件,在内部类物件建立的时候会把外部类的引用传递进去44.设计移动端的联络人储存与查询的功能,要求快速搜寻联络人,可以用到哪些资料结构?数据库索引,平衡二叉树(B树、红黑树)

45.红黑树特点

1.root节点和叶子节点是黑色2.红色节点后必须为黑色节点3.从root到叶子每条路径的黑节点数量相同46.linux异步和同步i/o:

1.同步:对于client,client一直等待,但是client不挂起:主执行绪呼叫2.异步:对于client,client发起请求,service好了再回调client:其他执行绪呼叫,呼叫完成之后进行回拨3.阻塞:对于service,在准备io的时候会将service端挂起,直至准备完成然后唤醒service:bio3.非阻塞:对于service,在准备io的时候不会将service端挂起,而是service一直去轮询判断io是否准备完成,准备完成了就进行操作:nio、linux的select、poll、epoll4.多路复用io:非阻塞io的一种优化,java nio,用一个执行绪去轮询多个 io埠是否可用,如果一个可用就通知对应的io请求,这使用一个执行绪轮询可以大大增强效能。1.我可以采用 多执行绪+ 阻塞IO 达到类似的效果,但是由于在多执行绪 + 阻塞IO 中,每个socket对应一个执行绪,这样会造成很大的资源占用。2.而在多路复用IO中,轮询每个socket状态是核心在进行的,这个效率要比使用者执行绪要高的多。5.异步io:aio,使用者执行绪完全不感知io的进行,所有操作都交给核心,io完成之后核心通知使用者执行绪。1.这种io才是异步的,2、3、4都是同步io,因为核心进行资料拷贝的过程都会让使用者执行绪阻塞。2.异步IO是需要操作系统的底层支援,也就是核心支援,Java 7中,提供了Asynchronous IO47.ConcurrentHashMap内部实现,HashTable的实现被废弃的原因:

1.HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的执行绪都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分资料,那么当多执行绪访问容器里不同资料段的资料时,执行绪间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将资料分成一段一段的储存,然后给每一段资料配一把锁,当一个执行绪占用锁访问其中一个段资料的时候,其他段的资料也能被其他执行绪访问。2.ConcurrentHashMap是由Segment阵列结构和HashEntry阵列结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于储存键值对资料。一个ConcurrentHashMap里包含一个Segment阵列,Segment的结构和HashMap类似,是一种阵列和连结串列结构, 一个Segment里包含一个HashEntry阵列,每个HashEntry是一个连结串列结构的元素,每个Segment守护者一个HashEntry数组里的元素,当对HashEntry阵列的资料进行修改时,必须首先获得它对应的Segment锁。48.HandlerThread是什么

1.MessageQueue + Looper + Handler49.IntentService是什么

1.含有HandlerThread的Service,可以多次startService()来多次在子执行绪中进行 onHandlerIntent()的呼叫。50.class和dex

1.dvm执行的是dex格式档案,jvm执行的是class档案,android程式编译完之后生产class档案。然后dex工具会把class档案处理成dex档案,然后把资原始档和.dex档案等打包成apk档案。2.dvm是基于暂存器的虚拟机器,而jvm执行是基于虚拟栈的虚拟机器。暂存器存取速度比栈快的多,dvm可以根据硬件实现最大的优化,比较适合移动装置。3.class档案存在很多的冗余资讯,dex工具会去除冗余资讯,并把所有的class档案整合到dex档案中。减少了I/O操作,提高了类的查询速度51.内存泄漏

1.其他执行绪持有一个Listener,Listener操作activity。那么线上程么有完毕的时候,activity关闭了,原本是要被回收的但是,不能被回收。2.例如Handler导致的内存泄漏,Handler就相当于Listener。3.在activity关闭的时候注意停止执行绪,或者将Listener的注册取消3.使用弱引用,这样即使Listener持有了activity,在GC的时候还是会被回收4.工具:LeakCanary52.过度绘制、卡顿优化:

1.过度绘制:1.移除Window预设的Background:getWidow.setBackgroundDrawable(null);2.移除XML布局档案中非必需的Background3.减少布局巢状(扁平化的一个体现,减少View数的深度,也就减少了View树的遍历时间,渲染的时候,前后期的工作,总是按View树结点来)4.在引入布局档案里面,最外层可以用merge替代LinearLayout,RelativeLayout,这样把子UI元素直接衔接在include位置5.工具:HierarchyViewer 检视检视层级2.卡顿优化:16ms资料更新53.apk瘦身:

1.classes.dex:通过程式码混淆,删掉不必要的jar包和程式码实现该档案的优化2.资原始档:通过Lint工具扫描程式码中没有使用到的静态资源3.图片资源:使用tinypng和webP,下面详细介绍图片资源优化的方案,向量图4.SO档案将不用的去掉,目前主流app一般只放一个arm的so包54.ANR的形成,各个元件上出现ARN的时间限制是多少

1.只要是主执行绪耗时的操作就会ARN 如io2.broadcast超时时间为10秒 按键无响应的超时时间为5秒 前台service无响应的超时时间为20秒,后台service为200秒55.Serializable和Parcelable 的区别

1.P 消耗内存小2.网络传输用S 程式内使用P3.S将资料持久化方便4.S使用了反射 容易触发垃圾回收 比较慢56.Sharedpreferences源代码简述

1.储存于硬盘上的xml键值对,资料多了会有效能问题2.ContextImpl记录着SharedPreferences的重要资料,档案路径和例项的键值对3.在xml档案全部内载入到内存中之前,读取操作是阻塞的,在xml档案全部内载入到内存中之后,是直接读取内存中的资料4.apply因为是异步的没有返回值, commit是同步的有返回值能知道修改是否提交成功5.多并发的提交commit时,需等待正在处理的commit资料更新到磁盘档案后才会继续往下执行,从而降低效率; 而apply只是原子更新到内存,后呼叫apply函式会直接覆盖前面内存资料,从一定程度上提高很多效率。 3.edit()每次都是建立新的EditorImpl物件.6.部落格推荐:全面剖析SharedPreferences57.操作系统如何管理内存的:

1.使用暂存器进行将程序地址和实体内存进行对映2.虚拟内存进行内存对映到硬盘上增大内存3.虚拟内存是进行内存分页管理4.页表实现分页,就是 页+地址偏移。5.如果程式的内存在硬盘上,那么就需要用页置换算法来将其调入内存中:先进先出、最近未使用最少等等6.部落格推荐:现代操作系统部分章节笔记58.浏览器输入地址到返回结果发生了什么

1.DNS解析2.TCP连线3.传送HTTP请求4.服务器处理请求并返回HTTP报文5.浏览器解析渲染页面6.连线结束59.java泛型型别擦除发生在什么时候,万用字元有什么需要注意的。

1.发生在编译的时候2.PECS,extends善于提供精确的物件 A是B的子集,Super善于插入精确的物件 A是B的超集3.部落格推荐:Effective Java笔记(不含反序列化、并发、注解和列举)、android阿里面试java基础锦集60.activity的生命周期

1.a启动b,后退键再到a的生命周期流程:a.create-->a.start-->a.resume-->a.pause-->b.create-->b.start-->b.resume-->b界面绘制-->a.stop-->b.pause-->b.stop-->b.destroy-->a.restart-->a.start-->a.resume2.意外销毁会呼叫saveInstance,重新恢复的时候回拨用restoreInstance。储存资料的时候使用了委托机制,从activity-->window-->viewGroup-->view 会递回呼叫save来保持本view的资料,restore则是递回恢复本view资料。我们可以在里面做一些自己需要的资料操作。61.面试常考的算法

1.快排、堆排序为首的各种排序算法2.连结串列的各种操作:判断成环、判断相交、合并连结串列、倒数K个节点、寻找成环节点3.二叉树、红黑树、B树定义以及时间复杂度计算方式4.动态规划、贪心算法、简单的图论5.推荐书籍:算法导论,将图论之前的例子写一遍62.Launcher程序启动另外一个程序的过程:启动一个app

63.开源框架源代码

1.Fresco1.mvc框架:1.Controller控制资料显示在Hierarchy中的Drawable的显隐2.ImagePipeline在Controller中负责进行资料获取,返回的资料是CloseableImage3.Drawee把除了初始化之外的操作全部交给Holder去做,Holder持有Controller和Hierarchy2.Drawable层次以及绘制:1.如果要绘制一次Drawable就呼叫invalidateSelf()来触发onDraw()2.Drawable分为:容器类(储存一些Drawable)、自我绘制类(进度条)、图形变换类(scale、rotate、矩阵变换)、动画类(内部不断重新整理,进行webp和gif的帧绘制)3.ImagePipeline返回的CloseableImage是由一个个DrawableFactory解析成Drawable的4.webp和gif动画是由jni程式码解析的,然后其他静态图片是根据不同的android平台使用BitmapFactory来解析的3.职责链模式:producer不做操作标n,表示只是提供一个consumer。获取图片--》解码图片快取Producer--》后台执行绪Producer--》client图片处理producer(n)--》解码producer(n)--》旋转或剪裁producer(n)--》编码图片内存快取producer--》读硬盘快取producer--》写硬盘快取producer(n)--》网络producer提供CloseableImage《--解码图片快取consumer《--client图片处理consumer《--解码consumer《--旋转或剪裁consumer《--编码图片内存快取consumer《--写硬盘快取consumer《--图片资料4.内存快取:1.一个CountingLruMap储存已经没有被引用的快取条目,一个CountingLruMap储存所有的条目包括没有引用的条目。每当快取策略改变和一定时间快取配置的更新的时候,就会将 待销毁条目Map中的条目一个个移除,直到快取大小符合配置。2.这里的引用计数是用Fresco元件实现的引用计数器。3.快取有一个代理类,用来追踪快取的存取。4.CountingLruMap是使用LinkedHashMap来储存资料的。5.硬盘快取:1.DefaultDiskStorage使用Lru策略。2.为了不让所有的档案集中在一个档案中,建立很多命名不同的资料夹,然后使用hash算法把快取档案分散3.DiskStorageCache封装了DefaultDiskStorage,不仅进行快取存取追踪,并且其在内存里面维持着一个 的键值对,因为档案修改频繁,所有只是定时重新整理,因此如果在内存中找不到,还要去硬盘中找一次。4.删除硬盘的快取只出现在硬盘资料大小超限的时候,此时同时也会删除快取中的key,所以不会出现内存中有key,但是硬盘上没有的情况。5.在插入硬盘资料的时候,采用的是插入器的形式。返回一个Inserter,在Inserter.writeData()中传入一个CallBack(里面封装了客户端插入资料的逻辑和档案引用),让内部实现呼叫CallBack的逻辑来插入档案资料,前面写的档案字尾是.temp,只有呼叫commit()之后才会修改后缀,让档案对客户端可见。6.使用了java提供的FileTreeVisitor来遍历档案6.物件池:1.使用阵列来储存一个桶,桶内部是一个Queue。阵列下标是资料申请内存的byte大小,桶内部的Queue存的是内存块的。所以阵列使用的是稀疏阵列2.申请内存的方式有两种 1.java堆上开辟的内存 2.ashme 的本地内存中开辟的内存7.设计模式:Builder、职责链、观察者、代理、组合、享元、界面卡、装饰者、策略、生产者消费者、提供者8.自定义计数引用:类似c++智慧指标1.使用一个静态IdentityHashMap 2.用SharedReference分装需要被计数引用的物件,提供一个销毁资源的销毁器,提供一个静态工厂方法来复制自己,复制一个引用计数加一。提供一个方法销毁自己,表示自己需要变成无人引用的物件了,此时引用计数减一。3.引用计数归零,销毁器将销毁资源,如bitmap的recycle或者是jni内存呼叫jni方法归还内存。9.部落格推荐:Android Fresco源代码文件翻译、从零开始撸一个Fresco之硬盘快取、从零开始撸一个Fresco之gif和Webp动画、从零开始撸一个Fresco之内存快取、从零开始撸一个Fresco之总结2.oKhttp:1.同步和异步:1.异步使用了Dispatcher来将储存在 Deque 中的请求分派给执行绪池中各个执行绪执行。2.当任务执行完成后,无论是否有异常,finally程式码段总会被执行,也就是会呼叫Dispatcher的finished函式,它将正在执行的任务Call从伫列runningAsyncCalls中移除后,主动的把快取伫列向前走了一步。2.连线池:1.一个Connection封装了一个socket,ConnectionPool中储存s著所有的Connection,StreamAllocation是引用计数的一个单位2.当一个请求获取一个Connection的时候要传入一个StreamAllocation,Connection中存着一个弱引用的StreamAllocation列表,每当上层应用引用一次Connection,StreamAllocation就会加一个。反之如果上层应用不使用了,就会删除一个。3.ConnectionPool中会有一个后台任务定时清理StreamAllocation列表为空的Connection。5分钟时间,维持5个socket3.选择路线与建立连线1.选择路线有两种方式:1.无代理,那么在本地使用DNS查询到ip,注意结果是阵列,即一个域名有多个IP,这就是自动重连的来源2.有代理HTTP:设定socket的ip为代理地址的ip,设定socket的埠为代理地址的埠3.代理好处:HTTP代理会帮你在远端服务器进行DNS查询,可以减少DNS劫持。2.建立连线1.连线池中已经存在连线,就从中取出(get)RealConnection,如果没有命中就进入下一步2.根据选择的路线(Route),呼叫Platform.get().connectSocket选择当前平台Runtime下最好的socket库进行握手3.将建立成功的RealConnection放入(put)连线池快取4.如果存在TLS,就根据SSL版本与证书进行安全握手5.构造HttpStream并维护刚刚的socket连线,管道建立完成4.职责链模式:快取、重试、建立连线等功能存在于拦截器中网络请求相关,主要是网络请求优化。网络请求的时候遇到的问题5.部落格推荐:Android资料层架构的实现 上篇、Android资料层架构的实现 下篇3.okio1.简介;1.sink:自己--》别人2.source:别人--》自己3.BufferSink:有快取区域的sink4.BufferSource:有快取区域的source5.Buffer:实现了3、4的快取区域,内部有Segment的双向连结串列,在在转移资料的时候,只需要将指标转移指向就行2.比java io的好处:1.减少内存申请和资料拷贝2.类少,功能齐全,开发效率高3.内部实现:1.Buffer的Segment双向连结串列,减少资料拷贝2.Segment的内部byte阵列的共享,减少资料拷贝3.SegmentPool的共享和回收Segment4.sink和source中被实际操作的其实是Buffer,Buffer可以充当sink和source5.最终okio只是对java io的封装,所有操作都是基于java io 的写在最后:能看到这里的人,我挺佩服你的.这篇文章是我在头条面试之前整理的,最后80%的题目都命中了,所以祝你好运.

文章标签: 报价宝 降噪耳机价格 耳机价格 红米手机价格 华为手机价格 小米手机价格 电视机价格 笔记本电脑价格 笔记本价格 汽车价格 数码相机价格 手机价格 汽车价格 笔记本电脑价格 红米手机价格