Java: Bir dosyada birden çok sınıf bildirimi


237

Java'da, bunlardan en çok birinin herkese açık olması koşuluyla , tek bir dosyada birden çok üst düzey sınıf tanımlayabilirsiniz (bkz. JLS §7.6 ). Örnek için aşağıya bakın.

  1. Bu teknik için düzenli ismi (benzer var mı inner, nested, anonymous)?

  2. JLS sistemi diyor olabilir bu ikincil sınıflar olamaz sınırlama uygulamamaktayız referred to by code in other compilation units of the package, örneğin, bunlar paketin-özel olarak ele alınamaz. Bu gerçekten Java uygulamaları arasında değişen bir şey mi?

ör. PublicClass.java:

package com.example.multiple;

public class PublicClass {
    PrivateImpl impl = new PrivateImpl();
}

class PrivateImpl {
    int implementationData;
}

11
+1 Güzel sorular. Meseleyi asla gerçekten çok düşünmedim, çünkü bunu yapmak neredeyse hiç gerekli değil.
Michael Myers

12
bunun izleyici bir özellik olduğunu unutmayın; java en başından beri sınıfları iç içe geçmiş olsaydı asla mümkün olmazdı.
Kevin Bourrillion

Yanıtlar:


120

Bu teknik için önerilen adım (tek bir kaynak dosyasında birden çok üst düzey sınıf dahil) "karışıklık" olacaktır. Cidden, bunun iyi bir fikir olduğunu düşünmüyorum - bu durumda bunun yerine iç içe bir tür kullanırdım. O zaman hangi kaynak dosyanın içinde olduğunu tahmin etmek hala kolay. Yine de bu yaklaşım için resmi bir terim olduğuna inanmıyorum.

Bunun aslında uygulamalar arasında değişip değişmediğine gelince - bundan şüpheliyim, ancak ilk etapta yapmaktan kaçınırsanız, asla umursamayacaksınız :)


71
Ben downvoter değilim, ama bu cevabın "normatif" olarak adlandırılabilecek bir şey olması (yani, "aslında ... ancak ..." yerine "yapmalısınız") sanırım bir iniş. Aslında soruların hiçbirine cevap vermiyor. Sanki herhangi bir şeyi iade etmek yerine alakasız bir istisna yaratmak / fikirler yerine gerçek olgular hakkında bilgi içeren bir istisna yaratmak gibi.
n611x007

6
@JonSkeet 'in iç içe bir tür kullanmak için öneri küçük bir istisna olduğunu düşündüm (aksi kabul ediyorum): ana sınıf genel ve type parametresi ikinci sınıf ise, ikinci sınıf olamaz iç içe olmak. Ve iki sınıf sıkıca bağlıysa (örneğin PublicClass ve PrivateImpl gibi), aynı dosyada üst düzey sınıf olarak PrivateImpl koymak iyi bir fikir olduğunu düşünüyorum.
jfritz42

6
@BoomerRogers: Hayır, bu kesinlikle değil "bileşeni esaslı programlama çekirdek temel" oluşturdu. Bir bileşene karşı programlama yapıyorsanız, kaynak kodun nasıl düzenlendiğini neden önemsesiniz ki? (Şahsen , servis bulucu modelinden ziyade bağımlılık enjeksiyonunu tercih ediyorum , ancak bu farklı bir konudur.) Aklınızda ayrı API ve kaynak kodu organizasyonu - bunlar çok farklı şeyler.
Jon Skeet

1
@JonSkeet Tekrar ifade edeyim: "Cevabınız" kişisel ilgisiz bir görüştür. (yani "karışıklık" ve "şüpheliyim" gibi cevaplar çok az bir değere sahiptir.) Bu nedenle, yayınınız 2 sorudan hiçbirine cevap vermiyor. Poligen yağlayıcıların cevabını kontrol edin ve her ikisine de cevap vermeyi başardığını göreceksiniz.
bvdb

1
@bvdb: (Ve kötü uygulama olan ancak şartname tarafından izin verilen birçok şey var. Bu public int[] foo(int x)[] { return new int[5][5]; }geçerli olsa bile insanları da yazmamalarını rica ediyorum .)
Jon Skeet

130

javac bunu aktif olarak yasaklamıyor, ancak içinde bulunduğu dosya ile aynı ada sahip olmadıkça başka bir dosyadan üst düzey bir sınıfa asla başvurmak istemeyeceğiniz anlamına gelen bir sınırlama var.

İki dosyanız olduğunu varsayalım: Foo.java ve Bar.java.

Foo.java şunları içerir:

  • kamu sınıfı Foo

Bar.java şunları içerir:

  • kamu sınıfı Bar
  • baz sınıfı

Diyelim ki tüm sınıflar aynı pakette (ve dosyalar aynı dizinde).

Foo.java, Bar'a değil Baz'a atıfta bulunur ve Foo.java'yı derlemeye çalışırsak ne olur? Derleme böyle bir hata ile başarısız olur:

Foo.java:2: cannot find symbol
symbol  : class Baz
location: class Foo
  private Baz baz;
          ^
1 error

Bunu düşünürseniz mantıklı geliyor. Foo.java Baz'a atıfta bulunuyorsa, ancak Baz.java (veya Baz.class) yoksa, javac hangi kaynak dosyaya bakılacağını nasıl bilebilir?

Bunun yerine javac'a Foo.java ve Bar.java'yı aynı anda derlemesini söylerseniz veya daha önce Bar.java'yı derlemiş olsanız bile (javac'ın bulabileceği Baz.class'ı bırakarak) bu hata ortadan kalkar. Ancak bu, yapım sürecinizi çok güvenilmez ve pul pul hissettirir.

Çünkü daha çok "gibi olan gerçek sınırlama, içinde bulunduğu dosyayla aynı ada sahip olmadıkça veya aynı dosyada adı verilen aynı sınıfa ait bir sınıfa başvurmuyorsanız, başka bir dosyadan üst düzey bir sınıfa başvurmayın dosya ile aynı şey "takip etmek biraz zor, insanlar genellikle her dosyaya sadece bir üst düzey sınıf koymak çok daha basit (daha katı) kural ile gidin. Bu, bir sınıfın herkese açık olup olmayacağı konusunda fikrinizi değiştirirseniz daha da iyidir.

Bazen herkesin bir şeyi belirli bir şekilde yapmasının gerçekten iyi bir nedeni vardır.


Maven, derlemeyi güvenilir kılmak için herhangi bir şey yapıyor mu?
Aleksandr Dubinsky

23

Sadece PrivateImplne dediğine inanıyorum : a non-public top-level class. Ayrıca beyan edebilirsiniz non-public top-level interfaces.

örneğin, SO'nun başka bir yerinde: Halka açık olmayan üst düzey sınıf - statik iç içe sınıf

Sürümler arasındaki davranış değişikliklerine gelince, 1.2.2'de "mükemmel çalışan" bir şey hakkında bu tartışma vardı. ancak güneş forumunda 1.4'te çalışmayı durdurdu: Java Derleyici - bir dosyada genel olmayan üst düzey sınıfları bildiremedi .


1
Bununla ilgili tek sorunum non-public top level class, bir dosyadaki tek sınıf olabilmenizdir, bu nedenle çokluğa değinmez.
Michael Brewer-Davis

Endişeyi anlıyorum, ancak gördüğünüz gibi bu, başkalarının tarihsel olarak kullandığı bir terminolojidir. Eğer kendi süremi uydurmam gerekirse, büyük ihtimalle arayacağım secondary top level types.
polygenelubricants

7

İstediğiniz kadar derse sahip olabilirsiniz

public class Fun {
    Fun() {
        System.out.println("Fun constructor");
    }
    void fun() {
        System.out.println("Fun mathod");
    }
    public static void main(String[] args) {
        Fun fu = new Fun();
        fu.fun();
        Fen fe = new Fen();
        fe.fen();
        Fin fi = new Fin();
        fi.fin();
        Fon fo = new Fon();
        fo.fon();
        Fan fa = new Fan();
        fa.fan();
        fa.run();
    }
}

class Fen {
    Fen() {
        System.out.println("fen construuctor");

    }
    void fen() {
        System.out.println("Fen method");
    }
}

class Fin {
    void fin() {
        System.out.println("Fin method");
    }
}

class Fon {
    void fon() {
        System.out.println("Fon method");
    } 
}

class Fan {
    void fan() {
        System.out.println("Fan method");
    }
    public void run() {
        System.out.println("run");
    }
}

1
@Nenotlep "Biçimlendirmeyi iyileştir" işlemi yaptığınızda, lütfen ters eğik çizgileri kaldırmak gibi kodun kendisine karışmamasına da dikkat edin.
Tom

3
Bu soruya cevap vermiyor.
ᴠɪɴᴄᴇɴᴛ

4

1.Bu teknik için düzenli bir isim var mı (iç, iç içe, anonim)?

Çok sınıflı tek dosya demosu.

JLS, sistemin, bu ikincil sınıflara paketin diğer derleme birimlerinde kodla atıfta bulunulmaması gibi kısıtlamaları uygulayabileceğini, örneğin, paket özel olarak değerlendirilemeyeceğini söylüyor. Bu gerçekten Java uygulamaları arasında değişen bir şey mi?

Bu kısıtlama olmayan herhangi bir farkında değilim - tüm dosya tabanlı derleyiciler, sınıf adıyla aynı adlandırılmamış dosyalarda kaynak kodu sınıflarına başvurmak izin vermez. (çok sınıflı bir dosya derleyip sınıfları sınıf yoluna koyarsanız, derleyiciler bu dosyaları bulur)


1

Etkili Java 2. baskıya göre (Madde 13):

"Bir paket-özel üst düzey sınıf (veya arabirim) yalnızca bir sınıf tarafından kullanılıyorsa, üst düzey sınıfı, onu kullanan tek sınıfın özel iç içe bir sınıfı haline getirmeyi düşünün (Madde 22). ancak paketindeki sınıfları, onu kullanan tek sınıfa indirir.

İç içe sınıf, üye sınıfın ekteki örneğe erişmesi gerekip gerekmediğine bağlı olarak statik veya statik olmayan olabilir (Öğe 22).


OP yuvalanmış sınıfları sormuyor.
charmoniumQ

0

Evet, genel bir dış sınıftaki genel statik üyelerle aşağıdaki gibi yapabilirsiniz:

public class Foo {

    public static class FooChild extends Z {
        String foo;
    }

    public static class ZeeChild extends Z {

    }

}

ve yukarıdakilere referans veren başka bir dosya:

public class Bar {

    public static void main(String[] args){

        Foo.FooChild f = new Foo.FooChild();
        System.out.println(f);

    }
}

aynı klasöre koyun. Şununla derleyin:

javac folder/*.java

ve şununla koş:

 java -cp folder Bar

Bu örnek soruyu cevaplamıyor. Aynı dosyada iki üst düzey sınıf tanımlanmış olanla aynı olmayan iç içe statik sınıfların bir örneğini veriyorsunuz.
Pedro García Medina

0

Java 11+ kullanıyorsanız, sadece FYI, bu kuralın bir istisnası vardır: java dosyanızı doğrudan çalıştırırsanız ( derleme olmadan ). Bu modda, dosya başına tek bir ortak sınıfta herhangi bir kısıtlama yoktur. Ancak, mainyöntemin bulunduğu sınıf dosyadaki ilk sınıf olmalıdır.


-5

Hayýr. Yapamazsýn. Ancak Scala'da çok mümkün:

class Foo {val bar = "a"}
class Bar {val foo = "b"}
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.