当前位置: 首页 > backend >正文

Fullstack 面试复习笔记:Java 基础语法 / 核心特性体系化总结

Fullstack 面试复习笔记:Java 基础语法 / 核心特性体系化总结

上一篇笔记:Fullstack 面试复习笔记:操作系统 / 网络 / HTTP / 设计模式梳理

目前上来说,这个系列的笔记本质上来说,是对不理解的知识点进行的一个梳理,而不是是更细节的八股文备战。可以基于这个蓝图做延伸,去找对应的八股文,但是为了方便更快地过一遍面试准备——我基本上做好一周内要ready的打算,就不包含八股文了……

基础结构 & 语法机制

基础类型(primitive type)

这里简单的回顾一下primitive type的基础,java中有的primitive type有:

类型字节数默认值范围 or 特性
byte10-128 ~ 127
short20-32,768 ~ 32,767
int40-2^31 ~ 2^31-1(默认整数类型)
long80L-2^63 ~ 2^63-1(必须加 L 后缀)
float40.0f单精度(精度约为 7 位)
double80.0d双精度(默认浮点数,约 15 位精度)
char2‘\u0000’Unicode 字符编码(不是 ASCII)
boolean1falsetrue / false
  • 自动装箱 & 拆箱(autuboxing/unboxing)
    • Java会对 -128127 这个区间的数字进行缓存,如:

      Integer a = 127;
      Integer b = 127;
      System.out.println(a == b); // trueInteger a = 128;
      Integer b = 128;
      System.out.println(a == b); // false
      

      除了 byte, booleanfloat/ double 外的其他wrapper clas都适用

    • 装箱对象的比较必须用 .equals(),不要用 ==

常用集合

  • HashMap vs Hashtable vs ConcurrentHashMap(线程安全机制)

    • HashMap非线程安全,性能好,适合单线程或通过 Collections.synchronizedMapConcurrentHashMap 实现安全
    • Hashtable线程安全,但通过方法加锁(synchronized),效率低,已过时
    • ConcurrentHashMap : 线程安全, 最新实现,代替 Hashtable
  • ArrayList vs LinkedList

    重点放在操作复杂度(时间复杂度)上

  • HashSet, TreeSet, TreeMap

    特性HashSetTreeSetTreeMap
    类型Set(不重复元素)Set(有序、不重复元素)Map(有序键值对)
    底层结构HashMapTreeMap(基于红黑树)红黑树(Red-Black Tree)
    是否排序❌ 否(无序)✅ 是(元素有序)✅ 是(key 有序)
    允许 null✅ 允许一个 null 元素✅ 默认支持一个 null 元素(但不可比较)✅ key 允许 null(但排序会报错)
    插入性能🚀 快(O(1) 平均)🐢 较慢(O(log n),因排序)🐢 较慢(O(log n),因排序)
    是否线程安全❌ 否❌ 否❌ 否
  • Comparable vs Comparator

    方式用法场景说明
    Comparable实现类内部排序(默认规则实现 compareTo() 方法,修改类本身,例如:User implements Comparable<User>
    Comparator外部传入排序规则(灵活定制传入 TreeSetTreeMap 构造器,可避免修改类
  • BigDecimal

    BigDecimal bd = new BigDecimal("123.45");
    // intVal = 12345
    // scale = 2
    // => intVal × 10^(-scale) = 123.45
    

对象机制

  • equals/hashCode 原则

    若两个对象通过 equals() 判断为相等,则它们的 hashCode() 也必须相等;否则会破坏集合类(如 HashMapHashSet)的查找一致性

  • Java 内存结构 + 对象引用类型(强/软/弱/虚)

    类型是否参与GC前回收典型用途特点说明
    强引用❌ 不可回收常规对象引用默认引用类型,只有失去所有强引用才会GC
    软引用✅ 内存不足时回收缓存(如图片)有可能在OOM前被GC,适合做内存敏感缓存
    弱引用✅ 下一次GC就回收ThreadLocal等生命周期短,不影响GC回收
    虚引用✅ 随时可回收跟踪对象回收无法通过它访问对象,需配合 ReferenceQueue

异常机制

  • checked vs unchecked

    Checked 异常是受检异常,编译器要求你显式处理(try-catch 或 throws);而 Unchecked 异常是运行时异常可以不处理,但最好处理

    异常类型是否强制捕获继承体系使用场景示例
    Checked✅ 是Exception(但非 RuntimeException受控环境、外部 IO、数据库等IOException, SQLException
    Unchecked❌ 否RuntimeException 及其子类程序逻辑错误、空指针等NullPointerException, IndexOutOfBoundsException
  • try-with-resources

    try-with-resources 是 Java 7 引入的新语法,用于在 try 块中自动关闭资源(实现了 AutoCloseable 接口的对象),避免 finally 中手动 close() 的繁琐与遗漏

    try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {String line = reader.readLine();System.out.println(line);
    } catch (IOException e) {e.printStackTrace();
    }
    

注解机制(Annotation)

  • 基本注解:@Override, @SuppressWarnings

  • 自定义注解

  • 元注解(Retention Policy)

    用于修饰注解本身,控制其生命周期、作用范围、能否继承等

    元注解含义(作用)
    @Retention注解保留到何时(编译时 / 运行时 / 类加载时)
    @Target注解可以放在哪些位置(类 / 方法 / 字段等)
    @Documented是否包含在 Javadoc 中
    @Inherited是否允许子类继承注解
    @Repeatable是否允许注解重复使用(Java 8+)

    提供一个案例简单说明一下:

    @Retention(RetentionPolicy.RUNTIME)  // 注解可以在运行时通过反射读取
    @Target(ElementType.METHOD)          // 注解只能贴在方法上
    public @interface MyCustomAnno {     // 自定义注解本体String value();
    }
  • 常见使用场景:Spring 注解驱动

Java 8+ 核心特性

Lambda 表达式

函数式接口实例 语法糖:简化匿名内部类

// comparator
List<String> names = Arrays.asList("Zhang", "Li", "Wang", "Zhao");names.sort((a, b) -> a.compareTo(b));
names.sort((a, b) -> b.compareTo(a));// runnable
Runnable task = () -> System.out.println("Hello from thread!");
Thread thread = new Thread(task);
thread.start();// forEach
List<String> list = Arrays.asList("apple", "banana", "cherry");list.forEach(item -> System.out.println("水果:" + item));

函数式接口(Functional Interface)

只包含一个抽象方法的接口,用于支持 Lambda 表达式,使方法行为可以像“函数”一样被传递

接口名参数返回用途示例说明
Runnable无参任务() -> System.out.println("Run")
Supplier<T>T提供一个对象() -> "Hello"
Consumer<T>T消费一个对象(只执行动作)(x) -> System.out.println(x)
Function<T,R>TR接收一个 T 返回一个 R(x) -> x.length()
Predicate<T>T布尔判断某个条件是否成立(x) -> x > 0
BiFunction<T,U,R>T,UR接收两个参数返回一个结果(a,b) -> a + b

出了上面的 Runnable 的例子,这里再提供一个 Comparator 的例子:

@FunctionalInterface
public interface StudentComparator {int compare(Student s1, Student s2);default void log() {System.out.println("Comparing students...");}static void staticHelper() {System.out.println("Static helper inside interface");}
}public class Student {String name;int age;double score;public Student(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}// ...
}List<Student> students = Arrays.asList(new Student("Alice", 20, 85.5),new Student("Bob", 22, 90.0),new Student("Charlie", 19, 78.0)
);// 使用 Lambda 表达式来定义比较规则(按年龄升序)
students.sort((s1, s2) -> s1.age - s2.age);// 也可以封装成函数式接口
StudentComparator byScore = (s1, s2) -> Double.compare(s1.score, s2.score);
students.sort(byScore::compare);// 对比传统开发,即不使用lambda和function interface的实现
// 方式一:匿名内部类(匿名实现 Comparator)
students.sort(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {return s1.age - s2.age;}
});// 方式二:单独定义一个类
students.sort(new StudentScoreComparator()); // 比分数// 单独定义一个类:实现 Comparator<Student>
class StudentScoreComparator implements Comparator<Student> {@Overridepublic int compare(Student s1, Student s2) {return Double.compare(s1.score, s2.score);}
}

可以看到,通过lambda+functional interface的方式,代码实现变得更加的简洁可读。

推荐做法是添加 @FunctionalInterface 的注解,这样Java可以更好的做验证。如果不加的话,在interface中只有一个abstract method的情况下,Java也可以自动推导当前interface是 @FunctionalInterface

Stream API

依旧使用上面的 Student 作为案例:

List<Student> students = List.of(new Student("Alice", 18, 90),new Student("Bob", 20, 75),new Student("Carol", 19, 90),new Student("David", 20, 85)
);
  • 中间操作:map, filter, sorted, distinct

    // 转为名字列表
    List<String> names = students.stream().map(student -> student.name).collect(Collectors.toList());// 过滤出成绩 ≥ 85 的学生
    List<Student> topStudents = students.stream().filter(s -> s.score >= 85).collect(Collectors.toList());// 按年龄升序排序
    List<Integer> distinctScores = students.stream().map(s -> s.score).distinct().collect(Collectors.toList());// 移除重复分数
    List<Integer> distinctScores = students.stream().map(s -> s.score).distinct().collect(Collectors.toList());
  • 终端操作:collect, reduce, count

    // 收集成列表
    List<String> names = students.stream().map(s -> s.name).collect(Collectors.toList());// 统计人数
    long count = students.stream().count();// 累加所有分数
    int totalScore = students.stream().map(s -> s.score).reduce(0, Integer::sum); // or (a, b) -> a + b
    
  • 分组统计:Collectors.groupingBy, partitioningBy

    虽然分组也是 collect 的一部分,但它使用了 Collectors.groupingBy,语义更复杂,因此单独列出

    // 按分数分组
    Map<Integer, List<Student>> groupedByScore = students.stream().collect(Collectors.groupingBy(s -> s.score));// 按年龄分组,并统计每组人数
    Map<Integer, Long> ageCountMap = students.stream().collect(Collectors.groupingBy(s -> s.age, Collectors.counting()));// 按分数分组后,每组提取名字列表
    Map<Integer, List<String>> scoreToNames = students.stream().collect(Collectors.groupingBy(s -> s.score,Collectors.mapping(s -> s.name, Collectors.toList())));
    

总结一下输出结果

场景代码片段输出类型
转字段列表map(...).collect(toList())List<T>
条件过滤filter(...).collect(toList())List<T>
分组统计groupingBy(..., counting())Map<K, Long>
分组后映射groupingBy(..., mapping(..., toList()))Map<K, List<V>>
规约求和reduce(0, Integer::sum)int
去重字段map(...).distinct()Stream<T>

Optional

  • Optional.of, Optional.empty, orElse, orElseGet, map
  • 避免 NPE、链式调用

举个例子:

public class User {private Address address;public Optional<Address> getAddress() {return Optional.ofNullable(address);}
}public class Address {private String city;public Optional<String> getCity() {return Optional.ofNullable(city);}
}// 传统写法
String city = null;
if (user != null && user.getAddress() != null && user.getAddress().getCity() != null) {city = user.getAddress().getCity();
}// 使用Optional
String city = user.getAddress().flatMap(Address::getCity)   // 注意是 flatMap,因为返回值是 Optional.orElse("Unknown");

补充一个常见的错误用法 vs 正确用法:

Optional<String> name = Optional.of("Tom");
if (name.isPresent()) {System.out.println(name.get()); // 虽然可以,但违背了 Optional 的设计初衷
}// 更推荐写成
name.ifPresent(System.out::println);// 或者
String result = name.orElse("Default");

接口默认方法 & 静态方法

  • default method 用于向后兼容

    interface中可以使用 default 添加新方法,继承原本的interface 的client端不需要实现新的 default 方法,需要使用对应方法的新用户也可以实现 overload

  • static method in interfaces

这里用截图举个例子说明比较简单:

ConcurrentHashMap(Java 8 重构点)

  • Java 8 改成了分段锁 + CAS(Compare-And-Swap,一种乐观锁,比起之前的 ReentrantLock 相比重试更快,也不会抢锁),取消了 Segment

    具体修改包括:

    特性Java 8 做了什么
    ❌ 取消 Segment不再有 Segment 数组,直接用 Node[] table
    ✅ 引入 CAS + synchronized取代 ReentrantLock 的粒度控制
    ✅ 链表转红黑树当链表长度超过阈值(默认 8)转为红黑树,提高查询效率(O(n) → O(log n))
    ✅ 支持 computeIfAbsent()forEach() 等并发友好新方法
    ✅ 更轻量的锁机制每个 bucket(table[i])单独加锁,或使用 CAS,无需全表锁定
  • computeIfAbsent 是高频问点

    • 工作流程:
      1. 如果 key 不存在,则执行 Lambda,生成新值(如 new ArrayList<>());
      2. CASsynchronized(针对单个桶) 安全地插入;
      3. 避免了 putIfAbsent() + get() 的双查找问题。
    • 高频面试陷阱:
      • Lambda 表达式可能会被重复调用(并发争抢下),但只有一个结果会被真正放进去;
      • 所以 Lambda 中逻辑要无副作用(side-effect-free)
  • synchronizedMap 对比

    特性ConcurrentHashMapCollections.synchronizedMap
    锁机制分段+CAS+局部 synchronized粗粒度同步(整个 Map 加锁)
    性能高并发读写表现优异写操作竞争大,性能差
    Null 支持❌ 不支持 key/value 为 null✅ 支持 null
    Java 推荐✅ 推荐🚫 已过时(在并发环境)

JUC

核心线程池类(基础构建块)

  • ExecutorService:线程池接口,支持任务提交、关闭、回收线程资源
  • Future:用于获取异步任务的返回结果,支持取消任务
  • Callable<T>:可返回结果并抛出异常的任务(对比 Runnable

并发工具类(线程同步控制)

  • CountDownLatch:等待多个线程完成,适合“倒计时”场景(如等待所有子任务执行完毕)
  • CyclicBarrier:多个线程在屏障点等待,适合阶段性同步(如并行计算后统一合并)
  • Semaphore:控制并发线程数(如数据库连接池限流)
  • ReentrantLock:可重入锁,支持公平/非公平机制,可精细控制加锁与释放
  • ThreadLocal:为每个线程维护独立变量副本,常用于用户上下文、连接隔离

Java 8+ 并发增强(异步编排)

  • CompletableFuture:链式异步任务编排工具,支持组合多个异步结果,替代传统 Future
  • ForkJoinPool:用于递归任务分割并行计算,Java 8 中 parallelStream() 默认使用
  • parallelStream():简化并行流处理,使用 ForkJoinPool.commonPool() 背后实现

线程池实现与调优点

  • ThreadPoolExecutor:线程池核心实现类,支持核心线程数、最大线程数、队列容量、拒绝策略等参数配置
  • ScheduledExecutorService:定时任务调度器,支持延迟/周期执行任务,替代老旧的 Timer

Java 内存可见性与原子性关键词(高频知识点)

  • volatile:保证变量可见性,不保证原子性(常用于双重检查锁 DCL 中)
  • synchronized:内置锁,保证原子性和可见性,支持对象级与类级加锁

反射 / 动态代理(Reflection & Dynamic Proxy)

基础 API(Class 对象)

  • Class<?> clazz = Class.forName("com.example.MyClass")
  • clazz.getDeclaredFields() / getDeclaredMethods():反射读取字段和方法
  • field.setAccessible(true):访问私有字段
  • 常用于通用框架 / 动态注册 / 对象转换等场景

动态代理(Proxy)

  • Proxy.newProxyInstance(classLoader, interfaces, handler):生成实现接口的代理对象

  • InvocationHandler 接口用于定义方法增强逻辑

    public class MyHandler implements InvocationHandler {private final Object target;public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// beforeObject result = method.invoke(target, args); // 调用真实方法// afterreturn result;}
    }
    
  • 🌟 用于 AOP、RPC Stub 构造、权限校验、日志追踪等

  • 只能代理 接口(类代理推荐用 CGLIB)

SPI 机制(Service Provider Interface)

  • Java 原生插件机制,用于服务发现与自动加载
  • 使用方式:
    • META-INF/services/com.example.InterfaceName 文件中声明实现类
    • 加载方式:ServiceLoader.load(InterfaceName.class)
  • 示例:JDBC 驱动加载、Spring Boot Starter 自动注册、Netty Codec 插件

注解处理器 / 自定义注解

这部分和上面的有一点重复,算是稍微多加一点补充吧……

注解元注解(原注解)

  • @Target:注解可用于哪些位置(如 TYPE, METHOD, FIELD)

  • @Retention:注解保留到哪个阶段(SOURCE、CLASS、RUNTIME)

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface LogExecutionTime {}
    

注解处理器(Annotation Processor)

  • 编译期注解处理工具(APT),可用于代码生成
  • 实现 javax.annotation.processing.Processor 或使用 AbstractProcessor
  • 常见场景:Lombok、MapStruct、Dagger、Spring Configuration Processor
http://www.xdnf.cn/news/11897.html

相关文章:

  • 【Vue】初学Vue(setup函数,数据响应式, 脚手架 )
  • vue 打包报错 Cannot find module ‘@vue/cli-plugin-babel/preset‘ - thread-loader
  • 力扣HOT100之二分查找:74. 搜索二维矩阵
  • 查找 Vue 项目中未使用的依赖
  • HashMap中的put方法执行流程(流程图)
  • 基于 PyTorch 的 VGG16 深度学习人脸识别检测系统的实现+ui界面
  • Kafka深度技术解析:架构、原理与最佳实践
  • Solana Web3 快速入门:创建并获取钱包账户的完整指南
  • vCenter与ESXi主机每分钟周期性断连修复
  • 《最近公共祖先》题集
  • 分布式电源接入配电网的自适应电流保护系统设计与实现
  • 【Rust 高级trait】Rust trait的一些高级用法解密
  • Excel 透视表以及透视图应用(基础版)
  • 什么是梯度磁场
  • BLE-AUDIO
  • 【八股消消乐】如何解决SQL线上死锁事故
  • [Harmony]网络状态监听
  • OpenHarmony平台驱动使用(十五),SPI
  • 玄机-第六章 流量特征分析-蚂蚁爱上树
  • Kafka 单机部署启动教程(适用于 Spark + Hadoop 环境)
  • 微信小程序前端面经
  • Hot100 Day02(移动0,乘最多水的容器、三数之和、接雨水)
  • 还原Windows防火墙
  • 点评中是如何实现短信登录的
  • 【C++】AVL树的概念及实现(万字图文超详解)
  • 电路图识图基础知识-降压启动(十五)
  • Python数据可视化科技图表绘制系列教程(二)
  • java从azure中读取用户信息
  • Kafka入门- 基础命令操作指南
  • NBA名人堂之-查尔斯·巴克利|里克·巴里|罗伯特·帕里什|斯科蒂·皮蓬|戴夫·德布斯切尔