文章标题
hello word
2020年,真的是特殊的的一年无论是对个人,国家,甚至全球。我们经历了难以想象的疫情,全国封禁宅家,停工停学,降薪裁员,这场疫情真的改变改变了很多人的命运,同样还有我。这一年,利用疫情全身心的投入跳槽换工作的准备,历时3个月,面了小影,有赞,快手,滴滴,字节,还投递了钉钉无反应。。。面过的都是拿到了书面或者口头offer最终选择去了字节哈。
明确自己的目标公司后,首先还是要问问自己有没有把握一次命中。没有,则需要沉淀自己,通过选择备选公司去打磨自己,目的是
坦诚清晰的沟通,对自己的未来有明确的规划,有上进心,有责任心,要能看出潜力,不卑不亢,自信但不要自负。
在软件设计的过程中设计模式占着举足轻重的作用,高可用的程序必定是建立在良好的设计上的,而设计模式正式这些良好设计的积累总结。设计模式又是符合面向的对象的六大原则而拓展出来的,如同抽象的具体实现,给软件开发者以指导作用。因此面向对象的设计原则是重中之重,下面将一一分析这六大原则。
当面试官问这道题是,他想考察什么内容呢?
面向对象编程的原则分别有六个
单一职责原则英文为Single Resposibility Principle,简单来说,一个类中应该是一组相关性很高的函数、数据的封装。但关于单一职责的划分界限并不是那么清晰,很多时候需要靠个人经验的界定。在开发功能之初,往往会将功能实现放在第一位。变量,方法都会堆积在一个类中方便调用,如一个简单的图片加载器包括:缓存的功能,网络图片的加载,未优化前代码如下
1 | public class ImageLoader { |
但如果了解单一职责的原则,我们就应该将他分为两个类进行实现ImageCache负责缓存,ImageLoader负责加载图片。优化后代码如下,
1 | public class ImageLoaderV1 { |
单一职责原则充分体现了面向对象特性中的封闭
开闭原则英文为Open Close Principle,是Java最基础的设计原则,它指导我们设计更稳定和灵活的系统。它的定义为对修改封闭,对扩展开放,要确保原有软件模块的正确性以及尽量少的影响原有模块就应该遵循开闭原则。通过分析上面的图片加载器,我们发现上面的图片加载器只是内存的缓存,我们需要扩展出磁盘缓存可用用户选择,这时我么会发现添加新的缓存方式需要修改原有的代码,且如果还需要扩展双缓存机制(内存+磁盘),则又需要修改原来的代码,这时候我们发现ImageCache这个类不支持缓存的拓展。这时候我们就应该考虑将缓存类进行抽象,定义出不同的缓存实现供ImageLoader引用,动态的添加不同的缓存方式,使程序更加稳定和灵活。代码如下
1 | // 缓存接口 |
由此,我们可以愉快的进行缓存的拓展,同时不需要修改原来的代码,符合开闭原则
里氏替换原则英文是Liskov Substitution Principle, 定义为所有引用基类的地方必须能透明的使用其子类的对象,里氏替换原则就是依赖于java特性中的继承和多态两大特性,而核心就是抽象,能使子类替换父类就是继承。
继承的优点
缺点
上面内存缓存和磁盘缓存都可以替代ImageLoader的变量,IImageCache就是体现了里氏替换原则原则。里氏替换原则和开闭原则往往是生死相依,不弃不离,里氏替换达到了对扩展开放对修改封闭的效果,两者都强调了一个重点特性抽象
本人从事Android客户端开发,最近在在深入Framwork学习,希望我的学习分享能帮到你。首先我们看一下关于Android系统的启动流程我们应该如何去分析,这里通过一张思维导图帮助大家整理思路。思维导图一方面罗列了本文的大纲,另一方面也是希望读者朋友可以保存图片至自己的复习资料里。以便随时通过该大纲去复习,可以关注我,收藏文章进一步沟通学习!
面对这道面试题,面试官试想考察什么呢?
Android中有哪些系统进程,具体我们可以在init.rc的配置找到相应的启动代码
1 | start zygote |
上面几个熟悉的服务进程都是通过init单独创建启动的,还有 一个我们熟悉的SystemServer,这个服务进程是通过Zygote进程创建而不是init进程。
关于Zygote的的相关知识可以参考跟我学:Android面试之深入Android Framework谈谈对Zygot的理解
它的启动流程是
在ZygoteInit.java的代码逻辑中,可以看到启动的关键代码
1 | int pid = Zygote.forkSystemServer(...) // 通过Zygote创建子线程 |
系统服务的启动指startBootstrapServices();startCoreServices();startOtherServices();内部的服务启动。启动startBootstrapServices()中包括了熟悉的AMS,PMS,StartPowerManager等等。startCoreServices()包含了BatteryService,UsageStatsService,WebViewUpdateService等等。以及startOtherServices()中的其他服务。
通过源码的阅读,我们可以发现最终服务是通过ServiceManager.addService(…) 将服务进行注册,然后才可以可被其他进程可见和使用
主线程:并没有找到哪个系统服务是在主线程的中的
工作线程: AMS,PMS运行在自己的工作线程,或者在公用的工作线程DisplayThread,FgThread, IoThread, UiThread。
Binder线程:应用在跨进程调用时肯定是在binder线程里的,然后再去切换线程
从上小结的startBootstrapServices();startCoreServices();startOtherServices();我们可以看出解决方式为
当AMS等其他服务都启动完毕,会调用mActivityManagerService.systemReady((),在这里面会通过startHomeActivityLocked(currentUserId, “systemReady”);启动桌面应用的activity, Launcher.java。启动后会通过PMS查找所有的已安装的应用,然后显示在界面上
看到最后,我相信你一定对Android系统的启动流程有一定了解了吧。回头看看第一部分的考查内容讲讲呗,对于每一个点的重点我都细心的为你做了高亮。还有纸上得来终觉浅,绝知此事要躬行。本文参考了Android api28的源码,希望你也去踩着点过一遍源码,肯定能加深理解!
我是Yangcy,该吃吃该喝喝,该学还得学,我们一起加油!