2010-02-25 10 views
201

En Java, puede definir múltiples clases de nivel superior en un solo archivo, siempre que, como máximo, una de ellas sea pública (consulte JLS §7.6). Vea a continuación, por ejemplo.Java: Declaraciones de clases múltiples en un archivo

  1. ¿Hay un nombre para esta técnica ordenada (análogo a inner, nested, anonymous)?

  2. El JLS dice que el sistema puede hacer cumplir la restricción de que estas clases secundarias no pueden ser referred to by code in other compilation units of the package, por ejemplo, no pueden ser tratados como paquete-privada. ¿Es eso realmente algo que cambia entre las implementaciones de Java?

por ejemplo, PublicClass.java:

package com.example.multiple; 

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

class PrivateImpl { 
    int implementationData; 
} 
+9

+1 Buenas preguntas. Realmente nunca he pensado mucho sobre el asunto, ya que casi nunca es necesario hacerlo. –

+12

tenga en cuenta que esta es una característica vestigial ; nunca hubiera sido posible si Java hubiera tenido clases anidadas desde el principio. –

Respuesta

109

Mi nombre sugerido para esta técnica (incluyendo varias clases de nivel superior en un único archivo de origen) sería "desorden". En serio, no creo que sea una buena idea. Usaría un tipo anidado en esta situación. Entonces todavía es fácil predecir en qué archivo de fuente se encuentra. Sin embargo, no creo que haya un término oficial para este enfoque.

En cuanto a si este hecho cambia entre las implementaciones - Lo dudo mucho, pero si se evita hacerlo en primer lugar, usted nunca tendrá que preocuparse :)

+49

No soy el que menosprecia, pero el hecho de que esta respuesta es algo que podría llamarse "normativo" (es decir, "debería" en lugar de "de hecho ... sin embargo ...") es la razón más probable para ello para obtener un voto negativo, creo. En realidad, no responde ninguna de las preguntas. Como plantear una excepción irrelevante en lugar de devolver algo/plantear una excepción que tenga información sobre hechos reales en lugar de opiniones. – n611x007

+6

Encontré lo que creo que es una pequeña excepción a la sugerencia de @JonSkeet de usar un tipo anidado (con el que estaría de acuerdo): si la clase principal es genérica y el parámetro tipo es la segunda clase, la segunda clase puede ' t estar anidado Y si las dos clases están estrechamente relacionadas (como PublicClass y PrivateImpl en la pregunta), creo que es una buena idea colocar PrivateImpl como una clase de nivel superior en el mismo archivo. – jfritz42

+0

No me refiero a resucitar nada demasiado antiguo, pero para alguien que tropieza con esto, quiero aclarar que no siempre es malo tener múltiples clases dentro de un archivo. Esto, como me parece, es la base central de la programación basada en componentes. Similar a cómo funciona Unity cuando llamas a GetComponent, FindComponent, etc. –

108

javac no prohíbe activamente este, pero tiene una limitación que significa que nunca querrá referirse a una clase de nivel superior desde otro archivo a menos que tenga el mismo nombre que el archivo.

Supongamos que tiene dos archivos, Foo .java y Bar.java.

Foo.java contiene:

  • Foo clase pública

Bar.java contiene:

  • public class Bar
  • clase Baz

Digamos también que todas las clases están en el mismo paquete (y los archivos están en el mismo directorio).

¿Qué sucede si Foo.java se refiere a Baz pero no a Bar e intentamos compilar Foo.java? La compilación falla con un error como este:

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

Esto tiene sentido si lo piensas bien. Si Foo.java se refiere a Baz, pero no hay Baz.java (o Baz.class), ¿cómo puede javac saber qué archivo fuente buscar?

Si en su lugar le dice a javac que compile Foo.java y Bar.java al mismo tiempo, o incluso si compiló previamente Bar.java (dejando la clase Baz donde javac puede encontrarla), este error desaparece . Sin embargo, esto hace que el proceso de creación se sienta muy inestable y escamoso.

Porque la limitación real, que es más como "no se refiere a una clase de nivel superior de otro archivo a menos que tenga el mismo nombre que el archivo o también se refiere a una clase que está en ese el mismo archivo que recibe el mismo nombre que el archivo "es un poco difícil de seguir, la gente generalmente sigue la convención mucho más directa (aunque más estricta) de simplemente poner una clase de nivel superior en cada archivo. Esto también es mejor si alguna vez cambia de opinión sobre si una clase debe ser pública o no.

A veces realmente hay una buena razón por la que todo el mundo hace algo de una manera particular.

+2

Excelente explicación para 'por qué no está funcionando!' – Ram

+0

¡Esta debería ser la respuesta aceptada! – leoll2

19

Creo que simplemente llame al PrivateImpl qué es: un non-public top-level class. También puede declarar non-public top-level interfaces también.

por ejemplo, en otra parte de SO: Non-public top-level class vs static nested class

En cuanto a los cambios en el comportamiento entre las versiones, había una discusión sobre algo que "ha funcionado perfectamente" en el punto 1.2.2. pero dejó de funcionar en 1.4 en el foro de sol: Java Compiler - unable to declare a non public top level classes in a file.

+1

Mi único problema con esto es que puede tener una 'clase no pública de nivel superior 'ser la única clase en un archivo, por lo que no se ocupa de la multiplicidad. –

+0

Entiendo la preocupación, pero como puede ver, esta es una terminología que otros han usado históricamente. Si tengo que crear mi propio término, probablemente lo llame 'tipos secundarios de nivel superior'. – polygenelubricants

4

1.¿Hay un nombre ordenado para esta técnica (análogo a interno, anidado, anónimo)?

Demostración de varias clases de un solo archivo.

2.El JLS dice que el sistema puede hacer cumplir la restricción de que estas clases secundarias no pueden ser referidos por código en otras unidades de compilación del paquete, por ejemplo, no pueden ser tratados como paquete-privada. ¿Es eso realmente algo que cambia entre las implementaciones de Java?

No conozco ninguno que no tenga esa restricción: todos los compiladores basados ​​en archivos no le permitirán consultar las clases de código fuente en archivos que no tienen el mismo nombre que el nombre de clase. (Si se compila un archivo multi-clase, y poner las clases en la ruta de clase, entonces cualquier compilador encontrarlos)

7

Puede tener tantas clases como desee como esto

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 Cuando realizas un "mejora de formato", ten cuidado de no interferir con el código en sí, como eliminar las barras invertidas. – Tom

+1

Eso no responde la pregunta. –

1

Según Effective Java segunda edición (punto 13):

"Si una clase de nivel superior paquete-privada (o interfaz) sólo es utilizado por una clase, considere hacer la clase de nivel superior una clase anidada privada de la única clase que lo usa (Artículo 22). Esto reduce su accesibilidad de todas las clases en su paquete a la clase que lo usa. Pero es mucho más importante para reducir la accesibilidad de una clase pública sepa que una clase de nivel superior del paquete y el privado: ... "

La clase anidada puede ser estática o no estático en función de si la clase miembro necesita acceso a la instancia adjunta (Elemento 22).

Cuestiones relacionadas