Clases glorificadas en el lenguaje Java

96

Algunas clases de la API estándar de Java se tratan de forma ligeramente diferente a otras clases. Estoy hablando de aquellas clases que no se podrían implementar sin un soporte especial del compilador y / o JVM.

Los que se me ocurren de inmediato son:

  • Object (obviamente) ya que, entre otras cosas, no tiene una superclase.
  • String ya que el idioma tiene soporte especial para el operador +.
  • Thread ya que tiene este método mágico start () a pesar del hecho de que no hay una instrucción de código de bytes que "bifurque" la ejecución.

Supongo que todas las clases como estas se mencionan de una forma u otra en el JLS. Corrígeme si me equivoco.

De todos modos, ¿qué otras clases de este tipo existen? ¿Existe alguna lista completa de "clases glorificadas" en el lenguaje Java?

aioobe
fuente
2
Los genéricos casi encajan, pero no del todo. Se implementan mediante un truco del compilador, pero no están aislados en una clase.
Bill the Lizard
2
Todos son tipos de reverencia. ;-)
starblue
1
¿Es mágico "thread.start"? Seguramente es solo un código nativo llamado para hacer esto.
jcoder
Ese pensamiento también me ha llamado la atención. Quizás el JNI solo sea suficiente para implementar la clase Thread. Supongo que si intentara hacer esto, usaría alguna API de subproceso a nivel del sistema operativo, bifurcaría la ejecución en la implementación del método start (), ejecutaría el método run () en el subproceso bifurcado y volvería. Pero luego el hilo de mi sistema operativo seguiría funcionando. ¿Funcionaría sin problemas junto con los hilos creados por la JVM? y honrar el modelo de memoria JLS y así sucesivamente?
aioobe
2
De acuerdo con la especificación, la única forma de crear un hilo es desde la clase Thread ( java.sun.com/docs/books/jvms/second_edition/html/… ). Por supuesto, se basa en una comunicación de nivel ingenuo con la JVM, pero si hiciera su propia JNI, podría iniciar un hilo, pero no conseguiría que la JVM entienda lo que está haciendo (bloqueos, modelo de memoria, etc. ). El hilo tiene el privilegio de que la especificación le asigna un privilegio especial: la única forma de iniciar un hilo.
Yishai

Respuestas:

35

Hay muchas respuestas diferentes, así que pensé que sería útil recopilarlas todas (y agregar algunas):

Clases

  • Clases de AutoBoxing : el compilador solo permite clases específicas
  • Clase : tiene sus propios literales (int.class por ejemplo). También agregaría su tipo genérico sin crear nuevas instancias.
  • Cadena : con su + -operador sobrecargado y el soporte de literales
  • Enum : la única clase que se puede usar en una declaración de cambio (pronto también se otorgará un privilegio a String). También hace otras cosas (creación automática de métodos estáticos, manejo de serialización, etc.), pero teóricamente podrían lograrse con código; es solo una gran cantidad de texto estándar, y algunas de las restricciones no se pueden aplicar en subclases (por ejemplo, el reglas especiales de subclasificación), pero lo que nunca podría lograr sin el estado privilegiado de una enumeración es incluirlo en una declaración de cambio.
  • Objeto : la raíz de todos los objetos (y agregaría sus métodos de clonación y finalización no son algo que pueda implementar)
  • Referencias : WeakReference, SoftReference, PhantomReference
  • Hilo : el lenguaje no le da una instrucción específica para iniciar un hilo, sino que lo aplica mágicamente al método start ().
  • Throwable : la raíz de todas las clases que pueden funcionar con throw, throws y catch, así como la comprensión del compilador de Exception vs RuntimeException y Error.
  • NullPointerException y otras excepciones como ArrayIndexOutOfBounds que pueden ser lanzadas por otras instrucciones de bytecode que no sean throw.

Interfaces

  • Iterable : la única interfaz que se puede utilizar en un bucle for mejorado

Las menciones honoríficas son para:

  • java.lang.reflect. Matriz : no sería posible crear una nueva matriz tal como la define un objeto Class.
  • Anotaciones Son una característica de lenguaje especial que se comporta como una interfaz en tiempo de ejecución. Ciertamente no podría definir otra interfaz de Anotación, al igual que no puede definir un reemplazo para Object. Sin embargo, podría implementar toda su funcionalidad y simplemente tener otra forma de recuperarlos (y un montón de texto estándar) en lugar de la reflexión. De hecho, hubo muchas implementaciones basadas en XML y etiquetas javadoc antes de que se introdujeran las anotaciones.
  • ClassLoader : ciertamente tiene una relación privilegiada con la JVM, ya que no hay una forma de lenguaje para cargar una clase, aunque hay una forma de código de bytes, por lo que es como Array de esa manera. También tiene el privilegio especial de ser devuelto por la JVM, aunque eso es un detalle de implementación.
  • Serializable : podría implementar la funcionalidad a través de la reflexión, pero tiene su propia palabra clave privilegiada y pasaría mucho tiempo familiarizándose con SecurityManager en algunos escenarios.

Nota: Dejé fuera de la lista las cosas que proporcionan JNI (como IO) porque siempre puede implementar su propia llamada JNI si así lo desea. Sin embargo, las llamadas nativas que interactúan con la JVM de manera privilegiada son diferentes.

Las matrices son discutibles: heredan Object, tienen una jerarquía entendida (Object [] es un supertipo de String []), pero son una característica del lenguaje, no una clase definida por sí misma.

Yishai
fuente
@Donal, muy cierto, estaba pensando en la anotación en tiempo de ejecución, pero las anotaciones a nivel de fuente se hicieron de esa manera (xdoclet más notablemente, o incluso en core java con @deprecated)
Yishai
Me he estado abriendo camino a través de una maraña de código que se escribió originalmente con el procesamiento xdoclet y luego se convirtió en anotaciones. Oh, cómo prefiero las anotaciones a eso (aunque, con encantamientos de maven adecuados, el efecto neto es el mismo).
Donal Fellows
@ KK_07k11A0585, Las colecciones son una api estándar que cualquier persona puede crear de una manera diferente (de hecho, hay implementaciones alternativas que se centran en primitivas, así como un proyecto de Google muy famoso que las mejora). Lo único especial que obtienen es Iterable, que se menciona en la respuesta. Son el pan y la mantequilla de la programación Java, sin duda, pero son solo clases regulares, sin privilegios especiales.
Yishai
@Yishai Al desarrollar cualquier aplicación, lo más importante que cobra importancia es la GESTIÓN DE DATOS. Todos podemos hacer una tarea de diferentes formas, pero la forma optimizada es la que ocupa menos memoria y tiene menos uso de referencias innecesarias. Mediante el uso de Colecciones, podemos ordenar, buscar y comparar una gran cantidad de datos, lo que proporciona algoritmos predefinidos como Búsqueda binaria, Orden de fusión, etc. También nos proporciona Comparador e Interfaces comparables para personalizar nuestras técnicas. La clase Colecciones puede no ser la mejor clase en Java, pero sin duda es una clase de cualidades glorificadas.
KK_07k11A0585
1
¿Qué hay de SecurityManager? ¿O algo relacionado con la reflexión o la serialización?
Antimony
19

Class, por supuesto. Tiene sus propios literales (una distinción con la que comparte String, BTW) y es el punto de partida de toda esa magia de reflexión.

Michael Borgwardt
fuente
Ah, buen punto. Entonces, ¿cuál es un ejemplo de una clase literal? ¿Te refieres a MyClass.class?
aioobe
4
@aioobe: exactamente. Tenga en cuenta que también tiene clase internacional, clase de carácter, etc.
Michael Borgwardt
12
  1. Enum. No se le permite subclasificarlo, pero el compilador sí.
  2. Muchas cosas en java.util.concurrent se pueden implementar sin soporte de JVM, pero serían mucho menos eficientes.
Darron
fuente
1
Puede subclasificar anónimamente enums (que es la base del patrón de visitante impl. Para los valores de enums). Pero sí, no puede subclasificar completamente una enumeración ;-)
Thierry
11

Todas las clases de números tienen un poco de magia en forma de Autoboxing .

Bill el lagarto
fuente
Te refieres a las clases que envuelven primitivas, que también incluyen Boolean y Character; pero excluye BigInteger.
emory
1
@emory: Correcto, solo las clases contenedoras primitivas. Desafortunadamente, eso excluye a BigInteger.
Bill the Lizard
10

Dado que se mencionaron las clases importantes , mencionaré algunas interfaces:

La Iterableinterfaz (desde 1.5): permite que un objeto participe en un bucle foreach:

Iterable<Foo> iterable = ...;
for (Foo foo : iterable) {

}

La Serializableinterfaz tiene un significado muy especial, diferente de una interfaz estándar. Puede definir métodos que se tendrán en cuenta aunque no estén definidos en la interfaz (como readResolve()). La transientpalabra clave es el elemento del lenguaje que afecta el comportamiento de los Serializableimplementadores.

Bozho
fuente
Es cierto que son interfaces, por lo que no requieren una implementación "especial" por consulta. (Similar a Throwable.)
aioobe
Serializable en realidad requiere una implementación especial. Es una interfaz que se espera que tenga dos métodos (olvido los nombres ... podría buscar en Google ...) pero no son obligatorios ni están definidos en el esquema de interfaz estándar.
corsiKa
@glowcoder: sin embargo, una vez se podría argumentar que toda la especialidad de Serializable no es relevante para el lenguaje Java, solo para la implementación de ObjectOutputStream y ObjectInputStream.
Michael Borgwardt
5
@Michael Borgwardt tiene - la transientpalabra clave
Bozho
1
No lo creo, Comparableno participa en nada interno. Puede escribir fácilmente NewComparabley nuevo NewArrays.sort(..)con la misma funcionalidad
Bozho
6
  1. Throwable , RuntimeException, Error AssertionError
  2. Referencias WeakReference, SoftReference, PhantomReference
  3. Enum
  4. Anotación
emory
fuente
Buena lista. +1, sin embargo, la anotación es una interfaz y no tiene implementación.
aioobe
1
El compilador trata las anotaciones de forma diferente a las interfaces normales. Al igual que enum, todos extienden Annotation, y el compilador lo hace automáticamente. Desde JavaDoc of Annotation: la interfaz común extendida por todos los tipos de anotaciones. Tenga en cuenta que una interfaz que amplía manualmente esta no define un tipo de anotación. También tenga en cuenta que esta interfaz no define en sí misma un tipo de anotación. Entonces, no puede crear una anotación usando la sintaxis normal, necesitaban cambiar el compilador para agregarlas.
Andrei Fierbinteanu
6

Matriz de Java como en int[].class

Alexander Pogrebnyak
fuente
¡Ah, bueno! la [Iclase;) aunque no es una clase API.
aioobe
2

No estoy seguro de esto. Pero no puedo pensar en una forma de implementar manualmente objetos IO.

demotics2002
fuente
Tienes razón, no se pueden implementar en Java puro. Deben implementarse a través de JNI (como cualquier otra clase que necesite realizar llamadas al sistema). Aparte de eso, sin embargo, no necesitan soporte especial del compilador o jvm.
aioobe
2

Hay algo de magia en la Systemclase.

System.arraycopy es un gancho al código nativo

public static native void arraycopy(Object array1, int start1, 
  Object array2, int start2, int length);

pero...

/**
 * Private version of the arraycopy method used by the jit
 * for reference arraycopies
 */
private static void arraycopy(Object[] A1, int offset1,
  Object[] A2, int offset2, int length) {
   ...
}
eljenso
fuente
1
Oye, ¿qué quieres decir con la segunda parte de la respuesta?
Pacerier
1

Bueno, ya que se ha mencionado el manejo especial de assert. Aquí hay algunos tipos más de excepciones que tienen un tratamiento especial por parte de jvm:

  • Excepción de puntero nulo
  • ArithmeticException.
  • StackOverflowException
  • Todo tipo de OutOfMemoryErrors
  • ...

Las excepciones no son especiales, pero jvm las usa en casos especiales, por lo que no puede implementarlas usted mismo sin escribir su propio jvm. Estoy seguro de que existen más excepciones especiales.

josefx
fuente
0

La mayoría de esas clases no se implementan realmente con la ayuda 'especial' del compilador o JVM. Object registra algunos nativos que hurgan en las estructuras internas de JVM, pero también puede hacerlo para sus propias clases. (Admito que esto está sujeto a la semántica, "las llamadas a un nativo definido en la JVM" pueden considerarse como soporte especial de JVM).

Lo que / es / especial es el comportamiento de las instrucciones 'nuevas' y 'lanzar' en cómo inicializan estas estructuras internas.

Sin embargo, las anotaciones y los números son bastante extraños.

milimoose
fuente
4
aioobe se refiere a clases que no puede implementar usted mismo, ya que tienen una estructura especial de soporte. No puede crear su propia clase Object como raíz del sistema de tipos sin heredar el formulario java.lang.Object. Object tiene soporte especial tanto del compilador como de jvm para asegurarse de que sea una clase raíz. Las llamadas nativas no son suficientes para evitar esto.
josefx