Почему основной метод Java статичен?
Сигнатура метода Java main ():
public static void main(String[] args){
...
}
Есть ли причина для этого метода быть статичным?
37 ответов
Метод является статическим, потому что в противном случае возникла бы неоднозначность: какой конструктор должен быть вызван? Особенно, если ваш класс выглядит так:
public class JavaClass{
protected JavaClass(int x){}
public void main(String[] args){
}
}
Должен ли JVM позвонить new JavaClass(int)
? За что это должно пройти x
?
Если нет, должен ли JVM создать экземпляр JavaClass
без запуска какого-либо метода конструктора? Я думаю, что не должно, потому что это будет особый случай всего вашего класса - иногда у вас есть экземпляр, который не был инициализирован, и вы должны проверять его в каждом методе, который может быть вызван.
Существует слишком много крайних случаев и неоднозначностей, чтобы JVM имела смысл создавать экземпляр класса перед вызовом точки входа. Вот почему main
статичен
Я не имею понятия почему main
всегда отмечен public
хоть.
Это просто соглашение. На самом деле, даже имя main() и передаваемые аргументы являются чисто условными.
Когда вы запускаете java.exe (или javaw.exe в Windows), на самом деле происходит несколько вызовов Java Native Interface (JNI). Эти вызовы загружают DLL, которая действительно является JVM (это верно - java.exe НЕ является JVM). JNI - это инструмент, который мы используем, когда нам приходится соединять мир виртуальных машин и мир C, C++ и т. Д.... Обратное также верно - по-моему, невозможно (по крайней мере, насколько мне известно) получить JVM работает без использования JNI.
По сути, java.exe - это очень простое приложение C, которое анализирует командную строку, создает новый массив String в 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' запускаемые классы в проекте.
main()
метод в C++
, C#
а также Java
статичны
Поскольку они могут быть вызваны механизмом выполнения без необходимости создания каких-либо объектов, тогда код в теле main()
сделаем все остальное
Давайте просто притворимся, что 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 Здесь полная подпись считается только одним договором.
Почему публичная статическая пустота main(String[] args)?
Вот как разрабатывается язык Java, а также создается и пишется виртуальная машина Java.
Oracle Java Language Specification
Проверьте главу 12 "Выполнение" - раздел 12.1.4 "Вызов Test.main":
Наконец, после завершения инициализации для класса Test (во время которого могли произойти другие последовательные загрузки, связывание и инициализация), вызывается метод main класса Test.
Метод main должен быть объявлен как public, static и void. Он должен принимать один аргумент, который является массивом строк. Этот метод может быть объявлен как
public static void main(String[] args)
или же
public static void main(String... args)
Спецификация Oracle Java Virtual Machine
Ознакомьтесь с главой 2 "Концепции языка программирования Java" - раздел 2.17 "Выполнение":
Виртуальная машина Java начинает выполнение, вызывая метод main некоторого указанного класса и передавая ему один аргумент, который является массивом строк. Это заставляет указанный класс быть загруженным (§2.17.2), связанным (§2.17.3) с другими типами, которые он использует, и инициализированными (§2.17.4). Метод main должен быть объявлен как public, static и void.
Oracle OpenJDK Source
Скачайте и распакуйте исходный файл jar и посмотрите, как написана JVM, посмотрите ../launcher/java.c
, который содержит собственный код C за командой java [-options] class [args...]
:
/*
* Get the application's main class.
* ... ...
*/
if (jarfile != 0) {
mainClassName = GetMainClassName(env, jarfile);
... ...
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
... ...
/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");
... ...
{ /* Make sure the main method is public */
jint mods;
jmethodID mid;
jobject obj = (*env)->ToReflectedMethod(env, mainClass,
mainID, JNI_TRUE);
... ...
/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
ReportExceptionDescription(env);
goto leave;
}
/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
... ...
Если это не так, какой конструктор следует использовать, если их несколько?
Более подробная информация об инициализации и выполнении программ Java доступна в Спецификации языка Java.
До вызова метода main ни один объект не создается. Наличие ключевого слова static означает, что метод может быть вызван без предварительного создания каких-либо объектов.
Потому что в противном случае для его выполнения потребуется экземпляр объекта. Но он должен вызываться с нуля, без предварительного конструирования объекта, поскольку обычно задача main() (bootstrap) состоит в том, чтобы проанализировать аргументы и построить объект, обычно используя эти аргументы / параметры программы.
Позвольте мне объяснить эти вещи гораздо проще:
public static void main(String args[])
Все Java-приложения, кроме апплетов, начинают выполнение с main()
,
Ключевое слово public
является модификатором доступа, который позволяет члену быть вызванным снаружи класса.
static
используется, потому что это позволяет main()
быть вызванным без создания экземпляра конкретного экземпляра этого класса.
void
указывает на то, что main()
не возвращает никакого значения.
Каково значение public static void main(String args[])
?
public
является спецификатором доступа, означающим, что любой может получить к нему доступ, например JVM(виртуальная машина Java).static
позволяетmain()
вызываться до того, как объект класса был создан. Это необходимо, потому чтоmain()
вызывается JVM до создания каких-либо объектов. Поскольку он статический, его можно напрямую вызывать через класс.class demo { private int length; private static int breadth; void output(){ length=5; System.out.println(length); } static void staticOutput(){ breadth=10; System.out.println(breadth); } public static void main(String args[]){ demo d1=new demo(); d1.output(); // Note here output() function is not static so here // we need to create object staticOutput(); // Note here staticOutput() function is static so here // we needn't to create object Similar is the case with main /* Although: demo.staticOutput(); Works fine d1.staticOutput(); Works fine */ } }
Точно так же мы иногда используем static для пользовательских методов, поэтому нам не нужно создавать объекты.
void
указывает на то, чтоmain()
объявленный метод не возвращает значение.String[] args
указывает единственный параметр вmain()
метод.args
- параметр, который содержит массив объектов типа классаString
,
Это просто соглашение, но, вероятно, более удобное, чем альтернатива. При использовании статического main все, что вам нужно знать для вызова Java-программы, - это имя и местоположение класса. Если бы он не был статичным, вам также пришлось бы знать, как создать экземпляр этого класса, или потребовать, чтобы у класса был пустой конструктор.
Апплеты, мидлеты, сервлеты и бобы различного типа создаются, а затем к ним применяются методы жизненного цикла. Вызов main - это все, что когда-либо делается для основного класса, поэтому нет необходимости удерживать состояние в объекте, который вызывается несколько раз. Вполне нормально прикрепить main к другому классу (хотя это и не очень хорошая идея), что мешает использовать класс для создания главного объекта.
Когда вы выполняете виртуальную машину Java (JVM) с java
команда,
java ClassName argument1 argument2 ...
Когда вы выполняете свое приложение, вы указываете его имя класса в качестве аргумента команды java, как указано выше.
JVM пытается вызвать основной метод указанного вами класса
- на данный момент объекты класса не созданы.
декларирование
main
как статическийallows
JVM дляinvoke
главныйwithout
создаваяinstance
класса.
давайте вернемся к команде
ClassName
это command-line argument
в JVM, которая говорит ему, какой класс выполнять. Следуя ClassName, вы также можете указать list of Strings
(разделенные пробелами) в качестве аргументов командной строки, которые JVM передаст вашему приложению. -Такие аргументы могут быть использованы для указания параметров (например, имени файла) для запуска приложения - вот почему существует параметр с именем String[] args
в основном
Ссылки: Java ™ Как программировать (ранние объекты), десятое издание
Если метод main не будет статичным, вам нужно будет создать объект вашего основного класса вне программы. Как бы вы хотели это сделать?
Недавно аналогичный вопрос был опубликован на Programmers.SE
- Почему статический метод main в Java и C#, а не конструктор?
В поисках окончательного ответа из первичного или вторичного источника, почему (в частности) Java и C# решили использовать статический метод в качестве точки входа, а не представлять экземпляр приложения экземпляром
Application
класс, с точкой входа, являющейся подходящим конструктором?
TL; DR часть принятого ответа,
На Яве причина
public static void main(String[] args)
в том, что
- Гослинг хотел
- код, написанный кем-то опытным в C (не в Java)
- быть выполненным кем-то, кто привык запускать PostScript в NeWS
Для C# рассуждения транзитивно похожи, так сказать. Разработчики языка сохранили синтаксис точки входа в программу знакомым для программистов из Java. Как говорит C# архитектор Андерс Хейлсберг,... наш подход к C# просто предлагал альтернативу... программистам на Java...
...
main() является статическим, потому что; в этот момент в жизненном цикле приложения стек приложения носит процедурный характер, поскольку еще не созданы объекты.
Это чистый лист. На этом этапе ваше приложение работает даже без объявления каких-либо объектов (помните, что существуют процедурные и ОО-шаблоны кодирования). Вы, как разработчик, превращаете приложение в объектно-ориентированное решение, создавая экземпляры ваших объектов и в зависимости от кода, скомпилированного внутри.
Объектно-ориентированный отлично подходит для миллионов очевидных причин. Однако прошли те времена, когда большинство разработчиков VB регулярно использовали в своем коде такие ключевые слова, как "goto". "goto" - это процедурная команда в VB, которая заменяется его OO-аналогом: вызов метода.
Вы также можете рассматривать статическую точку входа (основную) как чистую свободу. Если бы Java был достаточно разным, чтобы создавать экземпляр объекта и представлять вам только этот экземпляр при запуске, у вас не было бы выбора, НО написать процедурное приложение. Каким бы невообразимым это ни звучало для Java, возможно, есть много сценариев, которые требуют процедурных подходов.
Это, вероятно, очень неясный ответ. Помните, "класс" - это всего лишь набор взаимосвязанного кода. "Экземпляр" - это изолированное, живое и дышащее автономное поколение этого класса.
Прототип public static void main(String[])
это соглашение, определенное в JLS:
Метод main должен быть объявлен как public, static и void. Он должен указывать формальный параметр (§8.4.1), объявленный тип которого является массивом String.
В спецификации JVM 5.2. Запуск виртуальной машины мы можем прочитать:
Виртуальная машина Java запускается путем создания начального класса, который определяется способом, зависящим от реализации, с помощью загрузчика классов начальной загрузки (§5.3.1). Затем виртуальная машина Java связывает исходный класс, инициализирует его и вызывает метод открытого класса void main (String []). Вызов этого метода приводит к дальнейшему выполнению. Выполнение инструкций виртуальной машины Java, составляющих основной метод, может вызвать связывание (и, следовательно, создание) дополнительных классов и интерфейсов, а также вызов дополнительных методов.
Забавно, но в спецификации JVM не упоминается, что основной метод должен быть статическим. Но в спецификации также сказано, что виртуальная машина Java выполняет 2 шага раньше:
- связывает начальный класс ( 5.4. Linking)
- инициализирует его ( 5.5. Инициализация)
Инициализация класса или интерфейса состоит из выполнения его метода инициализации класса или интерфейса.
Определен метод инициализации класса или интерфейса:
Класс или интерфейс имеют не более одного метода инициализации класса или интерфейса и инициализируются (§5.5), вызывая этот метод. Метод инициализации класса или интерфейса имеет специальное имя
<clinit>
, не принимает аргументов и является недействительным.
И метод инициализации класса или интерфейса отличается от метода инициализации экземпляра, определенного следующим образом:
На уровне виртуальной машины Java каждый конструктор, написанный на языке программирования Java (JLS §8.8), отображается как метод инициализации экземпляра со специальным именем
<init>
,
Таким образом, JVM инициализирует метод инициализации класса или интерфейса, а не метод инициализации экземпляра, который на самом деле является конструктором. Поэтому им не нужно упоминать, что метод main должен быть статическим в спецификации JVM, поскольку это подразумевается тем фактом, что ни один экземпляр не создается до вызова метода main.
Это просто соглашение. JVM, безусловно, может иметь дело с нестатическими основными методами, если бы это было условием. В конце концов, вы можете определить статический инициализатор для вашего класса и создать миллион объектов перед тем, как попасть в метод main().
Я думаю, что ключевое слово "static" делает метод main методом класса, а методы класса имеют только одну его копию и могут использоваться всеми, а также для него не требуется объект для ссылки. Поэтому, когда класс драйвера скомпилирован, основной метод может быть вызван. (Я просто на уровне алфавита Java, извините, если я не прав)
Истинной точкой входа в любое приложение является статический метод. Если бы язык Java поддерживал метод экземпляра в качестве "точки входа", то среда выполнения должна была бы реализовывать его внутренне как статический метод, который создавал экземпляр объекта с последующим вызовом метода экземпляра.
После этого я рассмотрю обоснование выбора конкретного из следующих трех вариантов:
-
static void main()
как мы видим это сегодня. - Метод экземпляра
void main()
называется недавно построенный объект. - Использование конструктора типа в качестве точки входа (например, если класс входа был вызван
Program
тогда исполнение будет состоять изnew Program()
).
Сломать:
static void main()
- Вызывает статический конструктор окружающего класса.
- Вызывает статический метод
main()
,
void main()
- Вызывает статический конструктор окружающего класса.
- Создает экземпляр окружающего класса путем эффективного вызова
new ClassName()
, - Вызывает метод экземпляра
main()
,
new ClassName()
- Вызывает статический конструктор окружающего класса.
- Создает экземпляр класса (затем ничего не делает с ним и просто возвращает).
Обоснование:
Я пойду в обратном порядке для этого.
Имейте в виду, что одной из целей разработки Java было подчеркнуть (требовать, когда это возможно) хорошие практики объектно-ориентированного программирования. В этом контексте конструктор объекта инициализирует объект, но не должен отвечать за поведение объекта. Таким образом, спецификация, которая дала точку входа new ClassName()
запутало бы ситуацию для новых Java-разработчиков, заставив сделать исключение конструкцию "идеального" конструктора в каждом приложении.
Делая main()
Метод экземпляра, вышеупомянутая проблема, безусловно, решена. Однако это создает сложность, требуя, чтобы спецификация перечисляла подпись конструктора класса входа, а также подпись main()
метод.
В итоге, указав static void main()
создает спецификацию с наименьшей сложностью, придерживаясь принципа размещения поведения в методах. Учитывая, насколько просто реализовать main()
метод, который сам создает экземпляр класса и вызывает метод экземпляра, нет никакого реального преимущества для определения main()
как метод экземпляра.
public
Ключевое слово - это модификатор доступа, который позволяет программисту контролировать видимость членов класса. Когда члену класса предшествует public
затем к этому члену может обращаться код вне класса, в котором он объявлен.
Противоположно public
является private
, что предотвращает использование элемента кодом, определенным вне его класса.
В этом случае, main()
должен быть объявлен как public
, так как он должен вызываться кодом вне своего класса при запуске программы.
Ключевое слово static
позволяетmain()
быть вызванным без необходимости создания конкретного экземпляра класса. Это необходимо, так как main()
вызывается интерпретатором Java перед созданием каких-либо объектов.
Ключевое слово void
просто говорит компилятору, что main()
не возвращает значение.
Я не знаю, вызывает ли JVM метод main перед созданием объектов... Но есть гораздо более веская причина, почему метод main() является статическим... Когда JVM вызывает метод main класса (скажем,, Человек). он вызывает его через "Person.main()". Видите ли, JVM вызывает его по имени класса. Вот почему метод main() должен быть статическим и общедоступным, чтобы JVM мог получить к нему доступ.
Надеюсь, это помогло. Если это так, дайте мне знать, комментируя.
static - когда JVM выполняет вызов метода main, для вызываемого класса не существует объекта, поэтому он должен иметь статический метод, чтобы разрешить вызов из класса.
Публичные ключевые слова static void означают, что интерпретатор виртуальной машины Java (JVM) может вызывать основной метод программы для запуска программы (общедоступный) без создания экземпляра класса (статического), и программа не возвращает данные интерпретатору Java VM. (пусто), когда это заканчивается.
Статическое ключевое слово в методе main используется, потому что в методе main нет никаких экземпляров. Но объект создается, а не вызывается, в результате мы используем статическое ключевое слово в методе main. В jvm контекстная память создается, когда в него загружается класс. И все статические члены присутствуют в этой памяти. если мы сделаем основной статический объект теперь, он будет в памяти и может быть доступен для jvm (class.main(..)), поэтому мы можем вызывать основной метод без необходимости создания даже кучи.
Основной метод программы имеет зарезервированное слово static, что означает, что его можно использовать в статическом контексте. Контекст относится к использованию памяти компьютера во время работы программы. Когда виртуальная машина загружает программу, она создает для нее статический контекст, выделяя память компьютера для хранения программы и ее данных и т. Д. Динамический контекст - это определенный вид выделения памяти, который выполняется позже, во время работы программы. программа. Программа не сможет запуститься, если основной метод не может быть запущен в статическом контексте.
Любой метод, объявленный как статический в Java, принадлежит самому классу. Снова к статическому методу определенного класса можно получить доступ, только обратившись к классу, как Class_name.method_name();
Поэтому не нужно создавать экземпляр класса перед доступом к статическому методу.
Таким образом, метод main() объявлен как static
так что к нему можно получить доступ без создания объекта этого класса.
Так как мы сохраняем программу с именем класса, в котором присутствует метод main (или откуда программа должна начать выполнение, применимо для классов без main()
method()(продвинутый уровень)). Итак, вышеупомянутым способом:
Class_name.method_name();
основной метод может быть доступен.
Вкратце, когда программа компилируется, она ищет main()
метод, имеющий String
аргументы как: main(String args[])
в упомянутом классе (т. е. по названию программы), и поскольку в начале у него нет возможностей для создания экземпляра этого класса, поэтому метод main() объявляется как статический.
Метод main всегда должен быть статическим, потому что в RunTime JVM не создает никаких объектов для вызова метода main, и, как мы знаем в java, статические методы являются единственными методами, которые можно вызывать с использованием имени класса, поэтому основные методы всегда должны быть статическими.
для получения дополнительной информации посетите это видео: https://www.youtube.com/watch?v=Z7rPNwg-bfk&feature=youtu.be
Это объясняется простой причиной, заключающейся в том, что объект не обязан вызывать статический метод. Если бы это был нестатический метод, виртуальная машина Java сначала создает объект, а затем вызывает метод main(), что приведет к проблеме выделения дополнительной памяти.
Это просто соглашение, как мы можем видеть здесь:
Метод должен быть объявлен как public и static, он не должен возвращать никакого значения и должен принимать массив String в качестве параметра. По умолчанию первый неопциональный аргумент - это имя класса, который будет вызван. Следует использовать полное имя класса. Если указана опция -jar, первым аргументом, не являющимся опцией, является имя архива JAR, содержащего файлы классов и ресурсов для приложения, с классом запуска, указанным в заголовке манифеста Main-Class.
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html