Windows – Java JDK, version of compiler is not compatible with Java runtime

javawindows 10

I tried to compile a simple Hello world called with javac, but when I use the command 'java Hello', the JVM seems unable to read the bytecode.

Output of 'java Hello':

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: Hello has been compiled by a more recent version of the Java Runtime (class file version 57.0), this version of the Java Runtime only recognizes class file versions up to 52.0

        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

Best Answer

The error message is (hopefully) reasonably clear:

java.lang.UnsupportedClassVersionError:

Hello has been compiled by a more recent version of the Java Runtime (class file version 57.0), this version of the Java Runtime only recognizes class file versions up to 52.0

The compiler you used produced Java byte code that your Java runtime (JRE) does not understand, because the JRE is too old (in particular, older than the JDK you used to compile).

When compiling Java code, the compiler will produce Java byte code. There are different versions of Java byte code (each new Java release usually introduces a new version of byte code), and old JREs cannot run byte code if the version is too new for them.

There are two ways to solve this:

1) Use -target option

In principle, you could solve this by telling the compiler to compile for an older JRE - this is done using the -target option of javac (see e.g. the javac documentation for Java 9).

For example,

javac -target 1.8 HelloWorld.java

will compile byte code for the JRE from Java 1.8 (aka Java 8). This would solve the error you get, as the bytecode version 52 mentioned in the error message corresponds to Java 8 (for a table mapping bytecode versions to Java releases, see e.g. the Wikipedia page Java class file).

Note that while this approach will solve the error you get, you may run into other problems related to the Java API you compile against - you'd have to use the javac option -bootclasspath, or -release if you are on Java 9 or newer.

2) Use matching JRE/JDK

If solution 1) sounds complicated, that's because it is :-).

The pragmatic solution, especially if you are in the learning stage, is to simply use matching versions of virtual machine/JRE and compiler, and the easiest approach is to use the JRE that was installed with the JDK download (that is, use java and javac from the same download).

This is actually what should happen by default after you download and install the JDK, so the error you get probably means you have a second (third?) JRE installed somewhere.

If practical, just deinstall all JREs and JDKs except for the one JDK you want to use. If you need multiple JREs in parallel, make sure your configuration (PATH variable, IDE config etc.) all point to the same JDK. That will avoid these problems.

Note that some IDEs (for example Eclipse) have a built-in compiler - you may need to configere that separately, to match the version of the JDK you have installed, or ideally use the IDE with the JDK version recommended by the IDE.

Related Question