Как программно получить все установленные Java JVM (не по умолчанию), используя Java?

Кто-нибудь знает, как программно получить все JVM, установленные (не по умолчанию), используя Java?

Например, на компьютере пользователя установлено 2 JVM:

JDK 5
JDK 6

Мне нужно знать все версии, установленные для того, чтобы переключить ту, которая используется (по умолчанию), и затем программно вызвать javac для компиляции некоторого исходного кода с использованием определенной версии JDK.

Я искал некоторую информацию в Интернете, я нашел:

Но я не мог найти то, что искал.

10 ответов

Я недавно имел дело с очень похожей ситуацией. Следующий код делает почти то, что вам нужно. Он ищет Java JRE и JDK, а не только JDK, но его должно быть довольно легко редактировать в соответствии с вашими потребностями. Осторожно: только для окон

/**
 * Java Finder by petrucio@stackru(828681) is licensed under a Creative Commons Attribution 3.0 Unported License.
 * Needs WinRegistry.java. Get it at: https://stackru.com/questions/62289/read-write-to-windows-registry-using-java
 *
 * JavaFinder - Windows-specific classes to search for all installed versions of java on this system
 * Author: petrucio@stackru (828681)
 *****************************************************************************/

import java.util.*;
import java.io.*;

/**
 * Helper class to fetch the stdout and stderr outputs from started Runtime execs
 * Modified from http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
 *****************************************************************************/
class RuntimeStreamer extends Thread {
    InputStream is;
    String lines;

    RuntimeStreamer(InputStream is) {
        this.is = is;
        this.lines = "";
    }
    public String contents() {
        return this.lines;
    }

    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader    br  = new BufferedReader(isr);
            String line = null;
            while ( (line = br.readLine()) != null) {
                this.lines += line + "\n";
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();  
        }
    }

    /**
     * Execute a command and wait for it to finish
     * @return The resulting stdout and stderr outputs concatenated
     ****************************************************************************/
    public static String execute(String[] cmdArray) {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process proc = runtime.exec(cmdArray);
            RuntimeStreamer outputStreamer = new RuntimeStreamer(proc.getInputStream());
            RuntimeStreamer errorStreamer  = new RuntimeStreamer(proc.getErrorStream());
            outputStreamer.start();
            errorStreamer.start();
            proc.waitFor();
            return outputStreamer.contents() + errorStreamer.contents();
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return null;
    }
    public static String execute(String cmd) {
        String[] cmdArray = { cmd };
        return RuntimeStreamer.execute(cmdArray);
    }
}

/**
 * Helper struct to hold information about one installed java version
 ****************************************************************************/
class JavaInfo {
    public String  path;        //! Full path to java.exe executable file
    public String  version;     //! Version string. "Unkown" if the java process returned non-standard version string
    public boolean is64bits;    //! true for 64-bit javas, false for 32

    /**
     * Calls 'javaPath -version' and parses the results
     * @param javaPath: path to a java.exe executable
     ****************************************************************************/
    public JavaInfo(String javaPath) {
        String versionInfo = RuntimeStreamer.execute( new String[] { javaPath, "-version" } );
        String[] tokens = versionInfo.split("\"");

        if (tokens.length < 2) this.version = "Unkown";
        else this.version = tokens[1];
        this.is64bits = versionInfo.toUpperCase().contains("64-BIT");
        this.path     = javaPath;
    }

    /**
     * @return Human-readable contents of this JavaInfo instance
     ****************************************************************************/
    public String toString() {
        return this.path + ":\n  Version: " + this.version + "\n  Bitness: " + (this.is64bits ? "64-bits" : "32-bits");
    }
}

/**
 * Windows-specific java versions finder
 *****************************************************************************/
public class JavaFinder {

    /**
     * @return: A list of javaExec paths found under this registry key (rooted at HKEY_LOCAL_MACHINE)
     * @param wow64  0 for standard registry access (32-bits for 32-bit app, 64-bits for 64-bits app)
     *               or WinRegistry.KEY_WOW64_32KEY to force access to 32-bit registry view,
     *               or WinRegistry.KEY_WOW64_64KEY to force access to 64-bit registry view
     * @param previous: Insert all entries from this list at the beggining of the results
     *************************************************************************/
    private static List<String> searchRegistry(String key, int wow64, List<String> previous) {
        List<String> result = previous;
        try {
            List<String> entries = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, key, wow64);
            for (int i = 0; entries != null && i < entries.size(); i++) {
                String val = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, key + "\\" + entries.get(i), "JavaHome", wow64);
                if (!result.contains(val + "\\bin\\java.exe")) {
                    result.add(val + "\\bin\\java.exe");
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return result;
    }

    /**
     * @return: A list of JavaInfo with informations about all javas installed on this machine
     * Searches and returns results in this order:
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment (32-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment (64-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit     (32-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit     (64-bits view)
     *   WINDIR\system32
     *   WINDIR\SysWOW64
     ****************************************************************************/
    public static List<JavaInfo> findJavas() {
        List<String> javaExecs = new ArrayList<String>();

        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Runtime Environment", WinRegistry.KEY_WOW64_32KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Runtime Environment", WinRegistry.KEY_WOW64_64KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Development Kit",     WinRegistry.KEY_WOW64_32KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Development Kit",     WinRegistry.KEY_WOW64_64KEY, javaExecs);

        javaExecs.add(System.getenv("WINDIR") + "\\system32\\java.exe");
        javaExecs.add(System.getenv("WINDIR") + "\\SysWOW64\\java.exe");

        List<JavaInfo> result = new ArrayList<JavaInfo>();
        for (String javaPath: javaExecs) {
            if (!(new File(javaPath).exists())) continue;
            result.add(new JavaInfo(javaPath));
        }
        return result;
    }

    /**
     * @return: The path to a java.exe that has the same bitness as the OS
     * (or null if no matching java is found)
     ****************************************************************************/
    public static String getOSBitnessJava() {
        String arch      = System.getenv("PROCESSOR_ARCHITECTURE");
        String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
        boolean isOS64 = arch.endsWith("64") || (wow64Arch != null && wow64Arch.endsWith("64"));

        List<JavaInfo> javas = JavaFinder.findJavas();
        for (int i = 0; i < javas.size(); i++) {
            if (javas.get(i).is64bits == isOS64) return javas.get(i).path;
        }
        return null;
    }

    /**
     * Standalone testing - lists all Javas in the system
     ****************************************************************************/
    public static void main(String [] args) {
        List<JavaInfo> javas = JavaFinder.findJavas();
        for (int i = 0; i < javas.size(); i++) {
            System.out.println("\n" + javas.get(i));
        }
    }
}

Вам также понадобится обновленный WinRegistry.java для чтения значений из 32-разрядных и 64-разрядных разделов реестра Windows: /questions/40502991/chtenie-zapis-v-reestr-windows-s-ispolzovaniem-java/40502995#40502995

Я обычно не программист Java, поэтому мой код, вероятно, не соответствует соглашениям Java. Подай в суд на меня.

Вот пример запуска с моей 64-битной машины Win 7:

>java JavaFinder

C:\Program Files (x86)\Java\jre6\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 32-bits

C:\Program Files\Java\jre6\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

D:\Dev\Java\jdk1.6.0_31\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

C:\Windows\system32\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

C:\Windows\SysWOW64\java.exe:
  Version: 1.6.0_31
  Bitness: 32-bits

Я сделал быструю проверку реестра Windows, и этот ключ, кажется, предоставляет различные версии Java, установленные в системе.

HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment

При дальнейшем поиске в Google было подтверждено, что это правильное местоположение. Прочитайте эти статьи для деталей...

Быстро получить доступную Java JVM на рабочей станции (Windows)

Java 2 Runtime Environment для Microsoft Windows

На платформах Windows вы можете запросить, существует ли установленная JRE:

java -version:1.6 -version

Эта команда вернется с "Java-версией"1.6.0_xx"", если она у вас установлена. Если он не установлен, он скажет: "Невозможно найти спецификацию совещания JRE 1.6".

Похоже, что это не работает в Linux, потому что у Linux нет стандартного способа установки Java.

В командной строке Windows вы можете запустить следующие 2 команды (или запустить вместе как пакетный файл). Это будет выглядеть в Windows Установка и удаление программ (записи реестра) и сообщит, какие версии JAVA найдены с помощью ссылок установки / удаления, а также пути к папке и некоторых других вещей.

wmic product where "name LIKE '%%java%%'" get * /format:textvaluelist > temp_javavers.txt 

notepad.exe temp_javavers.txt

По сути, нет способа перечислить всю JVM, даже не из кода Java. Рассмотрим различные платформы, разных поставщиков JDK, JDK в комплекте с другими продуктами от баз данных до авиасимулятора и движка рендеринга видео. Большинство JDK представляют собой простые ссылки на другие, например, v1.2 указывает на установленную v.6 . Обычное дело - как получить версию: java -version Но у нас есть несколько моментов:

  1. Для Windows посмотрите реестр HKEY_LOCAL_MACHINE\Software\JavaSoft\ . Также рассмотрим режим Wow6432Node для 64-битной ОС. Проверьте продукты от основных поставщиков, которые создают программное обеспечение на Java.
  2. Mac OS X / System/Library/Frameworks/JavaVM.framework/Versions + Open JDK
  3. Linux и некоторые другие Unix - какие java, /etc/alternatives/java rpm -qa|grep java и т. Д.

Установлено довольно расплывчато - даже если JRE и JDK поставляются с установщиком, на самом деле нам просто нужно скопировать файлы JRE или JDK на компьютер и сразу же использовать их.

В общем, вам нужно найти все java или же java.exe исполняемые файлы на вашем локальном компьютере и вызов java -version чтобы увидеть1, если этот исполняемый файл с именем java/ java.exe на самом деле (часть) JRE.


Только что увидел, что вы запросили JVM и хотите вызвать компилятор. Если вы ищете JDK, используйте вышеуказанный метод, но найдите все javac/javac.exe, У них есть -version вариант тоже.


1 нет никакого риска - нет веселья, которое приходит с этим методом - пожалуйста, внимательно посмотрите на комментарий Шона! Если вы не можете доверять машине (или ее пользователям), то вы можете проверить, является ли исполняемый файл скриптом / пакетом или двоичным файлом - даже если двоичный файл может стереть и ваш диск, даже оригинальный исполняемый файл javac может быть заменен каким-то злобным кодом...

Я не уверен, что это ответит на ваш вопрос, но вы можете контролировать, какую основную версию JRE будет запускать апплет или приложение WebStart, используя функцию Family Versioning. Это позволяет вам указать основной выпуск Java, на котором работает апплет. Вы должны быть в состоянии определить местоположение javac оттуда.

http://www.oracle.com/technetwork/java/javase/family-clsid-140615.html

Чтобы найти версии Java, лучший подход, чем поиск javac.exe, - проверить реестр. Java создает раздел реестра HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment со строкой CurrentVersion установите номер версии, например, 1.5 или 1.6.

Вы можете использовать эту информацию, чтобы найти JVM:

  • HKEY_LOCAL_MACHINE \ Software \ JavaSoft \ Java Runtime Environment \ 1.5 \ JavaHome = C: \ Program Files \ Java \ j2re1.5
  • HKEY_LOCAL_MACHINE \ Software \ JavaSoft \ Java Runtime Environment \ 1.5 \ RuntimeLib = C: \ Program Files \ Java \ j2re1.4.2 \ bin \ client \ jvm.dll

Вы можете увидеть больше здесь: http://java.sun.com/j2se/1.4.2/runtime_win32.html

Я не знаком с доступом к реестру из Java, но вы всегда можете запустить интерфейс командной строки regedit и проанализировать результаты, что я и сделал.

..компилировать некоторый исходный код, используя определенную версию JDK.

Используйте JavaCompiler (в последней версии JDK, которую пользователь может заложить) с соответствующими опциями для -source, -target &-bootclasspath, Последние два являются частью параметров кросс-компиляции javac,

Как найти JDK, поп JFileChooser с путем текущего JRE в качестве каталога по умолчанию. Если пользователь не может перейти оттуда к JDK, сомнительно, что он должен писать код.

Как было сказано ранее, HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment должен перечислить доступные JVM, НО я только что узнал, что, хотя этот реестр в настоящее время перечисляет только 64-битную 1.6.0_31 JVM на моей машине, у меня также есть 32-битная Java, установленная под C:\Windows\SysWOW64,

Таким образом, информация, указанная в реестре, не отображает полную картину, и если вы хотите запустить 32-битную JVM в 64-битной Windows, вам также следует попробовать C:\Windows\SysWOW64,

Другие вопросы по тегам