I have three JDKs on my system and I'd like to see if I can tell if
they produce different .class files when compiling .java sources
and if I can tell which one produced which .class file. The JDKs on
my system are:
$ dpkg -l '*jdk*' | grep ^ii | cut -d' ' -f3
openjdk-11-jdk-headless:amd64
openjdk-8-jdk-headless:amd64
oracle-java8-jdk
For each of these compilers, I want to do:
mkdircompiler-foo&&compiler-foo
echo"public class Test { }">Test.java
javacTest.java
javap-verboseTest.class>Test.javap
With a bit of BASH foo, this becomes:
find/usr/lib/jvm/-namejavac|
whileread-rjava_compiler;do
compiler=$(basename"$(dirname"$(dirname"${java_compiler}")")")
fn=${compiler//-/}
mkdir"${fn}"
echo"public class Test { }">"${fn}"/Test.java
"${java_compiler}""${fn}"/Test.java
"$(dirname"${java_compiler}")"/javap-verbose"${fn}"/Test.class\
&>"${fn}"/Test.javap
done
Since I had three compilers, I now have three directories, each with
its own set of Test files:
$ tree
.
βββ java11openjdkamd64
β βββ Test.class
β βββ Test.java
β βββ Test.javap
βββ java8openjdkamd64
β βββ Test.class
β βββ Test.java
β βββ Test.javap
βββ oraclejava8jdkamd64
βββ Test.class
βββ Test.java
βββ Test.javap
3 directories, 9 files
Now, on to the fun part, diffing. There's no difference between the
.class files generated by Oracle JDK 8 and OpenJDK 8:
$ diff java8openjdkamd64/Test.class oraclejava8jdkamd64/Test.class
$ echo $?
0
The only difference is the path to the source file as reported by javap:
$ diff java8openjdkamd64/Test.javap oraclejava8jdkamd64/Test.javap
1c1
< Classfile /tmp/examine/java8openjdkamd64/Test.class
---
> Classfile /tmp/examine/oraclejava8jdkamd64/Test.class
On the other hand, when examining the difference in the .class files
produced by OpenJDK 8 and OpenJDK 11, there are several
difference. First off, the .class files differ:
$ diff java8openjdkamd64/Test.class java11openjdkamd64/Test.class
Binary files java8openjdkamd64/Test.class and java11openjdkamd64/Test.class differ
javap has more details for us:
$diffjava8openjdkamd64/Test.javapjava11openjdkamd64/Test.javap
1,3c1,3
< Classfile /home/torstein/tmp/examine/java8openjdkamd64/Test.class
< Last modified 04-Dec-2018; size 182 bytes
< MD5 checksum f22f52551c287057ed6d62d392d5647e
---
> Classfile /home/torstein/tmp/examine/java11openjdkamd64/Test.class
> Last modified 4 Dec 2018; size 182 bytes
> MD5 checksum 893ccf6fab86d0488097a4052360d7c1
7,8c7,11
< major version: 52
< flags: ACC_PUBLIC, ACC_SUPER
---
> major version: 55
> flags: (0x0021) ACC_PUBLIC, ACC_SUPER
> this_class: #2 // Test
> super_class: #3 // java/lang/Object
> interfaces: 0, fields: 0, methods: 1, attributes: 1
25c28
< flags: ACC_PUBLIC
---
> flags: (0x0001) ACC_PUBLIC
The difference here that really tells us that these are two compilers
defaulting to different Java language versions is the major version
field:
< major version: 52
---
> major version: 55
Pretty interesting, eh?