Dlaczego główna metoda Java jest statyczna?


505

Podpis metody metody main () Java to:

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

Czy istnieje powód, aby ta metoda była statyczna?


1
w tym przypadku nie powinniśmy wypowiadać podpisu metody , ponieważ termin odnosi się tylko do nazw metod i ich parametrów
Andrew Tobilko,

Java jest celowo zaprojektowana tak, aby wyglądała znajomo dla programisty C. Jest to bardzo zbliżone do konwencji C.
Thorbjørn Ravn Andersen

Odpowiedzi:


337

Metoda jest statyczna, ponieważ w przeciwnym razie pojawiłaby się dwuznaczność: który konstruktor powinien zostać wywołany? Zwłaszcza jeśli twoja klasa wygląda tak:

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

Czy JVM powinien zadzwonić new JavaClass(int)? Na co powinien przejść x?

Jeśli nie, to czy JVM powinien utworzyć instancję JavaClassbez uruchamiania żadnej metody konstruktora? Myślę, że nie powinno tak być, ponieważ w szczególny sposób zajmie się to cała twoja klasa - czasami masz instancję, która nie została zainicjowana i musisz ją sprawdzić za pomocą każdej metody, którą można wywołać.

Jest zbyt wiele przypadków krawędzi i niejednoznaczności, aby JVM musiało tworzyć instancję klasy przed wywołaniem punktu wejścia. Dlatego mainjest statyczny.

Nie mam pojęcia, dlaczego mainzawsze jest zaznaczony public.


4
Implementacja interfejsu nie rozwiązuje problemu tworzenia instancji.
Jacob Krall,

26
Osobiście podoba mi się, że public static void mainsłuży jako znacznik punktu wejścia - publiczny konstruktor bez parametrów nie krzyczy „To prawdopodobnie punkt wejścia!” w ten sam sposób.
Jacob Krall

5
@EdwinDalorzo - Co można uzyskać, zmuszając do utworzenia instancji klasy punktu wejścia? Wywołanie metody statycznej powoduje najmniejsze obciążenie klasy. Tworzenie instancji jest bezpłatne, jeśli ma to większy sens dla twojego projektu.
David Harkness

18
„Który konstruktor powinien zostać nazwany?” Jak to w ogóle możliwe ? Ten sam „problem” istnieje w przypadku decyzji, maindo której należy zadzwonić. Co dziwne (dla ciebie), JVM dobrze sobie z tym radzi.
Konrad Rudolph,

9
Główna metoda jest zawsze publiczna, ponieważ dostęp do niej musi mieć silnik wykonawczy JVM.
gthm

398

To tylko konwencja. W rzeczywistości nawet nazwa main () i przekazane argumenty są czysto konwencjonalne.

Po uruchomieniu java.exe (lub javaw.exe w systemie Windows) tak naprawdę dzieje się kilka wywołań Java Native Interface (JNI). Te wywołania ładują bibliotekę DLL, która tak naprawdę jest JVM (to prawda - java.exe NIE JVM). JNI to narzędzie, którego używamy, gdy musimy łączyć świat maszyn wirtualnych, świat C, C ++ itp. Odwrotność jest również prawdą - nie jest możliwe (przynajmniej o ile wiem) uzyskanie JVM działa bez użycia JNI.

Zasadniczo java.exe to bardzo prosta aplikacja C, która analizuje wiersz poleceń, tworzy nową tablicę String w JVM do przechowywania tych argumentów, analizuje nazwę klasy określoną jako zawierającą main (), używa wywołań JNI do znalezienia sama metoda main (), a następnie wywołuje metodę main (), przekazując nowo utworzoną tablicę ciągów jako parametr. Jest to bardzo, bardzo podobne do tego, co robisz, gdy używasz odbicia od Javy - zamiast tego używa tylko mylących nazw natywnych wywołań funkcji.

Byłoby całkowicie legalne, aby napisać własną wersję pliku java.exe (źródło jest rozpowszechniane z JDK) i pozwolić mu zrobić coś zupełnie innego. W rzeczywistości to właśnie robimy ze wszystkimi naszymi aplikacjami opartymi na Javie.

Każda z naszych aplikacji Java ma własny program uruchamiający. Robimy to przede wszystkim, aby uzyskać własną ikonę i nazwę procesu, ale przydało się to w innych sytuacjach, w których chcemy zrobić coś poza zwykłym wywołaniem main (), aby uruchomić rzeczy (na przykład w jednym przypadku robimy Współdziałanie COM, i faktycznie przekazujemy uchwyt COM do main () zamiast tablicy łańcuchów).

Tak długo i krótko: powodem, dla którego jest statyczny, jest b / c to wygodne. Powodem jest to, że nazywa się to „main”, ponieważ musiało to być coś, a main () jest tym, co robili w dawnych czasach C (w tamtych czasach nazwa funkcji była ważna). Przypuszczam, że java.exe mógł pozwolić ci tylko na podanie w pełni kwalifikowanej nazwy głównej metody, a nie tylko na klasę (java com.mycompany.Foo.someSpecialMain) - ale to tylko utrudnia IDE automatyczne wykrywanie „ uruchamialne ”klasy w projekcie.


66
+1: Bardzo fascynujące (szczególnie część o pisaniu niestandardowego java.exe)
Adam Paynter

9
Co ciekawe, nie zgadzam się z „To tylko konwencja”. Część odpowiedzi. Głównym pytaniem PO był powód statyczności w deklaracji. Nie sądzę, staticaby main()deklaracja była tylko dla celów konwencji. Fakt, że jest to „main ()”, a nie coś innego, jest jednak wykonalny.
Jared

2
@David Tak się stało. Wolałbym odpowiedź od jednej z osób, które były pierwotnie zaangażowane - ale było to bardzo dalekie wyjście. Większość pozostałych odpowiedzi jest niestety ćwiczeniem z rozumowania ad hoc. Ten podaje dość interesujące szczegóły, oprócz tego, że ma się pokorę, aby nie wymyślać złych szczegółów technicznych, aby uzasadnić (prawdopodobnie) nietechniczną przyczynę.
Konrad Rudolph,

2
@Jared - Mogliby wymagać publicznego konstruktora no-arg i uczynić go mainniestatycznym i nadal mieszczącym się w granicach języka. Bez odpowiedzi od projektantów będziemy musieli zgodzić się z tym. :)
David Harkness,

4
@BenVoigt Wywołujesz LoadLibrary (), aby uzyskać dll jvm. Następnie wywołujesz getprocaddress („JNI_CreateJavaVM”), a następnie wywołujesz funkcję JNI_CreateJavaVM ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ). Po załadowaniu maszyny wirtualnej używasz standardowych wywołań JNI, aby znaleźć poprawną klasę, załadować statyczną metodę główną i wywołać ją. Nie ma tu wiele miejsca na błędną interpretację. JNI jest absolutnie jak ładujesz maszynę wirtualną. Możesz być przyzwyczajony do pisania tylko JNI po stronie klienta przy użyciu natywnego słowa kluczowego, javah -jni itp., Ale to tylko połowa JNI.
Kevin Day,

188

main()Metoda C++, C#i Javasą statyczne
Ponieważ mogą one być następnie wywołany przez silnik wykonawczego bez konieczności wystąpienia jakichkolwiek przedmiotów następnie kod w ciele main()zrobi resztę.


1
W porządku, ale czy środowisko wykonawcze nie może utworzyć jednego obiektu klasy? A następnie wywołać metodę Main? Dlaczego?
Andrei Rînea

12
Skąd JVM wiedziałby, do którego konstruktora zadzwonić, gdyby Twoja główna klasa przeciążała konstruktory? Jakie parametry przejdzie?
Jacob Krall

1
@ Nie, kiedy mówisz, że klasa nadrzędna masz na myśli klasę zawierającą główną metodę? Ponieważ jeśli tak, to określenie „klasa rodzicielska” jest tutaj dość mylące, w przeciwnym razie nie miałoby to dla mnie sensu. Ponadto, jeśli zgodnie z konwencją używamy public static void main..., dlaczego nie może być tak, że klasa punktu wejścia aplikacji powinna mieć domyślnego publicznego konstruktora?
Edwin Dalorzo

2
@Jacob Skąd JVM wiedziałby, który static void maintelefon jest przeciążony ? Nie ma problemu.
Konrad Rudolph

4
@Namratha: Tak, czegoś brakuje. Po prostu nie jest prawdą, że „metoda statyczna nie może odwoływać się do metody niestatycznej”. Prawidłowe zdanie brzmi: „Każda metoda statyczna musi zapewniać obiekt, gdy używana jest dowolna metoda niestatyczna”. I popatrz, staticmetody takie jak mainczęsto używają newdo stworzenia takiego obiektu.
Ben Voigt

38

Dlaczego public static void main (String [] args)?

Tak zaprojektowano język Java, a wirtualną maszynę Java zaprojektowano i napisano.

Specyfikacja języka Java Oracle

Sprawdź rozdział 12 Wykonanie - rozdział 12.1.4 Wywołanie testu. Główne :

Wreszcie po zakończeniu inicjalizacji testu klasy (podczas którego mogły wystąpić inne kolejne ładowanie, łączenie i inicjowanie), wywoływana jest metoda główna testu.

Metoda main musi być zadeklarowana jako publiczna, statyczna i nieważna. Musi zaakceptować pojedynczy argument, który jest tablicą ciągów. Metodę tę można zadeklarować jako jedną z nich

public static void main(String[] args)

lub

public static void main(String... args)

Specyfikacja wirtualnej maszyny Oracle Java

Sprawdź Rozdział 2 Pojęcia dotyczące języka programowania Java - Część 2.17 Wykonanie :

Wirtualna maszyna Java rozpoczyna wykonywanie, wywołując metodę main określonej klasy i przekazując jej pojedynczy argument, który jest tablicą ciągów. Powoduje to załadowanie określonej klasy (§2.17.2), połączenie (§2.17.3) z innymi używanymi typami i zainicjowanie (§2.17.4). Metoda main musi być zadeklarowana jako publiczna, statyczna i nieważna.

Źródło Oracle OpenJDK

Pobierz i rozpakuj źródłowy słoik i zobacz, jak napisana jest JVM, sprawdź ../launcher/java.c, który zawiera natywny kod C za poleceniem 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
Problem polega na tym, że w rzeczywistości jest to bardzo dobra odpowiedź na pytanie w oryginalnej formie, z dużą ilością odniesień (+1). Chciałbym jednak dowiedzieć się o uzasadnieniu decyzji projektowej, aby zamiast metody konstruktora lub instancji zastosować metodę statyczną jako punkt wejścia.
Konrad Rudolph

1
@KonradRudolph, w przypadku pytań dotyczących języka i specyfikacji specyfikacji JVM, być może możesz skontaktować się z oryginalnym źródłem Oracle i sprawdzić, czy możesz uzyskać pozytywne opinie.
yorkw

2
Mówiąc ogólnie, gdy obliczenie wyniku metody zależy tylko od jej parametrów, a więc nie zależy od stanu wewnętrznego instancji obiektu, może być statyczne. I zaleca się ustawienie go jako statycznego dla utrzymania / ponownego użycia kodu. Jeśli metoda mainnie była statyczna, oznacza to, że stan instancji klasy musi być znany, a jego zdefiniowanie jest znacznie bardziej skomplikowane, podobnie jak tego, który konstruktor powinien zastosować jako pierwszy.
Yves Martin

@KonradRudolph Co ciekawe, Oak (poprzednik Javy) już wymagał, aby główna metoda miała podobny prototyp: public static void main(String arguments[])- Odniesienie: specyfikacja Oak 0.2 .
assylias

2
@ Yves Może być. Nie musi, jeśli inny projekt ma sens. Słyszałem kilka dobrych argumentów w komentarzach tutaj, ale nadal uważam, że proces jest bardzo podobny do wątku (tak jest ), a wątek w Javie jest zwykle reprezentowany jako przykład Runnable. Reprezentacja całego procesu w ten sam sposób (tj. Runnable.RunJako punkt wejścia) zdecydowanie ma sens w Javie. Oczywiście Runnablesama w sobie jest prawdopodobnie wadą projektową, ponieważ Java nie ma (jeszcze) anonimowych metod. Ale skoro już tam jest…
Konrad Rudolph

36

Udawajmy, że staticnie byłby wymagany jako punkt wejścia aplikacji.

Klasa aplikacji wyglądałaby wtedy następująco:

class MyApplication {
    public MyApplication(){
        // Some init code here
    }
    public void main(String[] args){
        // real application code here
    }
}

Różnica między kodem konstruktora a mainmetodą jest konieczna, ponieważ w OO konstruktor upewnia się tylko, że instancja jest poprawnie zainicjowana . Po inicjalizacji instancja może zostać użyta dla zamierzonej „usługi”. Umieszczenie pełnego kodu aplikacji w konstruktorze zepsułoby to.

Podejście to wymusiłoby na aplikacji trzy różne umowy:

  • Tam musi być konstruktor domyślny. W przeciwnym razie JVM nie wiedziałby, który konstruktor ma zadzwonić i jakie parametry należy podać.
  • Tam musi być mainmetoda 1 . Ok, to nie jest zaskakujące.
  • Klasa nie może być abstract. W przeciwnym razie JVM nie może go utworzyć.

Z staticdrugiej strony podejście wymaga tylko jednej umowy:

  • Musi być mainmetoda 1 .

Tutaj nie ma znaczenia abstractani wiele konstruktorów.

Ponieważ Java została zaprojektowana jako prosty język dla użytkownika, nie jest zaskakujące, że również punkt wejścia aplikacji został zaprojektowany w prosty sposób przy użyciu jednej umowy, a nie w skomplikowany sposób przy użyciu trzech niezależnych i kruchych umów.

Uwaga: ten argument to nie dotyczy prostoty w JVM ani w JRE. Ten argument dotyczy prostoty użytkownika .


1 Tutaj kompletny podpis liczy się jako tylko jedna umowa.


1
Faktycznie, wymagania są bardziej złożone: musi istnieć mainmetoda, która jest public, statici ma podpis void main(String[]). Zgadzam się, że gdyby metoda była metodą instancji, środowisko JRE miałoby nieco więcej pracy, ale rodzaj pracy byłby taki sam, a złożoność nie byłaby znacząco wyższa (patrz dyskusje w komentarzach do poprzedniej odpowiedzi). Nie sądzę, aby ta różnica stanowiła podstawę do ustalenia statycznego punktu wejścia, w szczególności dlatego, że istnieją wymagane metody rozstrzygania metody instancji i są one z łatwością użyteczne.
Konrad Rudolph

3
@KonradRudolph: Nie mam na myśli pracy, którą JRE musiałoby wykonać. Chodzi mi o to, aby zmusić każdego użytkownika języka do przestrzegania kolejnych umów w razie potrzeby. W tym sensie static public main(String[])metoda jest jednym podpisem, a zatem jedną umową. W przeciwnym razie należy przestrzegać trzech niezależnych umów.
AH

1
Ach Nadal nie zgadzam się z tym, że robi to jakąkolwiek różnicę. Klasy punktów wejścia mogłyby również zostać zaimplementowane Runnable. Oczywiście Java oczekuje, że programiści będą przestrzegać tej umowy przez cały czas, dlaczego miałaby to być zbyt duża wartość dla punktu wejścia aplikacji? To nie ma sensu.
Konrad Rudolph

3
@KonradRudolph: Nie ma sprzeczności: w jednym przypadku system narzuciłby trzy umowy na użytkownika. Kontrakty, które są wątpliwe, które nie są możliwe do sprawdzenia przez kompilator i które są z punktu widzenia użytkownika niezależne. W zwykłym Threadi Runnablesprawa nic nie jest ukryte przed użytkownikiem, może wyraźnie zobaczyć, co się dzieje i ma on zmianę do realizacji tylko te kontrakty, które mu odpowiadają - on jest pod kontrolą, a nie system.
AH

2
To najlepsza odpowiedź tutaj. Szkoda, że ​​wielu użytkowników czyta tylko 2 lub 3 najlepsze odpowiedzi na stronie; i jest mało prawdopodobne, że dotrze tam w najbliższym czasie. Wspomina o tym, że konstruktor jest ważny TYLKO do inicjalizacji - dlatego nie ma sensu kodować w stylu, w którym konstruktor uruchamia całą aplikację.
Dawood ibn Kareem

14

Jeśli nie, to jakiego konstruktora należy użyć, jeśli jest więcej niż jeden?

Więcej informacji na temat inicjowania i wykonywania programów Java dostępnych jest w specyfikacji języka Java .


12

Przed wywołaniem głównej metody żadne obiekty nie są tworzone. Posiadanie statycznego słowa kluczowego oznacza, że ​​można wywołać metodę bez wcześniejszego tworzenia jakichkolwiek obiektów.


Źle. A przynajmniej bardzo nieprecyzyjne. public class Main {static Object object = new Object () {{System.out.println („obiekt utworzony”); }}; public static void main (String [] args) {System.out.println ("in main"); }}
eljenso

Uczciwy komentarz. Technicznie powinienem był powiedzieć, że przed wywołaniem metody Main klasa zawierająca metodę main nie jest tworzona.
BlackWasp

12

Ponieważ w przeciwnym razie musiałaby zostać wykonana instancja obiektu. Należy go jednak wywołać od zera, bez konstruowania obiektu, ponieważ zwykle zadaniem funkcji main () (bootstrap) jest parsowanie argumentów i konstruowanie obiektu, zwykle przy użyciu tych parametrów argumentów / programu.


10

Pozwól mi wyjaśnić te rzeczy w znacznie prostszy sposób:

public static void main(String args[])

Wszystkie aplikacje Java, z wyjątkiem apletów, rozpoczynają wykonywanie od main().

Słowo kluczowe publicjest modyfikatorem dostępu, który umożliwia wywoływanie członka spoza klasy.

staticjest używana, ponieważ pozwala main()na wywołanie bez konieczności tworzenia instancji określonej instancji tej klasy.

voidwskazuje, że main()nie zwraca żadnej wartości.


9

Co to znaczy public static void main(String args[])?

  1. public jest specyfikatorem dostępu, co oznacza, że ​​każdy może uzyskać do niego dostęp / wywołać go, na przykład JVM (Java Virtual Machine.
  2. staticpozwala main()na wywołanie przed utworzeniem obiektu klasy. Jest to konieczne, ponieważ main()JVM wywołuje je przed utworzeniem jakichkolwiek obiektów. Ponieważ jest statyczny, można go bezpośrednio wywoływać za pośrednictwem klasy.

    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 */
        }
    }

    Podobnie, czasami używamy statycznego dla metod zdefiniowanych przez użytkownika, więc nie musimy tworzyć obiektów.

  3. voidwskazuje, main()że zadeklarowana metoda nie zwraca wartości.

  4. String[] argsokreśla jedyny parametr w main()metodzie.

    args- parametr zawierający tablicę obiektów typu klasy String.


6

Aplety, midlety, serwlety i fasola różnego rodzaju są konstruowane, a następnie wywoływane są metody cyklu życia. Wywołanie main jest wszystkim, co kiedykolwiek zrobiono klasie głównej, więc nie ma potrzeby utrzymywania stanu w obiekcie, który jest wywoływany wiele razy. Przypinanie main na innej klasie jest dość normalne (choć nie jest to świetny pomysł), co utrudniałoby wykorzystanie klasy do utworzenia głównego obiektu.


5

To tylko konwencja, ale prawdopodobnie wygodniejsza niż alternatywa. W przypadku statycznego elementu głównego wszystko, co musisz wiedzieć, aby wywołać program Java, to nazwa i lokalizacja klasy. Gdyby nie był statyczny, musiałbyś również wiedzieć, jak utworzyć instancję tej klasy lub wymagać, aby klasa miała pusty konstruktor.


To nie jest konwencja; jest to część specyfikacji języka; środowisko wykonawcze nie rozpozna klasy bez statycznej metody głównej jako prawidłowego punktu wejścia.
Rob

2
Sama specyfikacja językowa jest zgodna z konwencją. Dla projektantów Java nie ma rzeczywistego wymogu wyboru statycznego elementu głównego. Jednak, jak wyjaśnia Logan, alternatywy są bardziej skomplikowane.
David Arno,

@DavidArno Bardziej sensowne byłoby stwierdzenie, że konwencja jest zgodna ze specyfikacją języka.
Markiz Lorne

5

Jeśli główna metoda nie byłaby statyczna, musisz utworzyć obiekt swojej klasy głównej spoza programu. Jak chcesz to zrobić?


5

Po uruchomieniu maszyny wirtualnej Java (JVM) za pomocą javapolecenia

java ClassName argument1 argument2 ...

Kiedy wykonujesz aplikację, podajesz jej nazwę klasy jako argument polecenia java, jak wyżej

JVM próbuje wywołać główną metodę określonej klasy

—W tym momencie nie utworzono żadnych obiektów klasy.

Deklarowanie mainjako statyczne allowsJVM do invokemain withouttworzenia instanceklasy.

wróćmy do polecenia

ClassNamejest command-line argumentdla JVM, która informuje, którą klasę wykonać. Po nazwie klasy można również określić list of Strings(oddzielone spacjami) jako argumenty wiersza polecenia, które JVM przekaże aplikacji. - Tych argumentów można użyć do określenia opcji (np. Nazwa pliku) w celu uruchomienia aplikacji - dlatego istnieje parametr o nazwieString[] args w głównym

Odnośniki: Java ™ How to Program (Early Objects), wydanie dziesiąte


4

Ostatnio podobne pytanie zostało opublikowane na Programmers.SE

  • Dlaczego statyczna główna metoda w Javie i C # zamiast konstruktora?

    Szukając ostatecznej odpowiedzi z pierwotnego lub wtórnego źródła, dlaczego (zwłaszcza) Java i C # zdecydowały się na metodę statyczną jako swój punkt wejścia - zamiast reprezentować instancję aplikacji przez instancję Applicationklasy, przy czym punktem wejścia jest odpowiedni konstruktor?

TL; DR część zaakceptowanej odpowiedzi to:

Przyczyną tego public static void main(String[] args)jest Java

  1. Gąsiątko chciał
  2. kod napisany przez kogoś znającego język C (nie Java)
  3. do wykonania przez osobę przyzwyczajoną do uruchamiania PostScript na NeWS

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

 
W przypadku C # rozumowanie jest tranzytowo podobne, że tak powiem. Projektanci języków znali składnię punktów wejścia programu znaną programistom pochodzącym z Javy. Jak to ujął architekt C #, Anders Hejlsberg ,

... naszym podejściem do C # było po prostu zaoferowanie alternatywy ... dla programistów Java ...

...


3

Myślę, że słowo kluczowe „static” sprawia, że ​​główna metoda jest metodą klasową, a metody klasowe mają tylko jedną kopię i mogą być wspólne dla wszystkich, a także nie wymagają obiektu do odniesienia. Tak więc po skompilowaniu klasy sterownika można wywołać główną metodę. (Jestem tylko na poziomie alfabetu java, przepraszam, jeśli się mylę)


Wszystkie metody „mają tylko jedną kopię”.
Markiz Lorne

3

main () jest statyczny, ponieważ; na tym etapie cyklu życia aplikacji stos aplikacji ma charakter proceduralny, ponieważ nie utworzono jeszcze żadnych obiektów.

To czyste konto. Twoja aplikacja działa w tym momencie, nawet bez zadeklarowania żadnych obiektów (pamiętaj, że istnieją wzorce kodowania OO). Ty, jako programista, przekształcasz aplikację w rozwiązanie obiektowe, tworząc instancje swoich obiektów i zależnie od skompilowanego kodu.

Zorientowanie obiektowe jest świetne z milionów oczywistych powodów. Jednak minęły czasy, kiedy większość programistów VB regularnie używała w swoim kodzie słów kluczowych, takich jak „goto”. „goto” jest poleceniem proceduralnym w VB, które jest zastępowane przez jego odpowiednik OO: wywołanie metody

Można również spojrzeć na statyczny punkt wejścia (główny) jako czystą wolność. Gdyby Java była na tyle inna, że ​​tworzyła obiekt i przedstawiała ci tylko tę instancję podczas uruchamiania, nie miałbyś wyboru ALE, aby napisać aplikację proceduralną. Choć może się to wydawać niewyobrażalne dla Javy, istnieje wiele scenariuszy, które wymagają podejścia proceduralnego.

To prawdopodobnie bardzo niejasna odpowiedź. Pamiętaj, że „klasa” to tylko zbiór powiązanych ze sobą kodów. „Instancja” to izolowane, żyjące i oddychające autonomiczne pokolenie tej klasy.


7
To jest niepoprawne. Przed mainosiągnięciem jest utworzonych wiele obiektów . A jeśli do klasy zawierającej konstruktor statyczny zostanie dołączony konstruktor statyczny, zostanie on mainrównież wykonany przedtem .
Konrad Rudolph,

2

To tylko konwencja. JVM z pewnością poradziłby sobie z podstawowymi metodami niestatycznymi, gdyby taka byłaby konwencja. W końcu możesz zdefiniować statyczny inicjalizator w swojej klasie i utworzyć instancję obiektów zillion, zanim dotrzesz do metody main ().


2

Protoype public static void main(String[])to konwencja zdefiniowana w JLS :

Metoda main musi być zadeklarowana jako publiczna, statyczna i nieważna. Musi określać parametr formalny (§ 8.4.1), którego zadeklarowanym typem jest tablica Ciąg.

W specyfikacji JVM 5.2. Uruchomienie maszyny wirtualnej możemy przeczytać:

Wirtualna maszyna Java uruchamia się, tworząc klasę początkową, która jest określana w sposób zależny od implementacji, przy użyciu programu ładującego klasy bootstrap (§ 5.3.1). Maszyna wirtualna Java następnie łączy klasę początkową, inicjuje ją i wywołuje metodę klasy publicznej void main (String []) . Wywołanie tej metody prowadzi do dalszego wykonywania. Wykonywanie instrukcji maszyny wirtualnej Java stanowiących główną metodę może powodować łączenie (aw konsekwencji tworzenie) dodatkowych klas i interfejsów, a także wywoływanie dodatkowych metod.

Zabawne, że w specyfikacji JVM nie wspomina się, że główna metoda musi być statyczna. Ale specyfikacja mówi również, że wirtualna maszyna Java wykonuje 2 kroki przed:

Inicjalizacja klasy lub interfejsu polega na wykonaniu metody inicjalizacji klasy lub interfejsu.

W 2.9. Specjalne metody :

Klasy lub inicjalizacji interfejsu Metoda jest określona:

Klasa lub interfejs ma co najwyżej jedną metodę inicjalizacji klasy lub interfejsu i jest inicjowana (§5.5) przez wywołanie tej metody. Metoda inicjalizacji klasy lub interfejsu ma specjalną nazwę <clinit>, nie przyjmuje żadnych argumentów i jest nieważna.

Oraz klasa lub inicjowania interfejsu sposób różni się od sposobu przykład inicjalizacji zdefiniowane w następujący sposób:

Na poziomie wirtualnej maszyny Java każdy konstruktor napisany w języku programowania Java (JLS §8.8) pojawia się jako metoda inicjalizacji instancji o specjalnej nazwie <init>.

Zatem JVM inicjuje klasę lub metodę inicjalizacji interfejsu, a nie metodę inicjowania instancji, która w rzeczywistości jest konstruktorem. Nie muszą więc wspominać, że główna metoda musi być statyczna w specyfikacji JVM, ponieważ wynika to z faktu, że przed wywołaniem metody głównej nie są tworzone żadne instancje.


2

Słowo publickluczowe jest modyfikatorem dostępu, który pozwala programiście kontrolować widoczność członków klasy. Kiedy członek klasy jest poprzedzony public, dostęp do tego członka można uzyskać za pomocą kodu spoza klasy, w której został zadeklarowany.

Przeciwieństwem publicjest w stanie private, który zapobiega człon przed użyciem przez kod określony zewnątrz tej klasy.

W takim przypadku main()należy zadeklarować jako public, ponieważ musi zostać wywołany przez kod poza swoją klasą podczas uruchamiania programu.

Słowo kluczowe staticpozwala main()na wywołanie bez konieczności tworzenia określonej instancji klasy. Jest to konieczne, ponieważ main()jest wywoływane przez interpreter Java przed utworzeniem jakichkolwiek obiektów.

Słowo kluczowe voidpo prostu informuje kompilator, że main()nie zwraca wartości.


1

Prawdziwym punktem wejścia do dowolnej aplikacji jest metoda statyczna. Jeśli język Java obsługuje metodę instancji jako „punkt wejścia”, środowisko wykonawcze musiałoby zaimplementować ją wewnętrznie jako metodę statyczną, która zbudowała instancję obiektu, a następnie wywołała metodę instancji.

W ten sposób zbadam uzasadnienie wyboru jednej z następujących trzech opcji:

  1. A static void main()tak jak to dzisiaj widzimy.
  2. Metoda instancji void main()wywołana na świeżo skonstruowanym obiekcie.
  3. Użycie konstruktora typu jako punktu wejścia (np. Jeśli wywołana zostanie klasa wejścia Program, wówczas wykonanie będzie efektywne new Program()).

Awaria:

static void main()

  1. Wywołuje konstruktora statycznego klasy zamykającej.
  2. Wywołuje metodę statyczną main().

void main()

  1. Wywołuje konstruktora statycznego klasy zamykającej.
  2. Konstruuje instancję klasy zamykającej, skutecznie wywołując new ClassName().
  3. Wywołuje metodę instancji main().

new ClassName()

  1. Wywołuje konstruktora statycznego klasy zamykającej.
  2. Tworzy instancję klasy (następnie nic z nią nie robi i po prostu zwraca).

Racjonalne uzasadnienie:

Pójdę w odwrotnej kolejności do tego.

Należy pamiętać, że jednym z celów projektowych Java było podkreślenie (wymaganie, gdy to możliwe) dobrych praktyk programowania obiektowego. W tym kontekście konstruktor obiektu inicjuje obiekt, ale nie powinien być odpowiedzialny za zachowanie obiektu. Dlatego specyfikacja, która podała punkt wejścia, wprowadziłaby w new ClassName()błąd sytuację nowych programistów Java, wymuszając wyjątek od projektu „idealnego” konstruktora dla każdej aplikacji.

Dzięki stworzeniu main()metody instancji powyższy problem z pewnością został rozwiązany. Jednak komplikuje to wymaganie, aby specyfikacja wymieniała podpis konstruktora klasy wejściowej, a także podpis main()metody.

Podsumowując, określenie specyfikacji static void main()tworzy najmniej skomplikowaną specyfikację przy jednoczesnym zachowaniu zasady umieszczania zachowania w metodach . Biorąc pod uwagę, jak łatwo jest wdrożyć main()metodę, która sama konstruuje instancję klasy i wywołuje metodę instancji, nie ma prawdziwej przewagi nad określeniem jej main()jako metody instancji.


1
To tylko pytanie. W każdym razie Java potrzebuje modułu ładującego aplikacje, który wykonuje duże obciążenia przed wywołaniem main. Twoje uzasadnienie, że mainjesteś zbyt skomplikowany dla początkujących, wydaje się niewiarygodne. W rzeczywistości, statyczność mainjest bardzo myląca dla początkujących, wątpię, by konstruktor byłby bardziej. Mówisz, że „konstruktor nie powinien być odpowiedzialny za zachowanie obiektu”. Brzmi interesująco, ale nie jestem pewien, czy się zgodziłbym. Dlaczego nie Co temu zapobiega?
Konrad Rudolph,

1

static - Gdy JVM wywołuje metodę główną, nie istnieje żaden obiekt dla wywoływanej klasy, dlatego musi mieć metodę statyczną, aby umożliwić wywołanie z klasy.


1

Nie wiem, czy JVM wywołuje metodę główną przed utworzeniem instancji obiektów ... Ale istnieje znacznie silniejszy powód, dla którego metoda main () jest statyczna ... Kiedy JVM wywołuje metodę główną klasy (powiedzmy , Osoba). wywołuje go przez „ Person.main () ”. Widzisz, JVM wywołuje go według nazwy klasy. Dlatego metoda main () ma być statyczna i publiczna, aby JVM mógł uzyskać do niej dostęp.

Mam nadzieję, że to pomogło. Jeśli tak, daj mi znać, komentując.


0

Metody statyczne nie wymagają żadnego obiektu. Działa bezpośrednio, więc główne działa bezpośrednio.


0

Użyto statycznego słowa kluczowego w metodzie głównej, ponieważ w metodzie głównej nie ma żadnej instancji. Ale obiekt jest skonstruowany, a nie wywołanie, dlatego w głównej metodzie używamy statycznego słowa kluczowego. W kontekście jvm pamięć jest tworzona po załadowaniu do niej klasy i wszystkie statyczne elementy są w niej zapisane. jeśli zrobimy główny statyczny teraz, będzie on w pamięci i może być dostępny dla jvm (class.main (..)), abyśmy mogli wywołać główną metodę bez potrzeby tworzenia nawet sterty.


0

To tylko konwencja, jak widzimy tutaj:

Metodę należy zadeklarować jako publiczną i statyczną , nie może zwracać żadnej wartości i musi zaakceptować tablicę String jako parametr. Domyślnie pierwszym nie-opcyjnym argumentem jest nazwa klasy, która ma zostać wywołana. Należy użyć w pełni kwalifikowanej nazwy klasy. Jeśli podano opcję -jar, pierwszym argumentem nie będącym opcją jest nazwa archiwum JAR zawierającego klasę i pliki zasobów dla aplikacji, przy czym klasa startowa jest wskazywana przez nagłówek manifestu klasy głównej.

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


Masz na myśli regułę języka.
Markiz Lorne


0

Zasadniczo tworzymy CZŁONKÓW DANYCH i FUNKCJE CZŁONKOWSKIE jako STATYCZNE, które nie wykonują żadnego zadania związanego z obiektem. W przypadku metody głównej robimy to jako STATIC, ponieważ nie ma to nic wspólnego z przedmiotem, ponieważ główna metoda zawsze działa niezależnie od tego, czy tworzymy obiekt, czy nie.


0

Każda metoda zadeklarowana jako statyczna w Javie należy do samej klasy. Ponownie można uzyskać dostęp do metody statycznej określonej klasy tylko poprzez odwołanie się do klasy podobnejClass_name.method_name();

Dlatego nie trzeba tworzyć instancji klasy przed uzyskaniem dostępu do metody statycznej.

Tak więc metoda main () jest zadeklarowana jako staticumożliwiająca dostęp do niej bez tworzenia obiektu tej klasy.

Ponieważ zapisujemy program z nazwą klasy, w której obecna jest metoda główna (lub od której program powinien rozpocząć wykonywanie, dotyczy klas bez main()metody () (poziom zaawansowany)). Tak więc w wyżej wymieniony sposób:

Class_name.method_name();

główna metoda jest dostępna.

W skrócie, gdy program jest kompilowany, szuka main()metody zawierającej Stringargumenty takie jak: main(String args[])we wspomnianej klasie (tj. Według nazwy programu), a ponieważ na początku nie ma zasięgu, aby utworzyć tę klasę, więc main () metoda jest zadeklarowana jako statyczna.


Dzieje się tak, gdy program jest wykonywany, a nie kompilowany.
Markiz Lorne

0

Ze strony java.sun.com (więcej informacji na stronie):

Główna metoda jest statyczna, aby dać interpreterowi VM VM sposób na uruchomienie klasy bez uprzedniego utworzenia instancji klasy kontrolnej. Instancje klasy kontrolnej są tworzone w metodzie głównej po uruchomieniu programu.

Rozumiałem zawsze po prostu, że główną metodę, podobnie jak każdą metodę statyczną, można wywołać bez tworzenia instancji powiązanej klasy, umożliwiając jej uruchomienie przed czymkolwiek innym w programie. Gdyby nie był statyczny, musiałbyś utworzyć instancję obiektu przed jego wywołaniem - co stwarza problem z kurczakiem i jajkiem, ponieważ główna metoda jest generalnie tym, czego używasz do tworzenia instancji obiektów na początku programu.


Ale nie działa „przed czymkolwiek innym w programie”. Cały argument jest błędem, a co więcej, nie jest to pierwsza wzmianka o nim, ani nawet druga czy trzecia.
Konrad Rudolph

Przepraszam, że moja odpowiedź powtarza to, co powiedzieli inni; Odpowiedziałem tylko najlepiej, jak potrafiłem i na podstawie tego, co mogłem znaleźć w Internecie. Z wyników, na które patrzyłem, nie ma innego powodu, dla którego główna metoda jest statyczna; chyba że jest gdzieś głęboko ukryty, być może jest to jedyna dostępna odpowiedź. Moje rozumienie języka Java jest dość podstawowe, ale słyszałem powyższy powód (od profesorów, podręczników itp.) I nigdy nie.
Jesse M

@Jesse M Twój komentarz ma sens tylko wtedy, gdy nie zastanawiasz się, czy nie przeczytać najpierw innych odpowiedzi. Nawiasem mówiąc, nie jest to zbyt daleko idąca sprawa. Jak sam o tym wspomniałeś, twoje rozumienie jest dość podstawowe, więc jest bardzo prawdopodobne, że ktoś inny już odpowiedział na pytanie bardziej kompetentnie. Twój komentarz wydaje się racjonalizacją, aby Twoja odpowiedź wyglądała lepiej. To niezwykłe twierdzenie, że masz podręczniki i profesorów Java, którzy myślą o tym, co twierdzisz, i szczerze mówiąc, nie wierzę, że tak. (Wszelkie odniesienia?)
LeoR

1
@KonradRudolph Najlepsze komentarze wydają się dość rozsądne. main () jest używany jako punkt wejścia do programu, a na stronie Java jest kilka odnośników mówiących, że powinno to być podobne do tego, jak C / C ++ ma funkcję main (). Ponieważ Java to wszystkie obiekty, musi być statyczna, aby uniknąć tworzenia instancji obiektu. Ustawienie statyczne pozwala również na załadowanie i uruchomienie w JVM w czasie wykonywania. Zwracam tylko poprzednie odpowiedzi, ale zastanawiam się, co uważasz za satysfakcjonującą odpowiedź. Myślę, że najlepsze, co dostaniesz, to „Właśnie tak chcieli”. Należy pamiętać o dacie utworzenia Java.
trevor-e

1
@Jesse Spot-on. Jest całkiem możliwe, że jest to tylko kwestia konwencji (choć mam nadzieję, że nie, to byłaby tak nudna odpowiedź). Moje pierwotne zainteresowanie tym pytaniem polegało na tym, że myślałem, że użycie właściwej instancji do reprezentowania obiektu „działającej aplikacji” i posiadanie punktu wejścia jako metody (lub konstruktora) tej klasy byłoby znacznie bardziej oczywistym projektem, ponieważ Java został zaprojektowany, aby być zorientowany z get-go obiektu, a od pozornie analogicznych obiektów (nici, via Runnable) w Javie zrobić wykorzystać ten projekt. Dlaczego (pozorny) wyjątek tutaj?
Konrad Rudolph
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.