我的面试宝典:一线互联网大厂Java核心面试题库
以下是我个人的一些做法,希望可以给各位提供一些帮助:
整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!
283页的Java进阶核心pdf文档
Java部分:Java基础,集合,并发,多线程,JVM,设计模式
数据结构算法:Java算法,数据结构
开源框架部分:Spring,MyBatis,MVC,netty,tomcat
分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等
微服务部分:SpringBoot,SpringCloud,Dubbo,Docker
还有源码相关的阅读学习
int[] array = {1, 2, 3};
for(int i = 0; i <array.length; i++){
System.out.println(array[i]);
}
在 Java 中,如上述代码使用
数组对象.length
就可以得到该数组的长度
- 法二(使用增强 for 循环 for-each)
int[] array = {1, 2, 3};
for(int x : array){
System.out.println(x);
}
如上述代码,该语句会便利数组 array,并且每次都会将数组的元素保存在变量 x 中
- 法三(使用 Arrays 类中的 toString 方法)
// 使用 Arrays 类前先导入它的包
import java.util.Arrays;
public class TestDemo{
public static void main(Strings[] args){
int[] array = {1, 2, 3};
String ret = Arrays.toString(array);
System.out.println(ret);
}
}
// 打印结果为:[1, 2, 3]
Arrays 类 中 toString 的功能就是将当前的数组转换成字符串的形式返回,返回值就是字符串
上述遍历方式各有各的特点,至于什么时候用哪一遍历方式,据情况而定
1. 认识 JVM 内存区域划分
我们知道,一个 Java 文件的执行需要先通过编译变成字节码文件,字节码文件再痛过 Java 虚拟机运行
因为字节码文件是被 JVM 转换成平台所能执行的形式所运行的,那么 JVM 到底是怎样的呢?
JVM 本质其实就是一个用 C/C++ 代码实现的软件,它的内存被划分五块为如图所示的样子
那么这里面的各块都分别有啥意义呢?
- 程序计数器:是一个很小的空间,保存下一条执行的指令地址(通俗的来说就是你本来在敲代码,你老妈喊你去吃饭,但你吃完饭后还要回来执行完你没敲完的代码)
- Java 虚拟机栈:这就是我们平常说的栈,它重点是存储局部变量(像上面创建的数组
int[] array = {1, 2, 3}
的存储地址的引用就是保存在这里)
- 本地方法栈:本地方法栈与虚拟机栈的作用类似,只不过保存的内容是 Native 方法的局部变量(在有些版本的 JVM 的实现中(例如 HotSpot),本地方法和虚拟机栈是一起的)
- 堆:这就是我们平常说的堆,是 JVM 所管理的最大的内存区,使用 new 创建的对象都是在堆上保存(例如
int[] array = new int[]{1, 2, 3}
)
- 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(方法编译出的字节码就是保存在这里)
- 运行时常量池:这个是方法区的一部分(上述未画出),存放字面量(字符串常量)与符号引用(注意:从 JDK 1.8 开始,运行时常量池在堆上)
补充(Native 方法)
JVM 是一个基于 C++ 实现的程序,在 Java 程序执行过程中,本质上也需要调用 C++ 提供的一些函数和操作系统底层进行一些交互。因此在 Java 开发中也会调用到一些 C++ 实现的函数
既然知道了 JVM 的一些知识点,那么我们就可以对我们上述三种创建数组的代码做一个存储区域分析
int[] array1 = {1,2,3,4,5};
int[] array2 = new int[5];
int[] array3 = new int[]{1, 2, 3, 4, 5};
分析结果如图
- 我们知道,array1、array2、array3 是局部变量,所以它们会在栈上开辟一块内存。
- Java 中的数组都属于对象,而对象保存在堆中(对象就是一个实体,比如实际生活中的花草树木,或者上述代码中的
{1, 2, 3, 4, 5}
或者用更加规范的方式 new 出来的对象)
- 而保存在堆上的对象又有着自己的内存。上述三个局部变量又是引用变量(即这个变量里面存储的是一个地址),它们将会存储对应将每个对象的元素的首地址
- 按照术语来说,用array1举例就是:array1 就是一个引用,它引用了一个对象(指向一个对象)
2. 数组传参以及被调用的过程
我们直接通过一个图片来感受下面代码中数组传参以及被调用的过程
public static void main(String[] args){
int[] array = {1, 2, 3};
print(array;)
}
public static void print(int[] array){
for(int x : array){
System.out.print(x + " ");
}
}
// 打印结果为:1 2 3
3. 理解引用类型
从上图我们可以知道,参数传数组类型,实参和形参其实都是引用,共同指向同一个对象。
因此如果形参将对象的值改变,那么实参的值也随即改变。可以用一个代码举例
public static void main(String[] args){
int[] array = {10, 20};
System.out.print(“交换前:array[0] = " + array[0] + " array[1] =” + array[1]);
System.out.println();
swap(array);
System.out.print(“交换后:array[0] = " + array[0] + " array[1] =” + array[1]);
}
public static void print(int[] array){
int tmp = array[0];
array[0] = array[1];
array[1] = tmp;
}
// 结果为:
// 交换前:array[0] = 10 array[1] = 20;
// 交换后:array[0] = 20 array[1] = 10;
为了在理解上更加清晰,我们再举一个例子
public static void main(String[] args){
int[] array1 = {1, 2, 3};
int[] array2 = array1;
}
我们可以说 array2 这个引用指向 array1 这个引用吗?不能!这其实是表述有误!
引用不能说指向引用,引用只能说指向另一个引用所指的对象。故我们应该理解成:array2 这个引用指向了 array1 这个引用所指向的对象
小结
- 引用类型本质上只是存了一个地址
- Java 将数组设定成引用类型,这样后续进行数组参数传参,其实只是将数组的地址传到函数的形参中。这样可以避免对整个数组进行拷贝,减小开销
- Java 中的引用类型有:String、数组、类、接口、枚举、抽象类
4. 认识 null
我们来看一个代码
int[] array = null;
上述代码的意思就是 array 这个引用不指向任何对象。这其实和 C 语言里的空指针类似,当我们不道该数组初始化为多少时,就可以赋值为 null
注意
分享
1、算法大厂——字节跳动面试题
2、2000页互联网Java面试题大全
3、高阶必备,算法学习
Tui-1715653258901)]
2、2000页互联网Java面试题大全
[外链图片转存中…(img-Xx2NxEAO-1715653258901)]
3、高阶必备,算法学习
[外链图片转存中…(img-W7t8PBjY-1715653258902)]