AFAIK, in Java implicit constructors are always generated for a class without constructors [1], [2].
But in bytecode I could not find such restriction on the JVMS.
So:
is it valid according to the JVMS to define a class without constructor only to use its static methods as in the following jasmin hello world?
does it have any further consequences besides not being able to create instances of it? I won't be able to use
invokespecial
to initialize instances, which rendersnew
useless according to https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.2.4 (can't use uninitialized object).
Jasmin code:
.class public Main
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
.limit stack 2
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hello World!"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
.end method
that is, without a constructor:
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
?
Running with java Main
gives the expected output Hello World!
.
I have checked the javap -v
output and unlike Java, jasmin
did not generate the default constructor.
I have also tried to call new Main();
anyway to see what happens with:
public class TestMain {
public static void main(String[] args) {
Main m = new Main();
}
}
and as expected it gives a compilation error cannot find symbol
. If I add the constructor to the jasmin then TestMain
works.
Output of javap -v
for completeness:
public class Main
minor version: 0
major version: 46
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 Main.j
#2 = Class #17 // Main
#3 = NameAndType #21:#23 // out:Ljava/io/PrintStream;
#4 = Utf8 ([Ljava/lang/String;)V
#5 = Utf8 java/lang/Object
#6 = Class #5 // java/lang/Object
#7 = Utf8 Hello World!
#8 = Class #16 // java/io/PrintStream
#9 = String #7 // Hello World!
#10 = Class #19 // java/lang/System
#11 = Utf8 Code
#12 = Utf8 main
#13 = Fieldref #10.#3 // java/lang/System.out:Ljava/io/PrintStream;
#14 = Utf8 SourceFile
#15 = NameAndType #18:#22 // println:(Ljava/lang/String;)V
#16 = Utf8 java/io/PrintStream
#17 = Utf8 Main
#18 = Utf8 println
#19 = Utf8 java/lang/System
#20 = Methodref #8.#15 // java/io/PrintStream.println:(Ljava/lang/String;)V
#21 = Utf8 out
#22 = Utf8 (Ljava/lang/String;)V
#23 = Utf8 Ljava/io/PrintStream;
{
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #9 // String Hello World!
5: invokevirtual #20 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
SourceFile: "Main.j"
If anyone can generate that with javac (in particular no ACC_INTERFACE
nor ACC_SYNTHETIC
) that would be a good argument for validity.
new Main();
? – Neeleyerror: cannot find symbol
as expected. Then if I add the constructor to the Jasmin,new Main()
works. – Ardy