一、准备工作

复制一份jre到新的路径。使用新jre的命令运行jar包,输出所有使用的类。

.\jre\bin\java.exe -jar -verbose:class javafx-start-1.0.jar >>class.txt

此步骤尽可能的点击使用所有的功能。

运行时可先精简bin目录。进入目录删除所有文件,提示占用的即不能删除的,其余都删除。

生成class.txt文件后,里边会提示打开什么jar包。此处以精简rt为例。

/**
 * FileName: FileUtil
 * Date:     2022/9/16 16:54
 * Description:
 * History:
 */
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author aaa
 * @create 2022/9/16
 * @since 1.0.0
 */
public class FileUtil {

/**
 * @author soil
 */


    public static void main(String[] args) {
//        selectRtJar();
        getReplaceAllClass();
    }

    public static void getReplaceAllClass(){
        String sourse = "E:\\test/dytest/class_rt.txt";
        String outAddress = "E:\\test/dytest/class_demo2.txt";
        try {
            int count_L = 0;
            int loopCount = 0;
            // 源文件位置,打开它
            FileInputStream fin = new FileInputStream(sourse);
            InputStreamReader isr = new InputStreamReader(fin);
            BufferedReader br = new BufferedReader(isr);
            // 输出文件位置
            FileOutputStream fout = new FileOutputStream(outAddress);
            OutputStreamWriter osw = new OutputStreamWriter(fout);
            BufferedWriter bw = new BufferedWriter(osw);
            // 读一行
            String sp = br.readLine();
            // 只要没有读到文件尾就一直执行
            while (sp != null) {
                // 只读取以"[L"为开头的行
                if (sp.substring(0, 2).equals("[L")) {
                    // 以空格来分隔这个行,返回的字符串数组中的第二个就是我们需要的信息
                    String s = sp.split(" ")[1];
                    StringBuilder bs = new StringBuilder(s);
                    // 只是个测试输出,可以不加
                    System.out.println(bs);
                    // 循环遍历这个字符串,修改它,使它变成我们需要的格式
                    for (int i = 0; i < bs.length(); i++) {
                        char ch = bs.charAt(i);
                        // 简化循环,因为我们得到的信息很有规律。只要出现大写的字母,就说明已经到了不需要执行的时候了。
                        if (ch >= 65 && ch < 91)
                            break;
                        // 把'.'替换成'/',当然,代码中是因为方法的参数要求。
                        if (ch == '.') {
                            bs.replace(i, i + 1, "/");
                        }
                        // 这个是循环的执行此时。
                        loopCount++;
                    }
                    // 这里在输出你的文件信息。加工后用于后续操作。
                    bw.write(bs.toString() + '\n');
                    // 程序需要的类文件数目。
                    count_L++;
                }
                // 读行
                sp = br.readLine();
            }
            // 两个测试输出
            System.out.println(count_L);
            System.out.println(loopCount);
            br.close();
            bw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void selectRtJar(){

        String sourse = "E:\\test/dytest/class.txt";
        String outAddress = "E:\\test/dytest/class_rt.txt";
        FileInputStream fin = null;
        InputStreamReader isr= null;
        BufferedReader br= null;
        FileOutputStream fout= null;
        OutputStreamWriter osw= null;
        BufferedWriter bw= null;
        try{
            fin = new FileInputStream(sourse);
            isr = new InputStreamReader(fin);
            br = new BufferedReader(isr);
            // 输出文件位置
            fout = new FileOutputStream(outAddress);
            osw = new OutputStreamWriter(fout);
            bw = new BufferedWriter(osw);
            // 读一行
            String sp = br.readLine();
            // 只要没有读到文件尾就一直执行
            while (sp != null) {
                if (sp.contains("lib\\rt.jar")) {
                    bw.write(sp + '\n');
                }
                sp = br.readLine();
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(br!=null){
                    br.close();
                }
                if(bw!=null){
                    bw.close();
                }
                if(osw!=null){
                    osw.close();
                }
                if(fout!=null){
                    fout.close();
                }
                if(isr!=null){
                    isr.close();
                }
                if(fin!=null){
                    fin.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }

}

首先使用第一个方法selectRtJar()挑选出所有使用rtjar的类。

在用第二个方法getReplaceAllClass();将所有的类路径转化删除多余最后输出一份斜杠形式的文件夹路径。

二、操作复制打包rt等

进入lib目录,解压rt.jar文件。

运行如下类方法:

/**
 *
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author aaa
 *
 */
public class CopyClass {
    private String source = "E:\\test\\jre\\lib/"; // 类源目录
    private String dest = "E:\\test\\jre\\lib/"; // 类拷贝目的目录
    String[] jarArr = new String[] { "rt", "charsets" };

    /***
     *
     * @param source
     *            类源目录
     * @param dest
     *            类拷贝目的目录
     * @param jarArr
     *            需要的提取的jar文件
     */
    public CopyClass(String source, String dest, String[] jarArr) {
        this.source = source;
        this.dest = dest;
        this.jarArr = jarArr;
    }

    public static void main(String[] args) {
        String[] jarArr = new String[] { "rt"};
        CopyClass obj = new CopyClass("E:\\test/dytest\\jre\\lib/",
                "E:\\test/dytest\\jre\\lib/", jarArr);
        obj.readAndCopy("E:\\test/dytest/class_demo2.txt");
    }

    /***
     * @param logName
     *            提取class明细
     */
    public void readAndCopy(String logName) {
        int count = 0; // 用于记录成功拷贝的类数
        try {
            FileInputStream fi = new FileInputStream(logName);
            InputStreamReader ir = new InputStreamReader(fi);
            BufferedReader br = new BufferedReader(ir);

            String string = br.readLine();
            while (string != null) {
                if (copyClass(string) == true){
                    count++;
                } else{
                    System.out.println("ERROR " + count + ": " + string);
                }
                string = br.readLine();
            }
            br.close();
        } catch (IOException e) {
            System.out.println("ERROR: " + e);
        }
        System.out.println("count: " + count);

    }

    /**
     * 从原jar路径提取相应的类到目标路径,如将java/lang/CharSequence类从rt目录提取到rt1目录
     *
     * @param string
     *            提取类的全路径
     * @return
     * @throws IOException
     */
    public boolean copyClass(String string) throws IOException {
        String classDir = string.substring(0, string.lastIndexOf("/"));
        String className = string.substring(string.lastIndexOf("/") + 1, string.length()) + ".class";

        FileOutputStream fout;
        FileInputStream fin;
        boolean result = false;

        for (String jar : jarArr) {
            File srcFile = new File(source + "/" + jar + "/" + classDir + "/" + className);
            if (!srcFile.exists()) {
                continue;
            }

            byte buf[] = new byte[256];
            fin = new FileInputStream(srcFile);

            /* 目标目录不存在,创建 */
            File destDir = new File(dest + "/" + jar + "1/" + classDir);
            if (!destDir.exists())
                destDir.mkdirs();

            File destFile = new File(destDir + "/" + className);
            fout = new FileOutputStream(destFile);
            int len = 0;
            while ((len = fin.read(buf)) != -1) {
                fout.write(buf, 0, len);
            }
            fout.flush();
            result = true;
            break;
        }
        return result;
    }
}

改路径为自己的jre路径,运行之后会自动生成相关的rt1文件目录,如出现复制错误手动转移相关类。

进入rt1目录cmd。

运行命令 jar cvf rt.jar .

打包当前缩减后的jar,复制rt.jar到lib目录。

.\jre\bin\java.exe -jar javafx-start-1.0.jar

在此运行程序看是否可以执行。

如提示找不到main方法等,可以在复制java/lang,java/util,java/security这三个文件夹替换掉,如果还不行,再把sun/reflect,sun/misc,sun/security也替换掉!