コンストラクターではなく、JavaとC#の静的mainメソッドが必要な理由


54

Applicationクラスのインスタンス(エントリポイントを含む)でアプリケーションインスタンスを表すのではなく、(特に)JavaとC#が静的メソッドをエントリポイントとして持つことにした理由について、プライマリソースまたはセカンダリソースからの明確な回答を探しています。適切なコンストラクタであること)。


私の以前の研究の背景と詳細

これは以前に尋ねられました。残念ながら、既存の回答は単に質問を懇願しているだけです。特に、次の答えは私を満足させるものではありません。

  • コンストラクターがオーバーロードされると、あいまいさが生じます。–実際、C#(およびCとC ++)では異なる署名を使用できるMainため、同じ潜在的なあいまいさが存在し、対処されます。
  • staticこの方法は、その初期化の順序は明らかである前に、何のオブジェクトをインスタンス化することはできないことを意味します。–これは事実上間違っています。一部のオブジェクト前にインスタンス化されます(静的コンストラクターなど)。
  • したがって、親オブジェクトをインスタンス化することなく、ランタイムによって呼び出すことができます。–これはまったく答えではありません。

なぜこれが有効で興味深い質問であると思うのかをさらに正当化するために:

  • 多くのフレームワーク、クラスを使用してアプリケーションを表し、コンストラクターをエントリポイントとして使用します。たとえば、VB.NETアプリケーションフレームワークは、専用のメインダイアログ(およびそのコンストラクター)をエントリポイント1として使用します。

  • JavaもC#も技術的にmainメソッドを必要としません。まあ、C#をコンパイルするには1つが必要ですが、Javaでもそれは必要ありません。また、どちらの場合も実行には必要ありません。したがって、これは技術的な制限ではないようです。そして、最初の段落で述べたように、単なる慣習としては、JavaとC#の一般的な設計原則に不自然に合わないようです。

明確に言うと、静的メソッドを使用することには特別な欠点はありません。それは明らかに奇妙です。そのため、技術的な根拠があるのではないかと思いました。main

私は単なる推測ではなく、一次または二次情報源からの決定的な答えに興味があります。


1ただし、Startupこれをインターセプトする可能性のあるコールバック()があります。


4
@mjfgatesまた、私はこれがあることが明らかと判断していることを望んでいたではない、単に「人々はそれを私が望むようにしなかった理由」、と私は理由の中に本当に興味があること。
コンラッドルドルフ

2
Javaの場合、推論は簡単だと思います。Javaを開発するとき、彼らは言語を学ぶほとんどの人がC / C ++を事前に知っていることを知っていました。したがって、JavaはsmalltalkではなくC / C ++によく似ているだけでなく、C / C ++からの特異性も引き継ぎました(8進整数リテラルを考えてください)。c / c ++は両方ともmainメソッドを使用するため、Javaに対して同じことを行うのはその観点から理にかなっています。
Voo

5
@Jarrodあなたは不公平だ。暴言にならずにそれを明確にしたと思った。「建設的ではない」?どうして?単なる議論ではなく、明示的に参照を求めています。もちろん、これは興味深い質問であることに異論はありません。しかし、この種の質問がここでOTである場合、Programmers.SEが何の目的を果たしているのか、私は本当に見当たりません。
コンラッドルドルフ


3
質問:アプリケーションオブジェクトの場合、2つのことは必要ありませんか。1)コンストラクター。2)アプリケーションを実行するオブジェクトのメソッド。コンストラクターは、オブジェクトを有効にして実行可能にするために完了する必要があります。
マーティンヨーク

回答:


38

TL; DR

Javaでは、その理由public static void main(String[] args)

  1. ゴスリングが欲しかった
  2. Cの経験がある人(Javaではない)によって書かれたコード
  3. 実行中に使用者によって実行されるのPostScriptをニュース

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

 
C#の場合、推論はいわば推移的に類似しています。言語設計者は、Javaから来たプログラマーにとってプログラムエントリポイントの構文を使い慣れたものにしました。C#の建築家Anders Hejlsbergが言うように

... C#での私たちのアプローチは、Javaプログラマーに代わるものを提供することです...

 

ロングバージョン

上に展開し、退屈な参照でバックアップされます。

 

javaターミネーターハスタラビスタベイビー!

VM仕様、2.17.1仮想マシンの起動

... Java仮想マシンに初期クラスを指定する方法はこの仕様の範囲を超えていますが、コマンドラインを使用するホスト環境では、クラスの完全修飾名を次のように指定するのが一般的ですコマンドライン引数と、メソッドmainの引数として提供される文字列として使用される後続のコマンドライン引数用 たとえば、SunのJava 2 SDK for Solarisを使用して、コマンドライン

java Terminator Hasta la vista Baby!

クラスのメインメソッドTerminator(名前のないパッケージのクラス)を呼び出して、4つの文字列「Hasta」、「la」、「vista」、および「Baby!」を含む配列を渡すことにより、Java仮想マシンを起動します...

...参照:付録:衣服、ブーツ、バイクが必要です

  • 私の解釈:
    コマンドラインインターフェースの典型的なスクリプトのような使用を対象とした実行。

 

重要な脇道

...これにより、調査中に誤った痕跡が2つなくなるのを防ぎます。

VM仕様、1.2 Java仮想マシン

Java仮想マシンはJavaプログラミング言語を何も知りません...

前の章を勉強していると、上記のことに気づきました-1.1 役に立つと思った履歴(しかし役に立たなかった)

  • 私の解釈:
    実行はVM仕様のみによって管理され
    、Java言語とは無関係であることを明示的に宣言します
    => JLSおよび関連するJava言語を無視します

 

ゴスリング:Cとスクリプト言語の妥協案...

上記に基づいて、JVM履歴を Webで検索し始めました。助けにならなかった、結果にゴミが多すぎる。

次に、Goslingについての伝説を思い出し、検索をGosling JVMの履歴に絞り込みました。

ユーレカ!JVM仕様はどのようになったか

JVM Languages Summit 2008の基調講演では、James Goslingが議論しています... Javaの作成... Cとスクリプト言語の妥協...

  • 私の解釈:
    作成の時点で、
    Cとスクリプトが最も重要な影響と見なされているという明示的な宣言。
     
    既にVM Spec 2.17.1のスクリプト作成にうなずいているように見えますが、
    コマンドライン引数は十分に説明されてString[] args
    いますがstaticmainまだ存在しないため、さらに掘り下げる必要があります...

これを入力する際に​​注意してください-C、スクリプティング、VM Spec 1.2をJava以外と接続する-私は何かおなじみのような気がします... オブジェクト指向はゆっくりと消えていきます。私の手を取り、動き続けてください。

キーノートスライドはオンラインで入手できます:20_Gosling_keynote.pdf。キーポイントのコピーに非常に便利です。

    3ページ

        Javaの先史時代
        *私の思考を形作ったもの

    9ページ

        ニュース
        *ネットワーク拡張ウィンドウシステム
        *スクリプトに基づいたウィンドウシステム...
          PostScript(!!)

    16ページ

        大きな(しかし静かな)目標:
          どれくらい近くまで行けますか
          「スクリプト」の感じ...

    19ページ

        元のコンセプト
        *すべての建物についてでした
          物事のネットワーク、
          スクリプトによって編成
          言語
        *(Unixシェル、AppleScript、...)

    20ページ

        羊服のオオカミ
        *開発者を作成するためのC構文
          快適

ああ!Cの構文を詳しく見てみましょう。

「hello、world」の例...

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

... mainという名前の関数が定義されています。主な機能は、Cプログラムで特別な目的を果たします。ランタイム環境は、メイン関数を呼び出してプログラムの実行を開始します。

...メイン関数には実際には2つの引数がint argcありchar *argv[]、それぞれ、コマンドライン引数を処理するために使用できます...

近づいていますか?賭けます。上記の引用の「メイン」リンクをたどる価値もあります。

主な機能は、プログラムが実行を開始する場所です。プログラムの機能の高レベルな編成を担当し、通常、プログラムの実行時に指定されたコマンド引数にアクセスできます。

  • 私の解釈:
    C開発者にとって快適であるためには、プログラムのエントリポイントはでなければなりませんmain
    Javaは、クラスにあるように、任意の方法を必要とするためにも、Class.mainある
    それを取得ほど近い:静的呼び出し、単にクラス名とドットを、
    無コンストラクタください- Cはそのような何も知りません。
     
    これは 、Java からC#への簡単な移行の考え方を考慮して、C#にも一時的に適用さ
    れます。

Java SEから来た人がJava ME MIDP用のHello Worldを書き込もうとしているStack Overflowの質問を検索してチェックすることを、読者はおなじみのプログラムエントリポイントは重要ではないと考えています。注意しないMIDPのエントリポイントが何を持っていmainたりstatic

 

結論

上記に基づいて、私はそれを言うだろうstaticmainString[] argsJavaとC#の作成の瞬間にプログラムのエントリポイントを定義するための最も合理的な選択肢でした。

 

付録:服、ブーツ、バイクが必要です

VM Spec 2.17.1を読むのはとても楽しかったです。

...コマンドライン

java Terminator Hasta la vista Baby!

クラスのメインメソッドTerminator(名前のないパッケージのクラス)を呼び出し、4つの文字列「Hasta」、「la」、「vista」、「Baby!」を含む配列を渡すことにより、Java仮想マシンを起動します。

Terminatorロード、リンク、および初期化プロセスの例として、仮想マシンが実行するために実行するステップの概要を説明します。これについては後のセクションでさらに説明します。

最初の試行...クラスTerminatorがロードされていないことを発見します...

Terminatorロード後、mainを呼び出す前に初期化する必要があり、初期化する前に型(クラスまたはインターフェイス)を常にリンクする必要があります。リンク(§2.17.3)には、検証、準備、および(オプションで)解決が含まれます...

検証(§2.17.3)は、ロードされた表現Terminatorが整形式であることを確認します...

解決(§2.17.3)は、クラスからのシンボリック参照をチェックするプロセスTerminatorです...

 
Terminatorそうそう からのシンボリック参照。


2
なんらかの理由で、「近代」が実際の言葉であると信じることに苦労しました。
someguy

@Songoの答えのストーリーも映画のようなものです。それは最初にmetaで質問のクローズの議論で投稿されました:「質問が再び開かれるなら、私はおそらく以下のような答えを書くでしょう...」そしてそれは再び開くためにアピールをバックアップするために使用され、最終的にここに移動しました
gnat

16

漠然と虐待されているように感じます。コンストラクターはオブジェクトの初期化に使用されます。コンストラクターはオブジェクトを設定し、それを作成したコードが使用します。

基本的な使用機能をコンストラクター内に配置し、コンストラクターが外部コードで作成したオブジェクトを実際に使用しない場合、OOPの原則に違反しています。基本的に、明確な理由なしに本当に奇妙なことをします。

とにかくそれをしたいのですか?


5
しかし、「アプリケーションインスタンス」は論理的にオブジェクトではありませんか?なぜそれは虐待的でしょうか?オブジェクトの使用に関しては、実行中のアプリケーションを表すという1つの目的があります。私にとって非常にSoCのように思えます。「どうしてそんなことをしたいのですか?」–意思決定の理論的根拠に興味があるのは、他のメンタリティと対立するためです。
コンラッドルドルフ

7
@KonradRudolph:プロパティゲッターのようなコンストラクターは、一般に、何らかの非同期イベント(ユーザー入力など)が発生するのを待たずに、限られた時間内に完了することが期待されています。メインアプリケーションスレッドを起動するコンストラクターを持つことは可能ですが、すべてのアプリケーションに必要ではないかもしれないレベルの複雑さが追加されます。「Hello world」を標準出力に単純に出力するコンソールアプリケーションが余分なスレッドを生成する必要があることを要求するのは、間抜けです。Mainメソッドの使用は単純な場合にはうまく機能し、難しい場合には実際には問題になりません。
-supercat

9

Javaの場合、推論は簡単だと思います。Javaを開発するとき、開発者は、言語を学習するほとんどの人がC / C ++を事前に知っていることを知っていました。

したがって、JavaはsmalltalkではなくC / C ++によく似ているだけでなく、C / C ++からの特異性も引き継ぎました(8進整数リテラルを考えてください)。c / c ++は両方ともmainメソッドを使用するため、Javaに対して同じことを行うことはその観点から理にかなっています。

私はblochまたはこの行に沿って8進整数リテラルを追加した理由について誰かが言ったことを覚えていると確信しています、いくつかのソースを見つけることができるかどうかを確認します:)


2
C ++と同じように見えることがJavaにとって非常に重要である場合、なぜそれらがたとえばに変更さ:れたのextendsですか?またpublic static void main(String [ ] args)、クラス内とクラスint main(int argc, char **argv)外はまったく異なります。
svick

2
@svick 1つの可能性:Javaはインターフェースを導入し、明らかに2つの概念(インターフェース/クラスを継承)を分離したかった-動作しない「キーワード」が1つだけでした。そして「まったく違う」?これは可能な限り最も近いマッピングであり、これまでのところ、C ++プログラマーが静的メインメソッドがエントリポイントであるという問題を理解しているのを見たことはありません。Applicationと呼ばれるクラスや、コンストラクターが使用されるものを持つことに反して、ほとんどのC ++プログラマーにとっては奇妙に見えるものです。
Voo

cの@svick intとjavaのvoidは、アプリケーションからのリターンコードの生成方法に関係していました。javaでは、System.exit(int)が呼び出されない限り、その0です。パラメーターの変更は、文字列の配列が各言語で渡される方法に関係しています。Javaのすべてはクラス内にあります。他の場所にそれを保持するオプションはありません。変更する:には、extends構文の問題であり、本質的に同じです。他のすべては言語によって決定されます。

@MichaelTしかし、これらはすべて、JavaをC ++とは異なるものにする設計上の決定事項です。それで、どうしてJavaをC ++と同じに保つmain()ことが重要なのか、他のケースではどうやらそれが重要ではないように見えます。
svick

@svick Cのmainからも何も返さないことは完全に問題ないことと、そのような些細なことで誰も混乱することはほとんどありません。要点は、c ++とそのすべての間違いを再現することではなく、プログラマーをより家に戻すことだけでした。C ++プログラマーは、JavaやObjective-Cのコードを読むのが簡単になると思いますか?C ++プログラマーにとって、メインポイントまたはあるクラスのコンストラクターがエントリポイントとしてより明白になると思いますか?
Voo

6

さて、無限ループを実行するだけの主要な関数がたくさんあります。このように動作するコンストラクタ(決して構築されないオブジェクトを使用)は、私にとって奇妙に思えます。

この概念には非常に多くの面白いことがあります。生まれていないオブジェクト、死んで生まれたオブジェクト(コンストラクタですべての仕事を行うため)の上で実行されるロジック、...

これらのすべての副作用は、単純なパブリック(不明な人がアクセスする必要があるため)静的(開始するためにインスタンスが必要ないため)OOワゴンをはるかに破損することはありませんvoid main(エントリポイントであるため) )?

Javaに存在する単純で単純な関数エントリポイントの場合、publicとstaticが自動的に必要になります。であることが静的メソッド簡単なエントリーポイント:、それは我々が望んでいた何を達成するために、プレーン機能の近くに多くを得ることができるものに帰着します。

単純で単純な関数エントリポイントをエントリポイントとして採用しない場合。次に構築することを意図していないコンストラクタとして奇妙に思えないものは何ですか?


1
問題はファーストクラスの機能を持っていなかったと思います。main()をオブジェクト内に固定する(mainが呼び出される前にインスタンス化されない)ことは、ちょっとしたアンチパターンです。おそらく、構築されて非静的なmain()メソッドを実行する「アプリケーション」オブジェクトが必要です。その後、コンストラクタにスタートアップの初期化を設定できます。 = level main()fnも良いでしょう。静的メインは、全体的に少し面倒です。
gbjbaanb

3

開発中に、main()テストしようとしているクラスにを貼り付けることにより、クラスでいくつかのスタンドアロンテストをすばやく実行できます。


1
それはまた、など、さまざまな構成をテストするために開発中に複数のエントリポイントを可能にするよう私にはこれは、おそらく最も説得力のある理由である
cgull

0

どこかから始めなければなりません。静的メインは、使用できる最も単純な実行環境です(JVMおよび単純な文字列パラメーター以外)のインスタンスを作成する必要がないため、最小限の手間で(かつ低い尤度で)作成できます。コーディングエラーにより起動が妨げられるなど)、他の多くの設定をしなくても簡単なことができます。

基本的にKISSのアプリケーション。

[そして、もちろん、主な理由は次のとおりです。


3
私が言ったように、私はそれによって全く納得していません。オブジェクト前にインスタンス化され、コードは前に実行されます。これが理由だと私に納得させるには、元の開発者の一人からの引用が必要でしょう。
コンラッドルドルフ

2
Cコードからクラスをインスタンス化するのに必要な作業量は、静的メソッドの呼び出しとほとんど同じです。それから先に進みます)。
Voo

ユーザーオブジェクトを作成する必要はありません。オブジェクトコンストラクターは実行されません。APIは非常にシンプルです。そして、それは理解するのが最も簡単です。
ダニエルRヒックス

0

私の理解では、主な理由は簡単です。SunはUnixマシンを販売するUnix会社であり、Unixは、バイナリを呼び出すためのCの「main(args)」規約が設計されたものです。

さらに、JavaはCおよびC ++プログラマーが簡単に選択できるように明示的に設計されているため、単にCの規則を選択するだけの理由はありません。

すべてのクラスが呼び出しメソッドを持つことができる選択されたアプローチは、特にMain-Class実行可能なjarのMANIFEST.MFファイルの行と組み合わせて、非常に柔軟です。


もちろん、jarファイルはずっと後まで発明されていませんでした。
ダニエルRヒックス

-1

定義により複数のプログラムを作成する方法がないため、プログラムがOSプロセスの観点からはオブジェクトであるというOOPの哲学とは一致しません。

それに加えて、コンストラクターは決してエントリーポイントではありません。

mainを静的関数として使用するのが最も合理的な選択のように思えますが、実際には1日の終わりです。JVMやCLRなどのVMのアーキテクチャを考えると、他の選択肢はそれを不必要にプッシュすることになります。


1
間違っていると思います。複数のプロセス、したがって複数のオブジェクトを持つことできます。ちなみに、これは、Runnable複数のスレッドを持つようにオブジェクトをインスタンス化することとまったく同じです。
コンラッドルドルフ

プロセスは実行中のプログラムであり、1つのエントリポイントを介してプロセスを開始できるのは1回のみです。スレッドには独自のエントリポイントがありますが、まだ同じプロセス内にあります。
ヤムマルコビッチ

1
誰かの答えを以下で言ったように、これは関係ありません。関連するのは論理的な一貫性です。論理的に、プロセスはランチャー(OS、JVMなど)によってオブジェクトとして表され、初期化されます。
コンラッドルドルフ

@KonradRudolph本当ですが、プログラムの初期化はプロセスの初期化の一部に過ぎず、プログラムコンストラクターを正当化しません。
ヤムマルコビッチ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.