¿Qué es algo que casi nadie sabe acerca el lenguaje Java?


Java tiene varias curiosidades no tan conocidas, sobre todo si nos ponemos a explorar las classes (class como mecanismo de abstracción en Java). Para esta respuesta sólo demuestro dos curiosidades:


  1. Cada .class en Java comienza con el magic number 0xCAFEBABE; esto es, los primero 4 bytes de todos los .class.

  2. A la Python, el primer argumento de un método en Java puede ser la referencia this.





Para comprobar el punto (1) me he creado este método:




  1. // magic number 




  2. // chequea si los 4 primeros bytes del .class  




  3. // cooresponden con 0xCAFEBABE 




  4. static boolean checkMagicNumber() throws IOException 




  5. { 




  6. Class<?> cls = Main.class; 




  7. byte[] magicBytes = new byte[4]; 




  8. // leer los 4 primeros bytes de Main.class 




  9. cls.getResourceAsStream(cls.getSimpleName() + ".class") 




  10. .read(magicBytes); 




  11.  




  12. // ByteBuffer me ahorra algo de trabajo manual 




  13. // manipulano bits mecanicamente 




  14. ByteBuffer magicNumberAsBytes = 




  15. ByteBuffer.allocate(magicBytes.length); 




  16.  




  17. // de int (0xCAFEBABE) a ByteBuffer 




  18. magicNumberAsBytes.putInt(0xCAFEBABE); 




  19. // comparar 




  20. return 0 == Arrays.compare(magicNumberAsBytes.array(), 




  21. magicBytes); 




  22. } 






Básicamente lo que hace es leer los cuatro primeros bytes de la misma clase que estoy ejecutando, luego convierto el numero (mágico) que quiero comparar a byte[] y comparo ambos!








Para el punto (2) me he creado una clase Point con varios método donde declaro como primer parámetro la referencia a this. A diferencia de Python, claro, this debe ser declarado con su tipo de dato, para la clase sería Point this;. Poder declara el parametro de esta forma no es una simple curiosidad, existe una justificación y es poder decorar el parametro con una annotation para lo cual me creé un annotation dummy @Const (que no hace nada) para demostrar el uso. Este feature se llama reciever parameter. .


El primer método de Point donde utilizo la declaración es repr:




  1. // this reference como parametro explicito 




  2. private String repr(Point this){ 




  3. return String.format("%s(%.1f, %.1f)",  




  4. this.getClass().getSimpleName(),  




  5. this.x, this.y); 




  6. } 






Nota que no es posible como en Python hacer algo como esto: Point.repr(new Point(/*…*/));. Para Java el método repr no toma ningún argumento y es equivalente a:




  1. private String repr(){ /* misma definicion */} 






En el próximo método si uso la annotation y además un parametro “adicional”:




  1. // distancia entre dos puntos  




  2. double distance(@Const Point this, @Const Point other){ 




  3. return Math.hypot(x + other.x, y + other.y); 




  4. } 






Otra vez, si tengo dos Points pnt1 y pnt2 el método se llama así pnt1.distance(pnt2); como se dijo antes el primer parametro (el this explícito se ignora).


Nota: si quisiera declarar en una clase interna que un método acepta un parámetro explícito de la clase externa se haría así:




  1. class Out{ 




  2. /* metodo y definiciones de Out */ 




  3.  




  4. // clase interna 




  5. class In{ 




  6. /* otros métodos */ 




  7. /* ... */ 




  8. public void show(Out Out.this) { /* definición */} 




  9. } 




  10. } 






Out.this es el nombre de la referencia que es de tipo Out por eso es Out Out.this.


El main de mi ejemplo:




  1. public static void main(String[] args) 




  2. { 




  3. var coord1 = Point.of(4.1,8.5); 




  4. var origen = Point.of(0.0, 0.0); 




  5.  




  6. out.format("coord1: = %s%n", coord1); 




  7. out.format("Distancia al origen = %.1f%n", 




  8. origen.distance(coord1)); 




  9. try{ 




  10. out.format( 




  11. "Cada .class comienza por 0xCAFEBABE = %b%n", 




  12. checkMagicNumber()); 




  13. } 




  14. catch(IOException ioe){} 




  15. } 






Salida:




  1. coord1: = Point(4.1, 8.5) 




  2. Distancia al origen = 9.4 




  3. Cada .class comienza por 0xCAFEBABE = true








Notas al pie:


Chapter 8. Classes

Publicar un comentario

0 Comentarios