Java小型操作系统模拟(采用策略模式结合反射进行搭建,支持一些简单的命令)

Java小型操作系统模拟

    • 项目说明
    • 第一阶段:反射结合策略模式搭建基本的命令结构
    • 第二阶段:注解结合反射与策略模式,将结构进一步规范
    • 第三阶段:开启新的窗口,将控制台输入切换到新窗口中,同时创建右键菜单,使效果贴近命令行
    • 第四阶段,发现IDEA的编译与命令行编译不一致且导致类装载出错的情况进行处理--重新编写初始化的装载方法
    • 第五阶段,解决打包为jar后的装载问题及采用脚本自动编译
    • 项目下载

项目说明

主要是为了学习Java反射的知识,以及对操作系统的一些概念进行回顾,搭建了一个小型的操作系统,包括基本的一些命令,如:clear、help、cd、mkdir、ls等;同时支持用户及角色创建,密码登录等,相关文件采用加密存储在本地;同时采用资源分配的形式设计了磁盘资源和内存资源,采用首次适应、循环首次适应、最佳适应、最坏适应等策略;采用Java的Socket通信设计了简单的socket通信模式

第一阶段:反射结合策略模式搭建基本的命令结构

采用配置文件的形式指定命令的名称、描述与对应类的全路径,采用反射的形式创建对象并装载到容器中;策略模式结合HashMap的形式,可以较为方便的获取到命令对象,并执行对应的策略方法。

策略模式的体现,采用Map进行命令策略的管理

package os.strategy;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author bbyh
 * @date 2023-07-27 21:19
 * @description
 */
public abstract class BaseStrategy {
    private static final Map<String, BaseStrategy> STRATEGY_FACTORY = new HashMap<>(4);
    private static final Map<String, String> STRATEGY_DOC = new HashMap<>(4);
    private final String name;
    private final String doc;

    public BaseStrategy(String name, String doc) {
        this.name = name;
        this.doc = doc;
    }

    protected final void register() {
        STRATEGY_FACTORY.put(name, this);
        STRATEGY_DOC.put(name, doc);
    }

    public abstract void execute();

    public static BaseStrategy getStrategy(String name) {
        if (!STRATEGY_FACTORY.containsKey(name)) {
            throw new UnsupportedOperationException("该策略还不支持");
        }
        return STRATEGY_FACTORY.get(name);
    }

    public static Set<String> getCommandNameSet() {
        return new HashSet<>(STRATEGY_FACTORY.keySet());
    }

    public static Map<String, String> getCommandDoc() {
        return new HashMap<>(STRATEGY_DOC);
    }
}

采用配置文件结合反射装载对象;分为只装载指定目录,或装载指定目录及其子目录,要求都是基础策略类的子类

package os.util;

import os.strategy.BaseStrategy;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Properties;

/**
 * @author bbyh
 * @date 2023/7/28 12:19
 */
public class OsApplication {
    private static final String PACKAGE_PREFIX = "src/";
    private static final String DEFAULT_STRATEGY_PACKAGE = "strategy.impl";
    private static final String OS_COMMAND_PROPERTIES = "os-command-config.properties";
    private static final HashSet<Class<?>> CLASS_SET = new HashSet<>(4);

    private static void load() {
        for (Class<?> instance : CLASS_SET) {
            if (instance.getSuperclass() == BaseStrategy.class) {
                try (InputStream inputStream = Files.newInputStream(Paths.get(OS_COMMAND_PROPERTIES))) {
                    Properties properties = new Properties();
                    properties.load(inputStream);
                    if (properties.containsKey(instance.getName())) {
                        String[] split = properties.getProperty(instance.getName()).split(",");
                        try {
                            Constructor<?> constructor = instance.getConstructor(String.class, String.class);
                            Object newInstance = constructor.newInstance(split[0], split[1]);
                            Method register = newInstance.getClass().getSuperclass().getDeclaredMethod("register");
                            register.setAccessible(true);
                            register.invoke(newInstance);
                        } catch (NoSuchMethodException | InvocationTargetException |
                                 IllegalAccessException | InstantiationException e) {
                            throw new RuntimeException(e);
                        }
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static void runWithSpecifiedDirectory(Class<?> application) {
        initSpecifiedDirectory(application.getPackage().getName() + "." + DEFAULT_STRATEGY_PACKAGE);
        load();
    }

    private static void initSpecifiedDirectory(String scanPackage) {
        File basePackage = new File(PACKAGE_PREFIX + scanPackage.replace(".", "/"));
        File[] files = basePackage.listFiles(file -> file.getName().endsWith(".java"));
        loadClasses(scanPackage, files);
    }

    private static void loadClasses(String scanPackage, File[] files) {
        if (files != null) {
            for (File file : files) {
                try {
                    Class<?> instance = Class.forName(scanPackage + "." + file.getName().replace(".java", ""));
                    CLASS_SET.add(instance);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static void runWithRecursiveDirectory(Class<?> application) {
        initRecursiveDirectory(application.getPackage().getName());
        load();
    }

    private static void initRecursiveDirectory(String scanPackage) {
        File basePackage = new File(PACKAGE_PREFIX + scanPackage.replace(".", "/"));
        File[] files = basePackage.listFiles(file -> {
            if (file.isDirectory()) {
                initRecursiveDirectory(scanPackage + "." + file.getName());
            }
            return file.getName().endsWith(".java");
        });
        loadClasses(scanPackage, files);
    }
}

配置文件

os.strategy.impl.ClearStrategy=clear,清屏命令,清空屏幕
os.strategy.impl.HelpStrategy=help,帮助命令,查看当前系统支持的命令

项目结构
在这里插入图片描述

第二阶段:注解结合反射与策略模式,将结构进一步规范

采用类似SpringBoot的启动方式,自动装载指定目录下的命令类,采用注解的形式设置命令的名称与描述

采用注解设置启动装载包目录名,以及各个策略类的目录名称与相关说明

package os.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author bbyh
 * @date 2023/7/2 15:29
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyScan {
    String value() default "strategy.impl";
}

help命令,简单输出系统支持的命令和说明

package os.strategy.impl;

import os.annotation.StrategyAnnotation;
import os.annotation.StrategyDocAnnotation;
import os.strategy.BaseStrategy;

import java.util.Map;
import java.util.Set;

/**
 * @author bbyh
 * @date 2023-07-27 21:26
 * @description
 */
@StrategyAnnotation(commandName = "help")
@StrategyDocAnnotation(commandDoc = "帮助命令,查看当前系统支持的命令")
public class HelpStrategy extends BaseStrategy {
    public HelpStrategy(String name, String doc) {
        super(name, doc);
    }

    @Override
    public void execute() {
        System.out.println("系统支持的命令");
        Set<String> commandNameSet = BaseStrategy.getCommandNameSet();
        Map<String, String> commandDoc = BaseStrategy.getCommandDoc();
        for (String commandName : commandNameSet) {
            System.out.println(commandName + ":" + commandDoc.get(commandName));
        }
    }
}

同样加载指定目录下携带注解的策略子类,或者加载目录及其子目录的所有符合条件的类

package os.util;

import os.annotation.StrategyAnnotation;
import os.annotation.StrategyDocAnnotation;
import os.annotation.StrategyScan;
import os.strategy.BaseStrategy;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;

/**
 * @author bbyh
 * @date 2023/7/28 12:19
 */
public class OsApplication {
    private static final String PACKAGE_PREFIX = "src/";
    private static final HashSet<Class<?>> CLASS_SET = new HashSet<>(4);

    private static void load() {
        for (Class<?> instance : CLASS_SET) {
            if (instance.getSuperclass() == BaseStrategy.class) {
                try {
                    StrategyAnnotation nameAnnotation = instance.getAnnotation(StrategyAnnotation.class);
                    StrategyDocAnnotation docAnnotation = instance.getAnnotation(StrategyDocAnnotation.class);
                    if (nameAnnotation != null && docAnnotation != null) {
                        Constructor<?> constructor = instance.getConstructor(String.class, String.class);
                        Object newInstance = constructor.newInstance(nameAnnotation.commandName(), docAnnotation.commandDoc());
                        Method register = newInstance.getClass().getSuperclass().getDeclaredMethod("register");
                        register.setAccessible(true);
                        register.invoke(newInstance);
                    }
                } catch (NoSuchMethodException | InvocationTargetException |
                         IllegalAccessException | InstantiationException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 加载配置目录下的添加了StrategyAnnotation注解的类
     *
     * @param application 启动类
     */
    public static void runWithSpecifiedDirectory(Class<?> application) {
        StrategyScan strategyScan = application.getAnnotation(StrategyScan.class);
        initSpecifiedDirectory(application.getPackage().getName() + "." + strategyScan.value());
        load();
    }

    private static void initSpecifiedDirectory(String scanPackage) {
        File basePackage = new File(PACKAGE_PREFIX + scanPackage.replace(".", "/"));
        File[] files = basePackage.listFiles(file -> file.getName().endsWith(".java"));
        loadClasses(scanPackage, files);
    }

    private static void loadClasses(String scanPackage, File[] files) {
        if (files != null) {
            for (File file : files) {
                try {
                    Class<?> instance = Class.forName(scanPackage + "." + file.getName().replace(".java", ""));
                    CLASS_SET.add(instance);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 加载配置目录及其子目录下的添加了StrategyAnnotation注解的类
     *
     * @param application 启动类
     */
    public static void runWithRecursiveDirectory(Class<?> application) {
        initRecursiveDirectory(application.getPackage().getName());
        load();
    }

    private static void initRecursiveDirectory(String scanPackage) {
        File basePackage = new File(PACKAGE_PREFIX + scanPackage.replace(".", "/"));
        File[] files = basePackage.listFiles(file -> {
            if (file.isDirectory()) {
                initRecursiveDirectory(scanPackage + "." + file.getName());
            }
            return file.getName().endsWith(".java");
        });
        loadClasses(scanPackage, files);
    }
}

项目结构
在这里插入图片描述

第三阶段:开启新的窗口,将控制台输入切换到新窗口中,同时创建右键菜单,使效果贴近命令行

经过测试发现,上面两个系统在初始化加载类时有一些小问题,因为在实际使用时都是执行class文件,而在IDEA里面的执行是以Java文件为路径的,需要进行一些简单的小修改,当前这个阶段主要以IDEA里面的运行为主,后面再对路径和初始化逻辑进行一些调整,来保证兼容性

主窗体

package os.util;

import os.strategy.BaseStrategy;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.io.IOException;

/**
 * @author bbyh
 * @date 2023-07-29 15:51
 * @description
 */
public class MainFrame extends JFrame {
    public static final JLabel DISPLAY = new JLabel();
    private static final String DEFAULT_WORD_DIR = "C:\\root>";

    public MainFrame() {
        setTitle("BBYH OS System");
        setSize(1000, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        JScrollPane scrollPane = new JScrollPane(DISPLAY);
        DISPLAY.setOpaque(true);
        DISPLAY.setBackground(Color.WHITE);

        setLayout(new GridLayout(1, 1));
        add(scrollPane);
        setVisible(true);

        Font font = new Font("Consolos", Font.PLAIN, 24);
        DISPLAY.setFont(font);
        DISPLAY.setVerticalAlignment(SwingConstants.TOP);
        DISPLAY.setFocusable(true);
        init();

        // 右键菜单
        JPopupMenu rightMenu = new JPopupMenu();
        JMenuItem backgroundItem = new JMenuItem();
        JMenuItem fontItem = new JMenuItem();
        JMenuItem copyItem = new JMenuItem();

        backgroundItem.setFont(font);
        fontItem.setFont(font);
        copyItem.setFont(font);
        backgroundItem.setText("设置背景颜色");
        fontItem.setText("设置字体颜色");
        copyItem.setText("复制剪切版内容");

        rightMenu.add(backgroundItem);
        rightMenu.add(fontItem);
        rightMenu.add(copyItem);

        backgroundItem.addActionListener(evt -> {
            Color color = JColorChooser.showDialog(null, "设置背景颜色", Color.WHITE);
            if (color != null) {
                DISPLAY.setBackground(color);
            }
        });
        fontItem.addActionListener(evt -> {
            Color color = JColorChooser.showDialog(null, "设置字体颜色", Color.BLACK);
            if (color != null) {
                DISPLAY.setForeground(color);
            }
        });
        copyItem.addActionListener(evt -> {
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            Transferable transferable = clipboard.getContents(null);
            if (transferable != null) {
                if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    try {
                        String data = (String) clipboard.getData(DataFlavor.stringFlavor);
                        appendDisplay(data);
                    } catch (UnsupportedFlavorException | IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

        DISPLAY.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                char keyChar = e.getKeyChar();
                if (keyChar == KeyEvent.VK_BACK_SPACE && !"".equals(getContent())) {
                    DISPLAY.setText(getContent().substring(0, getContent().length() - 1));
                    appendDisplay("");
                } else if (keyChar == KeyEvent.VK_ENTER) {
                    appendDisplay("<br />");
                    try {
                        BaseStrategy.getStrategy(Context.getNextCommand()).execute();
                    } catch (Exception ex) {
                        appendDisplay(ex.getMessage() + "<br />");
                    }
                    appendDisplay(Context.getWorkDir());
                } else if (Character.isLetterOrDigit(keyChar)) {
                    appendDisplay(String.valueOf(keyChar));
                }
            }
        });

        DISPLAY.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    rightMenu.show(DISPLAY, e.getX(), e.getY() - 10);
                }
            }
        });
    }

    private static void init() {
        Context.setWorkDir(DEFAULT_WORD_DIR);
        appendDisplay(DEFAULT_WORD_DIR);
    }

    public static void appendDisplay(String content) {
        DISPLAY.setText("<html><body style='padding: 20px 10px'>" + getContent() + content + "</body></html>");
    }

    private static String getContent() {
        return DISPLAY.getText().replace("<html><body style='padding: 20px 10px'>", "").replace("</body></html>", "");
    }
}

Context上下文操作类

package os.util;

/**
 * @author bbyh
 * @date 2023-07-27 22:23
 * @description
 */
public class Context {
    private static String workDir;

    public static String getWorkDir() {
        return workDir;
    }

    public static void setWorkDir(String workDir) {
        Context.workDir = workDir;
    }

    public static String getNextCommand() {
        String text = MainFrame.DISPLAY.getText();
        return text.substring(text.lastIndexOf(getWorkDir()) + getWorkDir().length(), text.lastIndexOf("<br /></body></html>"));
    }
}

主程序

package os;

import os.annotation.StrategyScan;
import os.util.MainFrame;
import os.util.OsApplication;

/**
 * @author bbyh
 * @date 2023-07-27 21:18
 * @description
 */
@StrategyScan
public class Main {
    public static void main(String[] args) {
        OsApplication.runWithRecursiveDirectory(Main.class);
        new MainFrame();
    }
}

测试运行效果展示
在这里插入图片描述

第四阶段,发现IDEA的编译与命令行编译不一致且导致类装载出错的情况进行处理–重新编写初始化的装载方法

采用getResource方法获取类路径,来装在class文件,同时采用脚本来解决javac命令行执行时无法编译不被别的文件依赖的策略实现类

重新编写的装载方法,采用递归装载,装载启动类目录下及其子目录中带有注解的策略实现类

package os.util;

import os.annotation.StrategyAnnotation;
import os.annotation.StrategyDocAnnotation;
import os.strategy.BaseStrategy;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Objects;

/**
 * @author bbyh
 * @date 2023/7/28 12:19
 */
public class OsApplication {
    private static final HashSet<Class<?>> CLASS_SET = new HashSet<>(4);
    private static String BASE_PATH;

    /**
     * 加载配置目录及其子目录下的添加了StrategyAnnotation注解的类
     *
     * @param application 启动类
     */
    public static void runWithRecursiveDirectory(Class<?> application) {
        BASE_PATH = Objects.requireNonNull(application.getResource("/")).getPath();
        initRecursiveDirectory(application.getPackage().getName());
        load();
    }

    private static void initRecursiveDirectory(String packageName) {
        File[] files = new File(BASE_PATH + packageName.replace(".", System.getProperty("file.separator"))).listFiles(file -> {
            if (file.isDirectory()) {
                initRecursiveDirectory(packageName + "." + file.getName());
            }
            return file.getName().endsWith(".class");
        });
        loadClasses(packageName, files);
    }

    private static void load() {
        for (Class<?> instance : CLASS_SET) {
            if (instance.getSuperclass() == BaseStrategy.class) {
                try {
                    StrategyAnnotation nameAnnotation = instance.getAnnotation(StrategyAnnotation.class);
                    StrategyDocAnnotation docAnnotation = instance.getAnnotation(StrategyDocAnnotation.class);
                    if (nameAnnotation != null && docAnnotation != null) {
                        Constructor<?> constructor = instance.getConstructor(String.class, String.class);
                        Object newInstance = constructor.newInstance(nameAnnotation.commandName(), docAnnotation.commandDoc());
                        Method register = newInstance.getClass().getSuperclass().getDeclaredMethod("register");
                        register.setAccessible(true);
                        register.invoke(newInstance);
                    }
                } catch (NoSuchMethodException | InvocationTargetException |
                         IllegalAccessException | InstantiationException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    private static void loadClasses(String packageName, File[] files) {
        if (files != null) {
            for (File file : files) {
                try {
                    Class<?> instance = Class.forName(packageName + "." + file.getName().replace(".class", ""));
                    CLASS_SET.add(instance);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

需要注意的一点是,目前采用getResource方法对于打包为jar包时则会报空指针错误,后续将考虑采用新方法装载来解决该问题

第五阶段,解决打包为jar后的装载问题及采用脚本自动编译

自动编译的脚本,Windows

mkdir out
cd src
javac -d ../out os/Main.java os/strategy/impl/*.java -encoding UTF-8

cd ../out

java os.Main

自动编译的脚本,Linux

#!/bin/bash
mkdir out
cd src
javac -d ../out os/Main.java os/strategy/impl/*.java -encoding UTF-8
cd ../out
java os.Main

需要注意几点小问题,脚本.sh需要在Linux下创建使用,同时需要给它赋予x执行权限(chmod +x javac_os_java.sh);然后在执行时还需要对XShell安装一下图形服务x11,参考文章:xshell-linux 启动 jmeter 报 No X11 DISPLAY variable was set, but this program performed …;不过这个Xming对中文的显示有问题,有点难办

主函数(根据启动不一样采用不一样的装载策略)

package os;

import os.annotation.StrategyScan;
import os.util.MainFrame;
import os.util.OsApplication;

import java.util.Objects;

/**
 * @author bbyh
 * @date 2023-07-27 21:18
 * @description
 */
@StrategyScan
public class Main {
    public static boolean applicationRunning = true;
    private static final String FILE_PROTOCOL = "file";
    private static final String JAR_PROTOCOL = "jar";

    public static void main(String[] args) {
        String protocol = Objects.requireNonNull(OsApplication.class.getResource("")).getProtocol();
        if (Objects.equals(protocol, FILE_PROTOCOL)) {
            OsApplication.runWithRecursiveDirectory(Main.class);
        } else if (Objects.equals(protocol, JAR_PROTOCOL)) {
            OsApplication.runWithRecursiveJar(Main.class);
        }
        new MainFrame();
    }
}

装载工具类

package os.util;

import os.annotation.StrategyAnnotation;
import os.annotation.StrategyDocAnnotation;
import os.strategy.BaseStrategy;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author bbyh
 * @date 2023/7/28 12:19
 */
public class OsApplication {
    private static final HashSet<Class<?>> CLASS_SET = new HashSet<>(4);
    private static String BASE_PATH;
    public static final String FILE_SEPARATOR = "/";
    private static final String PREFIX_FILE = "file:";
    private static final String PREFIX_JAR = "jar:file:";
    private static final String SUFFIX_CLASS = ".class";

    /**
     * 加载配置目录及其子目录下的添加了StrategyAnnotation注解的类
     *
     * @param application 启动类
     */
    public static void runWithRecursiveDirectory(Class<?> application) {
        BASE_PATH = Objects.requireNonNull(application.getResource("")).toString().replace(PREFIX_FILE, "");
        String packageName = application.getPackage().getName();
        BASE_PATH = BASE_PATH.substring(0, BASE_PATH.lastIndexOf("/" + packageName + "/")) + FILE_SEPARATOR;
        initRecursiveDirectory(packageName);
        load();
    }

    private static void initRecursiveDirectory(String packageName) {
        File[] files = new File(BASE_PATH + packageName.replace(".", FILE_SEPARATOR)).listFiles(file -> {
            if (file.isDirectory()) {
                initRecursiveDirectory(packageName + "." + file.getName());
            }
            return file.getName().endsWith(SUFFIX_CLASS);
        });
        loadFileClasses(packageName, files);
    }

    private static void loadFileClasses(String packageName, File[] files) {
        if (files != null) {
            for (File file : files) {
                try {
                    Class<?> instance = Class.forName(packageName + "." + file.getName().replace(SUFFIX_CLASS, ""));
                    CLASS_SET.add(instance);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    private static void load() {
        for (Class<?> instance : CLASS_SET) {
            if (instance.getSuperclass() == BaseStrategy.class) {
                try {
                    StrategyAnnotation nameAnnotation = instance.getAnnotation(StrategyAnnotation.class);
                    StrategyDocAnnotation docAnnotation = instance.getAnnotation(StrategyDocAnnotation.class);
                    if (nameAnnotation != null && docAnnotation != null) {
                        Constructor<?> constructor = instance.getConstructor(String.class, String.class);
                        Object newInstance = constructor.newInstance(nameAnnotation.commandName().split(" ")[0], docAnnotation.commandDoc());
                        Method register = newInstance.getClass().getSuperclass().getDeclaredMethod("register");
                        register.setAccessible(true);
                        register.invoke(newInstance);
                    }
                } catch (NoSuchMethodException | InvocationTargetException |
                         IllegalAccessException | InstantiationException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static void runWithRecursiveJar(Class<?> application) {
        BASE_PATH = Objects.requireNonNull(application.getResource("")).toString().replace(PREFIX_JAR, "");
        BASE_PATH = BASE_PATH.substring(0, BASE_PATH.lastIndexOf("!/" + application.getPackage().getName() + "/")) + FILE_SEPARATOR;
        initRecursiveJar();
        load();
    }

    private static void initRecursiveJar() {
        try (JarFile jarFile = new JarFile(BASE_PATH)) {
            Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
            while (jarEntryEnumeration.hasMoreElements()) {
                JarEntry jarEntry = jarEntryEnumeration.nextElement();
                if (jarEntry.getName().endsWith(SUFFIX_CLASS)) {
                    Class<?> instance = Class.forName(jarEntry.getName().replace(SUFFIX_CLASS, "").replace("/", "."));
                    CLASS_SET.add(instance);
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

}

运行效果
在这里插入图片描述

项目下载

Gitee链接–Java模拟操作系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/52830.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

eclipse 最新版没有navigator视图如何解决

使用project exploere视图可以显示类似navigator视图 1.显示project exploere视图 window---->show view --->project exploere 2.project exploere视图转换为类似navigator视图 第一步&#xff1a;点击视图右上角三个点或者倒三角&#xff0c;点击fiters and custom…

Spring——更快捷的存储 / 获取Bean对象

文章目录 前言一、存储 Bean 对象类注解为什么有五个类注解使用类注解存储对象配置扫描路径(重中之重)添加注解存储 Bean 对象 方法注解配置扫描路径(重中之重)使用方法注解存储对象 二、获取 Bean 对象Autowired属性注入Setter注入构造方法注入 Resource 总结 前言 本人是一个…

git操作:修改本地的地址

Windows下git如何修改本地默认下载仓库地址 - 简书 (jianshu.com) 详细解释&#xff1a; 打开终端拉取git时&#xff0c;会默认在git安装的地方&#xff0c;也就是终端前面的地址。 需要将代码 拉取到D盘的话&#xff0c;现在D盘创建好需要安放代码的文件夹&#xff0c;然后…

K8S群集调度

目录 一、调度约束二、Pod 启动典型创建过程三、K8S的调度过程3.1 Predicate&#xff08;预选策略&#xff09; 常见的算法使用3.2 常见优先级选项3.3 指定调度节点3.3.1 nodeName指定3.3.2 nodeSelector指定3.3.3 Pod亲和性与反亲和1.节点亲和硬策略示例2.节点亲和软策略示例3…

数字工厂管理系统的实施步骤是什么

数字工厂管理系统是一种基于数字化技术和智能化设备的工厂管理系统&#xff0c;它可以实现工厂的全面、实时、动态管理&#xff0c;提高生产效率、降低成本、保证产品质量。实施数字工厂管理系统需要一系列的实施步骤&#xff0c;下面就数字工厂管理系统的实施步骤进行详细说明…

Is Mapping Necessary for Realistic PointGoal Navigation 论文阅读和代码分析

论文 论文信息 题目&#xff1a;Is Mapping Necessary for Realistic PointGoal Navigation? 作者&#xff1a;Ruslan Partsey、 Erik Wijmans 代码地址&#xff1a;rpartsey.github.io/pointgoalnav 来源&#xff1a;CVPR 时间&#xff1a;2022 Abstract 目标&#xff1a…

Godot在多边形内随机获取点

前言&#xff1a; 我做了一个随机生成器&#xff0c;可以生成游戏道具&#xff0c;之前是矩形比较好算&#xff0c;随着关卡设计我需要多边形的生成方式。 在矩形内获取随机点&#xff1a; func generateRandomCoordinateInRect(pos,size):"""根据范围生成随机…

记一次安装nvm切换node.js版本实例详解

最后效果如下&#xff1a; 背景&#xff1a;由于我以前安装过node.js&#xff0c;后续想安装nvm将node.js管理起来。 问题&#xff1a;nvm-use命令行运行成功&#xff0c;但是nvm-list显示并没有成功。 原因&#xff1a;因为安装过node.js&#xff0c;所以原先的node.js不收n…

二十一章:PUZZLE-CAM:通过匹配局部和全局特征来改进定位

0.摘要 弱监督语义分割&#xff08;WSSS&#xff09;被引入来缩小从像素级监督到图像级监督的语义分割性能差距。大多数先进的方法是基于类激活图&#xff08;CAM&#xff09;来生成伪标签以训练分割网络。WSSS的主要局限性在于从使用图像分类器的CAM生成伪标签的过程主要集中在…

【React Native】学习记录(一)——环境搭建

Expo是一套工具&#xff0c;库和服务&#xff0c;可让您通过编写JavaScript来构建原生iOS和Android应用程序。 一开始学习的时候直接使用的是expo。 npx create-expo-app my-appcd my-appnpm run start接下来需要搭建安卓和IOS端&#xff08;为此特意换成了苹果电脑&#xff09…

虹科案例|如何分析设备故障时间和次数,打破生产瓶颈?

虹科设备绩效管理系统 保障生产设备的稳定性和可靠性 生产设备的稳定性和可靠性是保证企业正常生产的重要条件之一&#xff0c;设备故障的频发严重影响企业的正常生产&#xff0c;那么如何分析设备故障时间和次数&#xff0c;查找设备故障原因&#xff0c;协助企业打破生产瓶…

【Spring Cloud】Gateway的配置与使用

文章目录 前言第一步&#xff0c;创建一个springboot工程第二步&#xff0c;添加依赖第三步&#xff0c;编写yml文件第四步&#xff0c;启动主启动类总结 前言 Gateway其实是springcloud 原生的东西&#xff0c;但是我还是想放在这里讲&#xff0c;因为我们使用nacos时&#x…

【腾讯云 Cloud Studio 实战训练营】CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手!

CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01; 文章目录 CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01;前言出现的背景一、CloudStudio 是什么&#xff1f;二、CloudStudio 的特点三、CloudS…

Mac 快速生成树形项目结构目录

我这里使用的是通过包管理 Homebrew安装形式。没有安装的话可以自行搜索 Homebrew 安装方式 brew install tree直接到项目的根目录执行 tree 命令 tree 效果如下&#xff1a; or &#xff1a; tree -CfL 3效果如下&#xff1a;

2023-07-27 LeetCode每日一题(删除每行中的最大值)

2023-07-27每日一题 一、题目编号 2500. 删除每行中的最大值二、题目链接 点击跳转到题目位置 三、题目描述 给你一个 m x n 大小的矩阵 grid &#xff0c;由若干正整数组成。 执行下述操作&#xff0c;直到 grid 变为空矩阵&#xff1a; 从每一行删除值最大的元素。如果…

LeetCode130.Surrounded-Regions<被围绕的区域>

题目&#xff1a;被围绕的区域 思路&#xff1a; 好吧&#xff0c;这题不会。 bfs递归 dfs非递归 dfs并查集 - 被围绕的区域 - 力扣&#xff08;LeetCode&#xff09; 将问题转化为与边界O相连的O。有点像岛屿问题了。 代码是&#xff1a; //codeclass Solution { public:vo…

8.事件对象

8.1获取事件对象 ●事件对象是什么 也是个对象&#xff0c;这个对象里有事件触发时的相关信息 例如&#xff1a;鼠标点击事件中&#xff0c;事件对象就存了鼠标点在哪个位置等信息 ●使用场景 可以判断用户按下哪个键&#xff0c;比如按下回车键可以发布新闻 可以判断鼠标点击…

绝绝子,这所211无歧视!极其保护一志愿!专硕爆冷全部录取!

一、学校及专业介绍 大连海事大学&#xff08;Dalian Maritime University&#xff09;&#xff0c;简称海大&#xff0c;位于辽宁省大连市&#xff0c;是中华人民共和国交通运输部所属的全国重点大学&#xff0c;位列国家“双一流”、“211工程”重点建设高校。 1.1 招生情况…

SQL-每日一题【1070. 产品销售分析 III】

题目 销售表 Sales&#xff1a; 产品表 Product&#xff1a; 编写一个 SQL 查询&#xff0c;选出每个销售产品 第一年 销售的 产品 id、年份、数量 和 价格。 结果表中的条目可以按 任意顺序 排列。 查询结果格式如下例所示&#xff1a; 示例 1&#xff1a; 解题思路 前置知…