Java desde C++

Este artículo pretende hacerles la vida más fácil a los programadores de C++ que se metan a ver cómo es eso de Java. No pretende ser purista, sino buscar la analogía, para acelerar el aprendizaje aprovechando los conceptos que ya se tienen.

Tipos de datos

En Java los tipos int, float, double, char y byte se comportan como tipos numéricos comunes de C/C++. Es decir, por ejemplo, que se pasan y reciben "por valor".

Todos los tipos numéricos son signed, y tienen la misma capacidad siempre, sim importar la plataforma.

Una excepción: El tipo "char" es un tipo casi numérico y sería unsigned. Correrespondería a un "unsigned short" (su tamaño es de dos bytes). Se usa solamente para almacenar caracteres Unicode.

Java tiene un tipo boolean específico, y no es posible usar una expresión numérica en una condición. Es decir que no se puede poner if(a), sino que hay que poner if(a != 0).

Objetos

La cosa se pone interesante con los objetos. En Java un objeto solamente puede estar en el heap, nunca en la pila. Por eso, la única manera de construirlos es con new, y solamente se puede referirlos mediante punteros. Para hacer la cosa más sencilla, en vez de usar "->" se usa simplemente el punto: ".". Pero a no engañarse por esto: una varibale de tipo objeto se comporta exactamente como una variable de tipo puntero lo haría en C++. Por ejemplo, si le asignamos un nuevo valor, esa variable apunta al nuevo objeto, si pasamos un objeto como parámetro, la referncia se pasa siempre "por valor". En Java no existe el pasaje por referencia.

Consecuentemente con lo anterior, es posible que una variable de tipo "objeto" no apunte a nada (tal como eso es posible para un puntero en C++). En ese caso apunta a null. Y null no es NULL. Mientras que NULL es una macro que se reemplaza por 0, null es una palabra clave del lenguaje.

Hay new, pero no hay delete. Los objetos son eliminados automáticamente por el garbage collector cuando no son referidos. El momento de la destrucción es impredecible, así que si bien uno puede crear un método "finalize()" que se llamaría cuando el objeto se destruye, se considera mala práctica poner código de destrucción allí. Entonces es más correcto decir que... en Java no hay destructores. El código de limpieza post-uso debe ponerse en métodos ad-hoc tipo close().

Java fuerza a que todos los objetos hereden de la clase Object. Es decir que en toda declaración de una clase hay un "extends Object" implícito.

Java no tiene punteros “a memoria”. La memoria como concepto no existe en Java, se accede a datos de más alto nivel completamente tipados (objetos, ints, etc). Los strings, entonces, no pueden ser punteros a memoria, son simplemente objetos. Cuando en Java se escribe "hola", estamos haciendo referencia a un objeto de la clase String que representa ese texto. Por eso es válido escribir "hola".length() (y daría 4).

Java no tiene herencia múltiple, por lo menos no de clases. Lo que sí tiene es una "herencia múltiple de interfaces". Una interfaz en Java es algo que se declara exactamente igual que una clase, pero usando la palabra interfaz. La diferencia es que en una interfaz todos los métodos son abstractos. Es decir que una interfaz es análogo a lo que en C++ se conoce como "clase puramente abstracta". Una clase puede extender un número ilimitado de interfaces, aunque no se dice "extender" en este caso en Java, sino "implementar".

En Java no existe la noción de "friend", para dar acceso a los miembros privados de una clase. Pero en cambio hay alcances de visibilidad más amplios que una clase. Si uno no le pone ningún modificador a un miembro, su visiblidad es "package", es decir que lo puede ver cualquier código dentro del mismo package. Esto es muy útil, porque si implementamos una biblioteca de imágenes en un package, es puede hacer una clase o un miembro que sea visible para todo ese código, pero que los clientes de la biblioteca no accedan. Esto termina siendo mucho más conveniente que el molesto "friend".

Todos los métodos son "virtual" (y esta palabra no no se usa en Java). Esto quiere decir que siempre se invoca al método de la clase correcta, y no importa el tipo de la variable mediante la que se accede al objeto. La máquina virtual puede en muchos casos optimizar las invocaciones cuando sabe que no hay posibilidad de que se llame a otra implementación, así que esto no debería ser un problema de eficiencia.

El cast de objetos es siempre seguro. No hay manera de forzar a que un objeto sea de una clase que no le corresponde. Esto quiere decir que solamente se puede castear a lo largo de la jerarquía de herencia de ese objeto. Si en tiempo de ejecución el objeto resulta no ser del tipo esperado se lanza una excepción InvalidCastException. Podría pensarse que en verdad, un cast en Java no es otra cosa que una forma especial de "assert" sobre el tipo del objeto. En C++ moderno este cast está disponible y se llama dynamic_cast (si se compila con RTTI).

Excepciones

Al igual que C++ Java tiene excepciones. La diferencia es que en Java es casi imposible no usarlas, mientras que en C++ su uso ha sido opcional, y dejado al gusto personal de cada programador. En Java existe lo que se conoce como "checked exceptions", que es que si uno llama código que tira una excepción que no extiende de RuntimeException o Error, uno está obligado a atraparla o declarar la función como que a su vez lanza esa excepción.

Mientras que en C++ uno puede lanzar como excepción cualquier objeto (como un string), en Java solamente se pueden lanzar objetos que hereden de Throwable. Esta clase tiene dos subclases: Exception para errores de la aplicación, y Error para errores graves de Java.

Por supuesto que una diferencia fundamental es que las aplicaciones Java corren dentro de una máquina virtual. Escribí un artículo que habla mayormente de la máquina virtual Java, puede interesar.


Vea mis otros artículos sobre programación en Java, por ejemplo uno de nivel híper básico sobre collections, u otro en el que trato de enumerar las cosas más importantes del mundo Java.


Me encantaría recibir cualquier tipo de comentarios sobre esta página. ¿Qué pongo? ¿Qué saco? Hecho por Nicolás Lichtmaier.

HTML 4.01 estricto válido

Creative Commons License
Licenciado bajo la licencia Creative Commons Attribution 3.0.