整理一些java面试题供自己复习
一、基本常识
Q:Java语言有哪些特点?
A:Java语言共有十大特点,分别为:简单性、面向对象、分布性、编译和解释性、稳健性、安全性、可移植性、高性能、多线索性、动态性。
参考:https://zhuanlan.zhihu.com/p/109053181
Q:JDK JRE JVM三者有什么区别与联系?
A:
- JDK 用于开发,JRE 用于运行java程序 ;如果只是运行Java程序,可以只安装JRE,无序安装JDK。
- JDk包含JRE,JDK和 JRE 中都包含 JVM。
- JVM 是 java 编程语言的核心并且具有平台独立性。
Q:Java如何实现跨平台?
A:通过java虚拟机(JVM)。JVM会将编译后的.class文件(16进制的文件流)翻译成机器认识的语言(二进制的机械码)。
Q:8大基本数据类型有哪些?
A:
Q:成员变量与局部变量的区别?
A:
二、基本算法
三、面向对象
Q:面向对象具有哪些特征,分别是什么?
A:封装、继承、多态。
Q:方法的重载有重写有什么区别?与返回值是否有关?
A:
重载(Overload):方法签名相同,参数列表不同(与返回值无关)。
重写/覆盖(Override):同名同参同返回,前面的权限修饰符不能比父类的更封闭,抛出的异常不能更宽泛。
Q:构造方法有什么特点,是否能被重写?
A:构造方法的名字必须与类名相同,且没有任何返回类型。不可重写。
构造方法名 = 类名,子类名 ≠ 父类名,又子类重写必须 = 父类方法重名。
相当于,父类名 = 父构造方法 = 子类名 = 子构造方法。
前后矛盾,故不可重写。
Q:值传递和引用传递有什么区别?为什么java只有值传递?
A:
值传递:传递值。(将复制后再操作)
引用传递:传递地址。(直接对参数操作)
Java在使用中不允许出现指针。
参考:java存在引用传递吗?
Q:接口和抽象类有什么区别?
A:抽象类主要作用是规范。
- 抽象类只能继承一次,但是可以实现多个接口
- 接口和抽象类必须实现其中所有的方法,抽象类中如果有未实现的抽象方法,那么子类也需要定义为抽象类。抽象类中可以有非抽象的方法
- 接口中的变量必须用 public static final 修饰,并且需要给出初始值。所以实现类不能重新定义,也不能改变其值。
- 接口中的方法默认是 public abstract,也只能是这个类型。不能是static,接口中的方法也不允许子类覆写,抽象类中允许有static 的方法
Q:四种访问权限修饰符的作用范围是什么?
A:
Q:this super static final4个关键字的总结。
A:
1.this
- 指向当前
注意:this不能用在static方法中。
2.super
- 指向父类
注意:super不能用在static方法中。
3.static
- 初始,静态、全局。
注意:用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块。
4.final
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
Q:==与equals有什么区别
A:
- ==只是比较是不是同一个对象。
- 而equals可以完成你的个性化比较,可以重写equals方法。
- 而如果子类没有复写,equals默认就是用==来判断俩对象是否相等的。
Q:Final Finally Finalize三个方法的作用是什么?
A:
- Final是一个修饰符,可修饰变量,方法等。
- Finally在try/catch中使用
- Finalize是一个方法,属于java.lang.Object类,finalize()方法是GC (garbage collector垃圾回收)运行机制的一部分,finalize()方法是在 GC清理它所从 属的对象时被调用的。
Q:深拷贝与浅拷贝有什么区别?
A:
- 浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址。
- 深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
- 使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
Q:强引用、弱引用、软引用、虚引用有什么区别?
A:
参考来源:知乎用户winterSunshine的回答
四、常用类
Q:String,StringBuffer, StringBuilder 的区别是什么?String为什么是不可变的?
A:
区别:
- String是字符串常量,而StringBuffer和StringBuilder是字符串变量。由String创建的字符内容是不可改变的,而由StringBuffer和StringBuidler创建的字符内容是可以改变的。
- StringBuffer是线程安全的,而StringBuilder是非线程安全的。StringBuilder是从JDK 5开始,为StringBuffer类补充的一个单线程的等价类。我们在使用时应优先考虑使用StringBuilder,因为它支持StringBuffer的所有操作,但是因为它不执行同步,不会有线程安全带来额外的系统消耗,所以速度更快。
String为什么不可变:
- 虽然String、StringBuffer和StringBuilder都是final类,它们生成的对象都是不可变的,而且它们内部也都是靠char数组实现的,但是不同之处在于,String类中定义的char数组是final的,而StringBuffer和StringBuilder都是继承自AbstractStringBuilder类,它们的内部实现都是靠这个父类完成的,而这个父类中定义的char数组只是一个普通是私有变量,可以用append追加。因为AbstractStringBuilder实现了Appendable接口。
Q:System.gc()与Runtime.gc()有什么不同?
System.gc()内部代码为Runtime.getRuntime().gc()。
区别:
- System.gc()是类方法,非本机方法(不与硬件和系统资源直接交互的代码)
- Runtime.gc()是实例方法,本机方法(一种与硬件和系统资源直接交互的编程语言)
Q:hashCode方法有什么作用?
A:快速定位。
【什么是hash】首先,需要明白hash是什么,hash是用来快速定位元素的一种数据结构,如给定一个变量我们可以通过hash 确定这个变量在内存中的位置 即 变量a 经过 hash(a)->就可以确定这个元素在内存中的位置。
【hashCode 方法的作用】object基类 中 有hashcode(),这就导致了所有我们自建的类都继承了hashcode 方法。hashcode在单一类当中只是一个实例方法并没有什么大的作用。
【hashcode 应用】 在Java集合类当中有实现map接口的HashMap、Set接口的HashSet 要知道set集合中存储的对象的引用所指向的对象是不能重复的。
比如你要实现 Set students[] = new HashSet<>();那么 Student 这个类中必须override(重写)hashCode()与equals(), 如果不重写hashCode,只重写equals(),那么当你Student a = new Student(“张晓”,13);Student b = new Student(“张晓”,13); 这两个对象的引用都能被存储至hashset 集合当中,但其实我们肉眼观察到的对象已经重复了,这就是因为hashcode没有重写,两个对象的hash code不一致导致的肉眼观察到的相同内容的对象被存储至了set集合当中。所以总结:多个 单一类对象实例中,如果两个对象的hashCode() 相同 ,那么两个对象equals() 一定相同 因为是同一个对象,但equals相同 hashCode()不一定相同在HashTable、HashSet、HashMap 集合中存储的对象,hashCode 与 equals 结合来确保元素的肉眼可见的非重复性。
五、异常
Q:异常与错误有什么区别??
A:
异常(Exception):主要是语法错误和语义错误,异常都会通过jvm虚拟机告诉你。
错误(Error):应用程序不能截获的严重问题。
Q:异常的类层次结构是如何的?
A:
Q:常见的异常有哪些?
A:
- 空指针异常类:NullPointerException
- 数据类型转换异常:java.lang.ClassCastException
- 没有访问权限:java.lang.IllegalAccessException
- 方法的参数错误:java.lang.IllegalArgumentException
- 数组下标越界异常:java.lang.IndexOutOfBoundsException
- 文件已结束异常:EOFException
- 文件未找到异常:FileNotFoundException
- 字符串转换为数字异常:NumberFormatException
- 指定的类不存在: java.lang.ClassNotFoundException
- 实例化异常:java.lang.InstantiationException
Q:如何自定义异常?
A:继承Exception类。
// 先自定义异常类,如用户不存在异常DollarsNotFoundException
public class DollarsNotFoundException extends Exception {
public DollarsNotFoundException () {
super();
}
public DollarsNotFoundException (String message) {
super(message);
}
public DollarsNotFoundException (Throwable cause) {
super(cause);
}
public DollarsNotFoundException (String message, Throwable cause) {
super(message, cause);
}
}
异常使用场景类
public void findMondy() throws DollarsNotFoundException{
try {
// todo
} catch(Exception e) {
throw new DollarsNotFoundException("你没钱!");
}
}
Q:throw与throws有什么区别?
A:
throw:抛出
throws:声明
语法:[(修饰符)] (返回值类型)(方法名)([参数列表])[throws(异常类)]{…}
public void doA(int a) throws Exception1,Exception3{…}
六、IO
Q:java中io流分为几种?字节流与字符流有什么区别?
A:
(1)按流向分类:
- 输入流
- 输出流
(2)按处理数据不同分类:
- 字节流:二进制,可以处理一切文件,包括:纯文本、doc、音频、视频等。
- 字符流:文本文件,只能处理纯文本。
(3)按功能不同分类:
- 节点流:包裹源头。
- 处理流:增强功能,提高性能。
Q:IO中BIO、NIO、AIO有什么区别?
A:
- BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
- AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
七、JAVA集合
Q:java集合类的集成体系是怎样的?
A:
Q:ArrayList与LinkedList有什么区别?
A:
总结:ArrayList适合查,LinkedList适合增删。
ArrayList和LinkedList都实现了List接口。但是在数据结构的实现上ArrayList是数组,LinkedList是双向链表,所以LinkedList比ArrayList会更耗内存,因为它一个节点要存两个引用,一个指向上一个元素,一个指向下一个元素。而数组查找元素的时间复杂度是O(1),链表查找元素的时间复杂度是O(n),所以查询多的情况下,ArrayList比LinkedList更适合。
只要不是首尾的增加或删除操作,那么LinkedList的效率就是比ArrayList高,因为ArrayList进行增删操作后,数组内就会有一些数据会受到影响,需要更换下标,影响的数据范围越广,效率越低。
Q:HashMap底层原理是怎样的
A:HashMap=数组+链表
put:
- 对key的hashCode()做hash,然后再计算index;
- 如果没碰撞直接放到bucket里;
- 如果碰撞了,以链表的形式存在buckets后;
- 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;
- 如果节点已经存在就替换old value(保证key的唯一性) 如果bucket满了(超过load factor*current
capacity),就要resize。
get:
- bucket里的第一个节点,直接命中;
- 如果有冲突,则通过key.equals(k)去查找对应的entry:
若为树,则在树中通过key.equals(k)查找,O(logn);
若为链表,则在链表中通过key.equals(k)查找,O(n)。