前言
前段时间换工作准备期间,总结了下在Android面试中易问的一些Java基础知识与面试题,不太全,大家查缺补漏吧。开始Review!
面向对象
Java面向对象编程思想
将属性与功能封装起来,通过归类与抽象将相同或相似的部分抽出,不同的部分分离,将复杂业务逻辑切分成相互独立的部分,降低开发的难度。
面向对象是解决了系统的可维护性,可扩展性和可重用性主要通过以下四大特性来实现:
- 抽象:核心思想!把相同的或相似的对象归为一类的这个过程就是抽象。抽象只关心对象中的主要问题,主要矛盾及相同的部分。它只在乎问题是什么,能够完成什么,而不在乎怎么去完成,交给他的实现类去解决。
- 封装:将某些属性包装在一起,再以全新的形式呈现出来。其中隐藏属性,方法或实现的细节称之为封装。
- 继承:重用现有的父类来生成新子类的一种特征,子类可通过继承父类来获取父类的属性与方法。
- 多态:同一函数在不同的类中有不同的实现,使类变得更灵活,更便于扩充。父类引用指向子类对象。
设计模式
单例模式5种:
- 懒汉式
- 饿汉式
- 同步线程锁懒汉式
- 双重线程锁懒汉式
- 最优单例
简单工厂模式
由一个工厂类,根据传入参数的不同,动态创建不同的产品,这些产品都继承自一个父类或接口的实例。得益于Java的多态特性。
集合
List集合:有序,可重复
- ArrayList:底层是动态数组顺序表数据结构,存储地址是连续的,所以查询速度快。但增删时需要移动其他元素的顺序,所以增删速度慢,线程不同步。
- LinkedList:底层是双向链表数据结构,同时也实现了Deque双端队列接口,链表节点存储地址不连续。每个存储地址之间通过指正关联,查询时需要指针遍历所有节点,所以查询速度慢。而增删只需断开某元素前后的链接进行增加与删除即可,所以增删速度快,线程不同步。
- Vector:类似ArrayList,线程同步,效率低。
Set集合:无序,不可重复
- HashSet:底层数组,哈希表数据结构,线程不同步。
- TreeSet:二叉树数据结构,可实现Comparable或Comparator接口来排序,线程不同步。
Map集合:键值对,键不可重复,值可以重复
- HashMap:哈希表数据结构,可存入null键,null值,线程不同步。
- HashTable:哈希表数据结构,不可存入null键,null值,线程同步。
- TreeMap:二叉树数据结构,可进行排序,线程不同步
网络编程
TCP/IP层级
- 应用层:向用户提供一些常用应用程序,例如电子邮件,文件传输访问等。包含常用协议HTTP(超文本传输协议:实现互联网中WWW服务)、DNS(域名解析:域名到IP地址间的转换)
- 传输层:提供应用程序之前的传输通道。主要传输协议为TCP(面向连接传输控制协议,三次握手,安全可靠性高,适用于传输大量数据,但速度慢)与UDP(面向无连接用户数据报协议,无需握手同步,安全可靠性低,适用于传输小量数据,但速度快,例如QQ)。
- 网络层:核心层,根据IP协议将分组装入IP数据报并发往目标网络或主机。主要传输协议为IP协议(用于源地址与目的地址间的传送数据报)与ICMP协议(传送IP控制信息)
- 网络接口层:最底层,接收IP数据报,并通过网络发送
执行顺序
静态变量,静态代码块,本地变量执行顺序
父类代码:
父类输出:
带继承关系的执行顺序**
子类代码:
子类输出
计算
Math的一些计算
- Math.round():四舍五入,+0.5后向下取整(Math.round(11.5)=12,Math.round(-11.5)=-11),float返回int,double返回long
- Math.rint():四舍五入,遇0.5则取偶数(Math.rint(11.4)=11.0,Math.rint(11.5)=12,Math.rint(10.5)=10)
- Math.floor():不大于它的最大整数(Math.floor(11.5)=11,Math.floor(-11.5)=-12)
- Math.ceil():不小于他的最小整数(Math.ceil(11.5)=12,Math.ceil(-11.5)=-11)
- Math.abs():绝对值(Math.abs(11.5)=11.5,Math.abs(-11.5)=11.5)
- Math.max():最大值(Math.max(-11.5, -11.4)=-11.4)
- Math.min():最小值(Math.min(-11.5, -11.4)=-11.5)
- Math.random():0.0-1.0之间的随机数
- Math.pow(x, y):x的y次幂
- Math.sqrt():开方
常量池计算
Java的8种基本类型(Byte, Short, Integer, Long, Character, Boolean, Float, Double), 除Float和Double以外, 其它六种都实现了常量池, 但是它们只在大于等于-128并且小于等于127时才使用常量池.
来看代码演示:
输出结果:
结论:当我们给Integer赋值时,实际上调用了Integer.valueOf(int)方法,查看源码,其实现如下:
而IntegerCache实现如下:
注意:cache数组是静态的。
面试题
最优单例模式
|
|
LinkedList工作原理与实现
LinkedList是以双向链表实现,链表无容量限制(但是双向链表本身需要消耗额外的链表指针空间来操作),其内部主要成员为 first 和 last 两个 Node 节点,在每次修改列表时用来指引当前双向链表的首尾部位,所以 LinkedList 不仅仅实现了 List 接口,还实现了 Deque 双端队列接口(该接口是 Queue 队列的子接口),故 LinkedList 自动具备双端队列的特性,当我们使用下标方式调用列表的 get(index)、set(index, e) 方法时需要遍历链表将指针移动到位进行访问(会判断 index 是否大于链表长度的一半决定是首部遍历还是尾部遍历,访问的复杂度为 O(N/2)),无法像 ArrayList 那样进行随机访问。(如果i>数组大小的一半,会从末尾移起),只有在链表两头的操作(譬如 add()、addFirst()、removeLast() 或用在 iterator() 上的 remove() 操作)才不需要进行遍历寻找定位。
使用LinkedList模拟一个堆栈或队列的数据结构
|
|
ConcurrentModificationException异常
计算下面代码的输出结果:
- 解答:会抛出ConcurrentModificationException异常,List不可在进行遍历时添加或移除其中的元素。
- 源码解析:ArrayList的父类AbstractList中有一个modCount成员变量来记录对List的修改次数,还有一个expectedModCount记录对ArrayList修改次数的期望值,modCount是它的初始值。遍历开始时modCount与expectedModCount都为0,而当我们在遍历中对List进行了add或remove操作后modCount会增加1,expectedModCount不变。而List在通过next()方法取下一次值时会先检查modCount与expectedModCount是否相等,不等则会抛出ConcurrentModificationException异常。
- 单线程中解决方案:使用Iterator遍历集合,调用Iterator的remove方法移除元素,其内部有expectedModCount = modCount的操作。
- 多线程中解决方案:多线程中使用上述方法也会抛出此异常,可在使用iterator迭代的时候使用synchronized或者Lock进行同步,或使用CopyOnWriteArrayList替换ArrayList。
通过代码输出365的二进制
- 简单版
|
|
- 负数版
|
|
总结
目前Java面试技术点总结的还不太全,我会持续更新,也欢迎码友们指出文中写的不对的地方,或者有遗漏的知识点也可以联系我,咱们一起来维护,方便你我他。最后祝各位求职顺利,入职满意的公司。