Java基础语法题
1.Java中‘==’和‘equals()’的区别是什么?
‘==’是在代码中用来比较两个变量的值的,如果比较的是基本数据类型变量(比如整数,浮点数,布尔值,字符),那么它比较的就是储存的具体数值;如果比较的是引用类型数据变量(比如对象,数组),那么它比较的就是储存对象在内存中的地址。
‘equals()’是Object类里的一个实列方法,因为所有的类都直接或间接继承自Object,所以所有对象都有equals()方法,使用这个方法时所有的对象类都要重写equals(),然后根据自己的属性需要来写这个比较方法,如果想通过name就能比较成功就只写上并判断name,如果想要比较对象所有属性都一样就把属性全部加上并判断。
具体实例:在比较字符串的时候,‘==’比较的是字符串的地址,而‘equals()’是将字符串里的每个字符都拿出来逐个比较。
2.‘hashCode()’的作用是什么?
Object类的一个方法,所有的类都有继承,通常在使用时也需要重写。用于帮助对象计算哈希值,为对象生成一个“快速定位码”,让基于散列的集合(如HashMap)能够高效查找,它必须与equals()保持一致:相等的对象必须有相等的哈希码。
注:在哈希算法中,如果两个对象的哈希值不一样,那么这两个对象是一定不一样的,只有哈希值一样才需要继续比较。因此一般情况下会先用hashCode()直接判断这两个对象的哈希值是否相同,如果不同就没必要再进行比较,如果相同再使用equals()方法进行比较。
3.以下代码的输出是什么并解释原因。(字符串常量池 JVM
堆内存)
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello"); // false
System.out.println(s1 == s2); // true or false? // true
System.out.println(s1 == s3); // true or false?
String n1 = "hello";
String n2 = "World";
String n3 = new String(n1+n2);// +
System.out.println(s1 == s2);这一行输出的是true;System.out.println(s1 == s3);这一行输出的是false。
在JVM内存中,有一块专门存放字符串的区域“字符串常量池”,每一个字符串在创建之后就是一个常量,像String s1 = "hello"和String s2 = "hello"中由于“hello”在字符串常量池中只有一个对象,所以s1和s2拿到的是同一个对象的地址。而String s3 = new String("hello")中由于new String()始终创建新对象,所以它会在常量池之外的堆内存中创建对象,s3拿到的对象的地址就和s1、s2不一样,最后输出的结果才会是true和false。
如果没有“String s1 = "hello"”;和“String s2 = "hello";”这两行代码,只有“String s3 = new String("hello");”这一行,在内存中会创建两个对象,一个在字符串常量池中,一个在堆内存中。
注:
String n1 = "hello";
String n2 = "World";
String n3 = new String(n1+n2);
这三行代码中,因为拼接操作‘+’的原理是调用StringBuilder类中的append方法,而最后还会调用一下toString方法,把StringBuilder对象转换成一个字符串对象,所以会多创建一个新的对象,最终这三行代码总共会创建4个对象。(函数调用部分过程如下图)

拓展:hash表经常用字符串作为“key”,不仅是因为字符串信息丰富便于表达,而且字符串就存储在字符串常量池里面,具有不可变性,重复使用字符串也不会导致重复占用内存空间,所以才经常选择字符串作为键类型。
4. 解释 Java 中的四种引用类型:强引用、软引用、弱引用和虚引用。 (JVM GC垃圾回收器)
如何理解“引用”:在内存中对象在堆里面,而代码在栈里面,需要在栈里面存储对象所在的堆内存地址才能够访问到对象数据,而“引用”是一个指向内存地址的值,它让你能够间接访问和操作内存中的数据,就好比遥控器(引用)和电视机(对象)。
GC垃圾回收器:它会判断你的程序中哪些数据是没有用的,然后清除没用的数据内存,保留有用的数据,对于以上四种引用,每一种都有对应的垃圾回收器的处理方案。
1. 强引用(Strong Reference)
最常见的引用类型,通过 new 创建的对象默认都是强引用。
特点:只要强引用存在,对象就不会被 GC 回收。
当内存不足时,JVM 会抛出 OutOfMemoryError 而不是回收强引用对象。
java
Object obj = new Object(); // 强引用
obj = null; // 切断强引用,对象变为可回收状态
2. 软引用(Soft Reference)
通过 java.lang.ref.SoftReference 类实现。
特点:
内存充足时,软引用对象不会被回收,内存不足时,软引用对象会被 GC 回收。
适合用于实现内存敏感的缓存。
java
SoftReference<byte[]> softRef = new SoftReference<>(new byte[1024 * 1024]);
byte[] data = softRef.get(); // 获取对象,可能为 null(如果已被回收)
// 通常与 ReferenceQueue 配合使用
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
SoftReference<byte[]> ref = new SoftReference<>(new byte[1024], queue);
3. 弱引用(Weak Reference)
通过 java.lang.ref.WeakReference 类实现。
特点:
只要发生 GC,无论内存是否充足,弱引用对象都会被回收。
适合用于实现弱缓存或监控对象生命周期;WeakHashMap 基于此实现。
java
WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get(); // 可能为 null(如果已被回收)
// WeakHashMap 示例
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "value");
key = null; // 下次 GC 时,该 entry 会被自动移除
4. 虚引用(Phantom Reference)
通过 java.lang.ref.PhantomReference 类实现。
特点:
最弱的引用,完全不会影响对象的生命周期。
无法通过 get() 方法获取对象(总是返回 null);必须与 ReferenceQueue 一起使用;主要用于对象被回收时收到系统通知,进行一些清理工作。
java
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
// 监控回收通知
new Thread(() -> {
while (true) {
Reference<?> ref = queue.poll();
if (ref != null) {
System.out.println("对象已被回收,进行清理操作");
break;
}
}
}).start();
对比总结
| 引用类型 | 回收时机 | 是否影响生命周期 | 常见用途 |
|---|---|---|---|
| 强引用 | 永不主动回收 | 是 | 普通对象引用 |
| 软引用 | 内存不足时回收 | 否(间接影响) | 内存敏感缓存 |
| 弱引用 | GC时立即回收 | 否 | 缓存、WeakHashMap |
| 虚引用 | GC时立即回收 | 否 | 对象回收监听、清理工作 |
5.final 、 finally 和 finalize 有什么区别?
1. final(关键字)
用于修饰类、方法和变量,表示"不可改变"。
final 类:不能被继承
java
final class FinalClass {
// 不能被其他类继承
}
// class SubClass extends FinalClass {} // 编译错误
final 方法:不能被子类重写
java
class Parent {
final void show() {
System.out.println("不能被子类重写");
}
}
class Child extends Parent {
// void show() {} // 编译错误,不能重写final方法
}
final 变量:一旦赋值就不能修改
java
final int MAX_VALUE = 100;
// MAX_VALUE = 200; // 编译错误
final List<String> list = new ArrayList<>();
list.add("item"); // 可以,引用本身不变,内容可变
// list = new ArrayList<>(); // 编译错误,不能改变引用
2. finally(代码块)
异常处理的一部分,用于定义必须执行的代码块。
特点:无论是否发生异常,finally 块都会执行通常用于释放资源(如关闭文件、数据库连接等)
唯一不执行的情况:System.exit() 或 JVM 崩溃
java
try {
// 可能抛出异常的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("捕获异常");
// return; // 即使有return,finally仍会执行
} finally {
System.out.println("总会执行 - 清理资源");
// 关闭文件、数据库连接等
}
// 输出:捕获异常 → 总会执行 - 清理资源
特殊场景:
java
public int testFinally() {
try {
return 1; // 先执行return表达式
} finally {
System.out.println("finally执行");
// return 2; // 如果finally中有return,会覆盖try中的return
}
// 返回1,但"finally执行"会先打印
}
3. finalize(方法)
Object 类的一个方法,用于垃圾回收前的清理。
特点:
在对象被垃圾回收器回收之前调用,不保证一定会执行(如果程序提前终止),执行时间不确定(由GC决定)
注:Java 9 开始已被弃用
java
class ResourceHolder {
private String resource;
public ResourceHolder(String resource) {
this.resource = resource;
}
@Override
protected void finalize() throws Throwable {
try {
System.out.println("清理资源: " + resource);
// 清理操作
} finally {
super.finalize(); // 调用父类的finalize
}
}
}
// 使用
ResourceHolder obj = new ResourceHolder("DB Connection");
obj = null; // 对象变为可回收
System.gc(); // 建议GC,但不保证立即执行finalize
对比表格
| 特性 | final | finally | finalize |
|---|---|---|---|
| 类型 | 关键字 | 代码块关键字 | 方法 |
| 作用域 | 类、方法、变量 | try-catch 块 | Object 类的方法 |
| 用途 | 定义不可变性 | 确保代码执行 | 对象回收前清理 |
| 执行时机 | 编译时/运行时定义 | 异常处理后 | GC 回收对象前 |
| 是否强制 | 是(一旦定义) | 是(总会执行) | 否(不保证执行) |
| 当前状态 | 常用 | 常用 | 已弃用(Java 9+) |
6. Java 异常体系是怎样的? RuntimeException 和 Checked Exception 有何区别?
Java异常体系以Throwable为根类,分为两大分支:Error表示不可处理的严重错误,Exception表示可以处理的异常。Exception又进一步分为受检异常和非受检异常。
RuntimeException:表示程序员应修复的bug,通过代码质量避免
CheckedException:表示程序应处理的合理异常情况,通过编码应对
| 特性 | RuntimeException | CheckedException |
|---|---|---|
| 编译检查 | 不检查 | 强制检查 |
| 处理要求 | 可处理可不处理 | 必须处理 |
| 设计理念 | 代码逻辑错误 | 外部环境问题 |
| 常见场景 | 空指针、数组越界 | 文件不存在、网络中断 |
如果要打比方的话:
Error:房子塌了(系统级灾难,无法修复)
RuntimeException:你被自己绊倒(代码写错了,可以避免)
CheckedException:出门下雨了(外部环境问题,需带伞应对)
java
// RuntimeException - 不需要强制处理
String str = null;
str.length(); // 运行时才报NullPointerException
// Checked Exception - 必须处理
try {
new FileReader("file.txt"); // 编译时强制检查
} catch (FileNotFoundException e) {
// 必须处理
}
更多推荐




所有评论(0)