You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

安卓应用分析:如何分析Jar内Class文件并反编译为Java文件

解决方案

1 Jar解压性能优化

现有代码速度慢的核心原因是采用了单字节读写模式,is.read()每次仅读取1字节,IO交互次数极高,在处理大体积Jar文件时性能会非常差。同时原代码仅调用mkdir(),会出现父目录不存在时创建子目录失败的问题。
优化后的代码如下,采用8KB缓冲区批量读写,同时补充目录层级创建逻辑:

import java.io.*;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarExtractor {
    private static final int BUFFER_SIZE = 8192; // 可根据硬件配置调整缓冲区大小

    public void extractJar(String jarFilePath, String destDirPath) throws IOException {
        File destDir = new File(destDirPath);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }

        try (JarFile jar = new JarFile(jarFilePath)) {
            Enumeration<JarEntry> enumEntries = jar.entries();
            byte[] buffer = new byte[BUFFER_SIZE];

            while (enumEntries.hasMoreElements()) {
                JarEntry entry = enumEntries.nextElement();
                File entryFile = new File(destDir, entry.getName());

                if (entry.isDirectory()) {
                    entryFile.mkdirs(); // 递归创建所有层级父目录
                    continue;
                }

                // 提前创建当前文件的父目录,避免写入失败
                entryFile.getParentFile().mkdirs();

                try (InputStream is = jar.getInputStream(entry);
                     FileOutputStream fos = new FileOutputStream(entryFile)) {
                    int readLen;
                    while ((readLen = is.read(buffer)) != -1) {
                        fos.write(buffer, 0, readLen);
                    }
                }
            }
        }
    }
}

优化后解压速度可以提升数十倍,同时解决了目录创建失败的异常问题。

2 Class文件反编译为Java文件实现

jd-core可以正常实现批量反编译,多数运行失败是因为依赖引入错误或者调用方式不对。可以直接在内存中处理Jar中的Class字节流,不需要先落地到本地磁盘,进一步提升处理效率。
jd-core的调用示例如下,需先引入对应版本的jd-core依赖:

import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
import org.jd.core.v1.api.loader.Loader;
import org.jd.core.v1.api.loader.LoaderException;
import org.jd.core.v1.api.printer.Printer;
import org.jd.core.v1.service.printer.PlainTextPrinter;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.io.*;

// 自定义Loader从Jar字节流加载Class
public class JarEntryLoader implements Loader {
    private final JarFile jarFile;

    public JarEntryLoader(JarFile jarFile) {
        this.jarFile = jarFile;
    }

    @Override
    public byte[] load(String internalName) throws LoaderException {
        try {
            JarEntry entry = jarFile.getJarEntry(internalName + ".class");
            if (entry == null) return null;
            try (InputStream is = jarFile.getInputStream(entry)) {
                return is.readAllBytes();
            }
        } catch (IOException e) {
            throw new LoaderException(e);
        }
    }

    @Override
    public boolean canLoad(String internalName) {
        return jarFile.getJarEntry(internalName + ".class") != null;
    }
}

// 反编译调用逻辑
public void decompileJar(String jarFilePath, String outputJavaDir) throws Exception {
    File outputDir = new File(outputJavaDir);
    outputDir.mkdirs();

    try (JarFile jarFile = new JarFile(jarFilePath)) {
        Loader loader = new JarEntryLoader(jarFile);
        ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();

        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
                continue;
            }
            // 去掉.class后缀得到内部类名
            String internalName = entry.getName().substring(0, entry.getName().length() - 6);
            Printer printer = new PlainTextPrinter();
            decompiler.decompile(loader, printer, internalName);
            String javaSource = printer.toString();
            
            // 写入.java文件
            File javaFile = new File(outputDir, internalName + ".java");
            javaFile.getParentFile().mkdirs();
            try (FileWriter writer = new FileWriter(javaFile)) {
                writer.write(javaSource);
            }
        }
    }
}

如果对jd-core的反编译效果不满意,也可以替换为Fernflower反编译器,它是IntelliJ IDEA默认集成的反编译器,对复杂语法、Lambda表达式的反编译准确率更高,调用逻辑和上述流程类似。

内容的提问来源于stack exchange,提问作者LeeTi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:45:00