Почему основной метод Java статичен? - PullRequest
481 голосов
/ 28 сентября 2008

Подпись метода Java main () метод:

public static void main(String[] args){
    ...
}

Есть ли причина для статичности этого метода?

Ответы [ 37 ]

378 голосов
/ 30 сентября 2008

Это просто соглашение. На самом деле, даже имя 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' запускаемые классы в проекте.

323 голосов
/ 29 сентября 2008

Метод является статическим, потому что в противном случае возникла бы неоднозначность: какой конструктор должен быть вызван? Особенно, если ваш класс выглядит так:

public class JavaClass{
  protected JavaClass(int x){}
  public void main(String[] args){
  }
}

Должна ли JVM вызывать new JavaClass(int)? Что должно пройти за x?

Если нет, должна ли JVM создавать экземпляр JavaClass без запуска какого-либо метода конструктора? Я думаю, что это не должно произойти, потому что это будет в особом случае весь ваш класс - иногда у вас есть экземпляр, который не был инициализирован, и вы должны проверять его в каждом вызываемом методе.

Слишком много граничных случаев и неопределенностей, чтобы JVM имела смысл создавать экземпляр класса перед вызовом точки входа. Вот почему main является статичным.

Понятия не имею, почему main всегда помечено public.

185 голосов
/ 28 сентября 2008

Метод main() в C++, C# и Java является статическим
Поскольку они могут быть вызваны механизмом времени выполнения без необходимости создавать экземпляры каких-либо объектов, код в теле main() сделает все остальное.

37 голосов
/ 12 июля 2012

Почему общедоступная статическая пустота main (String [] args)?

Вот как разрабатывается язык Java и разрабатывается и пишется виртуальная машина Java.

Спецификация языка Java Oracle

Извлечение Глава 12 Выполнение - раздел 12.1.4 Invoke 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

Скачайте и распакуйте исходный файл 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);

... ...
32 голосов
/ 15 июля 2012

Давайте просто притворимся, что 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 был разработан как простой язык для пользователя , неудивительно, что точка входа в приложение была разработана простым способом с использованием one контракта сложный способ с использованием трех независимых и хрупких контрактов.

Обратите внимание: этот аргумент не о простоте внутри JVM или внутри JRE. Этот аргумент о простоте для пользователя .


1 Здесь полная подпись считается только одним контрактом.
14 голосов
/ 28 сентября 2008

Если это не так, какой конструктор следует использовать, если их несколько?

Более подробная информация об инициализации и выполнении программ Java доступна в Спецификации языка Java .

12 голосов
/ 28 сентября 2008

Потому что в противном случае потребуется экземпляр объекта для выполнения. Но он должен вызываться с нуля, без предварительного конструирования объекта, поскольку обычно задача main () (bootstrap) состоит в том, чтобы проанализировать аргументы и построить объект, обычно используя эти аргументы / параметры программы.

12 голосов
/ 28 сентября 2008

До вызова основного метода не создаются объекты. Наличие ключевого слова static означает, что метод можно вызывать без предварительного создания каких-либо объектов.

9 голосов
/ 08 июля 2013

Что означает public static void main(String args[])?

  1. public - это спецификатор доступа, означающий, что любой может получить к нему доступ, например JVM (виртуальная машина Java).
  2. static позволяет вызывать main() до создания объекта класса. Это необходимо, потому что JVM вызывает main() до создания каких-либо объектов. Поскольку он статический, его можно напрямую вызывать через класс.

    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 для пользовательских методов, поэтому нам не нужно создавать объекты.

  3. void означает, что объявлен метод main() не возвращает значение.

  4. String[] args указывает единственный параметр в методе main().

    args - параметр, который содержит массив объектов типа класса String.

9 голосов
/ 09 мая 2015

Позвольте мне объяснить эти вещи гораздо проще:

public static void main(String args[])

Все Java-приложения, кроме апплетов, начинают выполнение с main().

Ключевое слово public - это модификатор доступа, который позволяет вызывать член извне класса.

static используется потому, что позволяет вызывать main() без создания экземпляра определенного экземпляра этого класса.

void указывает, что main() не возвращает никакого значения.

...