Чому основний метод Java статичний?


505

Підпис методу Java main () методу:

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

Чи є причина цього методу статичним?


1
у цьому випадку ми не повинні говорити про підпис методу , оскільки термін стосується лише назв методу та його параметрів
Андрій Тобілко,

Java навмисно призначена для того, щоб виглядати знайомим програмісту на C. Це дуже близько до конвенції C.
Thorbjørn Ravn Andersen

Відповіді:


337

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

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

Чи повинен дзвонити JVM new JavaClass(int)? Що має пройти x?

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

Для цього є занадто багато крайніх випадків і неоднозначностей, щоб мати сенс для JVM, щоб створити екземпляр класу до виклику точки входу. Ось чому mainстатична.

Я поняття не маю, чому mainзавжди позначений public.


4
Реалізація інтерфейсу не вирішує проблему з інстанцією.
Якоб Кралл

26
Мені особисто подобається, що це public static void mainслужить маркером точки входу - громадський конструктор без параметрів не кричить "Це, мабуть, точка входу!" таким же чином.
Джейкоб Кралл

5
@EdwinDalorzo - Що було б досягнуто, примушуючи призначати клас вхідної точки, щоб бути екземпляром? Виклик статичного методу покладає найменше навантаження на клас. Безкоштовно подати заявку, якщо це має більше сенсу для вашого дизайну.
Девід Харкнесс

18
"Якого конструктора слід викликати?" Як це, можливо, навіть проблема? Та сама "проблема" існує і для рішення, яке mainпотрібно закликати. Як не дивно (для вас), JVM справляється з цим просто чудово.
Конрад Рудольф

9
Основний метод завжди є загальнодоступним, оскільки до нього слід звертатися до двигуна виконання - JVM.
gthm

398

Це просто умовність. Насправді навіть назва 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 () замість рядкового масиву).

Отже, довге і коротке: причина статичної - це зручність, що зручно. Причина, яку називають "головною", полягає в тому, що це повинно було бути щось, а головне () - це те, що вони робили за старих часів С (а в ті часи назва функції була важливою). Я припускаю, що java.exe міг би дозволити вам просто вказати повністю кваліфіковане основне ім’я методу, а не просто клас (java com.mycompany.Foo.someSpecialMain) - але це просто ускладнює IDE автоматичним виявленням ' старти 'класів у проекті.


66
+1: Дуже захоплююча (особливо частина про написання звичаю java.exe)
Адам Пейнтер

9
Цікаво, що я не згоден із "Це просто умова". Частина відповіді. Основне питання ОП стало причиною статичності в декларації. Я не думаю, staticщо main()декларація - це лише заради конвенції. Однак те, що це "main ()", а не щось інше, можливо.
Джаред

2
@David Так і було. Я насправді вважав за краще відповідь когось із тих, хто спочатку брав участь, - але це був дуже далеко. Більшість інших відповідей, на жаль, є вправою для спеціальних міркувань. Цей приклад дає досить цікаві деталі, окрім того, що він має смирення не вигадувати неправильні технічні деталі, щоб обґрунтувати (ймовірно) нетехнічну причину.
Конрад Рудольф

2
@Jared - Вони могли вимагати публічного конструктора без аргументів і робити mainнестатичним і все ще вписуватися в межі мови. Не чуючи дизайнерів, нам просто доведеться погодитися не погодитися. :)
Девід Харкнесс

4
@BenVoigt Ви викликаєте LoadLibrary (), щоб отримати dvm dll. Потім ви викликаєте getprocaddress ("JNI_CreateJavaVM"), після чого ви викликаєте функцію JNI_CreateJavaVM ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ). Після завантаження VM ви використовуєте стандартні дзвінки JNI, щоб знайти правильний клас, завантажте основний статичний метод і викликайте його. Тут мало місця для неправильного тлумачення. JNI - це абсолютно те, як ви завантажуєте ВМ. Ви можете звикати писати лише JNI на стороні клієнта, використовуючи нативне ключове слово, javah -jni тощо, але це лише половина JNI.
День Кевіна

188

main()Метод C++, C#і Javaє статичним
Оскільки вони потім можуть бути викликані з допомогою середовища виконання двигуна без необхідності створення екземпляра які - або об'єктів , то код в тілі main()буде робити все інше.


1
Добре, але чи не міг час виконання інстанціювати один об'єкт класу? А потім викликати метод Main? Чому?
Андрій Ронеа

12
Як JVM дізнався, до якого конструктора викликати, якби ваш основний клас перевантажив конструктори? За якими параметрами він би пройшов?
Якоб Кралл

1
@Noah, коли ви говорите батьківський клас, ви маєте на увазі клас, що містить основний метод? Тому що якщо так, то термін "батьківський клас" тут досить заплутаний, інакше для мене це не мало б сенсу. Крім того, якщо за умовами ми використовуємо public static void main..., чому не може бути умовою, що клас точки введення додатка повинен мати публічний конструктор за замовчуванням?
Едвін Далорцо

2
@Jacob Як би JVM дізнався, хто перевантажений static void mainдзвінками? Зовсім не проблема.
Конрад Рудольф

4
@Namratha: Так, щось вам не вистачає. Просто не вірно, що "статичний метод не може посилатися на нестатичний метод". Правильне твердження: "Кожен статичний метод повинен забезпечувати об'єкт при використанні будь-якого нестатичного методу". І подивіться, staticтакі методи, як mainчасто використовують newдля створення такого об’єкта.
Бен Войгт

38

Чому загальнодоступний статичний недійсний main (String [] args)?

Ось так створена мова Java і створена та написана віртуальна машина Java.

Специфікація мови Oracle Java

Перевірте Розділ 12 Виконання - Розділ 12.1.4 Викликати тест. Головна :

Нарешті, після завершення ініціалізації для класу Test (під час якого можуть відбуватися інші послідовні завантаження, зв'язування та ініціалізація), викликається головний метод Test.

Метод основний повинен бути оголошений загальнодоступним, статичним та недійсним. Він повинен прийняти єдиний аргумент, який є масивом рядків. Цей метод можна оголосити як будь-яким

public static void main(String[] args)

або

public static void main(String... args)

Специфікація віртуальної машини Oracle Java

Перевірте Розділ 2 Концепції мови програмування Java - Розділ 2.17 Виконання :

Віртуальна машина Java запускає виконання шляхом виклику методу main деякого визначеного класу та передачі йому єдиного аргументу, який є масивом рядків. Це призводить до завантаження зазначеного класу (§2.17.2), пов'язаного (§2.17.3) з іншими типами, який він використовує, та ініціалізованого (§2.17.4). Метод основний повинен бути оголошений загальнодоступним, статичним та недійсним.

Джерело Oracle OpenJDK

Завантажте та витягніть джерельну банку і подивіться, як написано 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);

... ...

4
Проблема тут полягає в тому, що це насправді дуже гарна відповідь на питання в оригінальному вигляді з великою кількістю посилань (+1). Однак я хотів би дізнатися про обґрунтування дизайнерського рішення прийняття статичного методу вхідною точкою, а не методом конструктора чи екземпляра.
Конрад Рудольф

1
@KonradRudolph, для запитань щодо мови та дизайну специфікацій JVM, можливо, ви можете спробувати зв’язатись із оригінальним джерелом від Oracle і побачити, чи зможете ви отримати якісь позитивні відгуки.
yorkw

2
Взагалі кажучи, коли обчислення результату методу залежить тільки від його параметрів, так що це не залежить від внутрішнього стану об'єкта, він може бути статичним. І рекомендується встановити його як статичне для ремонту коду та його повторної використання. Якщо метод mainне був статичним, це означає, що стан екземпляра класу необхідно знати, і визначити, який конструктор використовувати перший, набагато складніше.
Ів Мартін

@KonradRudolph Цікаво, що Oak (попередник Java) вже вимагав, щоб основний метод мав подібний прототип: public static void main(String arguments[])- Довідка: Дуб 0,2 Spec .
assylias

2
@Yves Це може бути. Це не потрібно, якщо інший дизайн має сенс. Я чув кілька хороших аргументів у коментарях тут, але я все ще думаю, що процес фактично дуже схожий на потік (він є ), а потік на Java зазвичай представляється як екземпляр Runnable. Представляти весь процес однаковим чином (тобто мати Runnable.Runвхідну точку), безумовно, має сенс у Java. Звичайно, Runnableсам по собі є, мабуть, недоліком дизайну, викликаним тим, що у Java немає анонімних методів (поки що). Але оскільки це вже є…
Конрад Рудольф

36

Давайте просто зробимо вигляд, що 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 Тут повний підпис вважається лише одним договором.


1
На насправді, вимоги є більш складними: там повинен бути mainметод , який public, staticі має підпис void main(String[]). Я погоджуюсь, що якби метод був методом екземпляра, JRE мала б трохи більше роботи, але вид роботи був би однаковий, а складність не значно більша (див. Дискусії в коментарях попередньої відповіді). Я не вірю, що ця різниця пояснює рішення про те, щоб стати пунктом вступу статичним, зокрема, оскільки необхідні методи для вирішення методу екземпляра існують і вони легко застосовні.
Конрад Рудольф

3
@KonradRudolph: Моя думка не в тій роботі, яку повинен був би виконати JRE. Моя думка полягає в тому, щоб змусити кожного користувача мови виконувати більше договорів у міру необхідності. У цьому сенсі static public main(String[])метод - це один підпис, а отже, один договір. В іншому випадку потрібно дотримуватися трьох незалежних договорів.
AH

1
Ага. Я все ще не погоджуюся, що це має будь-яке значення. Класи точки входу цілком можуть реалізувати Runnable. Зрозуміло, Java очікує, що розробники постійно дотримуватимуться цього контракту, чому це повинно бути занадто великим для точки введення програми? Це безглуздя.
Конрад Рудольф

3
@KonradRudolph: Немає суперечності: в одному випадку система змусить користувачу три договори. Контракти, які є сумнівними, які не підлягають перевіренню через компілятор і які, з точки зору користувача, є незалежними. У звичайному Threadі Runnableсправі нічого не приховано від користувача, він може ясно бачити , що відбувається , і у нього є зміни , щоб реалізувати тільки ті контракти , які підходять йому - він знаходиться під контролем, а не система.
AH

2
Тут найкраща відповідь. Прикро, що багато користувачів прочитають лише перші 2 або 3 відповіді на сторінці; і цей навряд чи скоро потрапить туди. У ньому згадується важливий момент конструктора, який є ТОЛЬКО для ініціалізації - і тому немає сенсу кодувати в стилі, де конструктор запускає всю програму.
Давуд ібн Карім

14

Якщо це не так, який конструктор слід використовувати, якщо їх більше?

Більше інформації про ініціалізацію та виконання програм Java доступно у специфікації мови Java .


12

Перед тим, як викликати основний метод, жодні об'єкти не інстанціюються. Наявність статичного ключового слова означає, що метод можна викликати, не створюючи спочатку жодних об'єктів.


Неправильно. Або принаймні дуже неточний. public class Main {статичний об’єкт = новий об'єкт () {{System.out.println ("об'єкт створений"); }}; public static void main (String [] args) {System.out.println ("в основному"); }}
eljenso

Справедливий коментар. Технічно я повинен був сказати, що до виклику методу Main клас, що містить основний метод, не є екземпляром.
BlackWasp

12

Тому що в іншому випадку знадобиться екземпляр об'єкта для виконання. Але його потрібно викликати з нуля, не будуючи спочатку об'єкта, оскільки зазвичай це завдання main () функції (bootstrap), щоб проаналізувати аргументи та побудувати об'єкт, як правило, використовуючи ці параметри / параметри програми.


10

Дозвольте мені пояснити ці речі набагато простіше:

public static void main(String args[])

Усі програми Java, крім аплетів, починають їх виконання з main() .

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

static використовується тому, що дозволяє main() викликати без необхідності інстанціювати певний екземпляр цього класу.

voidвказує, що main()не повертає жодного значення.


9

У чому сенс public static void main(String args[])?

  1. public - це специфікатор доступу, який означає, що кожен може отримати доступ до нього або викликати його, наприклад, JVM (Java Virtual Machine.
  2. staticдозволяє main()викликати до того, як був створений об’єкт класу. Це не обов'язково, оскільки 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 */
        }
    }

    Аналогічно, ми використовуємо статичні колись для визначених користувачем методів, так що нам не потрібно робити об’єкти.

  3. voidвказує, що оголошений main()метод не повертає значення.

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

    args- параметр, який містить масив об'єктів класового типу String.


6

Аплети, міді, серветки та боби різних видів будуються, а потім застосовуються методи життєвого циклу. Invoking main - це все, що коли-небудь робиться для основного класу, тому немає необхідності утримувати стан в об'єкті, який викликається кілька разів. Цілком нормально закріплювати основний на іншому класі (хоча це не чудова ідея), який би перешкоджав використанню класу для створення основного об'єкта.


5

Це просто умовність, але, мабуть, зручніше, ніж альтернатива. Зі статичним основним, все, що потрібно знати, щоб викликати програму Java, - це ім'я та місцезнаходження класу. Якщо він не був статичним, ви також повинні знати, як інстанціювати цей клас, або вимагати, щоб у класу був порожній конструктор.


Це не умовність; це частина мовної специфікації; час виконання не визнає клас без статичного основного методу як дійсної точки входу.
Роб

2
Сама мовна специфіка слідує конвенції. Немає фактичної вимоги для дизайнерів Java, які вирішили вимагати статичного основного. Однак, як пояснює Логан, альтернативи є складнішими.
Девід Арно

@DavidArno Було б більше сенсу сказати, що конвенція відповідає мовній специфікації.
Маркіз Лорн

5

Якщо основний метод не був би статичним, вам потрібно створити об’єкт свого основного класу поза програмою. Як би ви хотіли це зробити?


5

Коли ви виконуєте команду віртуальної машини Java (JVM) за допомогою javaкоманди,

java ClassName argument1 argument2 ...

Під час виконання програми ви вказуєте назву її класу як аргумент команди java, як зазначено вище

JVM намагається викликати основний метод вказаного вами класу

—Від цього моменту, жодних об’єктів класу не було створено.

Оголошення mainстатичним allowsJVM invokeосновним withoutстворенням instanceкласу.

повернемося до команди

ClassName- це command-line argumentJVM, який повідомляє, який клас виконувати. Дотримуючись ClassName, ви також можете вказати list of Strings(розділені пробілами) як аргументи командного рядка, які JVM передасть вашій програмі. -Такі аргументи можуть використовуватися для вказівки параметрів (наприклад, імені файлу) для запуску програми. Ось чому String[] argsв основному є параметр, який називається

Посилання: Java ™ Як програмувати (ранні об’єкти), десяте видання


4

Нещодавно подібне запитання було розміщено на Programmers.SE

  • Чому статичний основний метод у Java та C #, а не конструктор?

    Шукаючи остаточну відповідь від первинного чи вторинного джерела, чому (особливо) Java та C # вирішили використовувати статичний метод в якості точки входу, а не представляти екземпляр програми екземпляром Applicationкласу, при цьому точка входу є відповідний конструктор?

TL; DR частина прийнятої відповіді:

Причиною Java public static void main(String[] args)є те, що

  1. Гослінг хотів
  2. код, написаний людиною, що має досвід C (не на Java)
  3. виконуватиметься хтось, хто звик працювати з PostScript на NeWS

http://i.stack.imgur.com/qcmzP.png

 
Для C # міркування транзитивно схожі, так би мовити. Мовні дизайнери зберегли синтаксис точки введення програми, знайомий програмістам, що надходять з Java. Як стверджує архітектор C # Андерс Хейльсберг ,

... наш підхід із C # просто запропонував альтернативу ... програмістам Java ...

...


3

Я думаю, що ключове слово "статичний" робить основний метод методом класу, а методи класів мають лише одну його копію і можуть бути спільними для всіх, а також не потребує об'єкта для посилання. Тож, коли складено клас драйверів, можна використовувати основний метод. (Я просто в алфавіті рівня Java, вибачте, якщо я помиляюся)


Усі методи "мають лише одну копію".
Маркіз Лорнський

3

main () є статичним, тому що; в цей момент життєвого циклу програми стек додатків має процедурний характер, оскільки немає об'єктів, які ще не знайдені.

Це чистий шифер. Ваша програма працює в цей момент, навіть не оголошуючи жодних об'єктів (пам’ятайте, що існують процедурні та схеми кодування OO). Ви, як розробник, перетворите додаток в об'єктно-орієнтоване рішення, створивши екземпляри своїх об'єктів і залежно від коду, складеного всередині.

Об'єктно-орієнтоване чудово підходить для мільйонів очевидних причин. Однак минули дні, коли більшість розробників VB регулярно використовували в своєму коді такі ключові слова, як "goto". "goto" - це процедурна команда в VB, яка замінюється на його аналог OO: метод виклику.

Ви також можете дивитися на статичну точку входу (головну) як на чисту свободу. Якби Java була достатньо різною, щоб створювати об'єкт і представляти вам лише цей екземпляр під час запуску, у вас не було б вибору АЛЕ написати процедурний додаток. Як би немислимо це не звучало для Java, можливо, існує багато сценаріїв, які вимагають процедурних підходів.

Це, мабуть, дуже незрозуміла відповідь. Пам'ятайте, що "клас" - це лише сукупність взаємопов'язаних кодів. "Екземпляр" - це ізольоване, живе і дихаюче автономне покоління цього класу.


7
Це неправильно. Багато об'єктів інстанціонується до того, як mainбуде досягнуто. І якщо ви включите статичний конструктор до класу, що містить main, він виконується і раніше main.
Конрад Рудольф

2

Це просто умовність. JVM, безумовно, може мати справу з нестатичними основними методами, якби це була конвенція. Зрештою, ви можете визначити статичний ініціалізатор у своєму класі та інстанціювати мільйон об’єктів, перш ніж потрапити до вашого основного () методу.


2

Прототип public static void main(String[])- це конвенція, визначена в JLS :

Метод основний повинен бути оголошений загальнодоступним, статичним та недійсним. Він повинен вказати формальний параметр (§ 8.4.1), декларований тип якого є масив String.

У специфікації JVM 5.2. Запуск віртуальної машини ми можемо читати:

Віртуальна машина Java запускається шляхом створення початкового класу, який задається залежним від реалізації способом, використовуючи завантажувач класів завантаження (§5.3.1). Потім віртуальна машина Java пов'язує початковий клас, ініціалізує його та викликає метод void main публічного класу (String []) . Викликання цього методу приводить до подальшого виконання. Виконання інструкцій віртуальної машини Java, що складають основний метод, може спричинити зв'язок (і, отже, створення) додаткових класів та інтерфейсів, а також виклик додаткових методів.

Цікаво, що в специфікації JVM не зазначається, що основний метод повинен бути статичним. Але специфікація також говорить, що віртуальна машина Java виконує 2 кроки раніше:

Ініціалізація класу або інтерфейсу складається з виконання його класу або методу ініціалізації інтерфейсу.

У 2.9. Спеціальні методи :

Метод класу або ініціалізації інтерфейсу визначається:

Клас або інтерфейс має максимум один метод ініціалізації класу або інтерфейсу і ініціалізується (§5.5) шляхом виклику цього методу. Метод ініціалізації класу або інтерфейсу має спеціальну назву <clinit>, не бере аргументів і недійсний.

І метод ініціалізації класу або інтерфейсу відрізняється від методу ініціалізації екземпляра, визначеного наступним чином:

На рівні віртуальної машини Java кожен конструктор, написаний мовою програмування Java (JLS § 8.8), виступає як метод ініціалізації екземпляра, який має спеціальну назву <init>.

Отже, JVM ініціалізує метод ініціалізації класу чи інтерфейсу, а не an метод ініціалізації екземпляра, який насправді є конструктором. Тому їм не потрібно згадувати, що основний метод повинен бути статичним у специфікації JVM, оскільки це мається на увазі через те, що жоден екземпляр не створюється перед викликом основного методу.


2

publicКлючове слово є модифікатором доступу, який дозволяє програмісту управляти видимістю членів класу. Коли члену класу передує public, то до нього може бути доступний код за межами класу, в якому він оголошений.

Протилежність public є private, що не дозволяє користувачеві використовувати код, визначений поза його класом.

В цьому випадку, main() повинен бути оголошений як public, оскільки він повинен бути викликаний кодом поза його класом при запуску програми.

Ключове слово staticдозволяє main() викликати без необхідності інстанціювати певний екземпляр класу. Це необхідно, оскільки main()викликає інтерпретатор Java до того, як будуть зроблені будь-які об'єкти.

Ключове слово voidпросто повідомляє компілятору, що main()не повертає значення.


1

Справжньою точкою входу до будь-якої програми є статичний метод. Якщо мова Java підтримувала метод екземпляра як "точку входу", тоді час виконання повинен буде реалізувати його внутрішньо як статичний метод, який побудував екземпляр об'єкта, після чого викликав метод екземпляра.

Якщо це не вийде, я вивчу обґрунтування вибору конкретного одного з наступних трьох варіантів:

  1. A, static void main()як ми це бачимо сьогодні.
  2. Метод екземпляра, що void main()викликається на щойно побудованому об'єкті.
  3. Використання конструктора типу як точки входу (наприклад, якщо клас запису викликався Program, то виконання буде ефективно складатися зnew Program() ).

Зламатися:

static void main()

  1. Викликає статичний конструктор класу, що вкладається.
  2. Викликає статичний метод main().

void main()

  1. Викликає статичний конструктор класу, що вкладається.
  2. Побудовує екземпляр класу, що додає, ефективно викликаючи new ClassName() .
  3. Викликає метод екземпляра main().

new ClassName()

  1. Викликає статичний конструктор класу, що вкладається.
  2. Конструює екземпляр класу (тоді нічого не робить з ним і просто повертається).

Обгрунтування:

Я піду в зворотному порядку для цього.

Майте на увазі, що однією з цілей дизайну Java було наголосити (вимагати, коли це можливо) належних об'єктно-орієнтованих практик програмування. У цьому контексті конструктор об'єкта ініціалізує об'єкт, але не повинен нести відповідальність за поведінку об'єкта. Тому специфікація, яка дала вхідну точкуnew ClassName() , заплутала б ситуацію для нових розробників Java, примушуючи виняток до дизайну "ідеального" конструктора для кожної програми.

Створюючи main()метод екземпляра, вищезазначена проблема, безумовно, вирішується. Однак це створює складність, вимагаючи специфікації, щоб перелічити підпис конструктора вхідного класу, а також підписmain() методу.

Підсумовуючи, вказівка ​​a static void main()створює специфікацію з найменшою складністю, дотримуючись принципу розміщення поведінки у методах . З огляду на те, наскільки просто реалізувати main()метод, який сам будує екземпляр класу та викликає метод екземпляра, немає реальної переваги вказувати main()як метод екземпляра.


1
Це просто випрошує питання. Java все одно потребує завантажувач додатків, який робить важкий підйом перед викликом main. Ваше обгрунтування mainнадто складного для початківців видається неймовірним. Насправді, статичний mainє дуже заплутаним для початківців, я сумніваюся, що конструктор буде більше. Ви кажете, що "конструктор не повинен відповідати за поведінку об'єкта". Це звучить цікаво, але я не впевнений, що згоден. Чому ні? Що це заважає?
Конрад Рудольф

1

статичний - Коли JVM робить виклик до основного методу, для об'єкта, який викликається, немає об'єкта, тому він повинен мати статичний метод, щоб дозволити виклик з класу.


1

Я не знаю, чи JVM викликає основний метод перед тим, як об'єкти ініціюються ... Але є набагато більш потужна причина, чому метод main () є статичним ... Коли JVM викликає основний метод класу (скажімо , Особа). він викликає його " Person.main () ". Розумієте, JVM викликає його за назвою класу. Ось чому головний () метод повинен бути статичним і загальнодоступним, щоб до нього можна було отримати доступ.

Сподіваюся, це допомогло. Якщо це було так, повідомте мене, коментуючи.


0

Статичні методи не потребують жодного об'єкта. Вона працює безпосередньо, тому основна програма працює безпосередньо.


0

Статичне ключове слово в основному методі використовується тому, що в основному методі немає жодної інстанції. Але об'єкт побудований, а не виклик, в результаті ми використовуємо статичне ключове слово в основному методі. У контексті jvm пам'ять створюється, коли клас завантажується в неї. І всі статичні члени присутні в цій пам'яті. якщо ми зробимо головну статику зараз, вона буде в пам’яті і може бути доступною jvm (class.main (..)), тому ми можемо викликати основний метод з необхідністю навіть створити купу.


0

Це просто умова, як ми можемо бачити тут:

Метод повинен бути оголошений загальнодоступним та статичним , він не повинен повертати жодного значення, і він повинен приймати масив String як параметр. За замовчуванням перший аргумент необов'язковий - це ім'я класу, до якого слід викликати. Слід використовувати повноцінне ім'я класу. Якщо вказано параметр -jar, перший аргумент, що не відповідає параметру, - це ім'я архіву JAR, що містить файли класів та ресурсів для програми, із класом запуску, вказаним заголовком маніфесту Main-Class.

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description


Правило мови, ви маєте на увазі.
Маркіз Лорн

0

Публічні статичні недійсні ключові слова означають, що інтерпретатор віртуальної машини Java (JVM) може викликати основний метод програми для запуску програми (public) без створення екземпляра класу (статичного), і програма не повертає дані інтерпретатору Java VM (пустота), коли вона закінчується.

Джерело: Основи, Частина 1, Урок 2: Будівництво


0

В основному ми робимо ті ЧЛЕНИ ДАНИХ і ФУНКЦІЇ ЧЛЕНА як СТАТИЧНІ, які не виконують жодного завдання, пов'язаного з об'єктом. І у випадку головного методу ми робимо це як СТАТИЧНИЙ, оскільки це не має нічого спільного з об'єктом, оскільки основний метод завжди працює, створюємо ми об’єкт чи ні.


0

Будь-який метод, оголошений статичним в Java, належить до самого класу. Знову статичний метод певного класу можна отримати, лише звернувшись до класу типуClass_name.method_name();

Таким чином, клас не повинен бути екземпляром, перш ніж отримати доступ до статичного методу.

Отже, метод main () оголошується staticтаким, що до нього можна отримати доступ, не створюючи об'єкт цього класу.

Оскільки ми зберігаємо програму з назвою класу, де присутній основний метод (або з того, звідки програма повинна розпочати його виконання, застосовна для класів без main()методу () (Розширений рівень)). Отже, вищезгаданим способом:

Class_name.method_name();

До головного методу можна отримати доступ.

Якщо коротко, коли програма складається, вона шукає main()метод, що має Stringтакі аргументи: main(String args[])у згаданому класі (тобто за назвою програми), і оскільки на початку у нього немає можливості інстанціювати цей клас, тому main () метод оголошено статичним.


Це відбувається, коли програма виконується, а не компілюється.
Маркіз Лорн

0

Від java.sun.com (на сайті є додаткова інформація):

Основний метод - статичний, щоб дати інтерпретатору Java VM спосіб запустити клас, не створюючи спочатку екземпляр класу управління. Екземпляри класу управління створюються в основному методі після запуску програми.

Моє розуміння завжди полягало в тому, що основний метод, як і будь-який статичний метод, можна викликати без створення примірника асоційованого класу, що дозволяє йому запускатись перед будь-чим іншим у програмі. Якби це не було статичним, вам доведеться інстанціювати об'єкт перед тим, як викликати його - що створює проблему "курка та яйце", оскільки головний метод, як правило, те, що ви використовуєте для інстанцізації об'єктів на початку програми.


Але він не працює "раніше нічого в програмі". Весь аргумент - це помилковість, і більше того, це не перша відповідь, в якій згадується, навіть навіть друга чи третя.
Конрад Рудольф

Мені шкода, що моя відповідь повторює те, що сказали інші; Я відповів лише найкраще, наскільки я розумів, і з того, що міг знайти в Інтернеті. З результатів, які я подивився, немає інших причин того, чому основний метод є статичним; хіба що є десь глибоко прихований десь, можливо, це єдина відповідь. Моє розуміння Java є досить базовим, але я чула вищезгадану причину (від професорів, підручників тощо) і ніколи іншої.
Джессі М

@Jesse M Ваш коментар має сенс лише в тому випадку, якщо ви навіть не подумали спочатку прочитати інші відповіді. Що, до речі, далеко не надумана справа. Як ви вже згадували про себе, ваше розуміння є досить базовим, тому дуже ймовірно, що хтось уже відповів на питання більш компетентно. І ваш коментар здається раціоналізацією для того, щоб ваша відповідь виглядала краще. Це надзвичайне твердження, що у вас є підручники Java та професори, які думають, що ви заявляєте, і, чесно кажучи, я не вірю, що вони так роблять. (Якісь посилання?)
LeoR

1
@KonradRudolph Найкращі коментарі здаються досить розумними. main () використовується як вхідний пункт до програми, і на веб-сайті Java є кілька посилань, які говорять про те, що це повинно бути схожим на те, як C / C ++ мають головну () функцію. Оскільки Java - це всі об'єкти, вона повинна бути статичною, щоб уникнути створення об'єктів. Наявність його статичним також дозволяє його завантажувати та виконувати в JVM під час виконання. Я просто повторюю попередні відповіді, але мені цікаво, що ви вважаєте задовільною. Я думаю, що найкраще у вас вийде "Ось так вони цього хотіли". Майте на увазі дату виготовлення Java.
trevor-e

1
@Jesse Spot-on. Цілком можливо, що це лише питання конвенції (хоча я сподіваюся, що це не так, це була б така нудна відповідь). Моє первісне зацікавлення цим питанням було тому, що я вважав, що використання власного екземпляра для представлення об'єкта «запущеної програми» та мати точку входу як метод (або конструктор) цього класу було б набагато очевиднішим дизайном, оскільки Java був розроблений як об'єктно-орієнтований під час руху, і оскільки, здавалося б, аналогічні об'єкти (потоки, через Runnable) в Java справді використовують цей дизайн. Чому тут (очевидний) виняток?
Конрад Рудольф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.