共计 8414 个字符,预计需要花费 22 分钟才能阅读完成。
前言
熬夜整顿了一份 java 根底面试题,心愿大家反对,如果文中有谬误心愿大家斧正;
公众号:常识追寻者
常识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)
一 java 根底面试
1.1 面向对象和面向过程的区别
- 面向过程:
长处:性能比面向对象高,因为类调用时须要实例化,开销比拟大,比拟耗费 资源
利用场景:单片机、嵌入式开发、Linux/Unix;
毛病:没有面向对象易保护、易复用、易扩大
- 面向对象
长处:因为面向对象有封装、继承、多态性的特 性,能够设计出低耦合的零碎,故易保护、易复用、易扩大;
利用场景:网页开发,后盾开发等;
毛病:性能比面向过程低
1.2 面向对象的个性
- 封装:将一个对象的属性私有化,并提供一个对外拜访的办法;
- 继承:在已有类的根底上建设新类;提供继承信息的类被称为父类(超类、基类);失去继 承信息的类被称为子类(派生类)
- 多态:一个对象的多种体现状态;用同样的对象援用调用同样的办法然而做了不同的事件;能够向上转型和向下转型
多态实现模式:
重写:子类对父类办法的重写;
笼罩:实现接口,并笼罩办法;
1.3 形象
形象是指将对象形象为具体类的过程;形象只关注对象有哪些属性和行为(办法);
1.4 Java 语言特点
- 简略易学;
- 面向对象(封装,继承,多态);
- 跨平台(Java 虚拟机实现平台无关性);
- 可靠性;
- 安全性;
- 反对多线程
- 反对编译与解释;
- 反对网络编程
1.5 JDK,JRE,JVM 之间的区别
JDK:java 开发工具包;蕴含 JRE, javac 等调优诊断工具;可能创立和编译程序;
JRE:java 运行环境;包含 Java 虚拟机(JVM),Java 类库,java 命令和其余的一些根底构件;不能创立程序;
JVM:java 虚拟机,提供运行字节码文件 (.class) 的环境反对;
jdk 蕴含 jre ; jre 蕴含 jvm
1.6 面向对象五大根本准则
- 繁多职责准则 SRP(Single Responsibility Principle);设计类时要性能繁多;
- 凋谢关闭准则 OCP(Open-Close Principle);一个模块对于拓展是凋谢的,对于批改是关闭;
- 里式替换准则 LSP(the Liskov Substitution Principle LSP);子类能够替换父类;
- 依赖倒置准则 DIP(the Dependency Inversion Principle DIP);高层次的模块不应该依赖于低层次的模块,他们都应该依赖于形象。形象不应该依赖于具体实现,具体实现应该依赖于形象;
- 接口拆散准则 ISP(the Interface Segregation Principle ISP);设计类时,性能接口拆分为多个;
开发设计类时需思考的事件,面试中如果碰见能答几个就几个;
1.7 什么是 java 主类
java 主类是 java 代码运行的入口,即蕴含 main 办法的类;
1.8 结构器是否被重写
子类无奈继承父类的结构器,所以结构器不能被重写(overidde),但能够被重载(overload);
1.9 重载和重写的区别
重写
:
- 产生在父类与子类之间
- 办法名,参数列表,必须雷同,返回值小于等于父类;
- 拜访修饰符大于等于父类(public>protected>default>private);父类办法为 private,则无奈重写;
- 重抛出异样的范畴要小于等于父类异样;
重载
:
- 产生在同一个类中
- 办法名雷同参数列表不同(参数类型不同、个数不同、程序不同);
- 办法返回值和拜访修饰符能够不同;
1.10 equals 与 == 的区别
==:断定是否是雷同一个对象,比拟的是变量 (栈) 内存中寄存的对象的 (堆) 内存地址,用来判断两个对象的地址是否雷同,;
equals: equals 用来比拟的是两个对象的内容是否相等; 但 Object 中的 equals 办法返回的却是 == 的判断;
1.11 什么是 hashCode
hashCode() 的作用是获取哈希码,也称为散列码;它实际上一个 int 整数;哈希码的作用是确定该对象在哈希表中的索引地位;散列表存储的是键值对(key-value),即能依据键获取值;
当一个对象插入散列表时先会比拟对象与散列表中已有的对象 hash 值,若不同,则直接插入散列表,若雷同(hash 碰撞),则会调用 equals 办法查看是否真的雷同, 如果 equal()判断不相等,间接将该元素放入汇合中,否则不放入;
对象中 hashCode()与 equals()的关系
- 如果两个对象相等,则 hashcode 也相等;
- 两个对象相等, 对两个对象别离调用 equals 办法都返回 true
- 两个对象有雷同的 hashcode 值,它们不肯定是同一个对象;
- equals 办法被笼罩过,则 hashCode 办法也必须被笼罩;
1.12 什么是值传递和援用传递
值传递:传递了对象的一个正本,即便正本被扭转,也不会影响源对象;
援用传递:着传递的并不是理论的对象,而是对象的援用;对外部对象的扭转会反映到理论对象;
个别认为,Java 内的传递都是值传递,Java 中实例对象的传递是援用传递;
1.13 什么是抽象类与接口
- 抽象类是对类的形象,是一种模板设计;而接口是行为的形象,能够了解为行为的标准;
- 抽象类中能够蕴含非形象办法;而接口是相对的形象办法;
- 接口默认是 public 办法,java8 中接口反对默认(default)办法;
- 一个类能够实现多个接口,但只能实现一个抽象类;
- 抽象类不能应用 final 润饰(final 润饰的类为固定类,无奈被继承)
1.14String、String StringBuffer 和 StringBuilder 的区别
- String 是只读字符串,并不是根本数据类型,而是一个对象;其无奈扭转;每次操作都会产生新对象;
- StringBuilder 并没有对办法进行加同步锁,线程不平安;
- StringBuffer 对办法加了同步锁,线程平安;
tip: 数据量少的时候应用 String; 单线程应用 StringBuilder ; 多线程应用 StringBuffer ; 应用 StringBuilder 性能比 StringBuffer 性能 晋升大略有 10%~15%;
1.15 用最有效率的办法计算 2 乘以 8
2 << 3 = 8 ; 2 左移 3 位
1.16 & 与 && 的区别
& 运算符 按位与;
&& 运算符是短路与:&& 右边的表达式的值是 false,左边的表达式会被间接短路掉,不会进行运算
1.17 static 关键字
static 变量在 Java 中属于类的,它在所有的实例中具备雷同的值。当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化;故须要用实例来拜访 static 变量;
1.18 Java 反对的数据类型
- 整数值型:byte,short,int,long;
- 字符型:char;
- 浮点类型:float,double;
- 布尔型:boolean;
类型
字节数
位数
short
2
16
int
4
32
long
8
64
float
4
32
double
8
64
char
2
16
1.19 final, finally, finalize 的区别
- final:用于申明属性, 办法和类, 别离示意属性不可变, 办法不可笼罩, 类不可继承.
- finally:异样解决语句构造的一部分,示意最初总是会执行.
- finalize:Object 类的一个办法,在垃圾收集器执行的时候会调用被回收对象的此办法;
1.20 instanceof 关键字
instanceof 严格来说是 Java 中的一个双目运算符,用来查看一个对象是否为一个类的实例;
1.21 为什么不能用浮点型示意金额
浮点数为非准确值,应该应用 BigDecimal 来润饰金额;
1.22 主动装箱与拆箱
- 装箱:主动将根本数据类型转换为包装器类型,调用 Integer 的 valueOf(int) 办法;
- 拆箱:主动将包装器类型转换为根本数据类型。调用 Integer 的 intValue 办法
tip: int 是根底数据类型,占用空间小;Integer 是对象占用空间大;
1.23 switch 中是否应用 string 做参数
在 idk 1.7 之前,switch 只能反对 byte, short, char, int 或者其对应的封装类以及 Enum 类型。从 idk 1.7 之后 switch 开始反对 String。
能够用在 byte 上,然而不能用在 long 上。
1.24 java 创建对象的几种形式
- 采纳 new
- 通过反射
- 采纳 clone
- 通过序列化机制
1.25 如何将 byte 转为 String
能够应用 String 接管 byte[] 参数的结构器来进行转换, 但编码必须正确;
1.26 final 有哪些用法
1. 被 final 润饰的类不能够被继承 2. 被 final 润饰的办法不能够被重写 3. 被 final 润饰的变量不能够被扭转。5. 被 final 润饰的常量,在编译阶段会存入常量池中。
1.27 java 当中的四种援用
- 强援用:如果一个对象具备强援用,它就不会被垃圾回收器回收。即便以后内存空间有余,JVM 也不会回收它,而是抛出 OutOfMemoryError 谬误,使程序异样终止。如果想中断强援用和某个对象之间的关联,能够显式地将援用赋值为 null,这样一来的话,JVM 在适合的工夫就会回收该对象。
- 软援用:在应用软援用时,如果内存的空间足够,软援用就能持续被应用,而不会被垃圾回收器回收,只有在内存不足时,软援用才会被垃圾回收器回收。
- 弱援用:具备弱援用的对象领有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱援用对象,无论以后内存空间是否短缺,都会将弱援用回收。
- 虚援用:如果一个对象仅持有虚援用,那么它相当于没有援用,在任何时候都可能被垃圾回收器回收。
1.28 Math. round(-1. 5) 等于多少?
Math.round(-1.5)的返回值是 -1。四舍五入的原理是在参数上加 0.5 而后做向下取整
1.29 String str=”i” 与 String str=new String(“i”)一样吗?
tring str=”i” 的形式,Java 虚构机会将其调配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中; 所以一个是常量,一个是对象,不一样;
1.30char 型变量中能不能存储一个中文汉字
char 类型能够存储一个中文汉字,因为 Java 中应用的编码是 Unicode,一个 char 类型占 2 个字节,所以能放一个中文。
1.31 break 和 continue 的区别
- break 跳出整个循环。
- continue 用于跳过本次循环,执行下次循环。
1.32 外部类与动态外部类的区别
外部类: 1、外部类中的变量和办法不能申明为动态。2、外部类实例化:B 是 A 的外部类,实例化 B:A.B b = new A().new B()
。3、外部类能够援用外部类的动态或者非动态属性及办法。
动态外部类: 1、动态外部类属性和办法能够申明为动态的或者非动态的。2、实例化动态外部类:B 是 A 的动态外部类,A.B b = new A.B()
。3、动态外部类只能援用外部类的动态的属性及办法。
1.33 throw 和 throws 的区别?
- throw 用于被动抛出 java.lang.Throwable 类的一个实例化对象,即通过关键字 throw 抛出一个 Error 或者 一个 Exception;
- throws 的作用是作为办法申明和签名的一部分;
1.34 error 和 exception 的区别
- Error 类和 Exception 类的父类都是 throwable 类
- Error 类个别是指与虚拟机相干的问题,如零碎解体,虚拟机谬误,内存空间有余,办法调用栈溢等。间接终止程序即可;
- Exception 类示意程序能够解决的异样,能够捕捉和有可能复原。须要程序员手动解决;
1.35 什么时候用断言(assert)
断言是一个蕴含布尔表达式的语句,在执行这个语句时假设该表达式为 true;如果表达式的值为 false,那么零碎会报告一个 AssertionError。
断言有两种模式:
assert Expression1
; 示意一个 boolean 表达式assert Expression1 : Expression2
; Expression2 示意一个根本类型、表达式或者是一个 Object,用于在失败时输入错误信息
assert false;
assert i == 0:”123″;// 当 i 不等于 0 时会输入错误信息
1.36 常见的五种运行时异样
- ClassCastException(类转换异样)
- IndexOutOfBoundsException(数组越界)
- NullPointerException(空指针异样)
- ArrayStoreException(数据存储异样,操作数组是类型不统一)
- BufferOverflowException(缓存溢出异样)
二 IO 流面试
2.1 序列化的含意
- 序列化:将对象写入到 IO 流中
- 反序列化:从 IO 流中复原对象
序列化机制将序列化的 Java 对象转换为位字节序列,这些字节序列能够保留在磁盘上,或通过网络传输,以达到当前复原成原来的对象,通常被序列化的要实现 Serializable 接口,并指定序列值
Externalizable 能够管制整个序列化过程,指定特定的二进制格局,减少平安机制
2.2 java 中 IO 流分类
- 依照流的流向分,能够分为输出流和输入流;
- 依照操作单元划分,能够划分为字节流和字符流;
- 依照流的角色划,能够分为节点流和解决流。
- InputStream/Reader: 所有的输出流的基类,前者是字节输出流,后者是字符输出流。
- OutputStream/Writer: 所有输入流的基类,前者是字节输入流,后者是字符输入流。
图片起源网络:
2.3 BIO、NIO、AIO 的区别
- BIO 就是传统的
java.io
包,它是基于流模型实现的,交互的形式是同步、阻塞形式 IO; 在读入输出流或者输入流时,在读写实现之前,线程会始终处于阻塞状态。 - NIO(New IO)是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的形象,能够构建多路复用的、同步非阻塞 IO 程序。
- AIO(Asynchronous IO)是 Java 1.7 之后引入的包,是 NIO 的降级版本,提供了异步非梗塞的 IO 操作形式,所以人们叫它 AIO,异步 IO 是基于事件和回调机制实现。
三 汇合面试
3.1 java 汇合架构
3.2 Collection 和 Collections 的区别
Collection:是 java.uitl 下的接口,他是各种汇合的父接口;
Conllecitons:是个 java.util 下的类,是针对汇合的工具类,提供一系列静态方法对汇合的搜寻、查找、同步等操作;
3.3 ArrayList 和 Vector 的区别
- 共同点:都实现了 List 接口,为有序的汇合,底层基于数组实现,通过索引取值,容许元素反复和为 null;都是实现 fail-fast 机制;
- 区别:ArrayList 不同步,Vector 是同步(ArrayList 比 Vector 快,不会过载);Vector 扩容原来的一倍,ArrayList 扩容原来的 0.5 倍;
3.4List,Set,Map 三者的区别?
List
:存储的元素有序可反复。Set
: 存储的元素是无序的、不可反复的。Map
: 应用键值对(kye-value)存储,通过 key 获取 value; key 不能反复;
3.5 ArrayList,LinkedList 区别
共同点:
ArrayList
和 LinkedList
都是线程不平安;
区别:
- ArrayList 的底层是数组实现,LinkedList 的底层是双向链表实现。
- ArrayList 通过索引获取值,查问快;LinkedList 通过遍历链表获取值查问慢;
- ArrayList 增删慢,LinkedList 增删快;
3.6Enumeration 和 iterator 接口的区别
- iterator 是 Enumeration 接口的替代品,只提供了遍历 vector 和 HashTable 类型汇合元素的性能;
- Enumeration 速度是 iterator 的 2 倍,同时占用更少的内存。
- terator 有 fail-fast 机制,比 Enumeration 更平安
- Iterator 可能删除元素,Enumeration 并不能删除元素
3.7 简述 Iterator 迭代器
Iterator 迭代器能够对汇合进行遍历,遍历形式都是 hasNext()
和 next()
办法,,在以后遍历汇合元素被更改的时候,就会抛出 ConcurrentModificationException
异样;
3.8 HashMap 和 Hashtable 的区别
共同点:都实现 Map 接口;
区别:
- HashMap 不同步;Hashtable 同步;HashMap 效率比 Hashtable 高;
- HashMap 容许为 null;Hashtable 不容许为 null
- Hashtable 默认的初始大小为 11,之后每次裁减,容量变为原来的 2n+1,HashMap 默认的初始化大小为 16;
- HashMap 在 jdk1.8 扭转了数据结构为 数组 + 链表 + 红黑树形式;HashTable 应用全表锁,效率低下;
3.9HashSet 和 HashMap 的区别
- HashMap 实现了 Map 接口;HashSet 实现了 Set 接口
- HashMap 贮存键值对;HashSet 仅仅存储对象
- HashMap 应用 put()办法将元素放入 map 中;HashSet 应用 add()办法将元素放入 set 中;
- HashMap 中应用键对象来计算 hashcode 值;ashSet 应用成员对象来计算 hashcode 值;
- HashSet 较 HashMap 来说比较慢;
3.10 HashMap 和 TreeMap 区别
TreeMap 实现 SortMap 接口,可能将记录依据键排序(默认升序排序),也能够指定排序的比拟器 Comparator,当用 Iterator 遍历 TreeMap 时失去排序后的后果;
对于插入、删除和定位元素等操作,抉择 HashMap;如果对一个有序的 key 汇合进行遍历,抉择 TreeMap
3.11 并发汇合和一般汇合区别
并发汇合常见的有 ConcurrentHashMap
、ConcurrentLinkedQueue
、ConcurrentLinkedDeque
等。并发汇合位于 java.util.concurrent 包下, 是 jdk1.5 之后才有;其相比与一般汇合增加了 synchronized 同步锁,线程平安,但效率低;
3.12 ConcurrentHashMap1.7 和 1.8 的区别
jdk1.8 的实现不再应用 jdk1.7 的 Segment+ HashEntry 分段锁机制实现,利用 Node 数组
+CAS+Synchronized
来保障线程平安;底层采纳 数组 + 链表 + 红黑树
的存储构造;
ConcurrentHashMap1.7
dk1.7
ConcurrentHashMap1.8
3.13HashMap 的长度为什么是 2 的幂次方
目标是为了能让 HashMap 存取高效,尽量减少 Hash 碰撞,尽量使 Hash 算法的后果均匀分布,每个链表 / 红黑树长度大致相同;
算法理论是取模,hash%length,计算机中求余效率不如位移运算,源码中做了优化 hash&(length-1);hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方
3.14 ArrayList 汇合如何高效退出 10 万条数据
间接在初始化的时候就指定 ArrayList 的容量值;
3.15 如何选用汇合
依据汇合的特点来选用汇合;依据键获取值选用 Map
接口下的汇合;须要排序抉择 TreeMap
, 不须要排序抉择 HashMap
, 须要线程平安选 ConcurrentHashMap
。
只寄存元素值时,就抉择实现 Collection
接口的汇合;须要元素惟一时抉择实现 Set
接口的汇合,如 TreeSet 或
HashSet; 不须要元素唯一性就抉择实现 List 接口, 如 ArrayList
或 LinkedList
;
3.16 疾速失败(fail-fast)和平安失败(fail-safe)的区别是什么
- 疾速失败:当你在迭代一个汇合的时候,如果有另一个线程正在批改你正在拜访的那个汇合时,就会抛出一个 ConcurrentModification 异样。在 java.util 包下的都是疾速失败。
- 平安失败:你在迭代的时候会去底层汇合做一个拷贝,所以你在批改下层汇合的时候是不会受影响的,不会抛出 ConcurrentModification 异样。在 java.util.concurrent 包下的全是平安失败的。
附:
HashMap 源码剖析:https://blog.csdn.net/youku1327/article/details/105332136;
ArrayList 源码剖析 https://blog.csdn.net/youku1327/article/details/105314040
tip: 须要懂 HashMap,ArrayList,LinkedList,ConcurrentHashMap 底层实现原理