Archivo para Abril 2009
Acceder a los miembros privados de una inner class (y viceversa)
Desde pequeños nos lo han grabado con fuego: “un miembro de una clase que esté definido como privado no es accesible desde fuera de la misma”. Sin embargo esta regla no va con las inner classes.
class Outer {
class Inner {
private int size = 0;
}
public static void main(String[] args) {
System.out.println(new Outer().new Inner().size);
}
}
Este código compila sin problemas, imprimiendo 0 (el valor de size, una variable privada de Inner).
A la inversa, una clase interna también puede acceder sin problemas a métodos y variables de su clase contenedora.
class Outer {
private int size = 0;
class Inner {
void print() {
System.out.println(size);
}
}
public static void main(String[] args) {
new Outer().new Inner().print();
}
}
En un primer vistazo esto puede chirriar un poco, pero en realidad una inner class no deja de ser un miembro más de una clase (en este caso, una clase miembro) que tiene acceso al resto.
La claúsula import
La engañosa cláusula import, al contrario de lo que su nombre podría indicar no carga ninguna clase ni paquete (al estilo del include de C, por ejemplo). Todas las clases que utiliza una aplicación están ya en el classpath y éstas se cargan a medida que se vayan utilizando. import permite utilizar los nombres de las clases como alias en vez de tener que usar el nombre completo y también evita posibles colisiones (clases con el mismo nombre).
// ExampleClass.java
package ws.otero.adrian.examples;
class ExampleClass { }
// Main.java
// con import
import ws.otero.adrian.examples.ExampleClass;
class Main {
public static void main(String[] args) {
ExampleClass exampleClass = new ExampleClass();
}
}
// sin import
class Main {
public static void main(String[] args) {
ws.otero.adrian.examples.ExampleClass exampleClass = new ws.otero.adrian.examples.ExampleClass();
}
}
Algunas clases están “importadas” por defecto, como son las del paquete java.lang (String o Integer, por ejemplo).
Una claúsula con un nombre un tanto extraño. Parece más obvio el nombre de su equivalente en C#, using.
Cuestiones convirtiendo un array a una lista con Arrays.asList()
Hace unos días comentaba uno de los muchos usos que tiene la clase Arrays de Java. Esta clase intenta solventar alguno de los problemas que pueden surgir al trabajar con arrays, como la ordenación o la búsqueda.
Pero si por cualquier motivo necesitamos convertir un array a una lista, podemos usar el método
public static <t> List</t><t> asList(T... a)
Pero mucho cuidado, este método nos crea una lista de tamaño fijo, y por detrás sigue funcionando sobre nuestro array (en realidad es una implementación especial de AbstractList). Veámoslo con dos ejemplos.
Ignorar y ocultar el directorio target de Maven en Eclipse

Algo que me resulta muy molesto al trabajar en Eclipse es el directorio target que utiliza Maven. No sólo por tenerlo siempre presente en el explorador (imagen superior), sino porque en la búsqueda de recursos (Ctrl + Shift + R) estos aparecen duplicados y no es la primera vez que edito el archivo equivocado.
Para ignorar este directorio, sólo tenemos que hacer click con el botón derecho sobre él, y en las propiedades marcar derived (desconozco cómo estará traducido al castellano).
Para ocultarlo, tenemos que echar mano de los filtros del explorador de paquetes. Pinchamos en el menú contextual de la vista (arriba, en la flecha que apunta hacia abajo) y luego en filters. En la caja de texto se pueden incluir todos los patrones de nombres de fichero / directorio que serán ocultados.

Java, los arrays y el método toString
Aunque lo normal es usar algún subtipo de Collection, muchas veces es necesario (o mejor) usar arrays. Esta tarea puede resultar tediosa, pues a pesar de que los arrays en Java no son más que un tipo especial de objetos, sólo poseen una propiedad: length.
La implementación de todos sus métodos los heredan directamente de Object por lo que no disponemos de muchas facilidades trabajando con ellos. Por ejemplo, para imprimir los elementos de un array debemos iterar y mostrarlos uno a uno.
Sin embargo desde Java 5 está disponible la clase Arrays, que viene a solventar algunos de los pequeños problemas que surgen con los arrays. Entre ellos el de imprimirlos:
int[] integers = {1,2,3};
System.out.println(Arrays.toString(integers));
Quizá ya conocíais este método. Si es así puede que os echéis las manos a la cabeza cuando os diga que yo utilizaba Arrays.asList() (convierte el array en una lista, la cual ya tiene un toString más humano).
En fin, nunca apagarás el ordenador sin saber una cosa nueva…
Internet Explorer cachea las peticiones de $.getJSON
Seguimos con traumas provocados por Internet Explorer. En esta ocasión le toca el turno a las peticiones ajax, las cuales por algún motivo el navegador de Microsoft cachea mientras el resto no.
La función $.ajax de jQuery permite un parámetro adicional cache para desactivarla manualmente, pero en mi caso realizaba la petición mediante la función $.getJSON. Para eliminar la caché en este método, previamente hemos de configurar el objeto ajax:
$(document).ready(function() {
$.ajaxSetup({cache: false});
// aquí ya podemos llamar a $.getJSON
});
En realidad lo que hace es añadir un parámetro (supongo que derivado de la fecha actual) a la url tipo _=1239723411253, para así engañar al navegador y hacerle creer que está solicitando una página nueva.
Y con esto ya tenemos a nuestro IE funcionando perfectamente. ¡Un trauma menos!
Ejecutar Internet Explorer 6, 7 y 8 con IETester

Por si no fuera poco castigo el tratar con las distintas versiones de IE, la integración de este programa en Windows hace imposible el tener varias versiones del mismo corriendo a la vez. Y así obviamente es complicado probar las aplicaciones en el que sigue siendo el navegador más usado.
Hasta ahora la mejor solución era Multiple IE, el cual permite ejecutar IE7 y anteriores, pero el proyecto está abandonado y con la salida de IE8 volvíamos a las andadas.
La solución viene ahora de la mano de IETester, con el que podremos echarnos las manos a la cabeza desde IE5.5 hasta IE8.
Detectar navegador y versión con jQuery
Cuando IE6 pase a mejor vida la nuestra cambiará. Mientras tanto, los parches, remiendos, apaños y chapuzas seguirán a la orden del día.
Una de las formas más habituales de solucionar los problemas de este navegador es mediante JavaScript, por ejemplo para arreglar los problemas con las transparencias de los PNGs. Pero estos scripts adicionales supondrían una penalización de rendimiento para el resto de navegadores (que poca culpa tienen), así que utilidades para la detección del browser como las que tiene jQuery nos vienen al pelo:
if ($.browser.msie && $.browser.version <= 6) { // script }
Java: cast implícito en el operador +=
Por estas latitudes hace un frío que pela, así que que mejor que dejar constancia de una pequeña curiosidad que comenté hace unos días sobre los operadores = y += en esta mañana de domingo.
Java realiza un cast implícito en la asignación de literales. Por eso estas expresiones son correctas:
byte b = 73; short s = 28730;
a pesar de que los literales numéricos como éstos se evalúan a int. Es decir, lo anterior es equivalente a:
byte b = (byte) 73; short s = (short) 28730;
Sin embargo, esto:
byte b = 128;
no compila, ya que 128 está fuera del rango de una variable de tipo byte y el compilador no realiza el casteo y nos avisa de ello. Tenemos que decirle que está bien y siga adelante con un cast explícito:
byte b = (byte) 128;
Aunque obviamente b no tiene ahora el valor 128, ya que se trunca a los primeros 8 bits.
Hasta aquí más o menos fácil, pero ahora viene lo interesante. ¿Debería lo siguiente compilar?
byte a = 10; byte b = 10; byte c = a + b;
La expresión a la derecha del operador = se evalúa a int, con valor 20. Una cantidad que puede perfectamente guardarse en una variable de tipo byte… pero esto no es correcto. El compilador no tiene en cuenta el valor que pueda resultar, y avisa de que se está intentando asignar un int a un byte. Lo resolvemos con un cast explícito como antes:
byte c = (byte) a + b;
Sin embargo, y aquí es dónde me he sorprendido, lo siguiente sí compila:
b += a;
Esta expresión supuestamente sería equivalente a:
b = b + a;
lo cual no debería compilar pues la expresión de la derecha se evalúa a int como acabamos de ver. Pero esto no funciona así, el operador += realiza un cast implícito al tipo de la variable sobre la que opera, por lo que la sentencia equivalente sería la siguiente:
b= (byte) b + a;
Una (tonto)curiosidad.
Struts en Google AppEngine

Este martes Google anunció la incorporación de Java a su “plataforma de desarrollo” (por llamarlo de alguna forma), AppEngine. En realidad en su máquina virtual pueden correr otros lenguajes, como Groovy, JRuby (y por tanto Rails) o Scala.
Por desgracia, y es que no todo iban a ser buenas noticias, tiene algunas limitaciones. Al no disponer de una base de datos relacional, no se pueden usar JDBC o Hibernate (al menos de forma directa), no soporta JNDI, JMX, EJBs… más info.
En cuanto al framework web, Google barre para casa y ofrece GWT, descartando el soporte para otros como Struts. Sin embargo en principio y viendo las características del entorno no parecía ser por razones técnicas. Y como veremos ahora, efectivamente es posible usar Struts en GAE.


