Reputation: 1598
If we see .class file structure, it says: offsets 0x04-0x05 are for minor version of JDK, and offsets 0x06-0x07 are for major version of JDK
I use eclipse for java project development with JDK1.5.0_7/JRE configured for JRE system library and class files shows offsets as 0x00 0x00 0x00 0x31.
How can I change the compiler to JDK1.5.0_7 so that offset becomes 0x00 0x07 0x00 0x31?
Upvotes: 0
Views: 1243
Reputation: 22993
You cannot specify the minor number yourself during the compilation.
The major and minor number does not indicate the version of the JDK used to compile. They indicate the version of the class file format. Have a look at this SO answer.
The class file version also specify the version of JRE able to execute this class file. For example: if the major.minor version is 0x30.0x00 you need at least a JRE 1.4 to execute this class file. Which not in all cases mean a previous JRE couldn't understand the byte code. As soon you use a Java language feature/runtime class which did not exist in a previous Java version this isn't true anymore.
A simple example
public class Scratch {
public static void main(String[] args) {
System.out.println("foobar");
}
}
This simple class can be compiled with a different then the default class file version of your JDK
Following would compile it for the version 1.4
javac -source 1.4 -target 1.4 Scratch
The generated bytecode would in this simple example still be the same. The lowest possible class file version for this simple example would be 2D.E (compile it with javac -target 1.1 -source 1.2 Scratch.java). And then a JRE 1.1 (verified with JRE 1.1.8) could run it.
To check the version you could use this snippet
import java.io.DataInputStream;
import java.io.FileInputStream;
public class ClassFileVersion {
// add exception handling, left out only for the example
public static void main(String[] args) throws Exception {
String filename = args[0];
try (DataInputStream in = new DataInputStream(new FileInputStream(filename))) {
int magic = in.readInt();
if (magic != 0xcafebabe) {
System.out.println(filename + " looks not like a Java class file.");
}
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
System.out.printf("majaor.minor: %X.%X hex %d.%d dec%n", major, minor, major, minor);
}
}
}
edit
Here a small snippet to demonstrate the impact.
Scratch.java
with your current JDKrun the class file minor version of the Scratch.class
Path path = Paths.get("Scratch.class"); byte[] bytes = Files.readAllBytes(path); bytes[5] = 1; // it was zero before Files.write(path, bytes, StandardOpenOption.TRUNCATE_EXISTING)
run the changed class file java Scratch
the execution will fail (error message might be differ in the wording, depending on your used JRE)
java.lang.UnsupportedClassVersionError: Scratch has been compiled by a more recent version of the Java Runtime (class file version 52.1), this version of the Java Runtime only recognizes class file versions up to 52.0
If you compile the source for a lower major version (the -target option) an previous JRE could execute the bytecode (see the limitations mentioned earlier).
Assume you run this with JDK 8 javac -target 1.4 -source 1.4 Scratch.java
. There are different things happen by the javac
. First it checks if Scratch.java
only use language features which were available in Java 1.4. Second the resulting Scratch.class
get a major.minor class file version which was used in Java 1.4 (30.0 hex). Then you could run this class with the JRE 1.4 as java Scratch
.
Upvotes: 2