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


54

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


Передумови та деталі мого попереднього дослідження

Про це запитували раніше. На жаль, існуючі відповіді просто випрошують питання . Зокрема, такі відповіді мене не задовольняють, оскільки я вважаю їх неправильними:

  • Була б двозначність, якби конструктор був перевантажений. - Насправді, C # (як і C і C ++) допускає різні підписи для Mainтого, що існує одна і та ж потенційна неоднозначність і з нею вирішується.
  • staticМетод означає об'єкти не можуть бути створені таким чином , перш ніж порядок ініціалізації ясний. - Це просто фактично невірно, деякі об'єкти є екземплярами раніше (наприклад , в статичному конструкторі).
  • Таким чином, вони можуть викликатися під час виконання без необхідності інстанціювати батьківський об'єкт. - Це зовсім не відповідь.

Просто для того, щоб далі обгрунтувати, чому я вважаю, що це справедливе і цікаве питання:

  • Багато структур роблять використовувати класи для подання додатків і конструкторів в якості точок входу. Наприклад, прикладна програма VB.NET використовує спеціальний головний діалог (та його конструктор) в якості точки входу 1 .

  • Ні Java, ні C # технічно не потребують основного методу. Ну, для компіляції потрібен C #, але Java навіть не такий. І в жодному разі це не потрібно для виконання. Отже, це не є технічним обмеженням. І, як я вже згадував у першому пункті, для звичайної умовності це виглядає дивно непридатним до загального принципу дизайну Java та C #.

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

Мене цікавить остаточна відповідь з первинного чи вторинного джерела, а не прості міркування.


1 Хоча є зворотний дзвінок ( Startup), який може перехопити це.


4
@mjfgates Також я сподівався дати зрозуміти, що це не просто "чому люди не зробили так, як я хочу", а що мене справді цікавлять причини.
Конрад Рудольф

2
Для Java я думаю, що міркування прості: Коли розробляли Java, вони знали, що більшість людей, які вивчають мову, заздалегідь знали б C / C ++. Отже, Java не тільки дуже схожа на C / C ++ замість того, щоб сказати smalltalk, але й перейняла ідіосинхроніки з C / C ++ (просто подумайте про восьмі цілі літерали). Оскільки c / c ++ обидва використовують основний метод, робити те ж саме для Java має сенс з цієї точки зору.
Voo

5
@Jarrod Ти несправедливий. Я думав, що це я зрозумів, що я не переймався. "Не конструктивна"? Як так? Я прямо прошу довідок, а не лише бурхливих дискусій. Ви, звичайно, не можете погодитися, що це цікаве питання. Але якщо подібного роду питання тут є ОТ, я дійсно не розумію, для чого слугує Programmers.SE.
Конрад Рудольф

2
Відповідна мета-дискусія .
янніс

3
Питання: Якщо це об’єкт програми, вам не потрібно дві речі. 1) Конструктор. 2) Метод на об'єкті для запуску програми. Конструктор повинен завершити, щоб об'єкт був дійсним і таким чином міг працювати.
Мартін Йорк

Відповіді:


38

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 ...

 

Довга версія

розширення вище та підкріплене нудними посиланнями.

 

java Термінатор Hasta la vista Baby!

VM Spec, 2.17.1 Запуск віртуальної машини

... Спосіб, яким початковий клас задається віртуальній машині Java, виходить за межі цієї специфікації, але типовим є в середовищі хостів, що використовують командні рядки, для повного кваліфікованого імені класу, що визначається як аргумент командного рядка та наступні аргументи командного рядка, що використовуються як рядки, що надаються як аргумент до методу main. Наприклад, використовуючи командний рядок Java Java SD 2 для Solaris

java Terminator Hasta la vista Baby!

запустить віртуальну машину Java шляхом виклику методу main class Terminator(клас у неназваному пакеті) і передасть йому масив, що містить чотири рядки "Hasta", "la", "vista" та "Baby!" ...

... див. також: Додаток: Мені потрібен ваш одяг, ваші черевики та мотоцикл

  • Моя інтерпретація:
    виконання, націлене на використання, як типові сценарії в інтерфейсі командного рядка.

 

важливий бічний крок

... що допомагає уникнути пари помилкових слідів у нашому розслідуванні.

VM Spec, 1.2 Віртуальна машина Java

Віртуальна машина Java нічого не знає мови програмування Java ...

Я звернув увагу вище, вивчаючи попередній розділ - 1.1 Історія, яку я вважав може бути корисною (але виявилася марною).

  • Моя інтерпретація:
    виконання регулюється лише специфікацією VM, яка
    прямо заявляє, що це не має нічого спільного з мовою Java
    => ОК, щоб ігнорувати JLS та що-небудь, що стосується мови Java, взагалі.

 

Гослінг: компроміс між мовою С та сценарієм ...

На підставі вище я почав шукати в Інтернеті історію JVM . Не допомогло, занадто багато сміття в результатах.

Потім я згадав легенди про Гослінг і звузив свій пошук до історії JVM Gosling .

Еврика! Як з'явився спец JVM

У цій доповіді з саміту JVM Languages ​​2008, Джеймс Гослінг обговорює ... створення Java, ... компроміс між C та мовою сценаріїв ...

  • Моє тлумачення:
    чітка заява про те, що на момент створення,
    С та сценарії вважалися найважливішими впливами.
     
    Вже бачили кивок до скриптинг в VM Spec 2.17.1,
    аргументи командного рядка , досить пояснити , String[] args
    але staticі mainще не там, потрібно копати далі ...

Зауважте, під час введення цього тексту - підключення C, сценаріїв та VM Spec 1.2 з його нічого не відрізняється від Java - мені здається, що щось знайоме, щось ... орієнтоване на об'єкти повільно проходить. Візьміть мене за руку і продовжуйте рухатись: Не сповільнюйтесь, ми вже майже там

Основні слайди доступні в Інтернеті: 20_Gosling_keynote.pdf , що досить зручно для копіювання ключових точок.

    сторінка 3

        Передісторія Яви
        * Що сформувало моє мислення

    сторінка 9

        NeWS
        * Мережева система розширених вікон
        * Віконна система на основі сценаріїв ....
          PostScript (!!)

    стор. 16

        Велика (але тиха) мета:
          Як близько я міг дістатися до
          "сценарій" відчуваю ...

    стор. 19

        Оригінальна концепція
        * Було все про будівництво
          мережі речей,
          оркестрований сценарієм
          мова
        * (Оболонки Unix, AppleScript, ...)

    стор. 20

        Вовк в одязі овець
        * Синтаксис C для створення розробників
          зручні

А-ха! Давайте подивимося ближче на синтаксисі C .

Приклад "привіт, світ" ...

main()
{
    printf("hello, world\n");
}

... визначається функція з назвою main. Основна функція служить спеціальне призначення в програмах C; середовище виконання часу викликає головну функцію для початку виконання програми.

... Основна функція насправді має два аргументи, int argcі char *argv[], відповідно, які можна використовувати для обробки аргументів командного рядка ...

Ми наближаємось? Будьте впевнені. Варто також дотримуватися "головного" посилання зверху цитатою:

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

  • Моя інтерпретація:
    Щоб зручно було розробнику C, програма введення програми повинна бути main.
    Крім того, оскільки Java вимагає, щоб будь-який метод був у класі, Class.mainвін
    настільки близький, наскільки це стає: статичне виклик, просто ім'я класу та крапка,
    будь-які конструктори, будь ласка - C нічого такого не знає.
     
    Це також транзитивно стосується C # з урахуванням
    ідеї простої міграції до неї з Java.

Читачі, які думають, що знайома точка вступу програми не має значення, запрошуємо шукати та перевіряти питання щодо переповнення стека, де хлопці з Java SE намагаються написати Hello World для Java ME MIDP. Примітка. Точка входу MIDP не має mainані норми static.

 

Висновок

На підставі вище , я б сказав , що static, mainі String[] argsбув в моменти Java і C # створення найбільш розумних рішень щодо визначення програми точки входу .

 

Додаток: Мені потрібен ваш одяг, ваші чоботи та ваш мотоцикл

Потрібно визнати, читання VM Spec 2.17.1 було надзвичайно цікавим.

... командний рядок

java Terminator Hasta la vista Baby!

запустить віртуальну машину Java шляхом виклику методу main class Terminator(клас у неназваному пакеті) та передасть йому масив, що містить чотири рядки "Hasta", "la", "vista" та "Baby!".

Тепер ми описуємо кроки, які може виконати віртуальна машина Terminator, як приклад процесів завантаження, зв’язування та ініціалізації, які описані далі в наступних розділах.

Початкова спроба ... виявляє, що клас Terminatorне завантажений ...

Після Terminatorзавантаження він повинен бути ініціалізований до виклику основного, і тип (клас чи інтерфейс) повинен бути завжди пов'язаний перед його ініціалізацією. Посилання (§2.17.3) включає перевірку, підготовку та (необов'язково) резолюцію ...

Перевірка (§2.17.3) перевіряє, Terminatorчи добре сформоване завантажене представлення ...

Резолюція (§2.17.3) - це процес перевірки символічних посилань з класу Terminator...

 
Символічні посилання від Terminatorо так.


2
Я чомусь важко повірив, що "сучасність" - це власне слово.
someguy

@Songo історія відповіді - це як фільм. Це було вперше розміщено на мета- дискусії під час обговорення питання про закриття запитання: "Якщо питання буде відновлено, я, мабуть, напишу відповідь, як нижче ..." Потім він був використаний для резервного копіювання звернення до повторного відкриття і, нарешті, переїхав сюди
гнат

16

Це просто відчуває мене жорстоко образливим. Конструктор використовується для ініціалізації об'єкта: він встановлює об'єкт, який потім використовується кодом, який його створив.

Якщо ви розмістите основні функції використання всередині конструктора, а потім ніколи не використовуєте об'єкт, який конструктор створює у зовнішньому коді, ви порушуєте принципи OOP. В основному, робити щось справді дивне без видимих ​​причин.

Навіщо ти хотів це зробити?


5
Але хіба «екземпляр програми» логічно не є об’єктом? Чому це було б образливо? Що стосується використання об'єкта - він має одну мету: представлення запущеної програми. Звучить дуже SoC -й для мене. "Чому б ти хотів це зробити?" - Мене просто цікавить обґрунтування рішення, оскільки я вважаю, що це суперечить решті менталітету.
Конрад Рудольф

7
@KonradRudolph: Зазвичай очікується, що конструктор, як і геть властивості, завершиться протягом обмеженого часу, не чекаючи, коли станеться деяка асинхронна подія (наприклад, введення користувача). Можна було б створити конструктор, який запустив основний потік додатків, але це додасть рівня складності, який може знадобитися не для всіх застосунків. Потрібно, щоб консольне додаток, яке просто друкує "Hello world" на стандартний вихід, породжувало додатковий потік. Використання Mainметоду добре працює для простого випадку, і насправді це не проблема в більш важких випадках, так чому б і ні?
supercat

9

Для Java я думаю, що міркування прості: Коли розробляли Java, розробники знали, що більшість людей, які вивчають мову, заздалегідь знали б C / C ++.

Отже, Java не тільки дуже схожа на C / C ++ замість того, щоб сказати smalltalk, але й перейняла ідіосинхроніки з C / C ++ (просто подумайте про восьмі цілі літерали). Оскільки c / c ++ обидва використовують основний метод, робити те ж саме для Java має сенс з цієї точки зору.

Я майже впевнений, що пам’ятаю блох або хтось щось сказав у цьому напрямку про те, чому вони додали восьмі восьмі цілі літерали, я побачу, чи зможу я знайти деякі джерела :)


2
Шукаючи ж , як C ++ був настільки важливий для Java, чому вони, наприклад , зміни :в extends? А public static void main(String [ ] args)всередині класу зовсім інше, ніж int main(int argc, char **argv)поза класом.
svick

2
@svick Одна з можливостей: Java представила інтерфейси, і чітко вони хотіли розділити два поняття (успадковуючи інтерфейси / класи) - лише одне "ключове слово", яке не працюватиме. І "зовсім інший"? Це найближче можливе відображення його, і поки що я ніколи не бачив, щоб програміст c ++ мав проблеми зрозуміти, що основним статичним методом є точка входу. На відміну від класу під назвою Application або того, чий конструктор використовується, це щось, що виглядатиме дивно для більшості програмістів c ++.
Voo

@svick int in c to void in java доводилося до того, як генерується код повернення з програми - у java, його 0, якщо не викликається System.exit (int). Зміна параметрів пов'язана з тим, як передаються масиви рядків у кожній мові. Усе в java - в класі - немає іншого варіанту мати його в іншому місці. Зміни :на extends- це питання синтаксису і по суті є однаковими. Все інше продиктовано мовою.

@MichaelT Але все це дизайнерські рішення, які відрізняють Java від C ++. То чому б зберігати Java те саме, що і C ++, було б важливо у випадку main(), коли, мабуть, це було недостатньо важливо в інших випадках.
svick

@svick За винятком того, що цілком нормально нічого не повертати з основного в C, і подібні дрібниці навряд чи когось збентежать. Сенс не полягав у тому, щоб відтворити c ++ та всі його помилки, а лише зробити програміста більше вдома. Як ви думаєте, що програмісту на C ++ буде легше читати час: Java або код Obje-c? Як ви вважаєте, що програмісту на C ++ буде більш очевидним головний метод або конструктор якогось класу як точка входу?
Voo

6

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

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

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

Для існування простої, простої, вхідної функції для функціонування Java, автоматично знадобиться загальнодоступна та статична. Незважаючи на те, що він є статичним методом , він зводиться до того, що ми можемо наблизитись до простої функції, щоб досягти бажаного: простої точки входу.

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


1
Я б сказав, що проблема не полягала у відсутності першокласних функцій. Додавання main () всередині об'єкта (що не є екземпляром до виклику основного) є дещо анти-шаблоном. Можливо, у них повинен бути об’єкт "застосунку", який будується і запускає його нестатичний метод main (), тоді ви можете поставити ініціалізацію запуску в конструктор, і це буде відчувати себе набагато краще, ніж статичні методи, хоча простий верхній- = рівень main () fn теж буде добре. Статичний головний - це трохи хитрість у всьому.
gbjbaanb

3

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


1
Це для мене, мабуть, є найбільш переконливою причиною, оскільки воно також дозволяє декілька точок входу під час розробки для тестування різних конфігурацій тощо
cgull

0

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

В основному це додаток KISS.

[І, звичайно, головна причина: чому б і ні?]


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

2
Обсяг роботи, необхідний для інстанціювання класу з коду С, майже однаковий виклику статичного методу. Навіть вам доведеться робити ті ж перевірки (чи існує клас? Нормально, чи є у нього відкритий конструктор з правильним підписом? добре тоді йти вперед).
Voo

Жоден об’єкт користувача не потрібно створювати. Конструктор об'єктів не виконується. API надзвичайно простий. І це найлегше зрозуміти.
Даніель Р Хікс

0

На моє розуміння, первинна причина проста. Sun була компанією Unix, що займається продажем машин Unix, а Unix - це те, для чого було розроблено C "main (args)" умову для виклику бінарних файлів .

Крім того, Java була чітко розроблена так, щоб було легко підібрати програмістів на C і C ++, тому не було жодної вагомої причини не просто підібрати C-конвенцію.

Обраний підхід, у якому кожен клас може мати метод виклику, є досить гнучким, особливо в поєднанні з Main-Classрядком у файлі MANIFEST.MF в банку, який можна виконати.


Звичайно, файл jar не був винайдений набагато пізніше.
Даніель Р Хікс

-1

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

Крім цього, конструктор не є точкою входу.

Мені здається, що найбільш розумним вибором є головна як статична функція, якою вона є насправді в кінці дня. Враховуючи архітектуру віртуальних машин, таких як JVM та CLR, будь-який інший вибір був би зайвим.


1
Я думаю, що ти там помилився. Це є можливість мати більш ніж один процес, отже , більше одного об'єкта. Між іншим, це цілком еквівалентно Runnableоб'єктам екземплярів мати декілька потоків.
Конрад Рудольф

Процес - це запущена програма, і ви можете запустити процес лише один раз через одну точку входу. Нитки мають власні точки входу, але все ще знаходяться в одному процесі.
Ям Маркович

1
Як я вже говорив нижче у відповіді someguy, це не актуально. Важливо - логічна послідовність. За логікою процеси запуску представляються у вигляді об'єктів (ОС, JVM і будь-що) і ініціалізуються.
Конрад Рудольф

@KonradRudolph True, але ініціалізація програми є лише однією частиною ініціалізації процесу і не легітимізує конструктор програми.
Ям Маркович
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.