1. 引言
Java类型系统是技术面试中的高频考点。本文整理了几个经典且容易踩坑的面试题,帮你快速梳理核心知识点。
2. 核心问题
2.1 问题1:Object类在类型体系中的地位?哪些类型继承自Object?数组呢?Lambda表达式能赋值给Object变量吗?
java.lang.Object
位于Java类继承体系的顶端。所有类都直接或间接继承自它:
- 显式继承:使用
extends
关键字 - 隐式继承:省略
extends
时默认继承 - 传递继承:通过继承链间接继承
但有8个基本类型不继承自Object:
boolean
、byte
、short
、char
、int
、float
、long
、double
根据JVM规范,数组也是对象:
int[] arr = new int[5];
Object obj = arr; // 合法
arr.hashCode(); // 可调用Object方法
Lambda表达式不能直接赋值给Object变量:
Object obj = () -> {}; // 编译错误!Object不是函数式接口
但可以通过强制转换实现:
Object obj = (Runnable) () -> {}; // 合法
2.2 问题2:基本类型和引用类型的区别?
✅ 核心差异对比表:
特性 | 引用类型 | 基本类型 |
---|---|---|
继承关系 | 继承自Object | 不继承任何类 |
可继承性 | 可被子类继承(final类除外) | 不可继承 |
参数传递 | 传递引用值 | 传递值本身 |
内存存储 | 对象头+实例数据 | 直接存储硬件值 |
空间开销 | 较大(对象头通常12-16字节) | 极小(如int仅4字节) |
⚠️ 关键区别:修改方法内基本类型参数不会影响外部值:
void modify(int x) {
x = 10; // 不影响调用者
}
int num = 5;
modify(num);
// num仍为5
2.3 问题3:Java的8种基本类型及内存占用?
类型 | 大小 | 取值范围 |
---|---|---|
boolean |
未定义 | true/false |
byte |
8位 | -128 ~ 127 |
short |
16位 | -32,768 ~ 32,767 |
char |
16位 | 0 ~ 65,535 (Unicode) |
int |
32位 | -2³¹ ~ 2³¹-1 |
long |
64位 | -2⁶³ ~ 2⁶³-1 |
float |
32位 | IEEE 754单精度 |
double |
64位 | IEEE 754双精度 |
💡
boolean
大小由JVM实现决定,通常用1字节存储
2.4 问题4:抽象类和接口的区别?使用场景?
核心区别:
- ✅ 继承数量:类可实现多个接口,但只能继承一个抽象类
- ✅ 设计目的:
- 抽象类:表示"是什么"(is-a关系),如
AbstractMap
- 接口:表示"能做什么"(has-a能力),如
Comparable
- 抽象类:表示"是什么"(is-a关系),如
使用场景:
// 抽象类:提供基础实现
public abstract class AbstractMap {
public boolean equals(Object o) {
// 通用实现...
}
}
// 接口:定义能力契约
public interface Comparable {
int compareTo(Object o);
}
2.5 问题5:接口成员的限制?
接口成员有严格限制:
- ✅ 字段:隐式
public static final
,必须是常量 - ✅ 方法:
- 隐式
public
- 要么隐式
abstract
- 要么显式
default
- 隐式
❌ 禁止操作:
interface BadExample {
private int x = 1; // 编译错误!字段不能是private
void method() {} // 编译错误!方法体需加default
}
2.6 问题6:内部类和静态嵌套类的区别?
非静态内部类:
- 隐式持有外部类引用
- 需通过外部类实例创建
```java
public class Outer {
public class Inner {
} }public Outer getOuter() { return Outer.this; // 访问外部类实例 }
// 创建方式 Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
**静态嵌套类**:
- 不持有外部类引用
- 可独立创建
```java
public class Outer {
public static class Nested {
}
}
// 创建方式
Outer.Nested nested = new Outer.Nested();
2.7 问题7:Java支持多重继承吗?
❌ 类不支持多重继承:
class A {}
class B {}
class C extends A, B {} // 编译错误!
✅ 接口可实现多重继承:
interface Flyable { void fly(); }
interface Swimmable { void swim(); }
class Duck implements Flyable, Swimmable {
// 实现多个接口
}
💡 Java 8的
default
方法让接口更接近多重继承,但避免了菱形问题
2.8 问题8:包装类和自动装箱是什么?
包装类:为8种基本类型提供对象形式
Boolean
、Byte
、Short
、Character
Integer
、Float
、Long
、Double
自动装箱/拆箱:编译器自动转换
// 装箱:int -> Integer
List<Integer> list = new ArrayList<>();
list.add(5); // 等价于 list.add(Integer.valueOf(5))
// 拆箱:Integer -> int
int value = list.get(0); // 等价于 list.get(0).intValue()
2.9 问题9:equals()和==的区别?
==操作符:
- 比较基本类型:值是否相等
- 比较引用类型:是否指向同一对象
String a = new String("Hi"); String b = new String("Hi"); System.out.println(a == b); // false(不同对象)
equals()方法:
- 默认行为同
==
- 通常被重写实现值比较
String a = new String("Hi"); String b = new String("Hi"); System.out.println(a.equals(b)); // true(值相同)
2.10 问题10:如何检查对象是否是某个类的实例?
不能用instanceof
(需要字面量类名),改用Class.isInstance()
:
Class<?> integerClass = Integer.class;
assertTrue(integerClass.isInstance(new Integer(42)));
assertTrue(integerClass.isInstance(42)); // 自动装箱
2.11 问题11:匿名类是什么?使用场景?
匿名类:一次性使用的无名类,定义和实例化同时完成
典型场景:
Java 8之前:实现单方法接口
Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("匿名线程"); } });
快速初始化集合:
Map<String, Integer> map = new HashMap<String, Integer>(){{ put("张三", 30); put("李四", 25); put("王五", 29); }};
💡 Java 8后优先用Lambda替代单方法接口的匿名类