Почему основной метод Java статичен?
Сигнатура метода Java main
является:
public static void main(String[] args) {
...
}
Есть ли причина, по которой этот метод должен быть статичным?
Переведено автоматически
Ответ 1
Это всего лишь соглашение. Фактически, даже имя main() и передаваемые в нем аргументы являются чисто условными.
В Java 21 представлены альтернативные соглашения в качестве функции предварительного просмотра; вы можете опустить String[]
параметр, public
модификатор и даже static
модификатор. Если вы опустите модификатор static
, экземпляр класса будет создан перед вызовом, для чего требуется, чтобы у класса был конструктор без частных параметров с нулевым параметром. Конструктора по умолчанию, созданного компилятором, если конструктор не был объявлен, достаточно.
При запуске java.exe (или javaw.exe в Windows) на самом деле происходит пара вызовов Java Native Interface (JNI). Эти вызовы загружают DLL, которая на самом деле является JVM (правильно - java.exe это НЕ JVM). JNI - это инструмент, который мы используем, когда нам нужно соединить мир виртуальных машин с миром C, C ++ и т.д... Верно и обратное - невозможно (по крайней мере, насколько мне известно) на самом деле запустить JVM без использования JNI.
В принципе, java.exe это супер простое приложение на C, которое анализирует командную строку, создает новый массив строк в JVM для хранения этих аргументов, анализирует имя класса, которое вы указали как содержащее main(), использует вызовы JNI для поиска самого метода main (), затем вызывает метод main (), передавая вновь созданный массив строк в качестве параметра. Это очень, очень похоже на то, что вы делаете, когда используете отражение из Java - просто вместо этого используются вызовы собственных функций с непонятными именами.
Для вас было бы совершенно законно написать свою собственную версию java.exe (исходный код распространяется вместе с JDK) и заставить его делать что-то совершенно другое. Фактически, это именно то, что мы делаем со всеми нашими приложениями на базе Java.
Каждое из наших Java-приложений имеет свой собственный лаунчер. В первую очередь мы делаем это, чтобы получить свой собственный значок и имя процесса, но это пригодилось и в других ситуациях, когда мы хотим сделать что-то помимо обычного вызова main (), чтобы все заработало (например, в одном случае мы выполняем взаимодействие с COM, и мы фактически передаем дескриптор COM в main () вместо массива строк).
Итак, короче говоря: причина, по которой он статичен, заключается в том, что это удобно. Причина, по которой он называется "main", заключается в том, что это должно было быть что-то, а main () - это то, что они делали в старые времена C (и в те дни имя функции было важным). Я полагаю, что java.exe можно было бы просто указать полное имя основного метода, а не просто класс (java com.mycompany.Foo.someSpecialMain), но это просто усложняет автоматическое определение "запускаемых" классов в проекте в IDE.
Ответ 2
Метод статичен, потому что в противном случае возникла бы двусмысленность: какой конструктор следует вызывать? Особенно если ваш класс выглядит следующим образом:
public class JavaClass{
protected JavaClass(int x){}
public void main(String[] args){
}
}
Должен ли JVM вызывать new JavaClass(int)
? Что он должен передавать x
?
Если нет, следует ли создавать экземпляр JVM JavaClass
без запуска какого-либо метода конструктора? Я думаю, что этого не должно быть, потому что это будет особый случай для всего вашего класса - иногда у вас есть экземпляр, который не был инициализирован, и вам приходится проверять его наличие в каждом методе, который может быть вызван.
Существует слишком много крайних случаев и неоднозначностей, чтобы JVM имело смысл создавать экземпляр класса перед вызовом точки входа. Вот почему main
является статическим.
Я понятия не имею, почему main
всегда отмечен public
.
Ответ 3
main
Метод в C ++, C # и Java статичен.
Это потому, что затем они могут быть вызваны механизмом выполнения без необходимости создавать экземпляры каких-либо объектов, тогда код в теле main
сделает все остальное.
Ответ 4
Давайте просто представим, что static
не требуется в качестве точки входа в приложение.
Тогда класс приложения выглядел бы следующим образом:
class MyApplication {
public MyApplication(){
// Some init code here
}
public void main(String[] args){
// real application code here
}
}
Различие между кодом конструктора и main
методом необходимо, потому что на языке OO конструктор должен только убедиться, что экземпляр инициализирован должным образом. После инициализации экземпляр можно использовать для предполагаемого "сервиса". Помещение полного кода приложения в конструктор испортило бы ситуацию.
Таким образом, этот подход принудительно заключит с приложением три разных контракта:
- Там должен быть конструктор по умолчанию. В противном случае JVM не знала бы, какой конструктор вызывать и какие параметры следует предоставить.
- Должен существовать
main
метод1. Ок, это неудивительно. - Класс не должен быть
abstract
. В противном случае JVM не сможет создать его экземпляр.
С другой стороны, для static
подхода требуется только один контракт:
- Должен быть
main
метод1.
Здесь не имеют значения ни abstract
, ни несколько конструкторов.
Поскольку Java была разработана как простой язык для пользователя, неудивительно, что точка входа приложения также была разработана простым способом с использованием одного контракта, а не сложным способом с использованием трех независимых и хрупких контрактов.
Пожалуйста, обратите внимание: Этот аргумент не касается простоты внутри JVM или внутри JRE. Этот аргумент касается простоты для пользователя.
1Здесь полная подпись считается только одним контрактом.