模块一:泛型深入 ⭐⭐⭐⭐⭐

面试题
什么是泛型?为什么要有泛型?
泛型的类型擦除是什么?
<? extends T><? super T> 的区别?

泛型是 JDK 5 引入的参数化类型机制,允许在定义类、接口、方法时使用类型参数。

为什么要有泛型?
  • 类型安全:编译期检查类型,避免 ClassCastException

  • 消除强转:不用每次都 (String) list.get(0)

  • 代码复用:一套代码适配多种类型

// 没有泛型:需要强转,运行时可能报错
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);  // 繁琐且危险
​
// 有泛型:编译期检查,无需强转
List<String> list2 = new ArrayList<>();
list2.add("hello");
String s2 = list2.get(0);  // 直接使用

泛型的类型擦除是什么?

Java 的泛型是伪泛型,只在编译期存在,运行时会被擦除为原始类型(通常是 Object)。

为什么要做类型擦除?
  • 向后兼容:JDK 5 引入泛型时,需要兼容 JDK 1.4 的代码

  • 实现简单:不需要修改 JVM 指令

// 编译前
List<String> list = new ArrayList<>();
list.add("hello");
​
// 编译后(类型擦除后)
List list = new ArrayList();
list.add("hello");

<? extends T><? super T> 的区别?

通配符 含义 读取 写入
<? extends T> 上界通配符,T 或 T 的子类 可以(返回 T) 不行(不知道具体类型)
<? super T> 下界通配符,T 或 T 的父类 不行(返回 Object) 可以(写入 T 或 T 子类)

// extends:只能读,不能写
List<? extends Number> list1 = new ArrayList<Integer>();
Number n = list1.get(0);  // 
list1.add(1);  //  编译报错
​
// super:只能写,不能(精确)读
List<? super Integer> list2 = new ArrayList<Number>();
list2.add(1);  // 
Integer i = list2.get(0);  //  编译报错,只能返回 Object


模块二:Java 8 新特性 ⭐⭐⭐⭐⭐
面试题
Java 8 有哪些新特性?
Lambda 表达式和函数式接口是什么?
常用的函数式接口有哪些?
Stream API 怎么用?mapflatMap 区别?
Optional 的作用是什么?
方法引用有哪几种?

Java 8 有哪些新特性?
  1. Lambda 表达式:匿名函数简化代码 ()->{}

    // Lambda 写法
    Runnable r2 = () -> System.out.println("hello");

  2. 函数式接口:只有一个抽象方法的接口 只有一个抽象方法的接口,用 @FunctionalInterface 标记

    // 函数式接口
    @FunctionalInterface
    interface MyFunc<T> {
        T apply(T t);
    }
  3. Stream API:集合操作的流式处理

    List<String> list = Arrays.asList("apple", "banana", "cherry");
    ​
    // filter + map + collect
    List<String> result = list.stream()
        .filter(s -> s.length() > 5)     // 过滤
        .map(String::toUpperCase)        // 转换
        .sorted()                        // 排序
        .collect(Collectors.toList());   // 收集
    ​
    map vs flatMap:
        map:一对一转换,返回单个值
    flatMap:一对多转换,返回 Stream 并扁平化
        
        // map:List<String> -> List<Integer>(长度)
    List<Integer> lengths = list.stream()
        .map(String::length)
        .collect(Collectors.toList());
    ​
    // flatMap:List<List<String>> -> List<String>(扁平化)
    List<List<String>> nested = Arrays.asList(
        Arrays.asList("a", "b"),
        Arrays.asList("c", "d")
    );
    //[ [a,b],[c,d] ]
    List<String> flat = nested.stream()
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
    // 结果:[a, b, c, d]

  4. Optional:优雅处理空指针

    // 传统写法
    if (user != null) {
        Address addr = user.getAddress();
        if (addr != null) {
            String city = addr.getCity();
        }
    }
    ​
    // Optional 写法
    Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("default");
    ​
    of(value)   创建非空 Optional
    ofNullable(value)   创建可空 Optional
    orElse(default) 为空时返回默认值
    orElseGet(supplier) 为空时执行函数
    map(func)   转换值
    ifPresent(consumer) 有值时执行
    ​

  5. 方法引用:简化 Lambda

  6. 新日期 APILocalDate/LocalDateTime

  7. 接口默认方法default 关键字


模块三:对象创建与序列化 ⭐⭐⭐⭐
面试题
Java 创建对象有几种方式?
Serializabletransient 的作用?
serialVersionUID 的作用?
Comparable 和 Comparator 的区别?

Java 创建对象有几种方式?
// 1. new
User user = new User(); //日常开发
​
// 2. 反射
User user = User.class.getDeclaredConstructor().newInstance();  //框架ioc
​
// 3. clone
User user = (User) original.clone(); //对象复制
​
// 4. 反序列化
ObjectInputStream ois = new ObjectInputStream(...); //高性能框架
User user = (User) ois.readObject();

序列化/反序列化 概念

序列化 = 把内存里的对象 → 变成一串可存储 / 可传输的字节数据

反序列化 = 把字节数据 → 恢复成内存里的对象

Serializabletransient 的作用?
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private transient String password;  // 不会被序列化
    private static int count;  // 静态变量不会被序列化
}

serialVersionUID 的作用?

序列化版本号,用于版本兼容性检查。

不写会怎样?

  • JVM 会根据类的结构自动生成

  • 类结构变化后,反序列化会失败(InvalidClassException

建议:显式声明,避免类结构变化导致反序列化失败

private static final long serialVersionUID = 1L;  // 固定版本号

Comparable 和 Comparator 的区别?

特性 Comparable Comparator
位置 类内部实现 外部独立实现
方法 compareTo(T o) compare(T o1, T o2)
耦合性 侵入性强 无侵入
灵活性 只有一种排序 可定义多种排序

模块五:设计模式基础

代理的概念

你写好了原方法(比如下单、查数据),想在方法执行前后加代码(打日志、开事务、判权限),又不想改原来的代码,就用代理帮你插代码。

JDK 动态代理 和 CGLIB动态代理

JDK:实现接口 做替身

CGLIB:继承父类 做替身

能用 JDK 的情况
// 有接口 → 能用JDK
interface A{}
class B implements A{}
​
不能用 JDK,只能用 CGLIB
// 光秃秃一个类,没接口 → JDK直接废,只能CGLIB
class C{}

JDK 动态代理基于接口,目标类必须实现接口

CGLIB 动态代理基于继承,无需接口

Spring:无接口用 CGLIB,现在默认全部 CGLIB

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐