Java tiene varias curiosidades no tan conocidas, sobre todo si nos ponemos a explorar las
class
es (class
como mecanismo de abstracción en Java). Para esta respuesta sólo demuestro dos curiosidades:- Cada .class en Java comienza con el magic number
0xCAFEBABE
; esto es, los primero 4 bytes de todos los .class. - 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:
- // magic number
- // chequea si los 4 primeros bytes del .class
- // cooresponden con 0xCAFEBABE
- static boolean checkMagicNumber() throws IOException
- {
- Class<?> cls = Main.class;
- byte[] magicBytes = new byte[4];
- // leer los 4 primeros bytes de Main.class
- cls.getResourceAsStream(cls.getSimpleName() + ".class")
- .read(magicBytes);
- // ByteBuffer me ahorra algo de trabajo manual
- // manipulano bits mecanicamente
- ByteBuffer magicNumberAsBytes =
- ByteBuffer.allocate(magicBytes.length);
- // de int (0xCAFEBABE) a ByteBuffer
- magicNumberAsBytes.putInt(0xCAFEBABE);
- // comparar
- return 0 == Arrays.compare(magicNumberAsBytes.array(),
- magicBytes);
- }
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
:
- // this reference como parametro explicito
- private String repr(Point this){
- return String.format("%s(%.1f, %.1f)",
- this.getClass().getSimpleName(),
- this.x, this.y);
- }
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:
- private String repr(){ /* misma definicion */}
En el próximo método si uso la annotation y además un parametro “adicional”:
- // distancia entre dos puntos
- double distance(@Const Point this, @Const Point other){
- return Math.hypot(x + other.x, y + other.y);
- }
Otra vez, si tengo dos
Point
s 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í:
- class Out{
- /* metodo y definiciones de Out */
- // clase interna
- class In{
- /* otros métodos */
- /* ... */
- public void show(Out Out.this) { /* definición */}
- }
- }
Out.this
es el nombre de la referencia que es de tipo Out
por eso es Out Out.this
.
El main de mi ejemplo:
- public static void main(String[] args)
- {
- var coord1 = Point.of(4.1,8.5);
- var origen = Point.of(0.0, 0.0);
- out.format("coord1: = %s%n", coord1);
- out.format("Distancia al origen = %.1f%n",
- origen.distance(coord1));
- try{
- out.format(
- "Cada .class comienza por 0xCAFEBABE = %b%n",
- checkMagicNumber());
- }
- catch(IOException ioe){}
- }
Salida:
- coord1: = Point(4.1, 8.5)
- Distancia al origen = 9.4
- Cada .class comienza por 0xCAFEBABE = true
Notas al pie:
0 Comentarios
Comenta lo que gustes y necesites, estare muy feliz de leerte, GRACIAS.