Java: meerdere klassenaangiften in één bestand

In Java kunt u meerdere topniveau-klassen in één bestand definiëren, zodat maximaal een van deze openbaar is (zie JLS §7.6 ). Zie hieronder bijvoorbeeld.

  1. Is er een opgeruimde naam voor deze techniek (analoog aan inner, nested, anonymous)?

  2. De JLS zegt het systeem May de beperking dwingen dat deze secundaire klassen niet referred to by code in other compilation units of the package, bijv , ze kunnen niet als pakket privé worden behandeld. Is dat echt iets dat verandert tussen Java-implementaties?

b.g., PublicClass.java:

package com.example.multiple;
public class PublicClass {
    PrivateImpl impl = new PrivateImpl();
}
class PrivateImpl {
    int implementationData;
}

Antwoord 1, Autoriteit 100%

Mijn voorgestelde naam voor deze techniek (inclusief meerdere lessen op het hoogste niveau in een enkel bronbestand) zou “puinhoop” zijn. Serieus, ik denk niet dat het een goed idee is – ik zou in plaats daarvan een genesteld type in deze situatie gebruiken. Dan is het nog steeds gemakkelijk om te voorspellen welk bronbestand het is. Ik geloof niet dat er echter een officiële term voor deze aanpak is.

Wat betreft of dit daadwerkelijk verandert tussen implementaties – ik betwijfel het ten zeerste, maar als u het in de eerste plaats vermijdt, hoeft u het nooit te geven 🙂


Antwoord 2, Autoriteit 112%

JAVAC verbiedt dit niet actief, maar het heeft wel een beperking die vrijwel betekent dat u nooit wilt verwijzen naar een klasse op het hoogste niveau uit een ander bestand, tenzij deze dezelfde naam heeft als het bestand waar het in is.

Stel dat je twee bestanden hebt, Foo.java en Bar.java.

Foo.java bevat:

  • openbare les Foo

Bar.java bevat:

  • bar voor openbare lessen
  • klas Baz

Laten we ook zeggen dat alle klassen zich in hetzelfde pakket bevinden (en dat de bestanden zich in dezelfde map bevinden).

Wat gebeurt er als Foo.java verwijst naar Baz maar niet naar Bar en we proberen Foo.java te compileren? De compilatie mislukt met een fout als deze:

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

Dit is logisch als je erover nadenkt. Als Foo.java naar Baz verwijst, maar er is geen Baz.java (of Baz.class), hoe kan javac dan weten in welk bronbestand moet worden gezocht?

Als je in plaats daarvan javac vertelt om Foo.java en Bar.java tegelijkertijd te compileren, of zelfs als je eerder Bar.java had gecompileerd (de Baz.class achterlatend waar javac het kan vinden), dan verdwijnt deze fout. Dit maakt je bouwproces echter erg onbetrouwbaar en schilferig.

Omdat de feitelijke beperking, die meer lijkt op “niet verwijzen naar een klasse op het hoogste niveau uit een ander bestand, tenzij deze dezelfde naam heeft als het bestand waarin het zich bevindt of u ook verwijst naar een klasse die zich in hetzelfde bestand met dezelfde naam als het bestand” is nogal moeilijk te volgen, mensen gaan meestal voor de veel eenvoudigere (hoewel striktere) conventie om slechts één klasse op het hoogste niveau in elk bestand te plaatsen. Dit is ook beter als je ooit van gedachten verandert of een les openbaar moet zijn of niet.

Soms is er echt een goede reden waarom iedereen iets op een bepaalde manier doet.


Antwoord 3, autoriteit 20%

Ik geloof dat je gewoon PrivateImplnoemt wat het is: een non-public top-level class. U kunt ook non-public top-level interfacesdeclareren.

bijv. elders op SO: Niet- openbare klasse op het hoogste niveauversus statische geneste klasse

Wat betreft gedragsveranderingen tussen versies, er was een discussie over iets dat “perfect werkte” in 1.2.2. maar stopte met werken in 1.4 in het sun’s forum: Java Compiler – kan geen non declareren openbare klassen op het hoogste niveau in een bestand.


Antwoord 4, autoriteit 13%

Je kunt zo veel lessen volgen als je wilt

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");
    }
}

Antwoord 5, autoriteit 3%

1.Is daar een opgeruimde naam voor deze techniek (analoog aan innerlijk, genesteld, anoniem)?

Multi-class single-bestand demo.

2.De JLS zegt dat het systeem de beperking kan afdwingen dat deze secundaire klassen niet kunnen worden aangeduid door de code in andere compilatie-eenheden van het pakket, b.v., ze kunnen niet worden behandeld als pakket-privé. Is dat echt iets dat verandert tussen Java-implementaties?

Ik ben niet op de hoogte van iemand die niet die beperking heeft – alle op bestandsgebaseerde compilers kunt u niet verwijzen naar broncodeklasses in bestanden die niet hetzelfde zijn genoemd als de klasnaam. (Als u een multi-class-bestand compileert en de klassen op het klassenpad kunt plaatsen, vindt elke compiler deze)


Antwoord 6, Autoriteit 3%

Just Fyi, als u Java 11+ gebruikt, is er een uitzondering op deze regel: als u uw Java-bestand rechtstreeks uitvoert (zonder compilatie ). In deze modus is er geen beperking op een enkele openbare klas per bestand. De klasse met de mainmoet echter de eerste in het bestand zijn.


Antwoord 7

Ja, u kunt, met openbare statische leden op een buitenste openbare klasse, zoals SO:

public class Foo {
    public static class FooChild extends Z {
        String foo;
    }
    public static class ZeeChild extends Z {
    }
}

en een ander bestand dat verwijst naar het bovenstaande:

public class Bar {
    public static void main(String[] args){
        Foo.FooChild f = new Foo.FooChild();
        System.out.println(f);
    }
}

Plaats ze in dezelfde map. Compileren met:

javac folder/*.java

en ren met:

java -cp folder Bar

Antwoord 8

Volgens effectieve Java 2e editie (item 13):

“Als een pakket-private top-level klasse (of interface) alleen door wordt gebruikt
één klasse, overweeg om de klasse van topniveau een privé geneste klas te maken
van de enige klasse die het gebruikt (item 22). Dit vermindert zijn
Toegankelijkheid van alle klassen in zijn pakket naar de ene klasse
dat gebruikt het. Maar het is veel belangrijker om de toegankelijkheid te verminderen
van een gratis publieke klasse dan een pakket-private top-level klasse:
… “

De geneste klasse kan statisch of niet-statisch zijn op basis van de vraag of de ledenklasse toegang heeft tot de omsluitstroom (item 22).


Antwoord 9

Nee. Dat kan je niet. Maar het is heel goed mogelijk in Scala:

class Foo {val bar = "a"}
class Bar {val foo = "b"}

Other episodes