1. 什么是面向对象?
面向对象三大特征:继承、封装、多态
关键语:一切事物皆对象。将现实的事物抽象出来
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
面向对象的六大原则
- 单一职责原则
一个类中应该是一组相关性很高的函数、数据的封装。如何划分一个类,一个函数的职责,每个人都有自己的看法,这需要个人经验、具体的业务逻辑而定。但是它也有一些基本的指导思想,例如:两个完全不一样的功能就不应该放在一个类中。一个类中应该是一组相关性很高的函数、数据的封装 - 开闭原则
软件中的对象(类、模块、函数等)应该是对于扩展是开放的,对于修改是封闭的。当软件需要变化时,应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现 - 里氏替换原则
所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲:只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或者异常,使用者可能根本就不需要知道是父类还是子类,但是反过来就不行了,有子类出现的地方父类未必能适应 - 依赖倒置原则
依赖倒置原则指代了一种特定的解耦形式,使得高层次的模块不依赖于底层地的模块的实现细节的目的。以下几个关键点:- 高层模块不应该依赖底层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或集成抽象类而产生的类就是细节,其特点就是:可以直接被实例化,也就是可以加上一个关键字new产生一个对象。高层模块就是调用端,底层模块就是具体实现类。在java的表现是:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生和的 。一句话概括:面向接口编程,或者说面向对象编程,这里的抽象指的是接口或者抽象类
- 接口隔离原则
定义是:客户端不应该依赖它不需要的接口。另一种定义是:类之间的依赖关系应该建立在最小的接口上。接口隔离原则非常庞大、臃肿的接口拆分成更小的和更具体的接口,这样在客户将会只需要知道他们感兴趣的方法。接口隔离原则的目的是系统解开耦合,从而容易重构、更改和重新部署
试想一下,如果在只是需要关闭一个对象时,它却暴露出了其他的接口函数,如OutputStream的write方法,这就使得更多的细节暴露在客户端代码面前,不仅没有很好地隐藏实现,还增加了接口的使用难度,而通过Closeable接口可关闭的对象抽象起来,这样只需要客户端依赖于Closeable就可以对客户端隐藏其他的接口信息,客户端只需要知道这个对象可关闭(只可以调用close方法)即可 - 迪米特原则
一个对象应该对其他对象有最少的了解,通俗讲:一个类应该对自己需要耦合或者调用的类知道得最少,类的内部如何实现与调用者或者依赖者没关系,调用者或者依赖者只需要知道它需要知道的方法即可,其他一概不用管。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另外一个类影响也越大
2.内存的优化
内存抖动
Android里内存抖动是指内存频繁地分配和回收,而频繁的gc会导致卡顿,严重时还会导致OOM
一个很经典的案例是string拼接创建大量小的对象(比如在一些频繁调用的地方打字符串拼接的log的时候,或在for里面创建对象、在onDraw函数里创建对象)
而内存抖动为什么会引起OOM呢?
主要原因还是有因为大量小的对象频繁创建,导致内存碎片,从而当需要分配内存时,虽然总体上还是有剩余内存可分配,而由于这些内存不连续,导致无法分配,系统直接就返回OOM了
内存泄漏
- 单例(主要原因还是因为一般情况下单例都是全局的,有时候会引用一些实际生命周期比较短的变量,导致其无法释放)
- 静态变量(同样也是因为生命周期比较长
- Handler内存泄漏
- 匿名内部类(匿名内部类会引用外部类,导致无法释放,比如各种回调)
- 资源使用未关闭(BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap)
3.电量的优化
以下几种造成耗电的场景
- 唤醒屏幕(还有屏幕的亮暗)
- CPU唤醒使用
- 蜂窝式无线(WIFI)
- 传感器
优化电量的方法
- 监听手机充电状态(有相关API获取);获取充电状态信息后,可以有针对的对部分代码优化。当在充电时才去执行一些非常耗电的操作。具体的业务是考虑将一些不需要及时与用户交互的操作放到充电时,例如:自动备份上传图片
- 屏幕唤醒;当 Android 设备空闲时,屏幕会变暗,然后关闭屏幕,最后会停止 CPU 的运行,这样可以防 止电池电量掉的快。但有些时候我们需要改变 Android 系统默认的这种状态:比如玩游戏时我们需要保持屏幕常亮,比如一些下载操作不需要屏幕常亮但需要 CPU 一直运行直到任务完成
- 传感器;使用传感器,选择合适的采样率,越高的采样率类型则越费电
- GPS;选择合适的定位,如果 App 只是需要一个粗略的定位那么就不需要使用 GPS 进行定位,既耗费电量,定位的耗 时也久
- JobScheduler;自 Android 5.0 发布以来,JobScheduler 已成为执行后台工作的很好的方式,其工作方式有 利于用户在适当的时机执行正确的事情。应用可以在安排作业的同时允许系统基于内存、电源 和连接情况进行优化。JobSchedule 的宗旨就是把一些不是特别紧急的任务放到更合适的时机批量处理。这样做有两个好处
- 避免频繁的唤醒硬件模块,造成不必要的电量消耗
- 避免在不合适的时间(例如低电量情况下、弱网络或者移动网络情况下的)执行过多的 任务消耗电量
- WakeLock;Android为了节省电量,会在用户无操作一段时间之后进入休眠状态。Wake Lock是一种锁的机制,只要有人拿着这个锁,系统就无法进入休眠。一些App为了能在后台持续做事情,就会持有一个WakeLock,那么手机就不会进入休眠状态,App要做的事情能做了,但是也更加耗电
- 无网络状态避免网络请求
4.网络的优化
- 请求合并
- 减少请求数据的大小
- 减少返回数据大小
- 对数据缓存
- 进行增量更新
- IP直连
- 文件、图片等的下载,采用断点续传,不浪费用户之前消耗过的流量
- 图片使用WEBP格式
5.其他
- Handler中有Loop死循环,为什么没有阻塞主线程?主线程的死循环一直运行是不是特别消耗CPU资源呢?
其实不然,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。 Gityuan–Handler(Native层)
6.Java中的集合
Collection
- List:Collection接口的子接口,该接口体系特点是:存储有序,元素可重复
- ArrayList:底层是数组数据结构,特点:查询快,增删慢。数组实现,查找快,增删慢由于是数组实现,在增和删的时候 会牵扯到数组增容,以及拷贝元素所以慢。数组是可以直接按索引查找,所以查找时较快
- LinkedList:底层是链表数据结构,特点:增删快,查询慢。链表实现,增删快,查找慢,由于链表实现,增加时只要让前一个元素记住自己就可以,删除时让前一个元素记住后一个元素,后一个元素记住前一个元素,这样的增删效率较高但查询时需要一个一个的遍历,所以效率较低
- Vector:底层是数组数据结构,特点:线程同步,效率低
- Set:Collection接口的子接口,该接口体系类特点是:存储无序,元素不可重复
- HashSet:底层是哈希表数据结构,特点:存取都快。通过hashCode和equals方法保证元素的唯一性
- TreeSet:底层是二叉树数据结构,特点:存取都快,通过比较性来保证元素的唯一性。底层是使用了红黑树(二叉树)的数据结构实现的。往 TreeSet添加元素的时候,如果添加的元素具备了自然顺序的特性,那么treeSet会按照元素的自然顺序进行排序存储。否则需要自定义比较规则,不然编译会报错
Map集合的根接口,特点是:存在键和值的映射关系,键有唯一性
- HashMap:底层是哈希表数据结构,特点:存取都快,通过hashCode和equals方法保证键的唯一性。存储无序,底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性
- TreeMap:可以对健进行自然排序,所以存储有序。底层是二叉树数据结构。可以对map集合中的键进行排序。需要实现Comparable接口复写 compareTo方法或者自定义类实现Comparator接口,创建比较器来对键值进行比较排序来判断键的唯一性
- HashTable:底层是哈希表数据结构,线程是同步的,不可以存入null键,null 值。效率较低,被HashMap 替代
| Collection | 我们需要保存若干个对象的时候使用集合 |
| —- | —- |
| List | 如果我们需要保留存储有顺序, 并且保留重复元素, 使用List
如果查询较多, 那么使用ArrayList
如果存取较多, 那么使用LinkedList
如果需要线程安全, 那么使用Vector | | Set | 如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set
如果我们需要将元素排序, 那么使用TreeSet
如果我们不需要排序, 使用HashSet, HashSet比TreeSet效率高
如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet |
看到array,就要想到角标
看到link,就要想到first,last
看到hash,就要想到hashCode,equals
看到tree,就要想到两个接口。Comparable,Comparator
