Компактные файлы кода и метод main

Последнее обновление: 23.05.2025

С выходом JDK 21 появилась экспериментальная возможность - компактные файлы кода и метод main, которая позволяет упростить программу на Java. А в JDK 25 эта возможность перестает быть экспериментальной и стала полноценной для применения. Суть этой возможности заключается в упрощении файла программы и метода main. В частности, теперь можно писать код без объявления класса с сокращением определения кода main.

Компактный метод main

Прежде всего мы можем определить более компактный метод main. Например, возьмем стандартную программу, которая размещена в файле Program.java

public class Program{ 
     
    public static void main (String args[]){
         
		    System.out.println("Hello METANIT.COM!");
    }
}

Таким образом, раньше для построения и запуска программы на Java требовалось:

  • Объявить класс (public class Program).

  • Создать статический метод main с параметром-массивом строк (public static void main (String args[])).

Теперь можно определить метод main без public static и параметра String args[]:

class Program{
    void main() {
        System.out.println("Hello METANIT.COM");
    }
}

Версии JDK 21, 22, 23 и 24 поддерживали такое определение метода main в качестве экспериментального, а для компиляции программы надо было указыть дополнительные опции. Например, для компиляции с помощью JDK 22 применялась команда:

javac --release 22 --enable-preview Program.java

Здесь 22 указывает на версию JDK, которую соответственно можно заменить на 21, 23, 24. И для запуска программы - также надо было указать дополнительную опцию --enable-preview:

java --enable-preview Program

Начиная с версии JDK 25 никаких дополнительных опций ни при компиляции, ни при запуске прогарммы указывать не нужно:

eugene@Eugene:/workspace/java$ javac Program.java
eugene@Eugene:/workspace/java$ java Program
Hello METANIT.COM!
eugene@Eugene:/workspace/java$ 

Рассмотрим общую механику вызова метода main. При запуске приложения лаунчер Java (программа запуска приложения) выбирает и вызывает основной метод запущенного класса:

  • Если класс определяет или наследует метод main с параметром String[], то лаунчер выбирает этот метод.

  • В противном случае, если класс определяет или наследует метод main без параметров, то лаунчер выбирает этот метод.

  • В противном случае лаунчер сообщает об ошибке и завершает работу.

После выбора метода дальнейшие действия зависят от того, выбран статический или не статический метод main:

  • Если выбранный метод - статический, то лаунчер вызывает его.

  • Иначе класс должен иметь не закрытый (без модификатора sealed) конструктор без параметров. Лаунчер вызывает этот конструктор, а затем у созданного объекта класса вызывает выбранный метод main.

    Если же класс не имеет конструктора без параметров, то лаунчер сообщает об ошибке и завершает работу.

Для примера возьмем файл программы со следующим кодом:

public class Program{
    void main(String[] args) {  
        System.out.println("With args");  
    } 

    void main() {  
        System.out.println("Without args");  
    } 
}

Здесь два определения метода main, оба нестатические, но один из них принимает параметр String[], поэтому именно этот метод и будет выбран для выполнения программы.

Компактные файлы

Если компилятор Java обнаружит исходный файл с полями и методами, которые не заключены в объявление класса, он будет считать, что исходный файл неявно объявляет класс, членами которого являются эти поля и методы. Такой исходный файл называется компактным исходным файлом.

Таким образом, раньше для построения и запуска программы на Java требовалось:

  • Объявить класс (public class Program).

  • Создать статический метод main с параметром-массивом строк (public static void main (String args[])).

Теперь в файле программы можно писать код без объявления класса:

void main() {
    System.out.println("Hello METANIT.COM!");
}

Для подобного файла неявно определяется класс верхнего уровня в неименованном пакете. То есть весь код файла фактически будет представлять этот класс, который:

  • Расширяет java.lang.Object и не реализует никаких интерфейсов

  • Имеет конструктор по умолчанию без параметров и никаких других конструкторов

  • Имеет в качестве своих членов поля и методы в компактном исходном файле

  • Должен иметь запускаемый метод main; в противном случае выдается ошибка времени компиляции

Поскольку поля и методы, объявленные в компактном исходном файле, интерпретируются как члены неявно объявленного класса, мы можем рядом с методом main определеть и использовать другие методы и поля, которые автоматически будут являться методами и полями класса. Например, определение и вызов метода:

String sayHello(){ 
    return "Hello";
}

void main(String[] args) {  

    System.out.println(sayHello()); 
}

Или определение и использование полей:

String message = "Hello Work";

void main(String[] args) {  

    System.out.println(message); 
}

Компактный исходный файл объявляет класс неявно, поэтому у класса нет имени, которое можно использовать в исходном коде. Компилятор Java генерирует имя класса при компиляции компактного исходного файла, но это имя зависит от реализации и не должно использоваться ни в каком исходном коде — даже в исходном коде в самом компактном исходном файле. Мы можем ссылаться на текущий экземпляр класса через this, явно или, как выше, неявно, но мы не можем создать экземпляр класса с помощью оператора new.

Определение других типов в файле

В том же файле мы можем определять и другие типы, например, классы:

void main(String[] args) {  

    Person tom = new Person("Tom");
    System.out.println(tom.getName()); 
}

class Person{
     
    private String name;
 
    Person(String name){
        this.name = name;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
     
        return this.name;
    }
}

В данном случае это будет аналогично тому, что класс Person был определн внутри класса, который представляет текущий файл.

Если вложенность класса нас не устраивает, мы можем явным образом определить для метода main конкретный класс, а рядом с ним остальные типы:

class Program{
    void main(String[] args) {  

        Person bob = new Person("Bob");
        System.out.println(bob.getName()); 
    }
}

class Person{
     
    private String name;
 
    Person(String name){
        this.name = name;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
     
        return this.name;
    }
}
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850