八股文-——java基础篇(3)
模块一:泛型深入 ⭐⭐⭐⭐⭐
| 面试题 |
|---|
| 什么是泛型?为什么要有泛型? |
| 泛型的类型擦除是什么? |
<? 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 怎么用?map 和 flatMap 区别? |
| Optional 的作用是什么? |
| 方法引用有哪几种? |
Java 8 有哪些新特性?
Lambda 表达式:匿名函数简化代码 ()->{}
// Lambda 写法 Runnable r2 = () -> System.out.println("hello");函数式接口:只有一个抽象方法的接口 只有一个抽象方法的接口,用
@FunctionalInterface标记// 函数式接口 @FunctionalInterface interface MyFunc<T> { T apply(T t); }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]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) 有值时执行 方法引用:简化 Lambda
新日期 API:
LocalDate/LocalDateTime接口默认方法:
default关键字
模块三:对象创建与序列化 ⭐⭐⭐⭐
| 面试题 |
|---|
| Java 创建对象有几种方式? |
Serializable 和 transient 的作用? |
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();
序列化/反序列化 概念
序列化 = 把内存里的对象 → 变成一串可存储 / 可传输的字节数据
反序列化 = 把字节数据 → 恢复成内存里的对象
Serializable 和 transient 的作用?
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
更多推荐




所有评论(0)