文章目录
- 前言
- 正文
- ▶ Exception与Error的区别?
- ▶ String、StringBuffer、StringBuilder的区别?
- ▶ final、finally、finalize的区别?
- ▶ int与Integer的区别?
- ▶ Vector、LinkedList、ArrayList的区别?
- ▶ HashMap、TreeMap、Hashtable的区别?
- ▶ HashMap与HashSet的区别?
- ▶ ConcurrentHashMap与Hashtable的区别?
- ▶ 重载与重写的区别?
- ▶ 抽象类与接口的区别?
- ▶ ==与equals的区别?
- ▶ 实现Runnable接口与Callable接口的区别?
- ▶ 强引用、软引用、弱引用、虚引用的区别?
- 总结
前言
在Java面试中,总会问到各种相似概念的区别,比如String、StringBuilder、StringBuffer的区别。
为了方便他人以及方便自己,总结了一些常见概念区别以及答案,希望能对大家有所帮助。
正文
▶ Exception与Error的区别?
两者都是继承了Throwable类,下图是关于Java异常层次结构的示意图。
Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。绝大部分的Error都会导致程序(例如JVM)处于非正常、不可恢复状态。既然是非正常情况,所以也不便于也不需要捕获,常见的比如OutOfMemoryError。
Exception分解为两个分支:RuntimeException(即不检查unchecked异常);其他异常(即可检查checked异常)。
分解这两种异常的规则是:由程序错误导致的异常属于RuntimeException
;而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常
。
常见的RuntimeException包括下面几种情况:
- 错误的类型转换
- 数组越界访问
- 访问null指针
常见的其他异常(可检查异常)包括下面几种情况:
- 试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图查找某个不存在的类
▶ String、StringBuffer、StringBuilder的区别?
String | StringBuffer | StringBuilder | |
---|---|---|---|
可变性 | 不可变(final class,属性也由final修饰) | 可变 | 可变 |
线程安全 | 安全(类似常量,原生的保证了基础线程安全) | 安全(有sync方法) | 不安全(无sync方法) |
性能 | 低(每次对其操作时都会生成新的String对象) | 低 | 高 |
▶ final、finally、finalize的区别?
final用于修饰类、属性以及方法
-
当修饰一个类时,该类不允许被继承
-
当修饰一个属性时,该属性被视为常量,不允许再次赋值
(若修饰的是一个引用对象,则引用对象初始化后不可以指向另一对象)
-
当修饰一个方法时,该类再被继承时,此方法不允许重写
finally是Java保证重点代码一定要被执行的一种机制。可以使用try-finally或者try-catch-finally来进行类似JDBC连接关闭、保证unlock锁等动作。
以下特例不会执行finally:
- 没有执行到try-catch语句,try-catch语句之前就报异常或者中止虚拟机
int i = 100 / 0;
try {
// do something
} catch(Exception e) {
// do something
} finally {
System.out.println("Finally");
}
- 在finally之前就中止了Java虚拟机,比如使用
System.exit();
try {
System.exit(0);
} catch(Exception e) {
// do something
} finally {
System.out.println("Finally");
}
- 守护线程被提前终止(main线程是非守护线程,程序的终止取决于非守护线程)
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("finally");
}
});
thread.setDaemon(true);
thread.start();
}
finalize是基础类java.lang.Object中的一个方法,其设计目的是保证对象在被垃圾回收前完成特定资源的回收。finalize机制现在已经不推荐使用,在JDK 9开始被标记为deprecated。
如果没有特殊的原因,不要使用finalize方法,也不要指望它来进行资源回收,因为你无法保证finalize方法什么时候执行,执行是否符合预期,使用不当会影响性能,导致程序死锁、挂起等。
▶ int与Integer的区别?
-
int是Java基本数据类型(byte、short、int、long、float、double、char、boolean)之一
-
Integer是int对应的包装类,它有一个int类型的字段存储数据,并且提供了基本操作,比如数学运算、int和字符串之间的转换等。在Java 5中,引入了自动装箱和自动拆箱功能
自动装箱:将基本数据类型装箱为对应的包装类
自动拆箱:将包装类拆解成对应的基本数据类型
▶ Vector、LinkedList、ArrayList的区别?
Vector | LinkedList | ArrayList | |
---|---|---|---|
底层实现 | 数组(Object[] elementData) | 双向链表(Node) | 数组(Object[] elementData) |
初始容量 | 10 | 无 | 10 |
扩容逻辑 | 提高1倍容量 | 无 | 提高50%的容量 |
线程安全 | 安全(由sync修饰方法) | 不安全(无sync修饰方法) | 不安全(无sync修饰方法) |
性能表现 | 增删慢O(N)、读取快O(1) | 增删快O(1)、读取慢O(N) | 增删慢O(N)、读取快O(1) |
应用场景 | 虽然Vector是线程安全的,但由于大多数方法都由synchronized修饰,效率较低。建议并发中使用CopyOnWriteArrayList或者Collections.synchronizedList(List list) | 非并发中存在大量增删操作 | 非并发中存在大量随机访问的操作 |
▶ HashMap、TreeMap、Hashtable的区别?
HashMap | TreeMap | Hashtable | |
---|---|---|---|
底层实现 | 数组+链表(红黑树)(Node<K,V>[] table) | 红黑树(Entry<K,V> root) | 数组+链表(Entry<?,?>[] table) |
初始容量 | 数组长度为16 | 无 | 11 |
装载因子 | 0.75 | 无 | 0.75 |
扩容逻辑 | 提高1倍容量 | 无 | 提高1倍容量+1 |
线程安全 | 不安全(无sync修饰方法) | 不安全(无sync修饰方法) | 安全(由sync修饰方法) |
顺序特性 | 无序 | 有序 | 无序 |
key为null | 允许key、value为null | 当未实现 Comparator 接口时,key不可为null;当实现 Comparator 接口时,若未对null情况进行判断,则key不可以为null | key、value不允许为null |
性能表现 | 在单线程环境下,使用HashMap存储key-value是一种不错的选择,在不考虑树化以及链表退化的情况下,进行数据读取可以达到常数时间的性能 | 由于底层是由红黑树实现的,在进行数据操作(get、put、remove之类)时都是O(log(n))的时间复杂度,顺序可由指定Comparator 或根据键的自然顺序来判断 | 由于大多数操作方法都由synchronized修饰,效率非常低下 |
应用场景 | 单线程环境中存储key-value数据 | 单线程环境中存储具有某种顺序的数据 | 虽然是线程安全,但是跟Vector一样,synchronized太笨重,不建议使用Hashtable。多线程环境下建议使用ConcurrentHashMap |
▶ HashMap与HashSet的区别?
HashMap | HashSet | |
---|---|---|
接口实现 | 实现了Map接口 | 实现了Set接口 |
底层实现 | 数组+链表(红黑树)(Node<K,V>[] table) | 哈希表(HashMap<E,Object> map) |
存储对象 | 存储键值对 | 仅存储对象 |
添加方法 | 使用put()方法进行添加 | 使用add()方法进行添加 |
Hash值 | 通过key进行计算 | 通过对象成员进行计算 |
性能表现 | 相较于HashSet较快,因为它是使用了唯一key获取对象 | 相较于HashMap较慢 |
▶ ConcurrentHashMap与Hashtable的区别?
ConcurrentHashMap | Hashtable | |
---|---|---|
底层实现 | JDK1.7分段数组+链表、JDK1.8数组+链表(红黑树)(Node<K,V>[] table) | 数组+链表(Entry<?,?>[] table) |
线程安全 | 在JDK1.7中使用分段锁对整个桶进行分割分段,每个锁只锁一部分的数据;在JDK1.8中直接使用Node数组+链表+红黑树实现,使用synchronized以及CAS操作数据,提高效率 | 使用synchronized来实现线程安全,当一个线程访问同步方法时,其他线程也访问同步方法时,可能会进入阻塞或者轮询状态,竞争激烈效率低 |
▶ 重载与重写的区别?
重载 | 重写 | |
---|---|---|
发生场景 | 同一个类当中 | 父子类中 |
方法要求 | 方法名相同、参数个数不同或者参数类型不同或者参数顺序不同,与返回值类型以及访问符类型无关 | 方法名、参数列表必须相同,返回值的范围小于等于父类,抛出异常范围小于等于父类,访问修饰符范围大于等于父类(父类中的private方法,子类无法重写) |
▶ 抽象类与接口的区别?
抽象类 | 接口 | |
---|---|---|
关键字 | 使用abstract修饰,继承抽象类使用extends关键字 | 使用interface修饰,实现接口使用implements关键字 |
方法 | 允许存在非抽象方法(具体的方法) | 不允许存在非抽象方法,所有方法不能被实现,方法默认为public修饰 |
变量 | 允许有各种类型的变量 | 任何变量都隐含有public static final的意义 |
实现/继承 | 若当前子类继承了抽象类且子类是抽象类则不需要实现抽象方法,反之需要实现;抽象类除了不能实例化其他跟普通类一样一个类只能继承一个抽象类; | 若一个类实现了接口,则必须实现接口的所有方法;接口也不允许实例化,但是可以实现,一个类可以实现多个接口 |
设计层面 | 是对类的抽象,是一种模板设计 | 是行为的抽象,是一种行为规范 |
▶ ==与equals的区别?
== :若比较对象为基本数据类型(boolean、byte、short、int、long、float、double、char)则比较的是两者的值是否相等;若比较对象为引用对象(String或者自己定义的Person实例),则比较的是两者的地址是否相等
equals() :
-
若没有覆盖equals方法,则默认使用==判断两者是否相等,比如Object中的equals方法
// Object的equals()源码 public boolean equals(Object obj) { return (this == obj); }
-
若覆盖了equals方法,则一般用来比较两者的值是否相等,比如String中的equals方法
// String的equals()源码 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
▶ 实现Runnable接口与Callable接口的区别?
Callable跟Runnable类似,都可以用来创建线程,不同的是Runnable无法返回值也无法抛出异常,而Callable则相反,不仅可以返回任意类型的结果,也可以抛出异常。
▶ 强引用、软引用、弱引用、虚引用的区别?
以下参考书籍《深入理解Java虚拟机》
强引用:即我们最常见的普通对象的引用,类似Object obj = new Object();
。只要还有强引用指向一个对象,就表明对象还存活,垃圾回收器就不会收集这种对象。
软引用:用来描述一些有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常前,将会把这些对象列进回收范围之中进行第二次回收。在JDK1.2之后,提供了SoftReference类来实现软引用。
弱引用:也是用来描述非必需对象的,但是它的强度比软引用更弱,被软引用关联的对象只能生存到下一次垃圾收集发生之前。
虚引用:又称幽灵引用或幻影引用,是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象的实例。
总结
以上就是常见的概念区别题,希望大家在面试前能够大致过一遍,做到心中有数。
若文中有出现错误的地方,欢迎留言指正!