Para desarrollar aplicaciones en java Desarrollar aplicaciones computacionales utilizando el lenguaje java es modelar y codificar clases que resuelven un problema de la vida real. Por tanto entender el concepto de “clase” es fundamental para ser productivo utilizando a la herramienta java. Es tentador iniciar el estudio de java estudiando y utilizando sus instrucciones, su sintaxis y sus palabras reservadas propias del lenguaje. La mayoría de los textos que le abordan así lo enfocan; es más, fue de esa manera como muchos desarrolladores de software aprendieron a utilizar este tipo de herramientas para concebir aplicaciones computacionales, sean estas al ambiente local, cliente servidor o aplicaciones orientadas al web. Pero, la experiencia indica, que, además de tentador, es bastante ineficiente y bastante improductivo para enfrentar problemas de la vida real. Por tanto se tiene el criterio que, una vez que el lector haga suyo el concepto de clase, se está en capacidad de iniciar y finalizar aplicaciones computacionales altamente en tiempos relativamente cortos. Pero se tiene un gran problema: el concepto de clase no es nada intuitivo ni fácil de entender. Es un concepto abstracto, que, por definición apela a la imaginación, a la creatividad y a otro gran tema de estudio que se podría denominar modelaje. (Y cuando se cita la palabra modelaje se debe tener en perspectiva que la expresión “arte” está a la vuelta de la esquina). A pesar de que el concepto clase es complejo de adoptar y adaptar, y a pesar de la dificultad que implica aprender a trabajar con algo que no se entiende a cabalidad, sí se tiene el convencimiento que, en el muy corto plazo, los réditos son muy, pero muy gratificantes. El concepto de clase Como cada autor tiene su propio concepto de clase, en muchos en los cuales se coincide y muy pocos no, se puede decir que, dada cualquier abstracción de cualquier naturaleza, es decir cualquier idea, algoritmo, metodología, entre otros, los cuales dispongan de características similares, se entendería como “clase” a la plantilla, patrón, estructura o modelo que represente esa abstracción. Una clase, perfectamente, puede ser la expresión matemática utilizada en el cálculo del área de un triángulo, por ejemplo. O la manera intuitiva de calcular áreas bajo un curva imaginando pequeñísimos rectángulos, calcularles su área y luego sumarlos para esperar que sea muy parecida al operador matemático denominado “integral” que, cualquier profesional emplearía. O, el conjunto de propiedades y actividades que implican la idea “persona humana”, “árbol”, “mapa”, “pintor”, “emisión de cheques”, “cajero automático”, y demás. Similarmente, una clase puede ser desarrollada utilizando otra clase que otra persona acabó y la expuso al conocimiento al público, pero, en aras de resolver un problema en particular, se hace necesario agregarle algún concepto, componente o idea que, la clase primera, es decir, la ancestral, no disponía. En java es muy común la idea esbozada en el párrafo anterior: dada una clase el analista la “incorpora” para resolver “el” problema que tiene en mente. Inclusive, se puede afirmar que trabajar bajo el contexto de otra clase ya elaborada es la norma del desarrollo de aplicaciones en java. La relación jerárquica de superclase y subclase es crucial entenderla para evitar descubrir el agua tibia cada vez que se aborda algún problema en particular. ¿Una clase que calcula áreas de triángulos? Teniendo por referencia la posible dificultad de asociar la idea de abstracción de una clase como la idea de “la clase que calcularía las áreas de triángulos”, se debe discriminar las expresiones “las áreas de los triángulos” con la expresión “un área de un triángulo” en particular. Cuando una clase sigue paso a paso las instrucciones que conducen al cálculo de un triángulo “en abstracto”, es decir, dadas una altura y una base definidas en un espacio determinado, se dice que se hace necesario hacer una instancia de una clase ya elaborada (ya codificada en java) para “estar en capacidad de conocer” el área. Nótese como paulatinamente lenguajes como java se empiezan a diferenciar de otros lenguajes, como el Pascal, por ejemplo. En java se construyen clases con el fin de implementarlas para la solución de un conjunto de problemas “con características similares”. En Pascal, se construyen archivos “ejecutables” a los cuales se les alimenta parámetros para resolver “problemas similares”. Instanciando una clase conduce a otro concepto medular en el lenguaje java: al concepto de objeto. La relación entre clase y objeto, y entre objeto y clase, ha abierto todo un nuevo paradigma computacional en el arte del desarrollo de aplicaciones: la programación orientada al objeto, OOP. Una clase que “calcula áreas de triángulos” es un patrón que implica la implementación del algoritmo propio del área de los triángulos, el producto de la base por la altura y dividiendo el resultado entre dos. Pero ese patrón de cálculo no necesita ser codificado pensando en un triángulo en particular, sino, y esta es la clave, pensando en cualquier triángulo del universo. La clase que calcula áreas de triángulos no necesita conocer cómo se obtuvo el valor de la base, ni si la altura tiene dimensiones de centímetros o metros, o, si el triangulo representa un terreno de construcción de una casa o, la configuración natural de tres estrellas en el firmamento. Este hecho tan interesante que obliga a los desarrolladores de software a pensar en abstracciones y no en problemas puntuales, ha hecho posible la resolución de planteamientos que, en otros tiempos, requería mucho esfuerzo para la resolución de problemas. De la clase a las propiedades y a los métodos La abstracción de clases es la misma idea de la abstracción de sistemas. Por lo tanto, pensar sistémicamente es requisito sine qua non para modelar clases. Así como los sistemas tienen estados y conductas, las clases tienen propiedades y métodos. Las propiedades son estados de las clases. Una propiedad puede ese el color, la cual, al instanciarlo, genera el color de un determinado objeto, esto es, combina las cantidades de “pigmentos” rojo, azul y verdes. El peso, el valor de las dimensiones, el volumen, el área, el tamaño, entre muchos otros “valores” naturales de un objeto, son ejemplos típicos de las propiedades que los objetos adquieren al ser instanciadas desde una clase. Por otra parte, los métodos reflejan las conductas de las clases. Conductas en el sentido de “qué hacer”, “cómo actuar”, “qué actividad ejecutar”, “qué evento disparar” cuando alguna instrucción, línea de código o el propio usuario al movimiento de un click del ratón, activa al método en cuestión. Por tanto es imperativo empezar a diseñar métodos. Y aprendiendo a construir métodos se aprende a ensamblar el código java. Los métodos En la Sección anterior se introdujo el verbo “ensamblar”. Y se hizo a propósito en este punto porque, construir clases y aplicaciones con java –como en cualquier otro lenguaje orientado al objeto- es, ni más ni menos, ensamblar continuamente partes ya terminadas de código. A cada una de estas partes de código se denominan métodos. Métodos son, por tanto, trozos de software que se pueden usar desde cualquier clase. Así como los juegos de piezas estándares y fijas que el jugador junta, arma, ensambla, en función de creatividad, (o desemsambla, desarma y separa) los métodos son líneas de código, por lo general pequeñas cantidades de líneas, que, una vez que se tiene la certeza que no tienen errores y son “multiuso”, el desarrollador de aplicaciones usa y descarta con la misma facilidad de que, con piezas estándares de un juego “de armar”, construye y destruye castillos sofisticados por mero placer. La primera clase Supóngase que se tiene necesita de resolver el problema del cálculo de volumen de un cilindro, de radio “r” y de altura “h”. Para ello se desarrolla una clase, denominada “CalculoDelVolumenDeUnCilindroSolido” la cual hace uso de algún método bastante genérico que genera el “CalculoDelAreaDeUnCirculo”, porque, conociendo el área de un círculo, es decir, de la base del cilindro, simplemente se multiplica esta área por la altura del cilindro y se tendría el volumen. Así, 1 2 3 public class CalculolDelVolumenDeUnCilindro{ public CalculolDelVolumenDeUnCilindro (double RadioDelCilindro, double AlturaDelCilindro;){ double AreaDeLaBaseDeUnCilindro; 4 double VolumenDeUnCilindro; 5 AreaDeLaBaseDeUnCilindro = CalculoDelAreaDeUnCirculo(RadioDelCilindro); 6 VolumenDeUnCilindro = AreaDeLaBaseDeUnCilindro * AlturaDelCilindro; 7 System.out.print("Volumen del cilindro: " + VolumenDeUnCilindro); 8 } 9 public double CalculoDelAreaDeUnCirculo (double Radio){ 10 double Area; 11 Area = 3.141521 * Radio * Radio; 12 return Area; 13 14 } } Por ser esta la primera clase que se presenta muchos elementos pudieran ser desconcertantes pero, una vez comprendidos, tienen su lógica y fundamento. Lo primero que resalta es la especificación de cualquier clase en la línea 1. Todas las clases en java inician con un “{”y cierran con “}”. Esta clase en particular tiene un método: “CalculoDelVolumenDeUnCilindroSolido”. La clase tiene un metodo, “CalculoDelAreaDeUnCirculo”, y otra estructura muy parecida al método con un nombre igual al de la clase. Al segundo método se le denomina “constructor”. El método “CalculoDelAreaDeUnCirculo” inicia con una “{” y termina con otro “}” , líneas 9 y 13. Lo que el método encierra entre los paréntesis redondos, (), se denominan “parámetros” del método. Los métodos pueden tener uno o más parámetros, ó, puede no tener parámetros del todo. Los parámetros son valores que “se transportan” (que se “comunican”) desde cualquier lugar donde se utiliza el método. Por ejemplo, dado cualquier valor de la variable denominada “radio”, el método “CalculoDelAreaDeUnCirculo” devuelve, a la línea de código que activó el método, es decir, el valor del “Area”, sin interesar para qué se utilizará, posteriormente, el valor del área. Ahora es importante mirar con detalle las líneas de código. En primer lugar la forma como se hacen “copias”, -es decir instancias-, de las clases. Por lo general, se tienen el formato: UnaClase UnaInstancia; Por ejemplo, dentro del paquete java existen clases primitivas, como la clase “double”, que define al conjunto de números reales desde un ámbito de valores muy grandes, como un poco más adelante se verá. Las instancias de las clases primitivas, como la clase “double” se formarían así: double AreaDeLaBaseDeUnCilindro; double VolumenDeUnCilindro; En otras palabras, se han generado lo que se podrían denominar “otra instancia” o “variables” cuya vigencia o vida útil estaría desde la línea donde se coloca el “{” hasta la línea donde se cierra la estructura, i.e., “}”. A pesar que el término variable es muy utilizando en buenos textos de java, no es de nuestro agrado porque tiende a equipar con otros conceptos que no son ciertos para java; por tanto, el término variable se tratará de no utilizarlo; se prefiere el término de instancia de clase. “Instancia” debe entenderse como sinónimo de “clon”, como “copia al carbón” de algo previamente establecido. De una misma clase perfectamente se pueden hacer muchas instancias para utilizarse dentro de cualquier estructura, esto es, dentro de cualquier aplicación que eventualmente nace de la clase. Dicho lo anterior, las dos líneas del código java antes reproducidas, perfectamente pudo especificarse como: double AreaDeLaBaseDeUnCilindro, VolumenDeUnCilindro; con idénticos resultados. Desde luego que java no solamente es capaz de generar instancias para números reales. También existen clases para números enteros muy grandes, para números reales pequeños, para caracteres alfanuméricos, etc. Una pequeña lista de estas clases primitivas, se comenta un poco adelante. Parámetros Lo próximo a comentar es el concepto de parámetros. Parámetros entre métodos, más concretamente, porque existen parámetros “entre clases” y parámetros “entre aplicaciones”. Los métodos –y los constructores- pueden recibir parámetros. Los métodos –y los constructores- son capaces de devolver resultados, pero, dentro del contexto de los constructores, es mejor concebir a la clase como a la entidad que devuelve resultados (no olvidar que la clase y el constructor siempre tienen el mismo nombre). “Pasar” parámetros entre constructores es sinónimo a “pasar” parámetros entre clases. Los parámetros, si existieran, se ubican en los “()” de los métodos y de los constructores. Si no existen parámetros, los “()” quedan vacíos. Cuando un método devuelve un resultado debe especificarse la clase con que se devuelve el valor; ello se conoce con el nombre de “la clase del método”. Nótese que, en alguna parte del método existe la instrucción “return” cuando algún valor (o alguna clase) se regresa. Pero pudiera darse el caso de un método que no tiene clase, que no devuelve valores para decirlo en sencillo. Cuando un método no se asocia a ninguna clase se dice que la clase del método es “de clase” “void” y, por supuesto, un método de “clase void” no puede tener la instrucción “return”. Si permanece alguna dificultad en entender “métodos que no devuelven valores”, debe retomarse lo antes comentado en torno a la “conducta” de un sistema. Las conductas no necesariamente generan datos o valores concretos, pueden generar acciones como activar algún otro evento, generar un aviso, poner a trabajar otro método, entre otros. Los constructores no pueden tener clases asociadas a él ni mucho menos la expresión “return”. Los constructores no están pensados para ser usados por la misma clase: están pensados para que otros constructores de otras clases lo accedan, sin menoscabo que cualquier clase pudiera acceder a cualquier método de alguna clase instanciada. Este punto es crucial en java y vale la pena reflexionar en torno a las diferencias entres método y constructor. A manera de resumen se puede afirmar que los métodos son funciones definidas programadas- dentro de las clases los cuales pueden tener o no insumos y pueden regresar o no información a otros métodos. Se reitera que cuando los métodos no tienen insumos los paréntesis redondos de los métodos están vacíos. Cuando un método no regresa valores, se dice que el método es de clase void. Las estructura de clases y métodos Por lo pronto, la estructura de una clase es: public class NombreDeLaClase{ } y la estructura de un metodo es: public clase_del_método NombreDelMetodo(ParametrosDeEntrada){ } Ejemplos de estructuras La expresión “System.out.print()” y “System.out.println()” son dos llamadas típicas de las clases. La idea es bien intuitiva: dentro de la clase “System” existe otra clase –una subclase por así decirlo- denominada “out” y, dentro de la clase “out” se tienen métodos (que también se pueden concebir como clases), dos de los cuales se denominan “print()” y “println()”. La resultante de una llamada a cualesquiera estos dos métodos es imprimir en la ventana de comando, o, salida al monitor como se decía en años pasados. Lo que eventualmente se escribe en la ventana es lo que se encierra entre los paréntesis redondos. La diferencia entre “print” y “println” es que la primera imprime sin crear filas nuevas cada vez que se acceda al método, es decir, sin generar el “carriagereturn” (el “enter”) cada vez que se imprime lo solicitado. Por otra parte, cada vez que se llama al método “println” éste siempre inicia en la primera columna de la ventana de salida. La estructura en la llamada del método “print” es muy frecuente cuando se trabaja con java. Por ejemplo, si se tiene: java.awt.Button UnBoton; se está expresando que se desea una copia, una instancia, que se almacenaría en una variable bajo el nombre de “UnBoton”, de la clase “Button”, la cual, a su vez, tiene por superclase a “awt” y ésta, a ”java”. Clases y archivos físicos Todas las clases del lenguaje java se almacenan en archivos físicos pero con una gran condición, estos archivos físicos han de tener el mismo nombre –y la misma secuencia de letras mayúsculas y minúsculas- que se le asigna a la clase y, han de tener la extensión .java Por ejemplo, cuando se tiene una clase denominada “MiClase”, se debe tener un archivo de texto denominado “MiClase.java”, el cual, una vez compilado, generaría el archivo “MiClase.class" Superclases y subclases Construída una clase, esta puede generar otras clases. Y pudiera ser que estas segundas clases sirvan para generar otras clases y así sucesivamente. O que de la primera y segunda clase, se conjuguen y formen otra nueva clase. Java, en realidad es un conjunto de clases a su disposición para que Ud. diseñe y desarrolle sus propias clases de forma tal que el arte de programar en java, y por ende el arte de la programación OOP, es tener habilidad de adaptar clases sin pretender nunca descubrir el agua tibia. A la clase "ancestral" se le denomina “superclase”. A las clases hijas del una superclase se les denominan “subclases”. Java tiene infinidad de clases a su disposición contenidas en un paquete antiguamente denominado JDK1, -ahora denominado J2SDK2-, un kit para el desarrollo de aplicaciones en java. Obviamente, este conjunto de clases economizan tiempo de desarrollo porque sencillamente ya están construídas. Todas las clases contenidas en el JDK tienen una clase ancestral denominada Object. La clase “java.awt.Frame”, contenida en el JDK, en la clase que “le economiza” al desarrollador rescribir el código relacionado a la lógica para producir una ventana del tipo Windows, tan popular entre los usuarios. La clase “java.awt.Button” construye botones, la clase ”java.awt.applet.Applet” construye aplicaciones denominados “applets” muy útiles para generar productos para ser utilizados exclusivamente en la web. La clase “javax.swing.JLabel” y la clase “java.awt.Label” 1 JDK son las iniciales de Java Development Kit. 2 J2SDK son las iniciales de Java 2 Standard Development Kit. ambas contenidas en el JDK construyen etiquetas con algunas diferencias significativas, y así sucesivamente. De la clase al objeto La gran pregunta es cómo obtener el “producto” de una clase, es decir, cómo se ejecuta una clase, cómo se obtiene un objeto. La respuesta ya se ha comentado pero, dada la importancia de la pregunta se enfatizará: los productos de una clase se obtienen instanciando la clase. Para ejecutar una clase se necesita otra clase que amarre la clase de referencia y la despliegue directamente al monitor o -indirectamente- a cualquier navegador del web. Clases que hacen interface al monitor se les denomina en el argot de java “como clases” “main”; clases que hacen interface -indirecta- a los navegadores, se les denomina “applet”. Clases primitivas y referenciadas Pero el comentario anterior lleva a otro punto muy importante. Es fundamental en java hacer la discriminación entre clases primitivas y clases no-primitivas. Se ha visto que, la estructura de instancia de una clase primitiva es: clase instancia; Mientras que, para una clase no-primitiva, o clase referenciada, la estructura de instancia a la clase es, clase instancia = new clase(); Por ejemplo, las instancias siguientes están correctamente estructuradas: boolean RespuestaDeArranque; int MiNumeroEntero; OrdenamientoDeMatriz MiInstancia = new OrdenamientoDeMatriz(); ClaseDelWeb A = new ClaseDelWeb(int TamanoDelMonitor); Clases referenciales Por supuesto, las clase que el desarrollador de aplicaciones diseña y la mayoría de las disponibles en las bibliotecas de java, son las clases denominadas noprimitivas. La instancias a estas clases tiene un mismo patrón, a saber: ClaseNoPrimitiva instancia = new ClaseNoPrimitiva(); Donde los “()” envían al constructor respectivo los parámetros del caso. Un punto importante en este punto: las clases pueden o no tener constructores. Tres observaciones son de rigor. En primer lugar, se puede hablar de clases que no contienen constructores, i.e., clases que sólo contienen métodos que pudiesen llamarse desde cualquier punto de cualquier clase. “Bibliotecas” sería un nombre oportuno a este tipo de clases. En segundo lugar, pueden existir clases con solo un constructor. Este constructor ha de mirarse como “el método” que condude la lógica de la clase. Algo así como el “conductor” de un carro: “el carro” es la clase pero quien decide qué conducta utilizar o que propiedad cambiar, es el constructor de la clase, o, la persona que tiene los controles del carro. En tercer lugar, pueden existir clases que tengan más de un constructor. A pesar de que todos los constructores se denominan con igual nombre de la clase, cada uno de estos constructores difieren en la cantidad, en la naturaleza de la clase y en el orden de los parámetros. ¿Y para qué sirve esto?, podría preguntarse el lector. Pues sencillamente para implementar una característica muy importante de los objetos denominada el polimorfismo; pero este tema se debe comentar con tiempo en otra oportunidad. Estructura del main La idea de la clase que eventualmente amarra a otra clase, el “main” es muy sencilla: esta clase es un medio para ejecutar directamente la clase que se tienen en mente o , la clase para alimentar de valores a las clases –si es que se tuviese el caso de constructores con parámetros- y presentarla al monitor. La estructura típica del “main” se presenta a continuación: public class EjecutaAlgunaClase{ public static void main( String args[] ){ LaClaseAEjecutar F = new LaClaseAEjecutar(); } public boolean handleEvent (java.awt.Event e){ if (e.id == java.awt.Event.WINDOW_DESTROY){ System.exit(0); return true; } return false; } } Todos los main tienen que ser públicos, de carácter estático y de clase void, -de “tipo” void, en al argot popular-. Además, la clase main ha de tener un “arreglo” de parámetros de clase String. Nótese la similitud entre esta estructura y la estructura de un método. Estructura del applet La estrategia de diseño de la clase para instanciar a un applet sigue a continuación: se busca una clase estándar clase que directamente incrusta la clase tipo applet e inmediatamente la envía a cualquier navegador de la Internet. Se adjunta la estructura para, posteriormente, comentarla. public class EjecutaUnApplet extends java.applet.Applet{ public java.awt.Button BotonPrincipal = new java.awt.Button("Inicio del Applet"); public void init(){ setBackground(new java.awt.Color(255,255,255)); add(BotonPrincipal); } public boolean action(java.awt.Event e, Object o){ if(e.target == BotonPrincipal){ } LaClaseAEjecutar F = new LaClaseAEjecutar(); return true; } return false; } El objetivo de utilizar a la clase “java.awt.applet.Applet” como superclase – haciendo uso de la instrucción “extends” en la primera linea- es únicamente, como medio para introducir la clase que se desea ejecutar, en el web. La clase “EjecutaUnApplet” únicamente despliega en pantalla un botón. Nótese que el botón es una instancia de la clase “java.awt.Button” la cual, al interpretarse por el compilador java, despliega un botón con un encabezado igual a “Inicio del Applet”. Al dar un click a este botón, se ejecuta la línea crítica de la clase: se hace la instancia de la clase que se desea ejecutar. Y eso es todo. Se ha reiterado que la clase applet es una forma indirecta de ejecutarla utilizando cualquier navegador del web. Se dice “indirecta” porque los navegadores –por lo pronto- no interpretan directamente a los applets: los navegadores requieren que los applets estén incrustados en archivos planos, con extensión “.html”. Los archivos html sí pueden interpretarse por los motores de los navegadores. A continuación se presenta un archivo html, típico para servir de interface, de puente, entre el applet y el navegador de Internet. <html> <body> <applet codebase="." applet code="EjecutaUnApplet.class" width=500 height=120> </applet> </body> </html> Nótese que la estructura del “main” es, fundamentalmente, la de un constructor. Clases main vrs. aplicaciones Es importante tomar nota de lo comentado hasta la Sección anterior: la estrategia del desarrollo de aplicaciones es básicamente la idea de desarrollar clases que satisfagan los requerimientos de los clientes, desde luego, pero, sin distraerse en el “problema” relacionado hacia la ejecución de la clase, es decir, sin distraerse en la decisión de orientar la salida hacia un “main” o hacia un “applet”. La orientación estratégica es, por tanto, desarrolle clases y, posteriormente, pregunte cómo se desea ejecutar la clase. Nótese que esta estrategia de desarrollo es concebir a las clases “main” y “applet” como representaciones abstractas de los objetos. Modelando clases Se tiene la fuerte convicción que la mejor metodología para el desarrollo de clases han de seguir fielmente los postulados que, desde el año 1536, escribiera Rene Descartes, en su célebre obra denominada “Discurso del método”. Sin pretender discutir su contribución desde el punto de vista filosófico o científico, se desea resaltar cuatro pasos fundamentales para abordar problemas que escribiera en el Capítulo 2: Zzz Se tiene el criterio que, si se desea desarrollar aplicaciones bajo el paradigna OOP los postulados cartecianos tienen una vigencia increíble. Bibliotecas y paquetes Se conocen con el nombre de “bibliotecas” a cualquier conjunto de clases, mientras que, con el nombre de “paquete”, a aquel conjunto de clases -y/o bibliotecas- que tienen una residencia (y un fin) definido. Los escuchadores El tema de “los escuchadores” es muy amplio en el lenguaje java, y, quizás, uno de los temas donde la programación orientada al objeto toma su importancia. Dado que el concepto de escuchador está fuertemente asociado al concepto de interface, se ha de recordar que una “interface” es un medio que existe entre dos entidades totalmente diferentes. Unos ejemplos ayudan a aclarar el concepto de interface. Entre el aparato de televisión y una persona, el “control remoto” es un excelente ejemplo de interface. Entre dos secciones de una geografía separados por un río, el puente puede interpretarse como una inteface para dos posibles secciones de una carretera. Entre el cerebro humano y una imagen foránea a su sistema, los ojos constituyen un perfecto ejemplo de interface que faculta el sentido de la vista. En otro orden de cosas, y antes de iniciar el tema de los escuchadores, es oportuno tener en mente la siguiente imagen que de seguro fortalecerá el concepto que se busca. Supóngase que Ud. asiste a una conferencia de carácter internacional y, su conferenciante dicta su ponencia en idioma japonés. Partiendo del hecho que Ud. no entiende japonés, deberá recurrir a audífonos para la traducción simultánea del japonés al español, su idioma natal. Otras personas que si entienden el idioma japonés, de hecho, no requieren los servicios ni de los audífonos ni del traductor. Junto a Ud. sus compañeros de fila son, digamos, personas de origen alemán, inglés y francés, cada uno de los cuales necesitan los servicios de las traducciones simultáneas respectivas, si, desde luego, no entendieran al idioma del conferenciante. Esta imagen de un ambiente multilenguas, donde todos los participantes necesitan entender, encaja perfectamente en el tema de los escuchadores de java. Con diferente nomenclatura, desde luego. Analícese el siguiente cuadro. Simbología en el ambiente social Simbología en el ambiente del lenguaje java El conferencista Una persona quien merece atención Un usuario quien debe ser satisfecho El auditorio Conjunto de personas que atienden la conferencia, los audífonos y las cabinas de traducción simultánea Una clase Los miembros del auditorio Personas Objetos Miembros del auditorio que no entienden el idioma del conferencista Personas con audífonos Objetos con capacidad de escuchar Sección de traducción simultánea de un idioma a otro Una cabina de traducción Una “interface” Conexión entre los audífonos de las personas y el micrófono del traductor Un trozo de cable La palabra reservada “implements” Personas que entienden japonés Personas que no necesitan audífonos Objetos que, para escuchar, no necesitan ninguna interface Personas que no les interesa ni escuchar ni entender al conferencista Personas desinteresadas Objetos sin ninguna capacidad de escuchar Ejemplo de cabina de traducción Cabina de traducción del idioma japonés al español La interface “java.awt.ActionListener” Otro ejemplo de cabina de traducción Cabina de traducción del idioma japonés al francés La interface “java.awt.MouseListener” Dispositivo que usan las personas para escuchar al traductor Los audífonos Los métodos abstractos de las interfaces Ejemplo de un dispositivo utilizado para escuchar al traductor Una persona que utiliza un audífono marca A Si se usa la interface “java.awt.ActionListener”, el método “ActionPerformed()” discrimina al objeto Otro ejemplo de un dispositivo utilizado para escuchar al traductor Una persona que utiliza un audífono marca B Si se usa la interface “java.awt.MouseListener”, el método “mouseClicked()” debe discriminar al objeto Ejemplo de un dispositivo utilizado para escuchar al traductor, pero con la particularidad de que, el mismo dispositivo sirve para muchos idiomas Una persona que utiliza un audífono marca C Si se usa la interface “java.awt.ActionListener” sobre un objeto que tiene muchos items, el método “ActionPerformed()” debe discriminar al objeto y luego al item. Con estas similitudes en mente, a continuación se presenta cinco clases que incorporan la habilidad de escuchar. Cuadro zzzzzzz Nótese lo siguiente: Se accede a la o las interfaces mediante la palabra reservada “implements” Si la interface utilizada fuese la “java.awt.ActionListener”, entonces cualquier objeto tiene la capacidad de escuchar si dispone de la instrucción “objeto.addActionListener”. Existen “eventos” que pueden ser escuchados sin necesidad de interfaces, como los eventos “action” y los eventos “”handleEvents”, entre otros. super vrs. this Estando en una clase producida a partir de otra clase, es decir estando en una subclase producida partir de una superclase, muchas veces se necesita hacer referencia a objetos tanto de la superclase como de la subclase. Para esto se usan las palabras reservadas “super” y “this”. El “super” hace referencia a la superclase. El “this” hace referencia a la subclase. Un par de ejemplos son de rigor. Acceso a las clases public Private protected Clases “final” Zzz Clases “abstract” Zzzzz Instrucciones básicas en java Conocido y comprendido el concepto de clase, es de rigor introducir instrucciones del lenguaje. Al introducir instrucciones irremediablemente arriban conceptos de sintaxis que se abordarían en el acto. Sintáxix básica Java es totalmente sensible a las letras mayúsculas y minúsculas. Para java el nombre “Hola” es totalmente distinto a “hola” y a “hoLa”. Todas las sentencias de java terminan con el separador “;”. Es perfectamente viable generar una sentencia de más de un renglón siempre y cuando el último símbolo de cada sentencia finalice con un “;”. Los comentarios en java se indican con un “//”. Si un grupo de renglones pertenece a comentarios, entonces el primer renglón ha de llevar los símbolos “/*” y el último renglón con el símbolo “*/”. Se recomienda utilizar nombres de instancias haciendo uso de letras mayúsculas y letras minúsculas, y, desde luego, que los nombres sean autodomentados. No se permiten nombres que incluyan el espacio en blanco. Todas las estructura en java inician con “{” y terminan con “}”. El uso de “()” es muy distinto al uso de los “[]”. Por lo general con los “()” se indica que, dentro de ellos, se ubica una lista de parámetros, mientras que los “[]” se indica que, lo instanciado, se comporta bajo el concepto de arreglo. Por defecto, todas las clases de java tienen a su disposición a las clases contenidas en la biblioteca “java.lang”. Haciendo reminicencia del lenguaje “C”, java permite operadociones aritméticas sobre la misma instancia –“variable” es mejor palabra en este punto- de la siguiente manera; C += 7; es exactamente lo mismo a escribir C = C + 7; C -= 7; es exactamente lo mismo a escribir C = C - 7; C *= 7; es exactamente lo mismo a escribir C = C * 7; C /= 7; es exactamente lo mismo a escribir C = C / 7; C % = 7; es exactamente lo mismo a escribir C = C mod 7; k++ significa que, a la varible k se le suma una unidad para la siguiente oportunidad en que k se utilice. (Este tipo de llamada se le denomina “de postincremento”). k-- significa que, a la varible k se le resta una unidad para la siguiente oportunidad en que k se utilice. ++k significa que, a la varible k se le suma una unidad para la segunda oportunidad en que se le utilice. (Este tipo de llamada se le denomina “de preincremento”). --k significa que, a la varible k se le resta una unidad para la segunda oportunidad en que se le utilice. dddddd Clase primitivas Las clases primitivas, aquellas que se encuentran en la bibioteca “java.lang” son instanciadas mediante la sintaxis: ClasePrimitiva instancia; donde, “ClasePrimitiva” puede ser cualesquiera de las siguientes clase: “byte”. Si se desea una instancia de un número entero de tamaño de 8 bits. Ello significa que, el ámbito de una clase “byte” sería desde 128 hasta +128. “short”. Si se desea una instancia de un número entero de tamaño de 16 bits. Ello significa que, el ámbito de una clase “short” sería desde –32,768 hasta +32,767. “int”. Si se desea una instancia de un número entero de tamaño de 32 bits. Ello significa que, el ámbito de una clase “int” sería desde –2,174,483,648 hasta +2,174,483,647. “long”. Si se desea una instancia de un número entero de tamaño de 64 bits. Ello significa que, el ámbito de una clase “long” sería desde –9,223,372,036,854,775,808 hasta +9,223,372,036,854,775,807. “float”. Si se desea una instancia de un número real de tamaño de 32 bits. Ello significa que, el ámbito de una clase “float” sería desde –3.40292347 E+38 hasta +3.40292347 E+38. “double”. Si se desea una instancia de un número entero de tamaño de 64 bits. Ello significa que, el ámbito de una clase “double” sería desde –1.797693... E +308 hasta +1.797693... E+308 “char”. Si se desea una instancia de un carácter de tamaño de 16 bits, por supuesto. Ello significa que, el ámbito de una clase “char” sería desde “0000” hasta “FFFF”, en hexadecimal, por supuesto. “boolean”. Si se desea una instancia de un valor boleano de tamaño de 8 bits. Ello significa que los únicos valores posibles de una clase “boolean” serian “”true” y “false”. Sentencias de control El “if” La instrucción “if” es quizás la instrucción que le dio dirección y sentido a la programación de las computadoras. Y por ninguna razón esta instrucción debe quedar fuera de java. El “if” es bastante intuitivo: if ( UnaCondicion) { ...... } else { ...... } es decir, cuando la condición del “if” es verdadera se ejecutan todas las lineas de código contenidas dentro del primer conjunto “{}”. Si por otra parte, la condición es falsa, se ejecutan las líneas de código contendias en el trozo “else{}” El “swicth” El “switch” es una sentencia de control mucho más amplia que la sentencia “if”. Su estructura es la siguiente: switch variable { case PosibleValor1 : ..... .... break; case PosibleValor2 : ..... .... break; case PosibleValorN : ..... .... break; default { ..... } } Sentencias de flujo El for El “for” es la instrucción que prácticamente nació con los lenguajes de programación. Tiene la siguiente sintaxix. for (DeclaracionContador = InicioContador; Condicion; IncrementoContador) { ....... } la cual se recorre una y otra vez hasta que la condición sea falsa. Por ejemplo, for (int k = 1; k zzzzz 10; k = k + 1){ ….. } genera la siguiente actividad: habiéndose creado un contador denominado “k”, éste se inicia en “1” y cada vez que el ciclo se cumpla, el contador se incrementa en una unidad. El ciclo se repite ad perpetum hasta que la condición se haga “false”, es decir, cuando k sea menor a 10. El “while” La sentencia “do-while” es muy parecida a la del “for”, a saber, while (Condicion){ ..... } El ciclo se repite ad perpetum hasta que la condición se haga “false”, El “do-while” La sentencia “do-while” es muy parecida a la del “for”, a saber, do { ..... } (Condicion); El ciclo se repite ad perpetum hasta que la condición se haga “false”, Sentencias de paso Se puede considera al “return” como una instrucción de paso, pero, dada la inegable utilidad de ella en todos los métodos “de clase void”, su explicación ya se llevó a cabo. Una instrucción “break” quiebra una secuencia de código repetitivos para retomar el control justo después de la terminación del ciclo, es decir, posterior a un “}”. Por lo general el uso del “break” es muy útil dentro de una instrucción “for”, “while” ó “do-while”. Como se comparte el criterio que las siguientes instrucciones de control debieran de evitarse, únicamente se citan para no promocionar su uso: se refiere a las instrucciones “continue” y el “label”. El lector interesado puede consultar cualquier texto de java para su respectiva explicación. Sentencias de manejo de errores El “try-catch-finally” El “throw” Los arreglos Los arreglos son estructuras de datos que, bajo un solo nombre de instancia, tiene la capacidad de almacenar muchos valores –muchos atributos, se diría en el argot del paradigma orientado al objeto-. El uso, la comodidad y el potencial de los arreglos son muy amplios, porque, con solo una instancia, se generan tantos objetos como el usuario desee. Los arreglos pueden ser de una, dos, o muchas dimensiones. A pesar de que un arreglo puede interpretarse como un vector matemático, una matriz, un cubo, o un arreglo abstracto de “n” dimensiones en el espacio Euclidiano de tamaño “n”, el lenguaje java opta por la notación de arreglo de arreglos: una matriz para java es un arreglo de una dimensión dentro de otro arreglo de una dimensión y así sucesivamente. Java reconoce los arreglos mediante los símbolos “[” y “]” y tantos pares de esos dos símbolos como dimensiones se deseen. Por ejemplo, al especificar, int A[]; A.length = 10; Se ha definido en memoria un arreglo de una dimensión denominado “A” que tiene diez celdas, cada una de ellas numeradas mediante 0,1,2,...9. Otra manera de especificar el tamaño es: a) Especificando los valores: int A[] = {31, 42, 13, 34, 75, 6, 7, 8, 9, 10}; b) Haciendo la instancia formal: int A[] = new int[10]; Por otra parte, al especificar, int B[][]; Se ha definido en memoria un arreglo de dos dimensiones denominado “B”. El tamaño de las “matrices” son muy interesantes, pues java no actúa bajo el concepto de “columna” facilitando en demasía los conceptos. Una matriz 3x4 puede declararse con cualesquiera de las siguientes maneras: int B[][] = new int [3][4]; int B[][] = {{1,2,3,4}, {11,12,13,14}, {21,22,23,24}}; pero, perfectamente, -y esto es una tremenda ventaja de java-, los arreglos no necesariamente tienen que ser del mismo tamaño, por ejemplo, int C[][]; C = new int [2][]; C[0] = new int[5]; C[1] = new int[3]; C[2] = new int[8]; simplemente es una matriz con tres filas con cantidades de columnas variables: la primera fila tiene 5 columnas, la segunda 3 y la tercera fila 8 columnas. Se tiene el criterio que es mucho mejor entender el tamaño y las dimensiones de los arreglos asociando siempre el concepto de fila; en el ejemplo anterior, es mejor pensar que cada una de las tres filas de “B” tiene a su vez, cada una de las filas, cuatro filas. Una nota importante en torno a arreglos: el tamaño de los arreglos, indistintamente de la manera de cómo se declaran, son de clase “final”, i.e., una vez declarados no pueden alterarse. Administrando los paneles Las cadenas Entendiendo por cadena a la clase capaz de representar simbolos alfanuméricos, letras, palabras, números, simbolos especiales y demás, java administra dos conjuntos de cadenas. La primera se relaciona al “char” y al “Character”. La segunda se relaciona al “String” y al “StringBuffer”. Conceptualmente sólo a las segundas clase se pueden clasificar como cadenas. Las primeras, en realidad, son representaciones numéicas de los simbolos alfanuméricos. La utilización de estas clases es sumamente amplia, baste con observar sus constructores. Constructores para la clase String String() String(byte[]) String(byte[], int, int) String(byte[], int, int, String) String(byte[], String) String(char[]) String(char[], int, int) String(String) String(StringBuffer) Constructores para la clase StringBuffer StringBuffer() StringBuffer(int) StringBuffer(String) Usos básicos de las clases String y StringBuffer Los String son clases donde se supone, el contenido de la instancia perdura hasta que no se redefina. Los StringBuffer son clases similares a los String pero, con la particularidad de que el contenido de la cadena puede alterarse por secciones. La clase String es mucho más eficiente que la clase StringBuffer Las cadenas pueden visualizarse como arreglos de caracteres alfanuméricos, así, String A = new String(“LUNA LIBERIANA”); 0 L 1 U 2 N 3 A 4 5 L 6 I 7 B 8 E 9 10 11 12 13 14 15 16 R I A N A StringBuffer B = new StringBuffer(“Tiempo para vivir”); 0 T 1 I 2 E 3 M 4 P 5 O 6 7 P 8 9 10 11 12 13 14 15 16 A R A V I V I R int Longitud; Longitd = A.length; el valor de Longitud es 14 Longitd = B.length; el valor de Longitud es 17 Char = MiCaracter; MiCaracter = A.charAt(7); el valor de MiCaracter es “B”. MiCaracter = B.charAt(0); el valor de MiCaracter es “T”. A = B.substruing(7,11); el valor de A es “PARA”. A = B.substring(0,2) + B.substring(7,9); el valor de A es “TIPA”. Los hilos Los hilos en java tienen la virtud de mitigar, en parte, los problemas de eficiencia que implica el diseño conceptual de la computadora: la lógica secuencial. (Por lo menos a la hora de escribir estas notas lo anterior es cierto, porque, es de esperar que, en un futuro no muy lejano las computadoras personales –de bajo costotengan una lógica paralela... y más de dos estados para evolucionar el actual paradigma binario que empezó a incomodar desde hace algún tiempo). Continuando con la idea de generar imágenes para luego trasladarla al ambiente del lenguaje java, los hilos tienen que mirarse como aquella persona, a quien denominaríamos “tinteritero”, quien, mediante hilos amarrados en sus dedos, tiene la habilidad de mover muchas figuras en un pequeño escenario, cuyas piezas de las figuras, -manos, piernas, cabeza,...- están asociadas a un hilo. Si el movimiento que ejerce uno o varios tinteritero actuando al unísolo es uniforme, armonioso e inteligente, las figuras, vistas como participante del auditorio, “pareciera” que tienen vida propia. Exactamente ocurre lo mismo en el ambiente java cuando se desarrollan apliacaciones con hilos. La clase, el tintoritero, hace uso de la superclase “java.awt.Threads” y la interface “java.awt.Runnable”... y obviamente, el potencial de java se extiende aún más pues, un hilo, puede encargarse del sonido de la aplicación, otro, por ejemplo, de las imágenes, otro, de un algoritmo en particular para resolver alguna situación en especial, y así sucesivamente. Las bases de dato Los servlets Jacó, marzo del 2002. Jacó, diciembre del 2002.