Java面试题(持续更新)
1.值传递和引用传递的区别
基本数据类型参数传递时,传递的是值的副本,改变值的副本,不会影响原来的变量
引用数据类型参数传递时,传递的是地址的副本,副本也是指向同一个变量,会影响原来的变量
String类型属于特殊的引用数据类型,作为参数传递,原来的值不会改变
2.== 与 equals的区别
扩展
2.1 String类型
String类如果直接使用 = 号赋值,将先从常量池中查找有没有同内容的变量
如果有,则直接使用已存在的内容的地址
如果没有,将此内容存在常量池中,完成赋值
这样做是为了节省内存空间
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1.equals(str2)); // true
System.out.println(str1.equals(str3)); // true
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
}
2.2 整形包装类
整形包装类和char包装类直接使用 = 号赋值,如果数值相同
取值范围在byte取值范围以内,使用 == 比较结果为 true
超过byte取值范围,使用 == 比较结果为 flase
因为JDK的开发人员为了节省内存空间,将byte取值范围内的数值存放在一个缓存数组中
如果在byte取值范围,那么将从数组中取出对应的值
如果不在byte取值范围内,直接new一个新的对象
public static void main(String[] args) {
Integer i1 = 25;
Integer i2 = 25;
System.out.println(i1 == i2); // true
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i3 == i4); // false
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); // true
Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8); // false
Byte b1 = 20;
Byte b2 = 20;
System.out.println(b1 == b2); // true
Short s1 = 120;
Short s2 = 120;
System.out.println(s1 == s2); // true
Short s3 = 200;
Short s4 = 200;
System.out.println(s3 == s4); // false
Long l1 = 20L;
Long l2 = 20L;
System.out.println(l1 == l2); // true
Long l3 = 300L;
Long l4 = 300L;
System.out.println(l3 == l4); // false
Character ch1 = 20;
Character ch2 = 20;
System.out.println(ch1 == ch2); //true
Character ch3 = 200;
Character ch4 = 200;
System.out.println(ch3 == ch4); //false
}
2.3重写equals方法
String类对equals方法进行了重写,改为比较内容,我们也可以对equals方法进行重写,改为比较两个对象的内容是否相同
public boolean equals(Object obj) {
// 第一步 先比较地址 如果地址相同 则直接return true 不需要继续比较 了
if(this == obj) {
return true;
}
// 代码执行到这里 表示 地址不同 那么我们应该比较内容 名字和身份证号
// 因为obj是父类对象 而父类对象不能直接获取name属性的值 所以需要强制向下转换,才能使用getIdCare()方法和getName()方法
Person p1 = (Person) obj;
if(this.getName().equals(p1.getName()) && this.getIdCard().equals(p1.getIdCard())) {
return true;
}
// 如果代码能够执行到这里 表示 上述条件不成立
return false;
}
3.冒泡排序
数组中,两两相邻比较,遇到条件成立的就交换位置
经分析:
比较的轮数是数组长度 -1 ,外层循环控制比较的轮数
每一轮比较的次数:最多的一次是数组长度 -1 ,依次递减,内层循环控制比较的次数
外层循环次数:N - 1
内层循环次数:N - 1 - i
public static void main(String[] args) {
int [] nums = {20,1,55,784,10,233,65};
for(int i = 0;i < nums.length - 1;i++) {
for(int j = 0;j < nums.length - 1 - i;j++) {
if(nums[j] < nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
4. String、StringBuffer、StringBulider三者的区别
String类是一个不可变对象 因为String类底层维护的是一个final修饰的char数组,任何对原字符串进行的增删改操作 都将产生一个新的字符串
StringBuffer和StringBuilder是可变字符串对象
StringBuffer是线程安全的 JDK1.0
StringBuilder线程不安全 JDK1.5
5.try...catch...finally
try-catch块中存在return语句,是否还执行finally块?如果执行,如下代码,说出执行顺序
public static void main(String[] args) {
System.out.println(m1()); //11
}
public static int m1() {
int num = 10;
try {
num ++;
return num;
} catch (Exception e) {
e.printStackTrace();
}finally {
num ++;
}
return num;
}
以上代码 在finally中对返回值的操作 不会影响返回值
实际开发中 不推荐在finally中对返回值做操作
执行顺序:先执行try中return 再执行finally 最后再次执行finally中的代码
还使用最初确定的返回值
6.集合和数组的区别
| 集合 | 数组 | |
|---|---|---|
| 长度 | 可变长度 | 固定长度 |
| 内容 | 只能是引用类型 | 可以是基本类型,也可以是引用类型 |
| 元素内容 | 可以存储不同类型(一般都是存储同一种类型) | 只能存储同一种类型 |
7.ArrayList与Vector的区别
| ArrayList | Vector |
|---|---|
| 线程不安全 | 线程安全 |
| 初始为0 | 初始为10 |
| 当空间不足时扩容为1.5倍 | 空间不足时扩容为2倍 |
8.HashMap数据的存放过程
HashMap中的元素是Node(节点),每个节点包含四个部分:key值、value值、根据key计算出来的hash值和下一个元素的引用next
当我们调用put方法往HashMap中存储数据,会先根据key的hash值找到当前元素应该存放在数组中的位置,
如果此位置没有元素,则直接存放,
如果此位置有元素,那么向下延伸为单向链表
如果链表的长度大于8并且元素的总个数超过64 那么单向链表转换为红黑树
在我们使用过程中,我们会删除元素,如果链表的长度小于6,将红黑树再次转换为链表
9.HashMap与Hashtable的区别
| HashMap | Hashtable |
|---|---|
| 线程不安全 | 线程安全 |
| 允许null键和值 | 不允许null键和值 |
| JDK1.2 | JDK1.0 |
10.Collections和Collection的区别
Collection是集合父接口
Collections是工具类,提供的有操作集合一些方法 比如查找集合最大、最小元素,集合排序等
11.创建线程的两种方式分别是什么?有什么区别?
1.继承Thread类:
编写简单,可直接操作线程
适用于单继承
2.实现Runnable接口:
避免单继承局限性
便于共享资源

浙公网安备 33010602011771号