部分面试题总结

最近在面试,遇到了一些问题,先记录下来,以便加深理解记忆

JAVA

1. Private,(Default),Protected,Public关键字的作用域

可以用一张表格体现

关键词 子类 全世界
Public
Protected
(Default)
Private

2. 对象创建的几种方式

  1. 使用new关键字
  2. 使用Class类的newInstance方法
  3. 使用Constructor类的newInstance方法
  4. 使用clone方法
  5. 使用反序列化

3. 线程池的用法

1. 线程池的作用:

线程池作用就是限制系统中执行线程的数量。

2. 为什么要用线程池:

  1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

3. ThreadPoolExecutor参数解释

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

  • corePoolSize - 池中所保存的线程数,包括空闲线程。
  • maximumPoolSize-池中允许的最大线程数。
  • keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
  • unit - keepAliveTime 参数的时间单位。
  • workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。
  • threadFactory - 执行程序创建新线程时使用的工厂。
  • handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。

官方文档强烈建议程序员使用较为方便的Executors工厂方法Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)Executors.newSingleThreadExecutor()(单个后台线程)

ExecutorService 真正的线程池接口
ScheduledExecutorService 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题
ThreadPoolExecutor ExecutorService的默认实现
ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现

4. 如何创建并运行java线程

  1. 创建Thread的子类
  2. 实现Runnable接口

5. 对称加密、非对称加密、MD5加密

1. 对称加密与非对称加密的区别:

对称加密称为密钥加密,速度快,但加密和解密的钥匙必须相同,只有通信双方才能知道密钥。
非对称加密称为公钥加密,算法更加复杂,速度慢,加密和解密钥匙不相同,任何人都可以知道公钥,只有一个人持有私钥可以解密。

2. 基于口令的对称加密与解密

系统自动生成的Key不容易记忆,我们可以使用我们容易记忆的口令同过java自带的一个工具将它转换成Key,在解密的时候我们就可以通过口令进行解密。

3. 非对称加密解密

非对称加密是公钥加密,私钥来解密,这个个人做用的少一点,主要针对于大型的网站大型的企业

4. MD5加密

1. MD5的作用

  • 一致性检验
  • 数字签名
  • 安全访问认证

2. MD5 算法具有很多特点:

  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算:从原数据计算出MD5值很容易。
  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
  • 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。

    3. 但实际上MD5不是一种加密算法,只是一种算法,因为它是一个不可逆的过程,即 MD5 生成消息摘要后是不能通过结果解析得到原来的内容,因此在大型企业应用中常用于用户密码进行MD5加密入库

4. 实现MD5加密

  1. 初始化MessageDigest对象
  2. 调用update方法传入要进行加密的byte数据
  3. (可选)调用reset方法重置要传入进行加密的数据
  4. 调用digest方法对传入的数据进行加密

Android

1. 组件化开发与插件化开发

组件化开发就是将一个app分成多个模块,每个模块都是一个组件(Module),开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并统一成一个apk,这就是组件化开发。
插件化开发和组件化开发略有不用,插件化开发时将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。

1. 组件化开发的优点:

  • 每个模块可以独立开发编译运行
  • 开发单个模块时可以共享资源和工具类
  • 可以针对单个模块测试

2. 插件化开发的优点:

  • 宿主和插件分开编译
  • 并发开发
  • 动态更新插件
  • 按需下载模块
  • 方法数或变量数爆棚

2. Android应用内存优化

为什么优化:

虽然 Java 对内存的释放有垃圾自动回收机制,但是实际开发中,不再用到的对象因为被错误引用会导致无法回收,从而造成内存泄漏,甚至内存溢出 OOM(OutOfMemory),程序崩溃。

优化方案:

  1. 检查使用多少内存
  2. 当界面不可见时释放内存
  3. 谨慎使用服务
  4. 使用优化的数据容器
  5. 避免在 Android 上使用枚举
  6. 使用 nano protobufs 序列化数据
  7. 避免内存流失
  8. 使用ProGuard来剔除不需要的代码
  9. 降低整体尺寸APK
  10. 优化布局层次
  11. 使用 Dagger 2依赖注入
  12. 请小心使用外部库
  13. 避免Bitmap浪费
  14. Cursor关闭
  15. 监听器的注销

3. 弱引用和软引用

  1. SoftReference:软引用–>当虚拟机内存不足时,将会回收它指向的对象;需要获取对象时,可以调用get方法。

  2. WeakReference:弱引用–>随时可能会被垃圾回收器回收,不一定要等到虚拟机内存不足时才强制回收。要获取对象时,同样可以调用get方法。

  3. WeakReference一般用来防止内存泄漏,要保证内存被虚拟机回收,SoftReference多用作来实现缓存机制(cache);

如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 (一般在使用Handler的时候会使用弱引用,以防止内存泄露)

4. IntentService作用是什么,AIDL解决了什么问题

生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至onStartCommand() 方法的Intetnt
生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题。在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。 AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据

5. Fragment 特点

Fragment可以作为Activity界面的一部分组成出现
可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用
在Activity运行过程中,可以添加、移除或者替换Fragment
Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响

6. Android Service与Activity之间通信的几种方式

  • 通过Binder对象
  • 通过Broadcast(广播)的形式

设计模式

总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
  • 其实还有两类:并发型模式和线程池模式。
    用一张图表示设计模式之间的关系

1. 单例模式

1. 模式的定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

2. 使用场景

确保某个类有且只有一个对象的场景,例如创建一个对象需要消耗的资源过多,如要访问 IO 和数据库等资源。

3. 优点与缺点

优点
  • 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
  • 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决;
  • 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  • 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
缺点
  • 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

2. 建造者(Builder)模式

1. 模式的定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

2. 使用场景

相同的方法,不同的执行顺序,产生不同的事件结果时;
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适;

3. 优点与缺点

优点
  • 良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节;
  • 建造者独立,容易扩展;
  • 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
缺点
  • 会产生多余的Builder对象以及Director对象,消耗内存;
  • 对象的构建过程暴露。

3. 代理(Proxy)模式

1. 模式的定义

代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

2. 模式的使用场景

就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

3. 优点与缺点

优点
  • 给对象增加了本地化的扩展性,增加了存取操作控制
缺点
  • 会产生多余的代理类

4. 迭代器(Iterator)模式

1. 模式的定义

迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。

2. 模式的使用场景

Java JDK 1.2 版开始支持迭代器。每一个迭代器提供next()以及hasNext()方法,同时也支持remove()(1.8的时候remove已经成为default throw new UnsupportedOperationException(“remove”))。对Android来说,集合Collection实现了Iterable接口,就是说,无论是List的一大家子还是Map的一大家子,我们都可以使用Iterator来遍历里面的元素,可以使用Iterator的集合

3. 优点与缺点

优点
  • 面向对象设计原则中的单一职责原则,对于不同的功能,我们要尽可能的把这个功能分解出单一的职责,不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
缺点
  • 会产生多余的对象,消耗内存;
  • 遍历过程是一个单向且不可逆的遍历;
  • 如果你在遍历的过程中,集合发生改变,变多变少,内容变化都是算,就会抛出来ConcurrentModificationException异常。

待续