1. Java模块化系统(JPMS)的requires transitive
作用
问题:如何在模块化项目中传递依赖?
解析:
- **
requires transitive
**:声明模块的依赖可被下游模块隐式继承。 - 示例:模块A依赖模块B并添加
transitive
,模块C依赖模块A时自动获得模块B的访问权限。
避坑:避免滥用传递依赖,导致模块间耦合过高。
2. Java 11+的HttpClient
与传统HttpURLConnection
的对比
问题:为什么推荐使用新版HttpClient
?
解析:
- 优势:支持HTTP/2、异步请求、响应式流处理。
- 核心类:
HttpRequest
、HttpClient
、HttpResponse
。
代码示例:
java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
3. 匿名内部类持有外部类引用导致的内存泄漏
问题:为什么匿名内部类可能引发内存泄漏?
解析:
- 隐式引用:匿名内部类默认持有外部类的
this
引用,若内部类生命周期长于外部类(如异步任务),外部类无法被回收。
避坑:使用静态内部类或弱引用(WeakReference
)隔离外部类引用。
4. 动态代理的底层实现与ASM/Javassist的关系
问题:JDK动态代理和CGLIB动态代理底层如何生成字节码?
解析:
- JDK动态代理:基于
Proxy
类生成实现接口的代理类(通过反射)。 - CGLIB:基于ASM或Javassist库直接操作字节码,支持无接口的类代理。
性能对比:CGLIB生成代理类速度较慢,但调用效率更高。
5. Unsafe
类的危险操作与使用场景
问题:为什么Unsafe
类被称为“后门”?
解析:
- 危险能力:直接操作内存(
allocateMemory
)、绕过构造函数创建对象(allocateInstance
)、修改私有字段(putObject
)。 - 使用场景:高性能框架(如Netty、Hadoop)用于堆外内存管理。
避坑:Java 9+需通过--add-opens
开启模块访问权限。
6. 元注解@Inherited
的继承范围限制
问题:@Inherited
注解是否能被接口实现类继承?
解析:
- 限制:
@Inherited
仅对类注解生效,接口上的注解无法被子类继承。
示例:
java
@Inherited
@Target(ElementType.TYPE)
@interface MyAnnotation {}
@MyAnnotation
class Parent {}
class Child extends Parent {} // Child类继承MyAnnotation
@MyAnnotation
interface MyInterface {}
class Impl implements MyInterface {} // Impl类不继承MyAnnotation
7. try-with-resources
的异常抑制机制
问题:多个资源关闭时异常如何处理?
解析:
- 异常抑制:若
try
块和资源关闭均抛异常,关闭时的异常会被添加到主异常的suppressed
数组中(通过Throwable.getSuppressed()
获取)。
代码验证:
java
try (AutoCloseable ac1 = () -> { throw new IOException("Close1"); };
AutoCloseable ac2 = () -> { throw new IOException("Close2"); }) {
throw new RuntimeException("Main");
} catch (Exception e) {
System.out.println(e.getMessage()); // "Main"
Arrays.stream(e.getSuppressed()).forEach(s -> System.out.println(s.getMessage())); // Close2, Close1
}
8. 记录类(Records)的隐式限制
问题:为什么Records类不能继承其他类?
解析:
- 设计约束:Records隐式继承
java.lang.Record
,而Java不支持多继承。 - 其他限制:
- 字段隐式
final
,不可修改; - 无法定义实例初始块(Instance Initializer)。
- 字段隐式
9. 动态类加载与类加载器命名空间隔离
问题:同一类被不同类加载器加载是否会导致ClassCastException
?
解析:
- 类加载器隔离:不同类加载器加载的同一个类,JVM视为不同类。
示例:
java
ClassLoader loader1 = new URLClassLoader(...);
ClassLoader loader2 = new URLClassLoader(...);
Class<?> clazz1 = loader1.loadClass("com.example.MyClass");
Class<?> clazz2 = loader2.loadClass("com.example.MyClass");
System.out.println(clazz1 == clazz2); // false
10. 本地方法(Native Method)的安全隐患
问题:为什么滥用JNI可能导致JVM崩溃?
解析:
- 直接内存操作:本地方法绕过JVM内存管理,错误操作(如野指针、内存泄漏)会导致JVM不稳定。
- 线程安全:本地方法未正确同步可能引发并发问题。
避坑:严格限制本地方法使用,优先使用Java API实现功能。