Szukam ostatecznej odpowiedzi z pierwotnego lub wtórnego źródła, dlaczego (zwłaszcza) Java i C # zdecydowały się na metodę statyczną jako punkt wejścia, zamiast reprezentować instancję aplikacji przez instancję Application
klasy (z punktem wejścia bycie odpowiednim konstruktorem).
Tło i szczegóły moich wcześniejszych badań
Zostało to już wcześniej zadane. Niestety istniejące odpowiedzi są jedynie pytaniem . W szczególności poniższe odpowiedzi mnie nie satysfakcjonują, ponieważ uważam je za nieprawidłowe:
- Byłoby niejednoznaczne, gdyby konstruktor został przeciążony. - W rzeczywistości C # (jak również C i C ++) pozwala na różne podpisy,
Main
dlatego istnieje taka sama potencjalna niejednoznaczność i jest ona rozpatrywana. static
Metoda oznacza, że nie obiekty mogą być tworzone wystąpienia przed tak kolejność inicjalizacji jest jasne. - Jest to po prostu nieprawdziwe, niektóre obiekty są wcześniej tworzone (np. W konstruktorze statycznym).- Dzięki temu mogą być wywoływane przez środowisko wykonawcze bez konieczności tworzenia instancji obiektu nadrzędnego. - To w ogóle nie jest odpowiedź.
Aby jeszcze bardziej uzasadnić, dlaczego uważam, że jest to ważne i interesujące pytanie:
Wiele ram zrobić użyć klas do reprezentowania aplikacji i konstruktorów jako punkty wejścia. Na przykład środowisko aplikacji VB.NET używa dedykowanego głównego okna dialogowego (i jego konstruktora) jako punktu wejścia 1 .
Ani Java, ani C # technicznie nie potrzebują głównej metody. C # wymaga kompilacji jednego, ale Java nawet tego. I w żadnym przypadku nie jest to konieczne do wykonania. Nie wydaje się to ograniczeniem technicznym. I, jak wspomniałem w pierwszym akapicie, dla samej konwencji wydaje się to dziwnie niezgodne z ogólną zasadą projektowania Java i C #.
Żeby było jasne, nie ma konkretnej wady posiadania main
metody statycznej , jest to po prostu wyraźnie dziwne , co sprawiło, że zastanawiałem się, czy kryje się za tym jakieś techniczne uzasadnienie.
Interesuje mnie ostateczna odpowiedź z pierwotnego lub wtórnego źródła, a nie zwykłe spekulacje.
1 Chociaż istnieje funkcja zwrotna ( Startup
), która może to przechwycić.
źródło
Odpowiedzi:
TL; DR
Przyczyną tego
public static void main(String[] args)
jest JavaW 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 ujął to architekt C #, Anders Hejlsberg ,
Długa wersja
rozwijając się powyżej i tworząc nudne referencje.
java Terminator Hasta la vista Baby!
Specyfikacja VM, 2.17.1 Uruchomienie maszyny wirtualnej
... patrz także: Załącznik: Potrzebuję twoich ubrań, butów i motocykla
wykonanie ukierunkowane do użycia jak typowe skrypty w interfejsie wiersza poleceń.
ważny boczny krok
... pomaga to uniknąć kilku fałszywych śladów w naszym dochodzeniu.
VM Spec, 1.2 The Java Virtual Machine
Powyżej zauważyłem, studiując poprzedni rozdział - 1.1 Historia, która moim zdaniem może być pomocna (ale okazała się bezużyteczna).
wykonanie jest regulowane przez samą specyfikację VM, która
wyraźnie oświadcza, że nie ma to nic wspólnego z językiem Java
=> OK, aby zignorować JLS i dowolny inny język Java
Gąsiątko: kompromis między C a językiem skryptowym ...
W oparciu o powyższe zacząłem przeszukiwać sieć w poszukiwaniu historii JVM . Nie pomogło, zbyt wiele śmieci w wynikach.
Potem przypomniałem sobie legendy o Goslingu i zawęziłem poszukiwania do historii JVM Goslinga .
Eureka! Jak powstała specyfikacja JVM
wyraźne oświadczenie, że w momencie tworzenia
C i skrypt zostały uznane za najważniejsze czynniki.
Już widać ukłon skryptów w VM Spec 2.17.1,
argumenty linii poleceń dostatecznie wyjaśnić
String[] args
, ale
static
imain
nie są tam jeszcze, trzeba kopać dalej ...Zauważ, że pisząc to - łącząc C, skryptowanie i VM Spec 1.2 z nic-of-Java - czuję się jak coś znajomego, coś ... obiektowego powoli odchodzi. Weź mnie za rękę i ruszaj się. Nie zwalniaj, jesteśmy już prawie na miejscu
Slajdy keynote są dostępne online: 20_Gosling_keynote.pdf , całkiem wygodne do kopiowania kluczowych punktów.
Aha! Spójrzmy bliżej na składni C .
Czy zbliżamy się? obstawiasz. Warto również kliknąć „główny” link z powyższego cytatu:
Aby być wygodnym dla programisty C, punkt wejścia programu musi być
main
.Ponadto, ponieważ Java wymaga, aby każda metoda była w klasie,
Class.main
jesttak blisko, jak to możliwe: wywołanie statyczne, tylko nazwa klasy i kropka,
proszę żadnych konstruktorów - C nie wie nic takiego.
Dotyczy to także tranzytowo C #, biorąc pod uwagę
pomysł łatwej migracji do niego z Java.
Czytelnicy myślący, że znajomy punkt wejścia programu nie ma znaczenia, są proszeni o wyszukiwanie i sprawdzanie pytań dotyczących przepełnienia stosu, w których faceci z Java SE próbują napisać Hello World dla Java ME MIDP. Uwaga Punkt wejścia MIDP nie ma
main
anistatic
.Wniosek
W oparciu o powyższe chciałbym powiedzieć, że
static
,main
iString[] args
były w chwilach Java i C # tworzenie najbardziej rozsądnych wyborów do definiują programu punktu wejścia .Dodatek: Potrzebuję twoich ubrań, butów i motocykla
Muszę przyznać, że czytanie VM Spec 2.17.1 było niesamowitą zabawą.
Symboliczne odniesienia od
Terminator
o tak.źródło
To po prostu wydaje mi się obelżywe. Do inicjalizacji obiektu służy konstruktor: ustawia obiekt, który jest następnie używany przez kod, który go utworzył.
Jeśli umieścisz podstawowe funkcje użytkowania wewnątrz konstruktora, a następnie nigdy nie użyjesz obiektu, który konstruktor tworzy w kodzie zewnętrznym, naruszasz zasady OOP. Zasadniczo robienie czegoś naprawdę dziwnego bez wyraźnego powodu.
Dlaczego i tak chcesz to zrobić?
źródło
Main
metody działa dobrze w prostym przypadku i nie jest tak naprawdę problemem w trudniejszych przypadkach, więc dlaczego nie?Jeśli chodzi o Javę, to myślę, że rozumowanie jest proste: deweloperzy wiedzieli, że większość osób uczących się języka zna wcześniej C / C ++.
Dlatego Java nie tylko przypomina C / C ++ zamiast powiedzieć smalltalk, ale także przejęła cechy charakterystyczne od C / C ++ (wystarczy pomyśleć o liczbach całkowitych ósemkowych). Ponieważ oba c / c ++ używają głównej metody, robienie tego samego dla java ma sens z tego punktu widzenia.
Jestem pewien, że pamiętam blocha lub kogoś, kto mówi coś w tym stylu o tym, dlaczego dodali ósemkowe liczby całkowite, zobaczę, czy uda mi się znaleźć jakieś źródła :)
źródło
:
naextends
? Apublic static void main(String [ ] args)
wewnątrz klasy jest zupełnie inaczej niżint main(int argc, char **argv)
poza klasą.:
naextends
to kwestia składni i zasadniczo są takie same. Cała reszta jest podyktowana językiem.main()
, gdy najwyraźniej nie było wystarczająco ważne w innych przypadkach.Istnieje wiele głównych funkcji, które po prostu uruchamiają nieskończoną pętlę. Konstruktor działający w ten sposób (z obiektem, który nigdy nie jest konstruowany) wydaje mi się dziwny.
W tej koncepcji jest tyle zabawnych rzeczy. Twoja logika działająca na nienarodzonym obiekcie, obiektach, które urodziły się, aby umrzeć (ponieważ wykonują całą pracę w konstruktorze), ...
Czy wszystkie te skutki uboczne nie spowodowałyby o wiele większego uszkodzenia wozu OO niż zwykły publiczny (ponieważ musi być dostępny przez nieznany) statyczny (ponieważ nie jest potrzebna żadna instancja, aby rozpocząć) void main (ponieważ jest to punkt wejścia )?
Aby prosty, prosty punkt wejścia funkcji istniał w Javie, publiczny i statyczny byłby automatycznie wymagany. Chociaż jest to metoda statyczna , sprowadza się do tego, co możemy zbliżyć do zwykłej funkcji, aby osiągnąć to, czego chcemy: prosty punkt wejścia.
Jeśli nie zamierzasz przyjąć prostego, prostego punktu wejścia funkcji jako punktu wejścia. Co dalej nie wydaje się dziwne jako konstruktor, którego nie zamierza się budować?
źródło
Możesz szybko uruchomić niektóre niezależne testy na klasie podczas programowania, umieszczając
main()
w klasie, którą próbujesz przetestować.źródło
Musisz gdzieś zacząć. Statyczny element główny jest najprostszym środowiskiem wykonawczym, jakie możesz mieć - nie trzeba tworzyć żadnej instancji (poza JVM i parametry prostego łańcucha) - więc może „wymyślić” minimum zamieszania (i niskie prawdopodobieństwo błędu kodowania uniemożliwiającego uruchomienie itp.) i może robić proste rzeczy bez wielu innych ustawień.
Zasadniczo aplikacja KISS.
[I oczywiście głównym powodem jest: dlaczego nie?]
źródło
Według mnie główny powód jest prosty. Sun był firmą uniksową sprzedającą maszyny uniksowe, a Unix jest tym, do czego została zaprojektowana konwencja C „główna (args)” do wywoływania pliku binarnego .
Ponadto Java została specjalnie zaprojektowana, aby była łatwa do pobrania dla programistów C i C ++, więc nie było żadnego dobrego powodu, aby po prostu nie wybierać konwencji C.
Wybrane podejście, w którym każda klasa może mieć metodę wywoływania, jest dość elastyczne, szczególnie w połączeniu z
Main-Class
linią w pliku MANIFEST.MF w uruchamialnym słoju.źródło
Nie jest zgodne z filozofią OOP, że program byłby obiektem z punktu widzenia procesu systemu operacyjnego, ponieważ nie ma sposobu, aby mieć więcej niż jeden z definicji.
Co więcej, konstruktor w żadnym wypadku nie jest punktem wejścia.
Wydaje mi się, że najbardziej rozsądnym wyborem jest posiadanie funkcji głównej jako funkcji statycznej, którą tak naprawdę jest pod koniec dnia. Biorąc pod uwagę architekturę maszyn wirtualnych, takich jak JVM i CLR, każdy inny wybór byłby niepotrzebnie popychany.
źródło
Runnable
obiektów, które mają wiele wątków.