
📃个人主页:编程的一拳超人
⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞
于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。 ——《人民日报》
目录
- 第一章 基础篇
- 1.1 Java介绍
- 1.2 J2SE、J2EE、J2ME三者区别
- 1.3 JDK、JRE、JVM区别
- 1.4 JDK常用的包
- 1.5 Java中的基本数据类型
- 1.6 Java中switch接受的数据类型
- 1.7 String、StringBuffer、StringBuilder区别
- 1.8 Char型变量能否存储一个汉字?
- 1.9 ==和equals方法的区别
- 1.10 静态变量和实例变量的区别
- 1.11 Integer和int的区别
- 1.12 Math.round()的使用
- 1.13 构造器是否可以被重写?
- 1.14 抽象类和接口的区别
- 1.15 新建对象的方式
- 1.16 &和&&的区别
- 1.17 面向对象的特性
- 1.18 面向对象中的多态特性
- 1.19 List、Set、Collection、Collections区别
- 1.20 线程和进程的区别
- 1.21 JVM内存结构
- 1.22 内存泄露和内存溢出
- 1.23 解析XML文件的技术
- 1.24 DOM4j与SAX对比
- 1.25 Java异常体系结构
- 1.26 抽象类和接口的区别(补充设计层面)
- 1.27 修饰符的作用
- 1.28 HashMap和Hashtable的区别
- 1.29 字节流和字符流的区别
- 1.30 运行异常和检查异常的不同
- 1.31 Error和Exception的区别
- 1.32 常用运行时异常
- 1.33 Sleep和Wait的区别
- 1.34 多线程实现方式
- 1.35 启动线程用run还是start?
- 1.36 List和Map的区别
- 1.37 ArrayList、Vector、LinkedList特性
- 1.38 Java序列化
- 1.39 堆和栈的区别
- 1.40 什么时候用断言?
- 1.41 Java中会有内存泄露吗?
- 1.42 简述反射的作用
第一章 基础篇
1.1 Java介绍
Java是由Sun Microsystems(现为Oracle)开发的跨平台、面向对象编程语言,核心特性包括:
- 跨平台性:通过Java虚拟机(JVM)实现“一次编写,到处运行”,字节码文件(
.class
)在不同系统的JVM中执行。 - 自动内存管理:通过垃圾回收(GC)自动管理对象内存,避免手动内存泄漏,提升开发效率。
- 面向对象:支持封装、继承、多态,通过类和接口实现代码复用,如抽象类定义通用行为,接口规范模块间契约。
- 丰富类库:提供
java.lang
(基础类)、java.util
(集合)、java.io
(IO)等核心包,支持网络、文件操作、多线程等功能。 - 版本演进:从J2SE/J2EE/J2ME到Java SE/EE/ME,适应桌面、企业、移动设备开发场景。
1.2 J2SE、J2EE、J2ME三者区别
版本 | 定位 | 技术栈 | 典型应用 |
---|---|---|---|
J2SE | 标准版,桌面/控制台开发 | Swing、AWT、基础IO/NIO、多线程 | 单机工具、桌面程序 |
J2EE (Java EE) | 企业版,分布式Web开发 | Servlet、JSP、EJB、Spring、Hibernate | 电商平台、ERP系统 |
J2ME | 移动版,嵌入式设备开发 | MIDP、CLDC | 早期手机应用、PDA程序 |
演进关系:J2SE是基础,J2EE基于J2SE扩展企业级API(如EJB、JTA),J2ME针对资源受限设备简化API,后因移动互联网发展,J2ME逐渐被Android/iOS开发取代。
1.3 JDK、JRE、JVM区别
- JVM(Java Virtual Machine)
- 核心功能:执行字节码,实现跨平台。包含类加载器、执行引擎、内存管理模块。
- 内存结构:堆(对象实例)、栈(局部变量/引用)、方法区(类元数据)、本地方法栈、程序计数器。
- JRE(Java Runtime Environment)
- 组成:JVM + 核心类库(
rt.jar
)+ 支持文件,是运行Java程序的最小环境,通过java
命令启动。
- 组成:JVM + 核心类库(
- JDK(Java Development Kit)
- 工具集:包含JRE、编译器(
javac
)、调试器(jdb
)、文档工具(javadoc
)等,用于开发阶段编译、调试代码。
- 工具集:包含JRE、编译器(
依赖关系:JDK ⊃ JRE ⊃ JVM,开发用JDK,运行用JRE。
1.4 JDK常用的包
- java.lang:基础核心类,如
String
(字符串)、Integer
(整数包装类)、System
(系统操作)、Thread
(线程),无需导入(自动加载)。 - java.io:输入输出包,支持文件操作与流处理,如
FileInputStream
(字节流)、BufferedReader
(字符流)、Serializable
(序列化接口)。 - java.net:网络编程,实现HTTP、FTP等协议,如
URL
(统一资源定位符)、Socket
(套接字)、HttpURLConnection
(HTTP连接)。 - java.util:工具类与集合框架,如
ArrayList
(动态数组)、HashMap
(键值对映射)、Collections
(集合工具类)、Date
(日期处理)。 - java.sql:数据库连接,定义JDBC接口,如
Connection
(数据库连接)、PreparedStatement
(预编译语句)、ResultSet
(结果集)。
1.5 Java中的基本数据类型
类型 | 位数 | 范围 | 包装类 | 默认值 |
---|---|---|---|---|
byte | 8位 | -128 ~ 127 | Byte | 0 |
short | 16位 | -32768 ~ 32767 | Short | 0 |
int | 32位 | -2^31 ~ 2^31-1 | Integer | 0 |
long | 64位 | -2^63 ~ 2^63-1 | Long | 0L |
float | 32位 | 单精度浮点型 | Float | 0.0f |
double | 64位 | 双精度浮点型 | Double | 0.0d |
char | 16位 | Unicode字符(0~65535) | Character | \u0000 |
boolean | 1位 | true/false | Boolean | false |
补充:
String
是引用类型,底层由char[]
实现,长度受内存限制(理论上限为Integer.MAX_VALUE
,实际受限于JVM堆空间)。- 自动拆箱/装箱:
int
与Integer
可自动转换,如Integer a = 10; int b = a;
。
1.6 Java中switch接受的数据类型
- JDK 1.5前:仅支持
byte
、short
、int
、char
及其包装类(自动拆箱)。 - JDK 1.5:新增
enum
枚举类型,通过枚举的ordinal()
方法映射为整数。 - JDK 1.7:支持
String
类型,通过字符串等值比较实现分支匹配。
示例:
String color = "red";
switch (color) {
case "red":
System.out.println("红色");
break;
// 其他case
}
1.7 String、StringBuffer、StringBuilder区别
特性 | String | StringBuffer | StringBuilder |
---|---|---|---|
可变性 | 不可变(常量池/堆) | 可变(线程安全,synchronized ) | 可变(非线程安全) |
性能 | 低(每次拼接生成新对象) | 中(锁开销) | 高(无锁,性能最优) |
线程安全 | 是(不可变天然安全) | 是 | 否 |
适用场景 | 少量字符串操作 | 多线程下字符串拼接 | 单线程下大量字符串拼接 |
底层实现:
String
底层为final char[] value
,不可变;StringBuffer
和StringBuilder
底层为char[]
,通过append()
动态扩展,区别在于前者方法加锁,后者无锁。- JDK 1.6优化:
String
使用+
拼接时,底层通过StringBuilder
实现,性能接近StringBuilder
。
1.8 Char型变量能否存储一个汉字?
- 可以。
char
采用Unicode编码(16位),支持中、日、韩等字符(如汉字编码范围U+4E00~U+9FFF
)。 - 示例:
char c = '中';
合法,存储其Unicode编码0x4E2D
。 - 注意:Java 7后支持代理对(Surrogate Pair)存储补充字符(如Emoji),但单个
char
仅能存储基本多语言平面(BMP)内的字符。
1.9 ==和equals方法的区别
- ==:
- 基本类型:比较数值是否相等(如
int a=1; int b=1; a==b
为true
)。 - 引用类型:比较对象内存地址(如
new String("a") == new String("a")
为false
)。
- 基本类型:比较数值是否相等(如
- equals():
- 定义在
Object
类,默认比较地址,可重写实现值比较。 - 常见重写类:
String
:比较内容(new String("a").equals("a")
为true
)。Integer
:值相等且在缓存范围(-128~127)时返回true
。Date
:比较时间戳。
- 定义在
最佳实践:比较对象值时优先使用equals()
,并注意null
安全(如Objects.equals(a, b)
)。
1.10 静态变量和实例变量的区别
特性 | 静态变量(类变量) | 实例变量(对象变量) |
---|---|---|
声明 | 带static 关键字 | 无static |
存储位置 | 方法区(类加载时分配) | 堆(对象创建时分配) |
访问方式 | 类名.变量 或 对象.变量 | 必须通过对象访问 |
生命周期 | 类加载到卸载 | 对象创建到垃圾回收 |
共享性 | 所有实例共享同一副本 | 每个实例独立副本 |
示例:
public class Demo {
static int staticVar = 0; // 静态变量
int instanceVar = 0; // 实例变量
}
1.11 Integer和int的区别
- 基本类型(int):
- 原始数据类型,存储4字节整数,默认值0,存储在栈(局部变量)或堆(成员变量)。
- 包装类(Integer):
- 引用类型,封装int值,默认值
null
,存储在堆中,支持自动拆箱/装箱。 - 缓存机制:自动装箱时,-128~127范围内的整数会缓存,超出范围新创建对象。
Integer a = 100; // 缓存中获取 Integer b = new Integer(100); // 新建对象 System.out.println(a == b); // false(地址不同)
- 引用类型,封装int值,默认值
1.12 Math.round()的使用
Math类取整方法对比:
- round(x):四舍五入,算法为
Math.floor(x + 0.5)
。round(11.5)
→ 12,round(-11.5)
→ -11(向零取整)。
- ceil(x):向上取整,返回≥x的最小整数(如
ceil(11.3)
→ 12,ceil(-11.3)
→ -11)。 - floor(x):向下取整,返回≤x的最大整数(如
floor(11.6)
→ 11,floor(-11.6)
→ -12)。
1.13 构造器是否可以被重写?
- 不能重写(Override):构造器不能被继承,子类构造器默认调用父类无参构造器(
super()
),无法覆盖父类构造逻辑。 - 可以重载(Overload):在同一类中定义多个参数不同的构造器,实现多样化初始化。
class Parent {
Parent() {}
Parent(int x) {} // 重载
}
class Child extends Parent {
Child() { super(); } // 调用父类无参构造器
}
1.14 抽象类和接口的区别
特性 | 抽象类(abstract class) | 接口(interface) |
---|---|---|
定义 | 类前加abstract ,可含抽象/非抽象方法 | 接口前加interface ,全抽象方法 |
构造器 | 可含构造器(供子类调用) | 不可含构造器 |
继承/实现 | 单继承(extends ) | 多实现(implements ) |
成员变量 | 可含普通变量、静态变量 | 只能是public static final 常量 |
方法 | 可含public /protected 抽象方法 | 默认为public abstract 方法 |
应用场景 | 代码复用(模板方法) | 定义行为契约(如API接口) |
设计原则:抽象类用于“是什么”(如“动物”抽象类),接口用于“能做什么”(如“飞行动物”接口)。
1.15 新建对象的方式
- new关键字:最常用,调用构造器初始化(如
new User("name")
)。 - 反射机制:通过
Class.newInstance()
或Constructor.newInstance()
动态创建,需处理异常。Class<?> clazz = Class.forName("User"); Object obj = clazz.newInstance();
- 克隆(clone):实现
Cloneable
接口,调用object.clone()
创建副本(浅拷贝/深拷贝)。 - 反序列化:通过
ObjectInputStream.readObject()
从字节流恢复对象,需实现Serializable
接口。 - 动态代理:通过
Proxy.newProxyInstance()
生成代理对象,用于AOP(如Spring切面代理)。
1.16 &和&&的区别
- 逻辑与(&&):
- 短路与,左表达式为
false
时右表达式不执行,提高效率。
if (str != null && str.length() > 0) { ... } // str为null时不执行length()
- 短路与,左表达式为
- 位运算与(&):
- 非短路,左右表达式均执行,可用于整数按位与(如
5 & 3
→ 1,二进制101 & 011 = 001
)。
- 非短路,左右表达式均执行,可用于整数按位与(如
- 共同点:作为逻辑与时结果相同,
&
还可作为位运算符。
1.17 面向对象的特性
- 三大特性(主流说法):
- 封装:隐藏内部实现,通过接口暴露功能(如类的私有字段通过公共方法访问)。
- 继承:子类继承父类属性和方法,实现代码复用(如
class Dog extends Animal
)。 - 多态:同一方法在不同对象上表现不同行为(如方法重写、接口实现)。
- 四大特性(部分教材):额外包含抽象,通过抽象类/接口定义通用行为,忽略具体实现(如定义
抽象类Shape
,子类Circle
/Rectangle
实现draw()
方法)。
1.18 面向对象中的多态特性
多态的三种表现形式:
- 向上转型:子类对象赋值给父类引用(如
Animal animal = new Dog();
),调用父类方法(若重写则调用子类实现)。 - 向下转型:父类引用转为子类类型(需强制转换,需确保类型兼容)。
if (animal instanceof Dog) { Dog dog = (Dog) animal; // 安全转型 }
- 重载与重写:
- 重载:同一类中方法名相同、参数不同(编译时多态)。
- 重写:子类覆盖父类方法(运行时多态,需满足方法签名一致)。
1.19 List、Set、Collection、Collections区别
- Collection:单列集合顶层接口,定义
add()
、remove()
、iterator()
等方法,派生List
和Set
。 - List:有序、可重复集合,实现类:
ArrayList
:动态数组,查询快,增删慢(数组搬运)。LinkedList
:双向链表,增删快,查询慢(需遍历)。Vector
:线程安全(synchronized
方法),性能低于ArrayList
。
- Set:无序、不可重复集合,实现类:
HashSet
:哈希表实现,无序。TreeSet
:红黑树实现,有序。
- Collections:工具类,提供排序(
sort()
)、同步包装(synchronizedList()
)、不可变集合(unmodifiableList()
)等静态方法。
1.20 线程和进程的区别
特性 | 进程(Process) | 线程(Thread) |
---|---|---|
定义 | 操作系统分配资源的基本单位 | 进程内的执行单元 |
资源共享 | 不共享代码/数据空间 | 共享进程资源(内存、文件句柄) |
调度 | 系统级调度,开销大 | 线程级调度,开销小 |
并发性 | 进程间并发 | 线程间并发(同一进程内) |
生命周期 | 独立,创建/销毁开销大 | 依赖进程,开销小 |
实现方式:线程可通过继承Thread
类或实现Runnable
接口创建,后者避免单继承限制,推荐使用。
1.21 JVM内存结构
JVM内存分为线程共享区域和线程私有区域:
- 共享区域:
- 堆(Heap):
- 存储对象实例和数组,分新生代(Eden、Survivor)和老年代,GC主要管理区域。
- 大小通过
-Xms
(初始)和-Xmx
(最大)配置,默认占物理内存1/4(最大值)。
- 方法区(元空间,Metaspace,JDK 8+):
- 存储类元数据、常量、静态变量,内存来自本地内存,通过
-XX:MetaspaceSize
控制大小。
- 存储类元数据、常量、静态变量,内存来自本地内存,通过
- 堆(Heap):
- 私有区域:
- 虚拟机栈:每个方法对应一个栈帧,存储局部变量、操作数栈,深度过深导致
StackOverflowError
(如无限递归)。 - 程序计数器:记录当前执行的字节码指令地址,唯一不OOM的区域。
- 虚拟机栈:每个方法对应一个栈帧,存储局部变量、操作数栈,深度过深导致
1.22 内存泄露和内存溢出
- 内存泄露(Memory Leak):
- 对象不再使用但未被GC回收(如静态集合未删除引用),长期积累导致内存溢出。
- 案例:未关闭的数据库连接、长生命周期对象持有短对象引用(如单例类持有局部对象)。
- 内存溢出(Out of Memory):
- 申请内存时无足够空间,如堆溢出(
java.lang.OutOfMemoryError: Java heap space
)或元空间溢出(OutOfMemoryError: Metaspace
)。 - 解决:优化对象生命周期、增大内存配置(
-Xmx4g
)、避免内存泄漏。
- 申请内存时无足够空间,如堆溢出(
1.23 解析XML文件的技术
五种主流技术对比:
- DOM4j:
- 基于DOM模型,加载整个XML到内存,支持XPath查询,适合中小文件(如配置文件)。
- SAX:
- 事件驱动,逐行解析,内存占用低,适合大文件(如日志解析),操作复杂。
- JAXB:
- 绑定XML Schema生成Java类,支持对象与XML互转,适合数据绑定(如Web服务数据交互)。
- JDOM:
- 简化DOM操作,纯Java实现,适合中小型项目。
- DOM:
- 官方标准,树状结构,性能较低,适合简单场景。
1.24 DOM4j与SAX对比
特性 | DOM4j | SAX |
---|---|---|
解析方式 | 内存树结构(加载整个文档) | 流式处理(逐行解析) |
内存占用 | 高(大文件易溢出) | 低 |
操作灵活性 | 高(支持增删改查、XPath) | 低(仅顺序处理) |
适用场景 | 小文件,需灵活操作 | 大文件,性能优先 |
示例:DOM4j读取节点:
Document doc = new SAXReader().read(file);
Element root = doc.getRootElement();
1.25 Java异常体系结构
Throwable
├── Error(系统错误,不可恢复)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── LinkageError
└── Exception(程序异常,可处理)
├── RuntimeException(运行时异常,Unchecked)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ └── ClassCastException
└── 非RuntimeException(检查异常,Checked)
├── IOException
│ ├── FileNotFoundException
│ └── SocketException
└── SQLException
- Error:如内存溢出、JVM崩溃,程序无法处理,JVM通常终止线程。
- Exception:
- 运行时异常:由逻辑错误引起(如空指针),编译器不强制处理。
- 检查异常:由外部环境问题引起(如文件不存在),必须捕获或声明抛出。
1.26 抽象类和接口的区别(补充设计层面)
- 设计目标:
- 抽象类:定义“是什么”,强制子类实现部分行为,允许提供默认实现(如模板方法模式)。
- 接口:定义“能做什么”,强制实现特定行为,不提供实现细节(如策略模式)。
- 语法细节:
- 接口支持Java 8+的默认方法(
default void method()
)和静态方法,抽象类不支持。
- 接口支持Java 8+的默认方法(
1.27 修饰符的作用
访问修饰符可见性矩阵:
修饰符 | 同一类 | 同一包 | 子类(不同包) | 全局 |
---|---|---|---|---|
private | ✔️ | ❌ | ❌ | ❌ |
默认(无) | ✔️ | ✔️ | ❌ | ❌ |
protected | ✔️ | ✔️ | ✔️ | ❌ |
public | ✔️ | ✔️ | ✔️ | ✔️ |
补充:static
修饰成员表示属于类,final
修饰类/方法/变量表示不可继承/重写/修改。
1.28 HashMap和Hashtable的区别
特性 | HashMap | Hashtable |
---|---|---|
线程安全 | 非线程安全(效率高) | 线程安全(方法加synchronized ,效率低) |
null支持 | 键/值可null (键唯一null ) | 键/值不可null |
继承 | 实现Map 接口 | 继承Dictionary 类 |
迭代器 | fail-fast(迭代时修改抛异常) | 非fail-fast(安全但一致性弱) |
适用场景 | 单线程高性能场景 | 历史遗留多线程场景(推荐ConcurrentHashMap 替代) |
1.29 字节流和字符流的区别
- 字节流(Stream结尾):
- 处理二进制数据(图片、视频),按字节读写(8位),如
FileInputStream
、OutputStream
。 - 需手动处理编码(如
new String(bytes, "UTF-8")
)。
- 处理二进制数据(图片、视频),按字节读写(8位),如
- 字符流(Reader/Writer结尾):
- 处理文本数据,按字符读写(16位Unicode),自动处理编码转换,如
FileReader
、BufferedWriter
。 - 适合按行处理(
readLine()
)。
- 处理文本数据,按字符读写(16位Unicode),自动处理编码转换,如
选择原则:纯文本用字符流,二进制数据用字节流。
1.30 运行异常和检查异常的不同
- 运行时异常:
- 继承
RuntimeException
,如NPE
、数组越界,编译器不强制处理,可忽略(但建议修复逻辑错误)。
- 继承
- 检查异常:
- 非
RuntimeException
,如IOException
、SQLException
,必须用try-catch
捕获或throws
声明,否则编译不通过。
- 非
示例:
// 检查异常必须处理
try {
FileInputStream fis = new FileInputStream("file.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
1.31 Error和Exception的区别
- Error:
- 严重系统错误,如
OutOfMemoryError
、ThreadDeath
,程序无法恢复,JVM通常终止线程,无需捕获。
- 严重系统错误,如
- Exception:
- 程序设计或实现问题,如输入错误、文件不存在,可通过异常处理机制恢复(如重试、提示用户)。
1.32 常用运行时异常
- NullPointerException(NPE):调用
null
对象的方法或属性(如str.length()
,str为null
)。 - ArrayIndexOutOfBoundsException:数组访问下标越界(如
int[] arr = new int[5]; arr[5] = 10;
)。 - ClassCastException:类型转换不兼容(如
Object obj = "string"; Integer i = (Integer) obj;
)。 - IllegalArgumentException:非法参数(如
Collections.binarySearch(list, null)
,列表不允许null
)。 - IndexOutOfBoundsException:集合索引越界(如
List.get(-1)
)。
1.33 Sleep和Wait的区别
特性 | sleep()(Thread方法) | wait()(Object方法) |
---|---|---|
释放锁 | 否(保持同步锁) | 是(释放对象锁) |
唤醒方式 | 时间到自动唤醒 | 需notify() /notifyAll() 唤醒 |
使用场景 | 线程休眠(如延迟执行) | 线程间通信(等待特定条件) |
异常处理 | 需捕获InterruptedException | 需在synchronized 块中使用 |
示例:
// sleep
try { Thread.sleep(1000); } catch (InterruptedException e) { ... }
// wait
synchronized (obj) { obj.wait(); }
1.34 多线程实现方式
两种核心方式:
- 继承Thread类:
class MyThread extends Thread { public void run() { /* 逻辑 */ } } new MyThread().start();
- 实现Runnable接口:
class MyRunnable implements Runnable { public void run() { /* 逻辑 */ } } new Thread(new MyRunnable()).start();
- 补充:Java 5+引入
Callable
接口(带返回值和异常),通过FutureTask
包装:Callable<Integer> task = () -> 42; Future<Integer> future = Executors.newSingleThreadExecutor().submit(task);
1.35 启动线程用run还是start?
- start():
- 启动线程,进入就绪状态,由JVM调度执行
run()
方法,允许多线程并发。
- 启动线程,进入就绪状态,由JVM调度执行
- run():
- 直接调用方法,在当前线程执行,无并发效果,等同于普通方法调用。
错误示范:
Thread thread = new Thread(() -> System.out.println("Run"));
thread.run(); // 错误:在主线程执行,无并发
1.36 List和Map的区别
特性 | List(单列集合) | Map(双列集合) |
---|---|---|
存储结构 | 有序、可重复元素 | 键值对(Key唯一,Value可重复) |
接口 | 继承Collection | 独立接口(不继承Collection ) |
访问方式 | 索引(如list.get(i) ) | 键查找(如map.get(key) ) |
常用实现 | ArrayList 、LinkedList | HashMap 、TreeMap |
1.37 ArrayList、Vector、LinkedList特性
实现 | ArrayList | Vector | LinkedList |
---|---|---|---|
数据结构 | 动态数组 | 动态数组(线程安全) | 双向链表 |
线程安全 | 非线程安全 | 线程安全(synchronized ) | 非线程安全 |
增删效率 | 中间位置慢(数组搬运) | 同ArrayList (锁开销) | 快(仅修改指针) |
查询效率 | 快(下标直接访问) | 同ArrayList | 慢(需遍历链表) |
适用场景 | 高频查询,单线程 | 历史遗留多线程场景(不推荐) | 高频增删,如队列/栈 |
1.38 Java序列化
- 用途:
- 对象持久化(如写入文件、Redis缓存)。
- 分布式通信(RMI、Hessian协议)。
- 缓存(Hibernate二级缓存)。
- 要求:
- 实现
Serializable
接口,建议显式定义serialVersionUID
避免版本不兼容。 - transient修饰字段不序列化(如临时数据)。
- 实现
- 案例:
class User implements Serializable { private static final long serialVersionUID = 1L; private transient String tempData; // 不序列化 }
1.39 堆和栈的区别
特性 | 堆(Heap) | 栈(Stack) |
---|---|---|
存储内容 | 对象实例、数组 | 基本类型、对象引用 |
线程安全 | 共享(需考虑并发) | 线程私有(无并发问题) |
分配方式 | 动态分配(new 关键字) | 自动分配(方法调用时创建) |
内存回收 | GC自动回收 | 方法结束后自动释放 |
空间大小 | 大(可配置-Xmx ) | 小(默认1M,-Xss 配置) |
补充:final
修饰的局部变量存储在栈中,若为对象引用,引用地址在栈,对象实例在堆。
1.40 什么时候用断言?
- 场景:
- 开发阶段验证参数合法性(如
assert x > 0 : "x must be positive"
)。 - 测试阶段检查不可达代码分支(如
assert false : "Should not reach here"
)。
- 开发阶段验证参数合法性(如
- 注意:
- 断言默认关闭,通过
-ea
参数启用(生产环境建议关闭,避免性能开销)。 - 不应用于处理正常业务逻辑,仅用于辅助调试。
- 断言默认关闭,通过
1.41 Java中会有内存泄露吗?
- 会,常见场景:
- 集合引用未清理:静态集合长期持有对象引用,如
static List<Object> list = new ArrayList<>();
。 - 长生命周期对象引用短对象:单例类持有局部对象引用,导致短对象无法回收。
- HashSet/HashMap键修改:修改对象中参与哈希计算的字段,导致无法正确删除(如修改
User
的hashCode()
相关字段后未从集合移除)。
- 集合引用未清理:静态集合长期持有对象引用,如
- 检测工具:JConsole、VisualVM分析堆dump,定位引用链。
1.42 简述反射的作用
反射允许程序在运行时动态操作类/对象,核心功能:
- 动态创建对象:无需编译时已知类,如通过
Class.forName("com.User").newInstance()
创建实例。 - 调用方法/字段:突破访问修饰符限制(
setAccessible(true)
调用私有方法)。 - 框架支撑:
- Spring IOC(动态创建Bean)、MyBatis(映射SQL)、JUnit(反射执行测试用例)。
- 风险:性能开销(编译期优化缺失)、破坏封装性(访问私有成员),建议仅在框架层使用。
通过以上深入拓展,覆盖Java基础的核心概念、常见面试考点及实战细节,帮助读者系统掌握基础知识,应对高频面试问题。