Java面试宝典带你复习--第一章基础篇

在这里插入图片描述

📃个人主页:编程的一拳超人

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞

于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。 ——《人民日报》


第一章 基础篇

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命令启动。
  • JDK(Java Development Kit)
    • 工具集:包含JRE、编译器(javac)、调试器(jdb)、文档工具(javadoc)等,用于开发阶段编译、调试代码。

依赖关系: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中的基本数据类型

类型位数范围包装类默认值
byte8位-128 ~ 127Byte0
short16位-32768 ~ 32767Short0
int32位-2^31 ~ 2^31-1Integer0
long64位-2^63 ~ 2^63-1Long0L
float32位单精度浮点型Float0.0f
double64位双精度浮点型Double0.0d
char16位Unicode字符(0~65535)Character\u0000
boolean1位true/falseBooleanfalse

补充

  • String是引用类型,底层由char[]实现,长度受内存限制(理论上限为Integer.MAX_VALUE,实际受限于JVM堆空间)。
  • 自动拆箱/装箱:intInteger可自动转换,如Integer a = 10; int b = a;

1.6 Java中switch接受的数据类型

  • JDK 1.5前:仅支持byteshortintchar及其包装类(自动拆箱)。
  • 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区别

特性StringStringBufferStringBuilder
可变性不可变(常量池/堆)可变(线程安全,synchronized可变(非线程安全)
性能低(每次拼接生成新对象)中(锁开销)高(无锁,性能最优)
线程安全是(不可变天然安全)
适用场景少量字符串操作多线程下字符串拼接单线程下大量字符串拼接

底层实现

  • String底层为final char[] value,不可变;
  • StringBufferStringBuilder底层为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==btrue)。
    • 引用类型:比较对象内存地址(如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(地址不同)  
    

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 新建对象的方式

  1. new关键字:最常用,调用构造器初始化(如new User("name"))。
  2. 反射机制:通过Class.newInstance()Constructor.newInstance()动态创建,需处理异常。
    Class<?> clazz = Class.forName("User");  
    Object obj = clazz.newInstance();  
    
  3. 克隆(clone):实现Cloneable接口,调用object.clone()创建副本(浅拷贝/深拷贝)。
  4. 反序列化:通过ObjectInputStream.readObject()从字节流恢复对象,需实现Serializable接口。
  5. 动态代理:通过Proxy.newProxyInstance()生成代理对象,用于AOP(如Spring切面代理)。

1.16 &和&&的区别

  • 逻辑与(&&)
    • 短路与,左表达式为false时右表达式不执行,提高效率。
    if (str != null && str.length() > 0) { ... } // str为null时不执行length()  
    
  • 位运算与(&)
    • 非短路,左右表达式均执行,可用于整数按位与(如5 & 3 → 1,二进制101 & 011 = 001)。
  • 共同点:作为逻辑与时结果相同,&还可作为位运算符。

1.17 面向对象的特性

  • 三大特性(主流说法)
    1. 封装:隐藏内部实现,通过接口暴露功能(如类的私有字段通过公共方法访问)。
    2. 继承:子类继承父类属性和方法,实现代码复用(如class Dog extends Animal)。
    3. 多态:同一方法在不同对象上表现不同行为(如方法重写、接口实现)。
  • 四大特性(部分教材):额外包含抽象,通过抽象类/接口定义通用行为,忽略具体实现(如定义抽象类Shape,子类Circle/Rectangle实现draw()方法)。

1.18 面向对象中的多态特性

多态的三种表现形式:

  1. 向上转型:子类对象赋值给父类引用(如Animal animal = new Dog();),调用父类方法(若重写则调用子类实现)。
  2. 向下转型:父类引用转为子类类型(需强制转换,需确保类型兼容)。
    if (animal instanceof Dog) {  
        Dog dog = (Dog) animal; // 安全转型  
    }  
    
  3. 重载与重写
    • 重载:同一类中方法名相同、参数不同(编译时多态)。
    • 重写:子类覆盖父类方法(运行时多态,需满足方法签名一致)。

1.19 List、Set、Collection、Collections区别

  • Collection:单列集合顶层接口,定义add()remove()iterator()等方法,派生ListSet
  • List:有序、可重复集合,实现类:
    • ArrayList:动态数组,查询快,增删慢(数组搬运)。
    • LinkedList:双向链表,增删快,查询慢(需遍历)。
    • Vector:线程安全(synchronized方法),性能低于ArrayList
  • Set:无序、不可重复集合,实现类:
    • HashSet:哈希表实现,无序。
    • TreeSet:红黑树实现,有序。
  • Collections:工具类,提供排序(sort())、同步包装(synchronizedList())、不可变集合(unmodifiableList())等静态方法。

1.20 线程和进程的区别

特性进程(Process)线程(Thread)
定义操作系统分配资源的基本单位进程内的执行单元
资源共享不共享代码/数据空间共享进程资源(内存、文件句柄)
调度系统级调度,开销大线程级调度,开销小
并发性进程间并发线程间并发(同一进程内)
生命周期独立,创建/销毁开销大依赖进程,开销小

实现方式:线程可通过继承Thread类或实现Runnable接口创建,后者避免单继承限制,推荐使用。

1.21 JVM内存结构

JVM内存分为线程共享区域线程私有区域

  • 共享区域
    1. 堆(Heap)
      • 存储对象实例和数组,分新生代(Eden、Survivor)和老年代,GC主要管理区域。
      • 大小通过-Xms(初始)和-Xmx(最大)配置,默认占物理内存1/4(最大值)。
    2. 方法区(元空间,Metaspace,JDK 8+)
      • 存储类元数据、常量、静态变量,内存来自本地内存,通过-XX:MetaspaceSize控制大小。
  • 私有区域
    1. 虚拟机栈:每个方法对应一个栈帧,存储局部变量、操作数栈,深度过深导致StackOverflowError(如无限递归)。
    2. 程序计数器:记录当前执行的字节码指令地址,唯一不OOM的区域。

1.22 内存泄露和内存溢出

  • 内存泄露(Memory Leak)
    • 对象不再使用但未被GC回收(如静态集合未删除引用),长期积累导致内存溢出。
    • 案例:未关闭的数据库连接、长生命周期对象持有短对象引用(如单例类持有局部对象)。
  • 内存溢出(Out of Memory)
    • 申请内存时无足够空间,如堆溢出(java.lang.OutOfMemoryError: Java heap space)或元空间溢出(OutOfMemoryError: Metaspace)。
    • 解决:优化对象生命周期、增大内存配置(-Xmx4g)、避免内存泄漏。

1.23 解析XML文件的技术

五种主流技术对比:

  1. DOM4j
    • 基于DOM模型,加载整个XML到内存,支持XPath查询,适合中小文件(如配置文件)。
  2. SAX
    • 事件驱动,逐行解析,内存占用低,适合大文件(如日志解析),操作复杂。
  3. JAXB
    • 绑定XML Schema生成Java类,支持对象与XML互转,适合数据绑定(如Web服务数据交互)。
  4. JDOM
    • 简化DOM操作,纯Java实现,适合中小型项目。
  5. DOM
    • 官方标准,树状结构,性能较低,适合简单场景。

1.24 DOM4j与SAX对比

特性DOM4jSAX
解析方式内存树结构(加载整个文档)流式处理(逐行解析)
内存占用高(大文件易溢出)
操作灵活性高(支持增删改查、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())和静态方法,抽象类不支持。

1.27 修饰符的作用

访问修饰符可见性矩阵:

修饰符同一类同一包子类(不同包)全局
private✔️
默认(无)✔️✔️
protected✔️✔️✔️
public✔️✔️✔️✔️

补充static修饰成员表示属于类,final修饰类/方法/变量表示不可继承/重写/修改。

1.28 HashMap和Hashtable的区别

特性HashMapHashtable
线程安全非线程安全(效率高)线程安全(方法加synchronized,效率低)
null支持键/值可null(键唯一null键/值不可null
继承实现Map接口继承Dictionary
迭代器fail-fast(迭代时修改抛异常)非fail-fast(安全但一致性弱)
适用场景单线程高性能场景历史遗留多线程场景(推荐ConcurrentHashMap替代)

1.29 字节流和字符流的区别

  • 字节流(Stream结尾)
    • 处理二进制数据(图片、视频),按字节读写(8位),如FileInputStreamOutputStream
    • 需手动处理编码(如new String(bytes, "UTF-8"))。
  • 字符流(Reader/Writer结尾)
    • 处理文本数据,按字符读写(16位Unicode),自动处理编码转换,如FileReaderBufferedWriter
    • 适合按行处理(readLine())。

选择原则:纯文本用字符流,二进制数据用字节流。

1.30 运行异常和检查异常的不同

  • 运行时异常
    • 继承RuntimeException,如NPE、数组越界,编译器不强制处理,可忽略(但建议修复逻辑错误)。
  • 检查异常
    • RuntimeException,如IOExceptionSQLException,必须用try-catch捕获或throws声明,否则编译不通过。

示例

// 检查异常必须处理  
try {  
    FileInputStream fis = new FileInputStream("file.txt");  
} catch (FileNotFoundException e) {  
    e.printStackTrace();  
}  

1.31 Error和Exception的区别

  • Error
    • 严重系统错误,如OutOfMemoryErrorThreadDeath,程序无法恢复,JVM通常终止线程,无需捕获。
  • Exception
    • 程序设计或实现问题,如输入错误、文件不存在,可通过异常处理机制恢复(如重试、提示用户)。

1.32 常用运行时异常

  1. NullPointerException(NPE):调用null对象的方法或属性(如str.length()str为null)。
  2. ArrayIndexOutOfBoundsException:数组访问下标越界(如int[] arr = new int[5]; arr[5] = 10;)。
  3. ClassCastException:类型转换不兼容(如Object obj = "string"; Integer i = (Integer) obj;)。
  4. IllegalArgumentException:非法参数(如Collections.binarySearch(list, null),列表不允许null)。
  5. 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 多线程实现方式

两种核心方式:

  1. 继承Thread类
    class MyThread extends Thread {  
        public void run() { /* 逻辑 */ }  
    }  
    new MyThread().start();  
    
  2. 实现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()方法,允许多线程并发。
  • 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)
常用实现ArrayListLinkedListHashMapTreeMap

1.37 ArrayList、Vector、LinkedList特性

实现ArrayListVectorLinkedList
数据结构动态数组动态数组(线程安全)双向链表
线程安全非线程安全线程安全(synchronized非线程安全
增删效率中间位置慢(数组搬运)ArrayList(锁开销)快(仅修改指针)
查询效率快(下标直接访问)ArrayList慢(需遍历链表)
适用场景高频查询,单线程历史遗留多线程场景(不推荐)高频增删,如队列/栈

1.38 Java序列化

  • 用途
    1. 对象持久化(如写入文件、Redis缓存)。
    2. 分布式通信(RMI、Hessian协议)。
    3. 缓存(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 什么时候用断言?

  • 场景
    1. 开发阶段验证参数合法性(如assert x > 0 : "x must be positive")。
    2. 测试阶段检查不可达代码分支(如assert false : "Should not reach here")。
  • 注意
    • 断言默认关闭,通过-ea参数启用(生产环境建议关闭,避免性能开销)。
    • 不应用于处理正常业务逻辑,仅用于辅助调试。

1.41 Java中会有内存泄露吗?

  • ,常见场景:
    1. 集合引用未清理:静态集合长期持有对象引用,如static List<Object> list = new ArrayList<>();
    2. 长生命周期对象引用短对象:单例类持有局部对象引用,导致短对象无法回收。
    3. HashSet/HashMap键修改:修改对象中参与哈希计算的字段,导致无法正确删除(如修改UserhashCode()相关字段后未从集合移除)。
  • 检测工具:JConsole、VisualVM分析堆dump,定位引用链。

1.42 简述反射的作用

反射允许程序在运行时动态操作类/对象,核心功能:

  • 动态创建对象:无需编译时已知类,如通过Class.forName("com.User").newInstance()创建实例。
  • 调用方法/字段:突破访问修饰符限制(setAccessible(true)调用私有方法)。
  • 框架支撑
    • Spring IOC(动态创建Bean)、MyBatis(映射SQL)、JUnit(反射执行测试用例)。
  • 风险:性能开销(编译期优化缺失)、破坏封装性(访问私有成员),建议仅在框架层使用。

通过以上深入拓展,覆盖Java基础的核心概念、常见面试考点及实战细节,帮助读者系统掌握基础知识,应对高频面试问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程的一拳超人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值