Java neden fonksiyon tanımlarının sınıf dışında bulunmasına izin vermiyor?


22

C ++ 'dan farklı olarak, Java' da sınıftaki sadece fonksiyon bildirimlerine ve sınıf dışındaki tanımlara sahip olamayız. Neden bu kadar?

Java'daki tek bir dosyanın yalnızca bir sınıf içermesi gerektiğini vurgulamak mı gerekiyor?



1
By tanımları size ortalama özelliklere veya yöntem imzaları başlık dosyaları ala do?
Deco

Sorunuza güzel bir hiciv cevabı: steve-yegge.blogspot.com/2006/03/…
Brandon

Yanıtlar:


33

C ++ ve Java arasındaki fark, dillerin en küçük bağlantı birimi olarak gördükleridir.

C montaj ile bir arada bulunacak şekilde tasarlandığından, bu birim bir adres tarafından adlandırılan alt yordamdır. (Bu, FORTRAN gibi yerel nesne dosyalarını derleyen diğer diller için geçerlidir.) Başka bir deyişle, bir işlevi içeren bir nesne dosyası, gibi bir adres dışında hiçbir şeye çözülmeyecek foo()bir sembole _foosahip olacaktır.0xdeadbeefbağlama sırasında. Hepsi bu kadar. Eğer işlev argümanları almaksa, işlevini beklediğiniz her şeyin adresini çağırmadan önce sıralı olduğundan emin olmak arayan kişiye bağlıdır. Normalde, bu işleri istifin üzerine yığmak suretiyle yapılır ve derleyici büyük işlerle ilgilenir ve prototiplerin eşleştiğinden emin olur. Nesne dosyaları arasında bunun kontrolü yoktur; Eğer arama bağlantısını kaldırırsanız, arama planlandığı gibi kapanmaz ve bunun hakkında bir uyarı almayacaksınız. Tehlikeye rağmen, bu, birçok dilden (derleme dahil) derlenen nesne dosyalarının çok fazla telaşlanmadan çalışan bir programa bağlanmasını mümkün kılar.

C ++, tüm fantazilerine rağmen aynı şekilde çalışır. Derleyici ayakkabısı ad alanlarını, sınıfları ve yöntemleri / üyeler / etc. Bu konvansiyonun içine, sınıfların içeriğini, onları benzersiz kılacak şekilde tutturulmuş tek adlara düzleştirmekle. Örneğin, gibi bir yöntem , bir nesne dosyasına ve çalışma zamanında olduğu gibi bir adrese konulduğunda Foo::bar(int baz)karışabilir . Bu tamamen derleyiciye bağlıdır, bu nedenle farklı yönetim şemalarına sahip iki nesneyi birbirine bağlamaya çalışırsanız şanssız kalırsınız. Çirkin olduğu gibi, mangling'i devre dışı bırakmak için bir blok kullanıp C ++ kodunu diğer dillere kolayca erişilebilir hale getirmenizi sağlar. C ++ serbest kayan fonksiyonlar kavramını C'den devraldı, çünkü büyük ölçüde yerel nesne formatı buna izin veriyor._ZN4Foo4barEi0xBADCAFEextern "C"

Java, kendi nesne dosya formatı olan yalıtılmış bir dünyada yaşayan farklı bir canavardır .class. Sınıf dosyaları , ortamın çalışma zamanında sınıflarında yerel bağlantı mekanizmasının bile hayal edemediği şeyleri yapmasını sağlayan içeriği hakkında zengin bilgiler içerir . Bu bilgi bir yerden başlamalı ve bu başlangıç ​​noktasıclass. Mevcut bilgi, derlenmiş kodun, C, C ++ veya diğer dillerdeki gibi kaynak kodda bir açıklama içeren ayrı dosyalara ihtiyaç duymadan kendini tanımlamasına olanak tanır. Bu, çalışma anında bile yerel bağlantı eksikliğini kullanan tüm tür güvenlik avantajı dillerini verir ve yansıma kullanarak rastgele bir sınıfı dosyadan çıkarmanıza ve bir eşleşme olmazsa garantili bir arızayla kullanmanıza olanak sağlayan şeydir. .

Bunu henüz çözemediyseniz, tüm bu güvenlik bir tradeoff ile birlikte gelir: Java programına bağladığınız her şey Java olmalıdır. ("Bağlantı" ile, herhangi bir zamanda bir sınıf dosyasındaki herhangi bir şeyin başka bir şeye atıfta bulunduğunu kastediyorum.) JNI kullanarak (yerel anlamda) yerel koda bağlayabilirsiniz , ancak yerel tarafı bozarsanız söyleyen gizli bir sözleşme vardır. , iki parçanın da sen varsın.

Java büyüktü ve özellikle ilk kullanıldığı zamanki donanımda hızlı değildi, tıpkı Ada'nın önceki on yılda olduğu gibi. Sadece Jim Gosling, Java'nın sınıfının en küçük bağlantı birimi haline getirilmesinde motivasyonlarının ne olduğunu kesin olarak söyleyebilir, ancak serbest bırakma araçları eklemenin çalışma zamanına kattığı ekstra karmaşıklığın bir anlaşma katili olabileceğini tahmin etmek zorunda kaldım.


bağlantı kopmuş, web arşivini al
no linkzɐɹƆ

14

Cevabın Wikipedia'ya göre, Java'nın basit ve nesneye yönelik olarak tasarlandığına inanıyorum. İşlevler, tanımlandıkları sınıflar üzerinde işlem yapmak içindir. Bu düşünme çizgisiyle, sınıf dışında işlevlere sahip olmak bir şey ifade etmez. Java'nın izin vermediği sonucuna atlayacağım çünkü saf OOP'a uymuyordu.

Benim için hızlı bir Google araması, Java dili tasarım motivasyonlarında fazla bir sonuç vermedi.


6
İlkel türlerin varlığı, Java'yı "saf OOP" olmaktan dışlamaz mı?
Radu Murzea

5
@SoboLAN: Evet ve fonksiyonlar eklemek onu daha az "saf OOP" yapar.
Giorgio

8
"Saf OOP" tanımınıza bağlı olarak @SoboLAN. Bir noktada, her şey sonuçta bilgisayar belleğindeki bitlerin bir birleşimidir ...
18'de jwenting

3
@jwenting: Programlama dillerinde soyutlamanın amacı, altta yatan bitleri mümkün olduğunca gizlemektir. Bu bitleri programınızda ne kadar çok görüyorsanız, programlama dilinizin sızdıran soyutlamalar sunduğunu düşünmeye başlamalısınız (bilerek metale yakın bir şekilde inşa edilmedikçe). Bu nedenle, evet, bitleri değiştirmek için her şey azalır, ancak farklı diller farklı soyutlama seviyeleri sunar, aksi takdirde montajı daha yüksek bir dilden ayırt edemezsiniz.
Giorgio

2
"Saf OOP" tanımınıza göre değişir: her veri değeri bir nesnedir ve her veri işlemi mesaj iletimi yoluyla elde edilen sonuç yöntemi çağrısıdır. Bildiğim kadarıyla daha fazla bir şey yok.
Giorgio,

11

Asıl soru, C ++ yöntemini yapmaya devam etmenin faydası ne olurdu ve başlık dosyasının orijinal amacı neydi? Kısa cevap, başlık dosya stilinin, birçok sınıfın aynı tipte potansiyel olarak başvuruda bulunabileceği büyük projelerde daha derleme sürelerine izin vermesidir. Derleyicilerin niteliğinden dolayı JAVA ve .NET'te bu gerekli değildir.

Bu cevaba bakınız: Başlık dosyaları gerçekten iyi mi?


1
+1, gerçekte insanların genel arayüz ile başlık dosyalarının sağladığı özel uygulama arasında ayrım yapmaktan hoşlandıklarını söylediklerini duyduğuma rağmen. Bu insanlar elbette yanılıyor. ;)
vaughandroid

6
@Baqueta Java ile bunu başarabilirsiniz interfaceve class:) Başlıklara gerek yok!
Andres F.

1
Basit bir sınıf örneğinin nasıl çalıştığını anlamak için 3+ dosyaya bakma isteğini asla anlayamayacağım.
Erik Reppen

@ErikReppen tipik olarak, arayüz (veya C'deki başlık dosyası), müşterilerin çözümlerini yazmak için kullanıcı tarafından okunabilir formda oldukları, geri kalanın sadece ikili formda sağlandığı şeydir (elbette Java, kaynakları sağlamaya gerek yoktur) Arayüzlerin, sınıf ve javadoc yapacak).
Şubat'ta

@jwenting Bu davayı düşünmemiştim. Bu aptalca kod tabanını sürdürmesi gereken bir sonraki zavallı herifi düşünmeye daha çok alışkınım, çünkü çoğu zaman sık sık bir sonraki tuhaf arayüze ve alt / üst sınıf merry'e bakarak saatler geçirdikten sonra gözlerimi bıçaklarım. yuvarlak yapı mimarisi.
Erik,

3

Bir Java dosyası bir sınıfı temsil eder. Sınıf dışında bir işlem yapsaydınız kapsam ne olurdu? Küresel mi olurdu? Yoksa Java dosyasının temsil ettiği sınıfa mı ait?

Muhtemelen, bir sebeple başka bir dosya yerine o Java dosyasına koymuşsunuzdur - çünkü o sınıfa diğer sınıflardan daha fazla gider. Bir sınıf dışında bir prosedür aslında o sınıfla ilişkilendirildiyse, neden onu ait olduğu sınıfın içine girmeye zorlamıyorsunuz? Java bunu sınıf içinde statik bir yöntem olarak ele alır.

Eğer bir dış sınıf prosedürüne izin verildiyse, muhtemelen içinde bulunduğu bildirilen sınıfa özel bir erişimi olmayacaktı, bu yüzden herhangi bir veriyi değiştirmeyen bir fayda fonksiyonuyla sınırlandıracaktı.

Bu Java sınırlamasının tek olası tarafı, herhangi bir sınıfla ilişkili olmayan genel prosedürlere sahipseniz, onları tutmak için bir MyGlobals sınıfı haline getirmeniz ve bu sınıfı bu prosedürleri kullanan diğer tüm dosyalarınızda içe aktarmanızdır. .

Aslında, Java içe aktarma mekanizması, çalışması için bu kısıtlamaya ihtiyaç duyuyor. Kullanılabilir tüm API'lerle birlikte, java derleyicisinin tam olarak neyin derleneceğini ve neyin derleneceğini bilmesi gerekir, bu nedenle dosyanın en üstündeki açık içe aktarma ifadeleri. Yapay bir sınıfa grubuna globalsi kalmadan, nasıl Java derlemek için derleyici söylerdim senin globalsi değil her türlü Sınıfyolu üzerinde globaller? Bir doStuff () ve başkasında doStuff () bulunan ad alanı çarpışmasına ne dersiniz? İşe yaramazdı. Sizi MyClass.doStuff () ve YourClass.doStuff () belirtmeye zorlamak bu sorunları düzeltir. Prosedürlerinizi dışarıdan değil MyClass'a girmeye zorlamak sadece bu kısıtlamayı açıklığa kavuşturur ve kodunuzda ek kısıtlamalar getirmez.

Java bir çok şeyi yanlış anladı - serileştirme o kadar çok küçük siğile sahipti ki, faydalı olmak neredeyse çok zordu (SerialVersionUID). Ayrıca tekilleri ve diğer genel tasarım modellerini kırmak için de kullanılabilir. Object'teki clone () yöntemi deepClone () ve shallowClone () 'ye bölünmeli ve tip güvenli olmalıdır. Tüm API sınıfları varsayılan olarak değiştirilemez hale getirilebilir (Scala'da oldukları gibi). Ancak tüm prosedürlerin bir sınıfa ait olması gereken kısıtlama iyi bir şeydir. Öncelikle herhangi bir zahmetli kısıtlama getirmeden dili ve kodunuzu basitleştirmek ve netleştirmek için hizmet vermektedir.


3

Bence cevap verenlerin ve seçmenlerin çoğunun soruyu yanlış anladıklarını düşünüyorum. C ++ bilmediklerini yansıtıyor.

"Tanım" ve "Beyan", C ++ 'da çok özel bir anlamı olan sözcüklerdir.

OP, Java'nın çalışma şeklini değiştirmek anlamına gelmez. Bu tamamen sözdizimi ile ilgili bir sorudur. Bunun geçerli bir soru olduğunu düşünüyorum.

C ++ 'da üye fonksiyonu tanımlamanın iki yolu vardır .

İlk yol, Java yoludur. Tüm kodu ayraç içine koymanız yeterlidir:

class Box {
public:
    // definition of member function
    void change(int newInt) { 
        this._m = newInt;
    }
private:
    int _m
}

İkinci yol:

class Box {
public:  
    // declaration of member function
    void change(int newInt); 
private:
    int _m
}

// definition of member function
// this can be in the same file as the declaration
void Box::change(int newInt) {
    this._m = newInt;
}

Her iki program da aynı. Fonksiyon changehala bir üye fonksiyonudur: sınıf dışında mevcut değildir. Ayrıca, sınıf tanımı, tıpkı Java'daki gibi, ALL üye fonksiyonlarının ve değişkenlerinin adlarını ve türlerini içermelidir.

Jonathan Henson, başlıkların C ++ 'da çalışma biçiminin bir eseri olduğu konusunda haklıdır: başlık dosyasındaki bildirimleri ve uygulamaları ayrı bir .cpp dosyasına koymanıza izin verir, böylece programınız ODR'yi (Tek Tanımlama Kuralı) ihlal etmez. Ancak bunun dışında bir yararı var: büyük bir sınıfın arayüzünü bir bakışta görmenize izin veriyor.

Java'da bu etkiyi soyut sınıflar veya arayüzler ile değerlendirebilirsiniz, ancak bunlar uygulama sınıfıyla aynı adı taşıyamaz, bu da onu oldukça sakar yapar.


ve bu ikinizin de insanları ya da Java'yı anlamadığını gösteriyor. Arabirim ve uygulama için aynı adı, paket içinde olmadıkları sürece kullanabilirsiniz.
Şubat'ta

Paketi (veya ad alanını veya dış sınıfı) adın bir parçası olarak kabul ediyorum.
Erik van Velzen

2

Bunun sınıf yükleme mekanizmasının bir eseri olduğunu düşünüyorum. Her sınıf dosyası yüklenebilir bir nesne için bir kaptır. Sınıf dosyalarının "dışında" bir yer yoktur.


1
Kaynak kodun ayrı birimlerde düzenlenmesinin, sınıf dosya biçiminin olduğu gibi tutulmasının neden önlendiğini anlamadım.
Mat

Genel sistemdeki daha iyi tasarım kararlarından biri olan sınıf dosyaları ve kaynak dosyalar arasında 1: 1 yazışma vardır.
Ddyer

@ddyer Daha önce hiç Foo $ 2 $ 1.class görmediniz mi? (bkz. Java iç sınıfı sınıfı dosya adları )

Bu bir "üzerine" haritalama yapar mı? Her durumda, her sınıf iyi bir tasarım kararı olan tam olarak bir kaynak dosyadan derlenir.
Ddyer,

0

Java'ya çok benzeyen C #, kısmi yöntemlerin yalnızca özel olması dışında, bu tür bir özelliğe sahiptir.

Kısmi Yöntemler: http://msdn.microsoft.com/en-us/library/6b0scde8.aspx

Kısmi Sınıflar ve Yöntemler: http://msdn.microsoft.com/en-us/library/wa80x488.aspx

Java'nın aynı şeyi yapamamasının bir nedenini göremiyorum, ancak muhtemelen bu özelliği dile eklemek için kullanıcı tabanından algılanan bir gereksinimin olup olmadığı ortaya çıkıyor.

C # için çoğu kod oluşturma aracı, kısmi sınıflar oluşturur; böylece geliştirici, istenirse sınıfa el ile kolayca yazılmış bir kod ekleyebilir.


0

C ++ sınıf metninin, üyelerini kullanan veya örnekleri üreten her derleme ünitesinin bir parçası olarak derlenmesini gerektirir. Derleme zamanlarını aklı başında tutmanın tek yolu, sınıf metninin kendisinin - mümkün olduğu ölçüde - yalnızca tüketicileri için gerçekten gerekli olan şeyleri içermesidir. C ++ yöntemlerinin genellikle kendilerini içeren sınıfların dışına yazılması, derleyicinin, sınıfın kullanıldığı her derleme birimi için bir kez her sınıf yönteminin metnini işlemesini istemek zorunda kalması nedeniyle motive edici, çok kötü bir hacktir. deli inşa zamanları.

Java'da, derlenmiş sınıf dosyaları, diğerlerinin yanı sıra, büyük ölçüde bir C ++ .h dosyasına eşdeğer bilgiler içerir. Sınıfın tüketicileri, derleyicinin .java dosyasını işlemesine gerek kalmadan ihtiyaç duydukları tüm bilgileri bu dosyadan çıkarabilirler. .H dosyasının içerdiği sınıfların hem uygulamaları hem de istemcileri için sağlanan bilgileri içerdiği C ++ 'ın aksine, Java'daki akış tersine çevrilir: istemcilerin kullandığı dosya derlemede kullanılan bir kaynak dosya değildir sınıf kodu, ancak bunun yerine derleyici tarafından sınıf kod dosyası bilgisini kullanarak üretilir. Sınıf kodunu, müşterilerin ihtiyaç duyduğu bilgileri içeren bir dosya ile uygulama içeren bir dosya arasında bölmeye gerek olmadığından, Java böyle bir bölünmeye izin vermez.


-1

Sanırım bunun bir kısmı Java'nın kendisini büyük takımlarda kullanımıyla ilgili olan korumacı bir dil olduğudur. Sınıfların üzerine yazılamaz veya yeniden tanımlanamaz. Yöntemlerin nasıl kullanılabileceğini ve kullanılamayacağını çok özel bir şekilde tanımlayan 4 erişim seviyeniz var. Her şey, devleri başkalarının veya kendilerinin neden olduğu tür uyuşmazlığı hijinksinden korumak için güçlü / statik olarak yazılmıştır. Sınıfları ve fonksiyonları en küçük üniteleriniz olarak kullanmak, bir uygulamanın nasıl geliştirileceğine ilişkin paradigmayı yeniden icat etmeyi çok kolaylaştırır.

Çift-amaçlı isim / fiil birinci sınıf fonksiyonların yağdığı ve bir açık açık pinatadan şeker gibi geçtiği JavaScript'le karşılaştırın, sınıf-eşdeğer fonksiyon yapıcısı prototipini yeni özellikler ekleyerek veya eskileri değiştirerek değiştirdi. Zaten herhangi bir zamanda yaratılmış, kesinlikle hiçbir şey herhangi bir yapıyı kendi versiyonunuzla değiştirmekten alıkoyamaz, 5 tür var ve bunlar farklı koşullar altında otomatik olarak dönüştürülüp otomatik olarak değerlendiriliyor ve her şeye yaklaşmak için yeni özellikler ekleyebilirsiniz:

function nounAndVerb(){
}
nounAndVerb.newProperty = 'egads!';

Nihayetinde nişler ve pazarlar hakkında. JavaScript, yaklaşık 100 kişinin (muhtemelen vasat olacak) ellerinde olduğu kadar uygun ve felakettir. Java, bir zamanlar onunla birlikte web kullanıcı arayüzü yazmaya çalışan küçük gruplardan oluşan küçük grupların elindedir. 100 devs ile çalışırken istediğin en son şey lanet olası paradigmayı yeniden icat eden biri. UI ile çalışırken veya hızlı bir gelişme, daha kritik bir mesele olduğunda, en son istediğiniz şey basitçe hızlı bir şekilde basitçe işlem yapmak için engellenmektir, çünkü dikkatli olmazsanız bunları çok aptalca yapmak kolay olacaktır.

Ancak günün sonunda, her ikisi de popüler olan genel kullanım dilleridir, bu nedenle burada biraz felsefi tartışma vardır. Java ve C # ile en büyük kişisel sığır eti, devlerin çoğunluğunun temel OOP'un değerini anladığı göründüğü eski bir kod temeli ile hiç görmedim veya çalışmadım. Oyuna her şeyi bir sınıfa sarmak zorunda kaldığınızda, belki de 3-5 satırlık sınıfların masif zincirleri olarak gösterilen işlevli spagetti yerine OOP yaptığınızı varsaymak daha kolaydır.

Bununla birlikte, yalnızca tehlikeli olacak kadar iyi bilen ve göstermekten korkmayan birinin yazdığı JavaScript'ten daha kötü bir şey olmadığı söyleniyor. Ve bence bu genel fikir. Bu adamın sözde Java'da kabaca aynı kurallarla oynaması gerekiyor. Ben piçin her zaman bir yolunu bulacağını tartışırdım.

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.