style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Duda con Serializable Interface

Hola a toda la comunidad,

El día de hoy tuve una entrevista para un nuevo proyecto como Java Developer, las preguntas fueron las normales y cotidianas pero hubo que me llamo la atención.

Como sabemos la interfaz Serializable es un interfaz vacía que se utiliza para "marcar" una clase la cual queremos serializar y así el compilador lo entiende.

La pregunte fue en donde esta escrito/establecido/declarado que el compilador lance una exception cuando intentes serializar una clase que no implemente esta interfaz, ya que la interfaz esta vacia y solo es para marcar, pero en donde esta establecido que las clases que estén marcadas pueden ser Serializable, de donde el compilador toma esta regla? Será que entendí mal al Ingeniero de India por su acento?

Espero me puedan ayudar con esta duda, busque en internet pero no encuentro una buena respuesta.

Saludos

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Posible respuesta

Bueno investigue la pregunta y parace ser que la JVM es la que al ver alguna clase con esta interfaz Serializable implementada la trata como tal, he conseguido la posicion en el proyecto solo que no he tenido la oportunidad de preguntar a la persona que me hizo esta pregunta.

Imagen de ezamudio

compilador?

Pero la JVM? Eso sería en tiempo de ejecución. Si en la pregunta te dijeron que el compilador es quien lanza la excepción, la respuesta es muy sencilla: los métodos para serializar esperan un Serializable, y por lo tanto cuando el compilador detecta esa invocación, verifica que el parámetro sea de tipo Serializable (o sea lo debe tener entre sus tipos; debe ser un objeto que implemente esa interfaz, aunque esté vacía, eso no importa). Es la parte del verificador de tipos dentro del compilador.

@Markos Primero que nada

@Markos Primero que nada felicidades por obtener el puesto

Segundo @ezamudio, si, si está en en la JVM, está hardcodeado ( je je bueno es un decir ) por ahí en algún lado misterioso. No recuerdo haber leído nada al respecto pero definitivamente está ahí adentro cableado en el mecanismo de serialización.

Cuando un objeto se serializa, se verifica en tiempo de ejecución que implemente esta interfaz, es simplemente para decir A ver, el programador esta consciente que esto va a pasar byte por byte por algún medio? ( cable o disco duro o arreglo de bytes ) ??? Si encuentra que es serializable introspecta la clase y va llamando el método writeObject o readObject, aunque sea privado ( http://stackoverflow.com/a/142676/20654 )

Esto es de las cosas más raras que tiene Java ( imho )

Pero el método para serializar objetos recibe Object , no Serializable, eso es porque se puede serializar uno que no implemente nada y recibir un error en tiempo de ejecución u otro que implemente Externalizable por ejemplo y que no haya queja.

Quizá la razón es porque Java no puede hacer algo como:

public writeObject( Serializable|Externalizable object ) {
   case ( is Serializable ) {
       object.writeObject( this );  // aun me causa conflicto que puedan llamar un método privado
    }
    case( is Externalizable ) {
      object.writeExternal( this );
    }
}

*blink *blink

Imagen de ezamudio

no pero...

Java no puede hacer eso porque no hay unión de tipos, pero sí hay sobrecarga de métodos, de modo que puedes tener writeObject(Serializable) y aparte writeObject(Externalizable). En Ceylon no necesitas sobrecarga de métodos precisamente porque tienes los tipos unión.

Dejate de eso. writeObject

Dejate de eso. writeObject es privado!! te digo, magia pura de bajo nivel.

Todo el bytecode que pase por la JVM pasará por ahí.

Lo más raro es que no encuentro nada al respecto en la spec de la JVM...

¬¬

http://docs.oracle.com/javase/specs/jvms/se7/html/index.html

Imagen de ezamudio

qué mal!

Ese es el tipo de cosas que están mal en Java. Es muy probable que en su momento hubo una razón por la que no pudieron hacer que esos métodos estuvieran en Serializable y simplemente hacer que los marshallers o lo que sea que serializa objetos (los ObjectOutputStream etc) acepten puro Serializable, pero pues a fin de cuentas me parece que no es un buen diseño.

Algo similar pasó con

Tooodos pero todos los lenguajes tienen este tipo de cosas ocultas.

Algo similar pasó con Comparable y los métodos equals y hash, deberían de ser partes de una interfaz y no de la clase object y así varias más.

Aún así Java tiene pocas cosas de esta naturaleza.

Por ejemplo dos cosas que me parecen curiosas son ejecutar una clase sin main :)

public class WithoutMain {
    static {
        System.out.println("Look ma, no main!!");
        System.exit(0);
    }

}

O esta otra que es copletamente inútil ( hasta ahora ) pero sigue siendo interesante:

(new Object() {
    public String someMethod(){
        return "some value";
    }
}).someMethod();

:)

Aquí hay varias más ( yo no calificaría a todas de casos raros, pero pues está entretenida la lista )

http://stackoverflow.com/questions/15496/hidden-features-of-java

Imagen de ezamudio

Comparable

Comparable es una interfaz.

En cuanto a equals y hash, en Ceylon pasó algo similar; esos métodos estaban definidos en la interfaz Equality, pero resultó ser muy impráctico tener que implementarla explícitamente en todos lados y referirse a ella (porque c.l.Object no la implementaba). Al final fue más práctico desaparecerla y meter esos métodos a Object, y ya.

Pero Comparable es una interfaz en Ceylon, al igual que en Java.

Lo de la clase sin main, pues es el constructor de clase, que tiene una sintaxis espantosa.

Para la última llamada, hasta te sobran paréntesis, según yo lo puedes invocar sin esos paréntesis. Concretamente ese ejemplo es inútil, pero cuando quieres hacer una clase anónima que implementa una interfaz o extiende una clase abstracta que solamente tiene un método, es muy útil. Por ejemplo:

new Thread(){ public void run() { System.out.println("Corriendo en otro hilo"); } }.start()

Yeap, solo que start ya es un

Yeap, solo que start ya es un método de Thread , la cosa ( curiosa ) es que la subclase no tiene ese métod y se puede invocar aun cuando la superclase ( object ) no lo tiene y ... y ...

¬¬ Seehh es lo mismo :)

Y sobre lo otro, es sobre esas cosas feas que resultan que se tienen que poner aunque el buen diseño indique lo contrario.

Imagen de bferro

Sobre la interfaz Serializable hace algún tiempo discutimos

Sobre el "posible error" de diseño con los métodos de ObjectOutputStream referentes a los tipos de argumentos, hace algún tiempo discutimos bastante. El post es éste .

Imagen de bferro

No hay nada espantoso ni raro

Aunque no me interesa defender a un lenguaje o a otro, debo decir que ni coincido con lo de espantoso del "constructor de clase" que comenta Enrique ni con lo que Oscar expresa como raro del código inútil para crear un objeto de una clase anónima.

En el primer caso, la especificación del lenguaje lo deja bien claro: todo bloque estático se ejecuta cuando la clase es cargada por cualquiera de los cargadores de clases que la máquina virtual utilice.
En el caso raro que comenta Oscar, una estructura similar está presente en millones de programas que usan Swing para la creación de listeners de eventos. Claro que el ejemplo de Oscar es inútil, pero no su estructura.

Mmmhh .... Es que lo raro no

Mmmhh ....

Es que lo raro no está en usar un método existente ... sino en poder usar un código nuevo.

Es decir, esto es perfectamente entendible:

new ActionListener() {
   public void actionPerformed( ActionEvent e ) {
   }
}.actionPerformed( null );

Porque finalmente el método actionPerformed está definido en la interfaz ActionListener lo que me causa "rareza" es esto:

new ActionListener() {
    public void actionPerformed( ActionEvent e ) {
    }
    public void deLaNada() {}
}.deLaNada();
Imagen de ezamudio

util

Ok ok ya entendi lo del metodo. sí es util:

public class A {
  protected void p() {...}
}

//en otro lado, otra clase, nada que ver con A
new A(){
  public void sp(){ p(); }
}.sp();

Voilá! le diste la vuelta a la protección de p().

bferro, lo que me parece espantoso del constructor de clase es unicamente la sintaxis. Como que ya no quedaba algo con qué definirlo y por eso dejaron lo que parece un bloque nomas ahi volando adentro de la clase.

Imagen de bferro

No veo la rareza en el ejemplo de Oscar

Que se puedan hacer cosas que son inútiles, es parte de cualquier lenguaje de programación, e incluso parte de los lenguajes que hablamos los humanos, siempre que respetemos la sintaxis del lenguaje. Cuántas barbaridades decimos en español que gramaticalmente están correctas.
El ejemplo de Óscar simplemente ilustra la posibilidad de definir una clase y crear un objeto de ella en la misma expresión. La parte que define la clase puede sin problema alguno añadir métodos a ella, además de los que hereda de su clase base. Si esos métodos tienen después utilidad es otro boleto, y ahí entonces viene lo de la posible inutilidad. Pero el lenguaje, si acepta que esa construcción define una clase, entonces no puede prohibir la definición de nuevos métodos para esa clase creada.

Con respecto a lo del bloque estático, el dilema es similar y tiene que ver con la definición que el lenguaje hace para los campos estáticos, que extiende al uso de bloques estáticos. Como ya hemos discutido al hablar de Scala y Ceylon esas cosas se pueden hacer de otra manera, pero esas maneras surgen gracias a que después de más de 20 años se ha demostrado las "posibles" ventajas de modelos de objetos puros, demostración que ha sido posible gracias a lenguajes como C++, Java y otros que consideraron otras ventajas con lenguajes de objetos impuros, así como de los lenguajes como Smalltalk y otros que consideraron las ventajas de un lenguaje puro.
No se puede analizar un lenguaje sacándolo del momento en que se crea. Son condiciones diferentes en cuanto a disponibilidad de recursos de hardware que existían hace más de 20 años cuando se crea C++ o más de 15 años cuando se crea Java,a la disponibilidad de recursos en este momento.
Adelantarse con las ideas es muy importante, pero a veces no resulta en la práctica. Es el caso de la máquina virtual que se diseñó para UCSD p-System en el año 1978 y que es una de las precursoras de la máquina virtual de Java. La idea era muy buena, pero la implementación no, pues se adelantó demasiado con respecto al hardware disponible en esos momentos.

Tomemos por ejemplo el siguiente código en Scala

object WithoutMain {
  println("El método main está por gusto")
  System.exit(0)
 
  def main (args:Array[String]) {
    println("No me dejan ejecutarme")
  }
}

Al ejecutar, por supuesto que obtenemos:

El método main está por gusto

Es muy similar al ejemplo que estamos discutiendo, sólo que Scala me obliga a escribir el método main. Alguien puede argumentar que ¿para qué me obliga a definir el método main si éste no se va a ejecutar?. Otro argumentará que Scala es más uniforme que Java estableciendo que todo programa ejecutable debe tener un método main para intentar su ejecución. yo sería ese otro, pero aceptaría lo que ese alguien dice

Imagen de JaimeItlzc

Bferro y en java

Y en java si se puede sin main? Yo no pudee a menos que sea por el IDE.

public class Prueba {
  static{
  System.out.print("Esto se ejecuta");
        System.exit(0);
    }
}

Y me lanza lo siguiente.
Error: no se ha encontrado el método principal en la clase lol.lol.Prueba, defina el método principal del siguiente modo:
public static void main(String[] args)

Imagen de bferro

Se puede. Ve el ejemplo de Oscar.

Efectivamente JaimeItlzc, sí se puede en Java. El IDE se percata de la ausencia de main y anuncia un error que no es

$ferro>javac Prueba.java

$ferro>java Prueba
Esto se ejecuta
$ferro>

No le damos la oportunidad al entorno de ejecución de emitir el error de que no encontró a main.
El documento de especificación del lenguaje no menciona esto de manera explícita, aunque lo deja "ver". Creo que la razón de no mencionarlo es porque el que lo escribe no espera que escribamos cosas inútiles con el lenguaje, como es este ejemplo, que quiere usar un bloque estático (no es otra cosa que un método estático sin nombre y sin lista de argumentos) para escribir nuestro programa principal.

Aja.. no es una ventaja del

Aja.. no es una ventaja del lenguaje, más bien un ejemplo curioso, pero no se debe de hacer.

De hecho sin el System.exit() java tira la excepción de que no existe el método main

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">