Search code examples
javajava-17

Compiling and running java with javac vs java ClassName.java has different results


The java version used is as follows:

java 17.0.3 2022-04-19 LTS
Java(TM) SE Runtime Environment (build 17.0.3+8-LTS-111)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.3+8-LTS-111, mixed mode, sharing)

The class is named: Test2.java (contents are as follows:)

import java.util.Random;

public class B {

    public static final void main(String[] args) {
        System.out.println(new Random().nextInt(10));
    }

}


public class T2 {

    public static void main(String[] args) {
        System.out.println("This from another function");
    }

}

Confusion:

Following commands run quite differently when trying to compile or run the class:

  1. With java Test2.java the result comes of as a random integer (as the code says).
  2. With javac Test2.java the compilation fails. This is what I was expecting in the first place for the command 1. But, it did not happen that way.

Thought process: In all of my experience I've learned that there should be only one public top level class and that public class's name should be same as the file name. In this case the Test2.java file should contain a class called Test2. But I deliberately created two top level public classes none of them containing the class name as of the file's.

Actual question: Why command1 runs and finds whatever first class's main method was and prints that statement although it shouldn't have compiled in the first place. Command2 works as expected. Why the discrepancy?


Solution

  • The source-file mode that lets you run a program that fits in a single file is a little bit different than the normal compile / execute process. In particular:

    In source-file mode, the effect is as though the source file is compiled into memory, and the first class found in the source file is executed.

    And

    • No other source files are found and compiled, as if the source path is set to an empty value.
    • . . .
    • The source file is compiled in the context of an unnamed module.
    • The source file should contain one or more top-level classes, the first of which is taken as the class to be executed.
    • The compiler does not enforce the optional restriction defined at the end of JLS 7.6, that a type in a named package should exist in a file whose name is composed from the type name followed by the .java extension.

    These changes are presumably to make it more convenient to have a complete program in a single .java file.