Neden bir kurucu yerine Java ve C # da statik bir ana yöntem?


54

Neden (özellikle) Java ve C # 'nın bir Applicationsınıf örneği tarafından bir uygulama örneğini temsil etmek yerine, giriş noktası olarak statik bir yönteme sahip olmaya karar verdikleri için birincil veya ikincil bir kaynaktan kesin bir cevap arıyorum. uygun bir kurucu olmak).


Önceki araştırmamın geçmişi ve detayları

Bu daha önce de sorulmuştu. Ne yazık ki, mevcut cevaplar sadece soruya yalvarıyor . Özellikle, aşağıdaki cevaplar beni tatmin etmiyor.

  • Yapıcı aşırı yüklenmiş olsaydı belirsizlik olurdu. - Aslında, C # (C ve C ++ 'ın yanı sıra) Main, aynı potansiyel belirsizliğin var olduğu ve ele alındığı için farklı imzalara izin verir .
  • Bir staticyöntem, başlangıç ​​sırasının net olmadığı için hiçbir nesnenin başlatılamayacağı anlamına gelir. - Bu sadece yanlış, bazı nesneler daha önce başlatıldı (örneğin statik bir kurucuda).
  • Böylece bir ana nesneyi başlatmak zorunda kalmadan çalışma zamanı tarafından çağrılabilirler. - Bu hiç bir cevap değil.

Sadece bunun neden geçerli ve ilginç bir soru olduğunu düşündüğümü daha fazla açıklamak için:

  • Birçok çerçeveler yapmak giriş noktaları gibi uygulamaları ve kurucular temsil etmek sınıflarını kullanın. Örneğin, VB.NET uygulama çerçevesi giriş noktası 1 olarak tahsis edilmiş bir ana diyalog (ve yapıcı) kullanır .

  • Ne Java ne de C # teknik olarak bir ana yönteme ihtiyaç duymazlar . C # 'ın derlenmesi gereken birine ihtiyacı var, ama Java bile değil. Ve her iki durumda da yürütme için gerekli değildir. Yani bu teknik bir kısıtlama gibi görünmüyor. Ve, birinci paragrafta bahsettiğim gibi, sadece bir kongre için, Java ve C # 'nın genel tasarım prensibine tuhaf bir şekilde uyuşmuyor gibi görünüyor.

Açık olmak gerekirse, statik bir yönteme sahip olmanın belirli bir dezavantajı yokturmain , sadece biraz gariptir , bu da arkasında bazı teknik gerekçeler olup olmadığını merak etmemi sağladı.

Sadece bir spekülasyon değil, birincil veya ikincil bir kaynaktan kesin bir cevap ile ilgileniyorum.


1 BunaStartup engel olabilecek bir callback ( ) olmasına rağmen .


4
@mjfgates Ayrıca, bu açıkça ortaya koyuyoruz umduğu değil sadece “insanlar bunu ben istediğim gibi neden yapmadıklarını” ve ben nedenlerle gerçekten ilgi olduğumu.
Konrad Rudolph

2
Java için mantığın basit olduğunu düşünürdüm: Java geliştirirken, dili öğrenen çoğu kişinin önceden C / C ++ bileceğini biliyorlardı. Bu yüzden Java, sadece küçük konuşma demek yerine C / C ++ 'a benzemiyor, aynı zamanda C / C ++' dan idiosynchrasies (sadece octal integer değişmezlerini düşünün) devraldı. Hem c / c ++ hem de ana yöntem kullandığından, java için aynı işlemi yapmak bu açıdan mantıklı geliyordu.
Voo

5
@ Jarrod Adaletsizsin. Bunu açıkça bir rant haline getirmediğimi sanıyordum . “Yapıcı değil”? Nasıl yani? Açıkça referanslar istiyorum, sadece vahşi tartışmalar için değil. Elbette, bunun ilginç bir soru olduğuna katılmakta özgürsünüz . Ancak bu tür sorular burada OT ise, Programcıların ne amaçla hizmet ettiğini gerçekten göremiyorum.
Konrad Rudolph


3
Soru: Eğer bir uygulama nesnesiyse, iki şeye ihtiyacınız yok. 1) Bir yapıcı. 2) Uygulamanızı çalıştırmak için nesne üzerinde bir yöntem. Yapıcı nesnenin geçerli olması ve böylece çalıştırılabilir olması için tamamlamalıdır.
Martin York

Yanıtlar:


38

TL; DR

Java'da, neden arasında public static void main(String[] args)olmasıdır

  1. Gosling istedi
  2. C de deneyimli bir kişi tarafından yazılmış kod (Java’da değil)
  3. çalışan çeken biri tarafından yürütülecek PostScript üzerinde News

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

 
C # için akıl yürütme, konuşmaya benzer şekilde geçişsel olarak benzer . Dil tasarımcıları, program giriş noktası sözdizimini Java'dan gelen programcılar için tanıdık tuttu . C # mimarı olarak Anders Hejlsberg koyar ,

... C # ile olan yaklaşımımız Java programcılarına alternatif ... sunmaktır ...

 

Uzun versiyon

Yukarıda genişleyen ve sıkıcı referanslarla destekledi.

 

java Terminator Hasta la vista Bebeğim!

VM Spec, 2.17.1 Sanal Makine Başlatması

... Başlangıç ​​sınıfının Java sanal makinesinde belirtilme şekli, bu belirtimin kapsamı dışındadır, ancak sınıfın tam adı için belirtilecek sınıfın tam adı için komut satırı kullanan ana bilgisayar ortamlarında tipiktir. bir komut satırı argümanı ve sonraki komut satırı argümanları için ana yöntemin argümanı olarak sağlanacak dizeler olarak kullanılacaktır. Örneğin, Solaris için Sun'ın Java 2 SDK'sını kullanarak komut satırı

java Terminator Hasta la vista Baby!

sınıfın ana yöntemini Terminator(adlandırılmamış bir pakette bulunan bir sınıf) çağırarak ve "Hasta", "la", "manzara" ve "Bebek!"

... ayrıca bakınız: Ek: Kıyafetlerinize, botlarınıza ve motosikletinize ihtiyacım var

  • Yorumum:
    komut satırı arayüzündeki tipik komut dosyaları gibi kullanımı hedeflenen yürütme.

 

önemli yan

... araştırmalarımızda birkaç yanlış izden kaçınmaya yardımcı oluyor.

VM Spec, 1.2 Java Sanal Makinesi

Java sanal makinesi Java programlama dilinden hiçbir şey bilmiyor ...

Önceki bölüm okurken yukarıda dikkatimi çekmiştim - 1.1 Yararlı olabileceğini düşündüğüm tarih (ancak işe yaramaz hale geldi).

  • Yorumum:
    yürütme tek başına VM spec tarafından yönetilir,
    açıkça JLS ile ilgisi olmadığını ve JLS'yi ve ilgili herhangi bir Java dilini
    yoksaymak için => TAMAM olduğunu beyan eder.

 

Gosling: C ve betik dili arasında bir uzlaşma ...

Yukarıdakilere dayanarak, JVM tarihi için web’i aramaya başladım . Yardım etmedim, sonuçta çok fazla çöp.

Sonra Gosling hakkındaki efsaneleri hatırladım ve Gosling JVM tarihine olan araştırmamı daralttım .

Eureka! JVM Spec Nasıl Oluştu?

JVM Languages ​​Summit 2008’deki bu açılış konuşmasında James Gosling ... Java’nın yaratılışını ... C ile betik dili arasında bir uzlaşmaya varıyor ...

  • Benim yorumum:
    Yaratılış anında
    C ve kod yazmanın en önemli etkiler olarak kabul edildiğine dair açık beyan .
     
    Zaten VM Spec 2.17.1 yılında komut dosyası için selam görülen,
    komut satırı argümanları yeterince açıklamak String[] args
    ancak staticve maindaha da kazmak gerekir henüz bulunmamaktadır ...

Bunu yazarken not edin - C'yi, komut dosyasını ve VM Spec 1.2'yi Java'sız bir şeyle bağlarken - tanıdık bir şey gibi hissediyorum, bir şey ... nesne yönelimli yavaş yavaş geçiyor. Elimi tut ve hareket etmeye devam et 'Yavaşlama

Keynote slaytları çevrimiçi olarak mevcuttur: 20_Gosling_keynote.pdf , kilit noktaları kopyalamak için oldukça uygundur.

    sayfa 3

        Java Prehistoryası
        * Düşüncemi ne şekillendirdi

    sayfa 9

        Haberler
        * Ağa Bağlı Genişletilebilir Pencere Sistemi
        * Kodlamaya dayalı bir pencere sistemi ....
          PostScript (!!)

    sayfa 16

        Büyük (ama Sessiz) Amaç:
          Ne kadar yakın
          "senaryo" hissi ...

    sayfa 19

        Orijinal kavram
        * Her şey bina ile ilgiliydi
          şeylerin ağları,
          bir komut dosyası tarafından düzenlendi
          dil
        * (Unix kabukları, AppleScript, ...)

    sayfa 20

        Koyun kılığındaki bir kurt
        * C sözdizimi geliştiriciler yapmak
          rahat

Aha! C sözdizimine daha yakından bakalım .

"Merhaba dünya" örneği ...

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

... main adında bir fonksiyon tanımlanıyor. Ana işlevi C programlarında özel bir amaca hizmet; çalışma zamanı ortamı, programın yürütülmesine başlamak için ana işlevi çağırır.

... Asıl işlevin aslında iki argümanı vardır int argcve char *argv[]sırasıyla komut satırı argümanlarını işlemek için kullanılabilir ...

Yaklaşıyor muyuz? emin ol. Ayrıca yukarıdaki alıntıdan "ana" bağlantıyı izlemeye değer:

Ana işlev, bir programın yürütmeye başladığı yerdir. Programın işlevselliğinin üst düzey organizasyonundan sorumludur ve genellikle yürütüldüğü zaman programa verilen komut argümanlarına erişime sahiptir.

  • Yorumum:
    C geliştiricisi için rahat olması için program giriş noktasının olması gerekir main.
    Ayrıca, Java sınıfta herhangi bir yöntem gerektirdiğinden Class.main,
    olabildiğince yakındır: statik çağrı, sadece sınıf adı ve nokta,
    lütfen yapıcı yok - C böyle bir şey bilmiyor.
     
    Bu aynı zamanda geçişli dikkate alarak, C # için geçerlidir
    Java dan kendisine kolay geçiş fikrini.

Tanıdık programın giriş noktasının önemli olmadığını düşünen okuyucular, Java SE'den gelen kişilerin Java ME MIDP için Hello World yazmaya çalıştığı Yığın Taşması sorularını araştırmaya ve kontrol etmeye davetlidir . Not MIDP giriş noktasının hiçbiri mainyoktur static.

 

Sonuç

Söyleyebilirm yukarıda dayanarak static, mainve String[] argstanımlamak için Java ve C # oluşturma en makul seçenek anlarda idi programı giriş noktası .

 

Ek: Kıyafetlerine, botlarına ve motosikletine ihtiyacım var

Kabul etmeliyim ki, VM Spec 2.17.1'i okumak çok eğlenceliydi.

... komut satırı

java Terminator Hasta la vista Baby!

sınıfın ana yöntemini Terminator(adlandırılmamış bir pakette bulunan bir sınıf) çağırarak ve "Hasta", "la", "vista" ve "Baby!" dizelerini içeren bir diziyi geçerek bir Java sanal makinesini başlatır .

Şimdi, sanal makinenin Terminatorileriki bölümlerde daha ayrıntılı olarak açıklanan yükleme, bağlama ve başlatma işlemlerinin bir örneği olarak yürütmek için atması gereken adımları açıklıyoruz.

İlk deneme ... sınıfın Terminatoryüklenmediğini keşfetti ...

TerminatorYüklendikten sonra , ana çağrılmadan önce başlatılmalıdır ve başlatılmadan önce bir tür (sınıf veya arabirim) her zaman bağlanmalıdır. Bağlama (§2.17.3) doğrulama, hazırlık ve (isteğe bağlı) çözülmeyi içerir ...

Doğrulama (§2.17.3), yüklü temsilinin Terminatoriyi bir şekilde oluşturulduğunu kontrol eder ...

Karar (§2.17.3) sınıftan sembolik referansları kontrol etme işlemidir Terminator...

 
TerminatorEvet sembolik referanslar .


2
Nedense "modernitenin" gerçek bir kelime olduğuna inanmakta zorlandım.
someguy,

@Songo cevabının hikayesi de bir film gibidir. İlk olarak metada , soru kapatmanın bir tartışmasında yayınlandı : "Eğer soru yeniden açılacaksa, muhtemelen aşağıdaki gibi bir cevap yazardım ..." Sonra yeniden açılmaya olan temyizini desteklemek için kullanıldı ve sonunda buraya taşındı.
gnat

16

Bu sadece bana belli belirsiz küfürlü geliyor. Bir nesnenin başlatılması için yapıcı kullanılır: daha sonra onu oluşturan kod tarafından kullanılan bir nesne kurar.

Yapıcının içine temel kullanım işlevselliği koyarsanız ve daha sonra yapıcının harici kodda oluşturduğu nesneyi asla kullanmazsanız, OOP ilkelerini ihlal ediyorsunuz demektir. Temel olarak, bariz bir sebep olmadan gerçekten garip bir şey yapmak.

Neden bunu yine de yapmak istiyorsun?


5
Fakat “uygulama örneği” mantıksal olarak bir nesne değil mi? Bu neden küfürlü olsun ki? Nesneyi kullanmaya gelince - bunun bir amacı vardır: çalışan uygulamayı temsil etmek. Bana çok SoC geliyor. “Neden bunu yapmak istiyorsun?” - Kararın gerekçesini yalnızca zihniyetin geri kalanıyla çelişkili bulduğum için ilgilendim.
Konrad Rudolph

7
@KonradRudolph: Bir mülk alıcısı gibi bir yapıcının, bazı zaman uyumsuz bir olayın (kullanıcı girişi gibi) gerçekleşmesini beklemeden sınırlı bir süre içinde tamamlaması beklenir. Ana uygulama iş parçacığını başlatan, ancak tüm uygulamalar için gerekmeyebilecek bir karmaşıklık düzeyi ekleyen bir kurucuya sahip olmak mümkün olacaktır. Standart çıktıya "Merhaba dünya" yazdıran bir konsol uygulamasının gerektirmesi, fazladan bir iş parçacığının yumuşatılması gerekir. Bir Mainyöntem kullanmak basit vaka için iyi çalışır ve zor durumlarda gerçekten bir sorun değildir, neden olmasın?
supercat

9

Java için mantığın basit olduğunu düşünürdüm: Java geliştirilirken, kullanıcılar dili öğrenen çoğu kişinin önceden C / C ++ bileceğini biliyordu.

Bu yüzden Java, sadece küçük konuşma demek yerine C / C ++ 'a benzemiyor, aynı zamanda C / C ++' dan idiosynchrasies (sadece octal integer değişmezlerini düşünün) devraldı. Hem c / c ++ hem de ana yöntem kullandığından, java için aynı işlemi yapmak bu açıdan anlamlıydı.

Bu satır boyunca neden sekizli tamsayı değişmezleri ekledikleriyle ilgili bir şeyler söylediğini hatırladığımdan eminim, bakalım bazı kaynaklar bulabilecek miyim :)


2
Örnek değişikliği için yaptılar neden seyir halinde C ++ ile aynı, Java için çok önemliydi :için extends? Ve public static void main(String [ ] args)bir sınıfın içinde bir sınıfın int main(int argc, char **argv)dışında oldukça farklıdır .
svick

2
@svick Bir olasılık: Java arayüzleri tanıttı ve iki kavramı ayırmak istediler (arayüzleri / sınıfları miras alarak) - işe yaramayacak tek bir "anahtar kelime" ile. Ve "oldukça farklı"? Bu mümkün olan en yakın haritalama ve şimdiye kadar bir c ++ programcısı görmedim, statik ana yöntemin giriş noktası olduğunu anlamada bir sorun yaşamadım. Uygulamanın bir sınıfı veya kurucusu kullanılan bir sınıfa sahip olmanın aksine, çoğu c ++ programcısına garip gelecek gibi görünüyor.
Voo

java'da geçersiz kılmak için int in c (svick), bir uygulamadan bir dönüş kodunun nasıl üretildiğiyle ilgilidir - Java'da, System.exit (int) kullanılmadığı sürece 0 olur. Parametrelerin değişmesi, dize dizilerinin her dilde nasıl geçtiği ile ilgilidir. Java'daki her şey bir sınıfa girer - başka bir yerde olması için bir seçenek yoktur. Değişen :için extendssözdizimi meselesidir ve esasen aynıdır. Diğer her şey dil tarafından belirlenir.

@MichaelT Fakat hepsi Java'yı C ++ 'dan farklı kılan tasarım kararları. Öyleyse neden Java'yı, C ++ ile aynı main()tutuyorsa, diğer durumlarda yeterince belirgin olmadığı durumlarda önemlidir.
svick

@svick C de ana bilgisayardan herhangi bir şey döndürmemek tamamen dürüst olmasının dışında, bu tür önemsizlikler hiç kimseyi şaşırtmaz. Mesele, c ++ 'ı ve tüm hatalarını yeniden yaratmak değil, yalnızca programcıyı evde daha fazla yapmaktı. C ++ programcısının okumayı kolaylaştıracak ne düşünüyorsun: Java ya da objektif-c kodu? Bir C ++ programcısına, giriş noktası olarak bir ana metodu veya bir sınıfın kurucusu için neyin daha belirgin olacağını düşünüyorsunuz?
Voo

6

Orada sonsuz bir döngü çalıştıran birçok ana işlev var. Bu şekilde çalışan (asla inşa edilmeyen bir nesneyle) bir inşaatçı bana tuhaf geliyor.

Bu konseptle ilgili çok komik şeyler var. Doğmamış bir nesnenin üzerinde çalışan mantığınız, ölmek için doğmuş nesneler (tüm işlerini kurucuda yaptıkları için), ...

Tüm bu yan etkiler, OO vagonunu basit bir halktan çok daha fazla bozmaz mı (çünkü bilinmeyene erişilmesi gerekiyor) statik (çünkü başlamamız için hiçbir örneğe gerek yok) geçersiz ana (çünkü giriş noktasıdır) )?

Java'da basit, sade, işlevli bir giriş noktası olması için, genel ve statik otomatik olarak gerekli olacaktır. Statik bir yöntem olmasına rağmen , istenenleri başarmak için düz bir işleve daha fazla yaklaşabileceğimiz şeye kaynaşıyor: basit bir giriş noktası.

Basit, sade, işlevli bir giriş noktasını giriş noktası olarak kabul etmeyecekseniz. Sırada ne var ki yapımı olmayan bir inşaatçı olarak tuhaf görünmüyor?


1
Sorunun birinci sınıf fonksiyonlara sahip olmadığını söyleyebilirim. Ana nesneyi () ana nesnenin (ana çağrılmadan önce başlatılmayan) içine yapıştırmak bir kalıp karşıtıdır. Belki de inşa edilen ve statik olmayan main () yöntemini çalıştıran bir "uygulama" nesnesine sahip olmaları gerekir, daha sonra başlangıç ​​kurucusunu kurucuya yerleştirebilirsiniz ve statik yöntemlere sahip olmaktan çok daha iyi olurdu, basit bir üst = main seviyesi () fn de iyi olur. Statik ana, hepsinde bir miktar çamur.
gbjbaanb

3

Geliştirme sırasında, main()test etmeye çalıştığınız sınıfa yapıştırarak, bir sınıftaki bağımsız testleri hızla uygulayabilirsiniz.


1
Ayrıca, bu farklı yapılandırmalar, test etmek için geliştirme sırasında çoklu giriş noktalarını verdiğinden bana bu muhtemelen en önemli sebep
cgull

0

Bir yerden başlamalısın. Statik ana, sahip olabileceğiniz en basit yürütme ortamıdır - hiçbir şeyin (JVM dışında ve basit dize parametrelerinin dışında) oluşturulması gerekmez - bu nedenle minimum sıkıntı ile "yukarı gelemez" (ve düşük ihtimal olabilir) bir kodlama hatasının başlangıcını, vb. engeller) ve başka birçok kurulum yapmadan basit şeyler yapabilir.

Temelde KISS uygulaması.

[Ve, elbette, ana nedeni: Neden olmasın?]


3
Dediğim gibi, buna ikna olmadım. Nesneler do önce örneği almak ve kod önce çalıştırılmaktadır. Bunun sebebi olduğuna beni ikna etmek için orijinal geliştiricilerin birinden bir alıntı yapması gerekiyor.
Konrad Rudolph

2
Bir sınıfı C kodundan başlatmak için gereken iş miktarı, statik bir yöntemi çağırmakla hemen hemen aynıdır. Aynı denetimleri yapmanız gerekebilir (sınıf var mı? İyi, doğru imzayla bir kamu kurucusu var mı?) iyi o zaman devam et).
Voo

Hiçbir kullanıcı nesnesinin oluşturulması gerekmez. Nesne yapıcı yürütülmez. API cayır cayır basittir. Ve bunu anlamak en kolay olanıdır.
Daniel R Hicks

0

Anladığım kadarıyla birincil nedeni basittir. Sun, Unix makineleri satan bir Unix şirketiydi ve Unix, C "ana (args)" sözleşmesinin bir ikili çağırma çağrısı için tasarlandığı şeydi.

Ek olarak Java, C ve C ++ programcıları için kolayca seçilebilecek şekilde tasarlanmıştı, bu nedenle sadece C kurallarını kaldırmanın iyi bir nedeni yoktu.

Her sınıfın bir çağrı yöntemine sahip olabileceği seçilen yaklaşım, özellikle Main-Classçalıştırılabilir bir kavanozdaki MANIFEST.MF dosyasındaki çizgi ile birlikte oldukça esnektir .


Elbette, kavanoz dosyası çok sonraya kadar icat edilmedi.
Daniel R Hicks

-1

OOP felsefesi ile tutarlı değil, bir programın bir işletim sistemi süreci açısından bir nesne olacağı, çünkü tanımı gereği birden fazla seçeneğe sahip olamayacağımız anlamına geliyor.

Bunun üzerine, yapıcı hiçbir şekilde bir giriş noktası değildir.

Bana aslında günün sonunda olduğu statik bir işlev olarak sahip olmak için en makul seçenek gibi görünüyor. JVM ve CLR gibi VM'lerin mimarisi göz önüne alındığında, başka bir seçenek gereksiz yere onu zorlardı.


1
Bence orada yanılıyorsun. İse daha fazla işlem, bu nedenle birden fazla nesne olması mümkündür. Bu arada, bu tamamen Runnableçoklu nesnelere sahip nesnelerin başlatılmasıyla aynıdır .
Konrad Rudolph

İşlem çalışan bir programdır ve bir işlemi yalnızca bir giriş noktası üzerinden yalnızca bir kez başlatabilirsiniz. Dişlerin kendi giriş noktaları vardır, ancak yine de aynı süreç içindedirler.
Yam Marcovic

1
Birinin cevabının altında söylediğim gibi, bu konuyla ilgili değil. İlgili olan mantıklı tutarlılık. Mantıksal olarak, işlemler başlatıcı tarafından nesneler olarak temsil edilir (OS, JVM, her neyse) ve başlatılır.
Konrad Rudolph

@KonradRudolph Doğru, ancak bir programın başlatılması, bir işlemin başlatılmasının yalnızca bir kısmıdır ve bir program kurucusunu meşrulaştırmaz.
Yam Marcovic
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.