如何使用ASM将类的protected、包私有字段修改为public
字节码修改实现方案
你可以通过ASM字节码操作框架完成成员访问权限的修改,完整实现逻辑如下:
1. 核心修改逻辑
你需要遍历目标类的所有字段、方法,将非private的访问修饰符(protected、包私有)替换为public,访问修饰符的判断基于字节码中的访问标志位实现。
首先自定义字节码访问器:
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class AccessRepairVisitor extends ClassVisitor { public AccessRepairVisitor(ClassVisitor classVisitor) { // ASM版本根据你兼容的JDK版本选择,ASM9支持到JDK17+ super(Opcodes.ASM9, classVisitor); } // 修改字段访问权限 @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { // 排除private成员,将其余所有成员改为public if ((access & Opcodes.ACC_PRIVATE) == 0) { access = Opcodes.ACC_PUBLIC; } return super.visitField(access, name, descriptor, signature, value); } // 修改方法访问权限 @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { // 构造方法、普通方法统一处理,排除private成员 if ((access & Opcodes.ACC_PRIVATE) == 0) { access = Opcodes.ACC_PUBLIC; } return super.visitMethod(access, name, descriptor, signature, exceptions); } }
2. 补全loadClass方法
将修改后的字节码通过defineClass方法加载为Class对象即可:
@Override public Class<?> loadClass(String className) throws ClassNotFoundException { if (! this.needsAccessRepair(className)) return super.loadClass(className); try (InputStream unmodified = this.getResourceAsStream(className.replace(".", "/") + ".class")) { if (unmodified == null) { throw new ClassNotFoundException("类资源不存在: " + className); } // 读取原始字节码 byte[] rawClassBytes = unmodified.readAllBytes(); // 执行字节码修改 ClassReader classReader = new ClassReader(rawClassBytes); ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES); classReader.accept(new AccessRepairVisitor(classWriter), 0); byte[] modifiedClassBytes = classWriter.toByteArray(); // 加载修改后的类 return defineClass(className, modifiedClassBytes, 0, modifiedClassBytes.length); } catch (Exception e) { throw new ClassNotFoundException("修改类权限失败: " + className, e); } }
3. 注意事项
- ASM版本需要和你处理的类的编译JDK版本匹配,处理JDK8的类用ASM5以上即可,处理JDK17+的类需要用ASM9以上版本。
- 如果需要连
private成员也修改为public,直接去掉访问权限判断的条件即可。 - 如果你需要修改JDK核心类库的类,需要打破双亲委派模型才能生效,普通业务类无需额外处理。
- 修改完成后要保证类的父类、依赖的接口已经被对应类加载器加载,避免链接错误。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

