讲点自己平常总结的面试题
沉浸式求职学习
1.JDK、JRE、JVM之间的关系
- JDK:java Development kit java语言的软件开发包,包含JRE
- JRE:java runtime environment java运行的环境,包含JVM
- JVM:java virtual machine java虚拟机,是一种用于计算机设备的规范,java语言有个很大的特点,是在不同平台上运行不需要重新编译,就是因为JVM屏蔽了具体平台的信息,使得java编译程序只需要在JVM上运行目标代码,就可以在多种平台上不加修改的运行。
2.类加载机制
首先类加载机制是为了将类加载到内存。
JVM分为三步实现类加载:加载、链接、初始化
-
加载:指的是把类的class文件读入内存,创建一个class对象,所以,程序中的所有类都会有一个java.lang.class
- 类加载器通常是JVM提供的,叫做系统类加载器;除此之外,开发人员也能继承ClassLoader创建自己的加载器
- 加载类的二进制数据方式:
- 从本地加载class文件
- 网络加载
- jar包也可以加载
-
链接:加载后生成一个Class对象,链接阶段主要是负责把类的二进制数据合并到JRE中
- 验证:确保Class的字节流信息符合当前JVM的规范和要求,不然会产生危害
- 文件格式验证:版本号
- 元数据验证:语义分析
- 字节码验证:数据流和控制
- 符号引用验证:符号引用转换成直接的引用
- 准备:为类的静态变量分配内存,并且赋予默认值
- 解析:将类的符号引用转化为直接引用
- 验证:确保Class的字节流信息符合当前JVM的规范和要求,不然会产生危害
-
初始化:为类的静态变量赋值。
准备阶段和初始化阶段看起来是差不多的,但是实际上是不矛盾的。
如果类中有语句:
private static int a =10;
那么它的执行过程是这样的,首先字节码文件先被加载到内存中,然后进行链接的验证,验证通过后进入准备阶段,给a分配内存,因为a是static,所以默认值是int类型的默认值,即为0,然后到初始化这一步,我们才真正的把10这个int值赋给a。
3.== 和 equals的区别
== 对于基本类型来说,就是比较值相等;对于引用类型来说,是比较地址是否相等。
对于equals来说的话,,本质就是 == ,只不过String或者Integer等引用类型重写了equal方法,然后把它变成了值的比较;
Object中的equals方法如下:
其实就是返回了一个 ==
但是String中重写了:
如果地址相同直接返回true;第二步是强转成String类型,然后把两个字符串都转换成char数组,循环比较每一个字符。
4.String是基本数据类型吗?
NO,java中只有八大基本类型,其中
- 整型:int long short byte
- 浮点类型:double float
- 布尔类型:boolean
- 字符类型:char
基本数据类型具有原子性,不可再分,内存中直接储存这个类型的值,通过内存地址即可直接访问到数据。
基本类型不能应用于泛型的,但是String可以。
5.为什么使用final修饰String
使用 final 修饰 String 的第一个好处是安全,第二个好处是高效
- Java 语言之父 James Gosling 的回答,他会更倾向于使用 final,因为它能够缓存结果,当你在传参时 不需要考虑谁会修改它的值;如果是可变类的话,则有可能需要重新拷贝出来一个新值进行传参,这样在性能上就会有一定的损失。
- James Gosling 还说,迫使 String 类设计成不可变的另一个原因是安全,当你在调用其他方法时,比如 调用一些系统级操作指令之前,可能会有一系列校验,如果是可变类的话,可能在你校验过后,它的内部的值又被改变了,这样有可能会引起严重的系统崩溃问题,这是迫使 String 类设计成不可变类的重要原因。
6. String StringBuffer StringBuilder
String类型是不可变的,所以字符串拼接的时候使用String的话性能不好
所以我们用另一个StringBuffer,提供了append和insert方法用于字符串拼接,而且使用了synchronized,所以线程安全
源码:
因为它使用了synchronized保证线程安全所以性能不是很高,所以JDK1.5就有了StringBuilder,它也提供了append和Insert方法,但是没用synchronized修饰,所以性能好一些,所以适合非并发操作。
7.为什么重写 equals 时,必须重写 hashCode?
- 在 Set 集合存储数据时,如果只重写了 equals 方法,那么默认情况下,Set 进行去重判断时,会先判断两个对象的 hashCode 是否相同,而此时因为没有重写 hashCode 方法,所以会默认调用 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法会得到两个对象的哈希值,而两个对象因为引用地址不同,所以哈希的结果也是不同的,因此会直接返回 false,于是 Set 集合就插入了两个相等的对象。
- 但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode,因为属性为基础数据类型或 String,所以哈希之后得到的 hashCode 值也是相同的,于是再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个相等的数据了,那么整个程序也能正常执行了。