这个系列课程是面向已经掌握Java基础语法的开发者设计的进阶训练营,重点解决实际开发中那些教科书里不会讲但工作中一定会遇到的痛点问题。我在带Java新人团队时发现,很多开发者虽然能写基础代码,但遇到泛型擦除、注解处理器、反射动态代理这些"熟悉的陌生人"时就会手足无措——这正是本课程要攻克的技术高地。
以泛型为例,表面上看就是个类型参数化的语法糖,但当你需要:
List<String>这种基础用法是远远不够的。课程会通过MyBatis源码解析+手写迷你ORM框架的实战,让你真正掌握类型擦除背后的实现原理和应对方案。类型擦除不是简单的删除类型信息,JVM在编译阶段会进行两个关键操作:
java复制// 源码
public class Box<T extends Number> {
private T value;
public void set(T val) { this.value = val; }
}
// 编译后(通过javap -p查看)
public class Box {
private Number value;
public void set(Number val) { ... }
// 编译器生成的桥接方法
public synthetic void set(Object val) {
set((Number)val);
}
}
开发实战技巧:
ParameterizedType接口:java复制Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
Type actualType = ((ParameterizedType)type).getActualTypeArguments()[0];
}
java复制// 错误示范:直接创建泛型数组会触发ClassCastException
T[] arr = new T[10];
// 正确做法:使用Array.newInstance结合类型标记
public <T> T[] createArray(Class<T> clazz, int size) {
return (T[]) Array.newInstance(clazz, size);
}
注解处理器的核心价值在于编译期代码生成和验证。以手写Lombok的@Getter为例:
java复制@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface MyGetter {}
java复制@SupportedAnnotationTypes("com.example.MyGetter")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyGetterProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(MyGetter.class)) {
// 生成getter方法代码
String fieldName = element.getSimpleName().toString();
String methodName = "get" + fieldName.substring(0,1).toUpperCase()
+ fieldName.substring(1);
// 使用JavaPoet等工具生成方法...
}
return true;
}
}
避坑指南:
META-INF/services/javax.annotation.processing.Processor文件FilerAPI创建新源文件时要注意处理重复生成问题直接上基准测试数据(JMH测试,纳秒/操作):
| 操作类型 | 直接调用 | 反射调用 | 反射+setAccessible | MethodHandle |
|---|---|---|---|---|
| 普通方法调用 | 15 | 1200 | 800 | 50 |
| 字段访问 | 12 | 950 | 600 | 40 |
| 构造函数调用 | 20 | 1500 | 1000 | 70 |
优化方案对比:
Method/Field对象(基础优化)setAccessible(true)跳过访问检查(有安全风险)MethodHandle(需要JVM 7+)动态代理的典型应用场景:
java复制public class DebugProxy implements InvocationHandler {
private Object target;
public static Object newInstance(Object obj) {
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new DebugProxy(obj));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
}
Tomcat打破双亲委派的经典实现:
java复制class WebappClassLoader extends URLClassLoader {
protected Class<?> loadClass(String name, boolean resolve) {
// 1. 检查本地已加载类
Class<?> clazz = findLoadedClass(name);
if (clazz != null) return clazz;
// 2. 优先自己加载WEB-INF/classes和WEB-INF/lib下的类
try {
clazz = findClass(name);
if (clazz != null) return clazz;
} catch (ClassNotFoundException e) {
// ignore
}
// 3. 最后委派给父加载器
return super.loadClass(name, resolve);
}
}
热加载实现关键点:
-XX:+TraceClassUnloading监控类卸载情况ASM修改方法体的典型流程:
java复制ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if ("targetMethod".equals(name)) {
return new MethodVisitor(Opcodes.ASM7, mv) {
@Override
public void visitCode() {
// 在方法开始插入代码
visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
visitLdcInsn("Method entered!");
visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
super.visitCode();
}
};
}
return mv;
}
};
cr.accept(cv, ClassReader.EXPAND_FRAMES);
byte[] newBytes = cw.toByteArray();
以手写简单锁为例展示AQS核心逻辑:
java复制class MyLock {
private final Sync sync = new Sync();
private static class Sync extends AbstractQueuedSynchronizer {
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
public void lock() { sync.acquire(1); }
public void unlock() { sync.release(1); }
}
异步任务编排的几种典型模式:
java复制// 1. 并行执行后合并结果
CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> queryA());
CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> queryB());
futureA.thenCombine(futureB, (a, b) -> a + b)
.thenAccept(System.out::println);
// 2. 异常处理流水线
CompletableFuture.supplyAsync(() -> parseJson(input))
.exceptionally(ex -> {
log.error("Parse failed", ex);
return defaultValue;
})
.thenApplyAsync(data -> process(data))
.handle((result, ex) -> {
if (ex != null) return fallbackResult;
return result;
});
// 3. 超时控制方案
CompletableFuture.supplyAsync(() -> longTimeTask())
.completeOnTimeout(defaultValue, 2, TimeUnit.SECONDS)
.thenAccept(result -> { ... });
核心实现步骤:
java复制public void scan(String basePackage) throws Exception {
String path = basePackage.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
if (url.getProtocol().equals("file")) {
File dir = new File(url.toURI());
for (File file : dir.listFiles()) {
if (file.getName().endsWith(".class")) {
String className = basePackage + "." +
file.getName().replace(".class", "");
Class<?> clazz = classLoader.loadClass(className);
if (clazz.isAnnotationPresent(Component.class)) {
registerBean(clazz);
}
}
}
}
}
}
java复制private void injectDependencies(Object instance, Class<?> clazz) throws Exception {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
Object dependency = getBean(field.getType());
field.setAccessible(true);
field.set(instance, dependency);
}
}
}
java复制private final ThreadLocal<Set<String>> dependencyStack = ThreadLocal.withInitial(HashSet::new);
public Object getBean(Class<?> type) throws Exception {
String beanName = type.getSimpleName();
if (dependencyStack.get().contains(beanName)) {
throw new IllegalStateException("Circular dependency detected: " +
String.join(" -> ", dependencyStack.get()) + " -> " + beanName);
}
dependencyStack.get().add(beanName);
try {
// ...正常创建bean逻辑
} finally {
dependencyStack.get().remove(beanName);
}
}