如何通过双击图标来执行JAVA程序?

6
我写了一个Java程序。现在我想通过双击桌面上的可执行版本来打开我的控制台Java应用程序,而不需要使用IDE、Eclipse等。我已经将Java项目导出为Runnable .JAR文件,但无法打开。当我尝试使用cmd打开应用程序时,输入"java -jar ApplicatonName.jar",一切都很好。但这个过程太复杂,也不够用户友好。因此,有没有可能使用Java实现这样的功能呢?提前感谢您的帮助 :)

也许可以看看Launch4j - Mike Christensen
1
这将取决于操作系统与 *.jar 相关联的方式。另一个问题是,通常情况下,双击图标与基于 GUI 的应用程序相关联,而不是控制台应用程序,因此双击图标可能看起来没有任何反应,但应用程序已经启动,只是没有显示任何内容... - MadProgrammer
3个回答

5
根据操作系统创建一个batsh文件,将java -jar ApplicationName.jar放入该文件中。
双击该文件即可启动应用程序。
Windows示例:
创建一个名为MyProgram.bat的文件。在文本编辑器中打开该文件。添加java -jar MyApplicationName.jar(将MyApplicationName替换为应用程序的名称/ jar文件的名称)。保存文件。双击创建的文件以打开您的程序。

3
今天早上我遇到了同样的问题,稍微搜索了一下并根据现有知识创建了一个静态类。它可以解决Windows的问题,但其他系统的用户应该能够轻松添加必要的内容 - 只是我不知道正确的系统命令(如果有的话)。我为帮助保留了printEnvironmentInfo()方法。 它做了什么: 使标准Java控制台应用程序能够双击启动,而不需要更改操作系统或创建文件。步骤如下:
  1. 当在IDE中时,仅返回。
  2. 当有控制台时,仅返回。
  3. 在新控制台中启动当前运行的.jar文件并退出。
如何使用:
  1. 创建Java控制台应用程序。
  2. 创建AutoRunFromConsole类文件,并将以下代码粘贴在软件包语句下,替换所有内容。
  3. 在你的主方法中作为(其中之一)第一条语句,执行AutoRunFromConsole.runYourselfInConsole(true)(如果想让控制台在应用程序结束后关闭,则为false)。
它的工作原理: 确定正在运行的Java应用程序的.jar文件名,并检查该文件是否实际存在于当前目录中以及是否实际为文件。
如果这不起作用,我们必须在IDE中,并且有一个控制台。这应该是可靠的,但也有替代方法:另一种对(重载的)方法的调用允许您传递主方法的命令行参数。如果第一个参数为“ide”(忽略大小写),则该方法将返回。当使用此其他调用时,如果无法确定可执行文件名(可以甚至提供备用措施),则会显示消息(见下文)。
检查System.console()是否返回null。如果不是,则直接返回。
根据操作系统确定命令行字符串(目前仅适用于Windows,但您只需要填写空白处),然后使用Runtime.getRuntime().exec()执行它。如果尚不支持OS,则会显示消息窗口,指出程序需要从控制台运行,包括语法。 如果您有改进意见(特别是其他系统的可行命令行字符串),请告诉我。
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.security.CodeSource;
import java.util.Map;
import java.util.Properties;




/**
 * Created by Reddit user king_of_the_universe / StackOverflow user Dreamspace President / dreamspace-president.com
 * <p>
 * v[(2), 2015-11-13 13:00 UTC]
 * <p>
 * One static method call will start a new instance of *THIS* application in the console and will EXIT the current
 * instance. SO FAR ONLY WORKS ON WINDOWS! Users of other systems need to assist here. The methods are all in place.
 */
final public class AutoRunFromConsole {


    final private static String FAILMESSAGE_TITLE = "Please run in console.";
    final private static String FAILMESSAGE_BODY = "This application must be run in the console (or \"command box\").\n\nIn there, you have to type:\n\njava -jar nameofprogram.jar";


    private static void showFailMessageAndExit() {

        JOptionPane.showMessageDialog(null, FAILMESSAGE_BODY, FAILMESSAGE_TITLE, JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
    }


    private enum OSType {
        UNDETERMINED, WINDOWS, LINUX, MACOS
    }


    private static OSType getOsType() {

        //        final String osName = System.getProperty("os.name");
        //        final String osVersion = System.getProperty("os.version");
        //        final String osArchitecture = System.getProperty("os.arch");
        //        System.out.println("\n\nOSNAME: " + osName);
        //        System.out.println("\n\nOSVERSION: " + osVersion);
        //        System.out.println("\n\nOSARCHITECTURE: " + osArchitecture);

        final String osName = System.getProperty("os.name", "").toLowerCase();
        if (osName.startsWith("windows")) {
            return OSType.WINDOWS;
        } else if (osName.startsWith("linux")) {
            return OSType.LINUX;
        } else if (osName.startsWith("mac os") || osName.startsWith("macos") || osName.startsWith("darwin")) {
            return OSType.MACOS;
        }

        return OSType.UNDETERMINED;
    }


    /**
     * Checks if the program is currently running in console, and if not, starts the program from console and EXITS this
     * instance of the program. Should be (one of) the first calls in your program.
     * <p>
     * This is the less safe variant of the method: To check if you're currently in the IDE, it just tries to find the
     * executable name and if it exists in the current path. This should word perfectly at all times in IntelliJ - I
     * don't know what values getExecutableName() returns inside Eclipse, but I suspect it will work just as well.
     * <p>
     * It's also less safe because you can't give a fallback executable name, but I believe it should do the trick in
     * all situations.
     * <p>
     * If this is used on a system other than Windows, a message box is shown telling the user to start the program from
     * the console. BECAUSE I DON'T KNOW HOW TO OPEN A CONSOLE ON OTHER SYSTEMS. SEE startExecutableInConsole();
     */
    public static void runYourselfInConsole(final boolean stayOpenAfterEnd) {

        runYourselfInConsole(false, stayOpenAfterEnd, null, null);
    }


    /**
     * Checks if the program is currently running in console, and if not, starts the program from console and EXITS this
     * instance of the program. Should be (one of) the first calls in your program.
     * <p>
     * This is the safer variant of the method: The first command line argument GIVEN BY THE IDE'S RUN CONFIGURATION
     * should be "ide" (Case is ignored.), which this method will use to determine if it's running from the IDE.
     * <p>
     * It is also safer because you can give a fallback executable name in case getExecutableName() could not determine
     * it.
     * <p>
     * Ultimately, it is safer because if the executable could not be determined, it shows a message box telling the
     * user to start the program from the console.
     * <p>
     * You will probably never make use of this variant. It's meant to be a solution if all else seems to fail (e.g.
     * customer calls and you need a quick fix).
     * <p>
     * If this is used on a system other than Windows, a message box is shown telling the user to start the program from
     * the console. BECAUSE I DON'T KNOW HOW TO OPEN A CONSOLE ON OTHER SYSTEMS. SEE startExecutableInConsole();
     *
     * @param psvmArguments          The arguments given to the main method.
     * @param fallbackExecutableName Can be null. In case getExecutableName() can't determine the proper name, the
     *                               fallback is used.
     */
    public static void runYourselfInConsole(final String[] psvmArguments, final String fallbackExecutableName, final boolean stayOpenAfterEnd) {

        runYourselfInConsole(true, stayOpenAfterEnd, psvmArguments, fallbackExecutableName);
    }


    /**
     * see the other two methods
     */
    private static void runYourselfInConsole(final boolean useSaferApproach, final boolean stayOpenAfterEnd, final String[] psvmArguments, final String fallbackExecutableName) {

        String executableName = getExecutableName(fallbackExecutableName);

        if (useSaferApproach) {
            if (isRunFromIDE(psvmArguments)) {
                return;
            }
        } else {
            if (executableName == null) {
                // Running from IDE.
                return;
            }
        }

        if (isRunningInConsole()) {
            return;
        }

        if (executableName == null) {
            showFailMessageAndExit();
        }

        startExecutableInConsole(executableName, stayOpenAfterEnd);

        System.exit(0);
    }


    /**
     * Opens a console window and starts the Java executable there.
     * <p>
     * If this is used on a system other than Windows, a message box is shown telling the user to start the program from
     * the console. BECAUSE I DON'T KNOW HOW TO OPEN A CONSOLE ON OTHER SYSTEMS.
     *
     * @param executableName   the full file name of the executable (without path)
     * @param stayOpenAfterEnd If true (and if someone can figure out the necessary parameters for other systems than
     *                         Windows), the console will not close once the executable has terminated. This is useful
     *                         e.g. if you want to give some kind of bye bye message because you actually assumed that
     *                         people start the program from console manually.
     */
    private static void startExecutableInConsole(final String executableName, final boolean stayOpenAfterEnd) {

        String launchString = null;

        switch (getOsType()) {
        case UNDETERMINED:
            break;
        case WINDOWS:
            if (stayOpenAfterEnd) {
                launchString = "cmd /c start cmd /k java -jar \"" + executableName+"\""; // No, using /k directly here DOES NOT do the trick.
            } else {
                launchString = "cmd /c start java -jar \"" + executableName+"\"";
            }
            break;
        case LINUX:
            break;
        case MACOS:
            // launchString="/usr/bin/open -a Terminal /path/to/the/executable";
            break;
        }

        if (launchString == null) {
            showFailMessageAndExit();
        }

        try {
            Runtime.getRuntime().exec(launchString);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * @param args the args as given to PSVM
     * @return whether the first command line argument was "ide" (ignoring case). Don't forget to change your IDE's run
     * configuration accordingly.
     */
    private static boolean isRunFromIDE(final String[] args) {

        return args != null && args.length > 0 && args[0].equalsIgnoreCase("ide");
    }


    /**
     * @return if System.console() is available. DOES NOT WORK properly from IDE, will return false then even though it
     * should be true. Use isRunFromIDE or other means additionally.
     */
    private static boolean isRunningInConsole() {

        return System.console() != null;
    }


    /**
     * @param fallbackExecutableName Can be null. In the very unlikely case this method can't determine the executable,
     *                               the fallback will also be checked. But if the fallback also doesn't exist AS A FILE
     *                               in the CURRENT path, null will be returned regardless, even if you're sure that
     *                               your fallback should be correct.
     * @return the name of the running jar file, OR NULL if it could not be determined (which should be a certainty
     * while in IDE, hence can be abused for determining that).
     */
    public static String getExecutableName(final String fallbackExecutableName) {

        // APPROACH 1 - THE ONE EVERYBODY ON STACKOVERFLOW IS REPEATING
        String executableNameFromClass = null;
        final CodeSource codeSource = AutoRunFromConsole.class.getProtectionDomain().getCodeSource();
        if (codeSource == null) {
            System.err.println("UNEXPECTED: Main.class.getProtectionDomain().getCodeSource() returned null");
        } else {
            final String path = codeSource.getLocation().getPath();
            if (path == null || path.isEmpty()) {
                System.err.println("UNEXPECTED: codeSource.getLocation().getPath() returned null or empty");
            } else {

                executableNameFromClass = new File(path).getName();

            }
        }


        // APPROACH 2 - QUERY SYSTEM PROPERTIES
        final Properties properties = System.getProperties();
        final String executableNameFromJavaClassPathProperty = properties.getProperty("java.class.path");
        final String executableNameFromSunJavaCommandProperty = properties.getProperty("sun.java.command");


        //        System.out.println("\n\nexecutableNameFromClass:\n" + executableNameFromClass);
        //        System.out.println("\n\nexecutableNameFromJavaClassPathProperty:\n" + executableNameFromJavaClassPathProperty);
        //        System.out.println("\n\nexecutableNameFromSunJavaCommandProperty:\n" + executableNameFromSunJavaCommandProperty);
        //        System.out.println("\n\nfallbackExecutableName:\n" + fallbackExecutableName);


        if (isThisProbablyTheExecutable(executableNameFromClass)) {
            return executableNameFromClass;
        }

        if (isThisProbablyTheExecutable(executableNameFromJavaClassPathProperty)) {
            return executableNameFromJavaClassPathProperty;
        }

        if (isThisProbablyTheExecutable(executableNameFromSunJavaCommandProperty)) {
            return executableNameFromSunJavaCommandProperty;
        }

        if (isThisProbablyTheExecutable(fallbackExecutableName)) {
            return fallbackExecutableName;
        }

        return null;
    }


    /**
     * @param candidateName suspected name of the running java executable
     * @return if name is not null, ends with ".jar" (Case is ignored.), and points to a FILE existing in the CURRENT
     * directory.
     */
    private static boolean isThisProbablyTheExecutable(final String candidateName) {

        if (candidateName == null || !candidateName.toLowerCase().endsWith(".jar")) {
            return false;
        }

        final File file = new File(candidateName);
        return file.exists() && file.isFile();
    }


    public static void main(final String[] args) {

        AutoRunFromConsole.runYourselfInConsole(true);
        printEnvironmentInfo();
    }


    /**
     * for debugging purposes
     */
    public static void printEnvironmentInfo() {


        System.out.println("\n\n\n\n-------------------------- System.getProperties() --------------------------");
        final Properties properties = System.getProperties();
        for (final Map.Entry<Object, Object> entry : properties.entrySet()) {
            System.out.println(entry);
        }

        System.out.println("\n\n\n\n----------------------------- System.getenv() ------------------------------");
        final Map<String, String> env = System.getenv();
        for (final Map.Entry<String, String> entry : env.entrySet()) {
            System.out.println(entry);
        }

        System.out.print("\n\n\n\n");
    }


}

不错!但是我注意到一个bug:如果你双击运行它,在CMD窗口中无法高亮文本。 - You'reAGitForNotUsingGit
@AndroidDev 可能是你这边出了问题,我这边测试正常。而且我也不知道如何改变 CMD 窗口的功能(更不用说通过 Java 了)。 - Dreamspace President

1

我知道这个答案有点晚。但对于现在看到这个问题的人可能会有帮助。

首先右键点击文件,选择“打开方式”...

然后选择“始终使用此程序打开jar文件”。

接着点击“选择其他应用程序”(或类似选项)。

浏览到你的Java安装目录\bin。(例如:C:\Program files\Java\jdk-17\bin)

然后选择jar.exe


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接