Como aprobar en JAVA

79
por David Muñoz Díaz Este documento está escrito para ayudar a quien lo necesite. Puedes hacer con él lo que quieras, pero siempre de forma gratuita y desinteresada. Además, es demasiado malo como para venderlo. Se reirían de ti :) Si quieres aportar algo a este documento, no dudes en ponerte en contacto con el Grupo de Usuarios de Linux de la Universidad Carlos III de Madrid ([email protected] ).

Transcript of Como aprobar en JAVA

por David Muñoz Díaz

Este documento está escrito para ayudar a quien lo necesite. Puedes hacer con él lo que quieras,pero siempre de forma gratuita y desinteresada. Además, es demasiado malo como para venderlo. Sereirían de ti :)

Si quieres aportar algo a este documento, no dudes en ponerte en contacto con el Grupo deUsuarios de Linux de la Universidad Carlos III de Madrid ([email protected]).

ContenidoAquí tienes la lista de contenidos del texto. Los apartados marcados con * son sólo orientativos y no estánampliamente explicados aquí, ya que no forman parte del objetivo de este texto. Puedes encontrar unaexplicación exhaustiva de estos apartados en cualquier libro de Java, además de las explicaciones que tedará el profesor de la asignatura. Bueno, en algunas ocasiones, que debería dar.

Prefacio* (que no, que es coña)

Introducción. Cultureta.pelín de historia

Platón y la OOPel problema...... y la soluciónconcepto de objeto

propiedadesmétodos

concepto de clase

Java¿por qué Java? caracteríaticas generales de Java *

facilidad (je je jeeee) lenguaje interpretado tamaño de los programasorientado a InternetJVM

Cómo usar el compilador y la JVM (javac, java)

El movimiento se demuestra andandodefinción de una mesa

propiedadestipos básicos de datos *métodos

valor de retornoparámetros

creación y uso de objetoscreación

primero: las referenciassegundo: new

usoel operador punto

más sobre creación: constructores¿qué son?peculiaridadesdefinición y uso

breve iniciación al polimorfismo *métodos get/set

¿Por qué?uso

Variables de clase. Modificador Staticel problema...... y la soluciónuso de static

en propiedadesen métodos

constantes

El método main, arrays y ¡a lanzar programas!por qué el método maindefinición del método mainargumentos

un inciso: arrayssacabó el inciso

nuestro primer programa

Programando a lo bestia: estructuras de controlSentencias condicionales

sentencia ifexpresión lógicabloque de sentenciascomparadores de magnitudAND, OR, NOTcomparadores de cadenasifs anidadosif sin elses: CUIDADO!

solución rara solución más rara

sentencia switchusobreakcomerte el coco 4

Sentencias repetitivasdefiniciónsentencia while

regla general para el uso de buclesvariación do - while

sentencia for¿While o for?

Recursividaddefiniciónmetodología: la cola del cinepartes de un método recursivolos factoriales

Herenciapara qué sirvecómo se usa: extendsredefinición de métodosuso de super()una nota bastante importante

Castingpreludio al casting: las referencias

la señora referenciacómo funcionacomparación de referenciasArreglando bicicletas: parámetros que son referencias

casting¿Por qué?cómo se usa

resumencomerte el coco 6upcasting, downcasting, Y siguiendo con el inglés, explicit and implicit cast

upcastingdowncastingcasting implícitocasting explícito

La Clase Object definicióncontenido * ¿para qué ese contenido?la gran utilidad de la clase Object: referencias de tipo Object

Interfacesdefiniciónuso básico de interfacesuso avanzado de interfaces: referencias de tipo de interfaces¿herencia?¿Interfaces?¿comorl?

Epílogo

El contenido de este texto es el estrictamente necesario para poder abordarcualquier problema de Programación. Este texto es, por tanto, la base necesaria parapoder enfrentarnos a las asignaturas de Programación y Laboratorio de Programación.En este texto no vamos a ver determinados temas, como Applets, paquetes, pruebas deprogramas, etc. Para cualquier consulta sobre dichos temas, te recomiendo los libros deJava de la editorial Sun o alguno de la infinidad de manuales gratuitos que hay por lared.

Por tanto, es necesario que te conciencies de que leer este texto no implicaaprobar: implica ser capaz de aprobar. Si te sirve de algo, cuando yo llegué a primero,sabía bastante menos de lo que hay aquí escrito.

Prefacio

No te engañes: tenemos mucha labor por delante. Pero no hay que pensar que esardua y temible. En absoluto. O al menos, espero que no lo sea para ti.

Programar implica siempre dos cosas:

Primero, hay que comerse el coco bastante, pero no para alcanzar complejosconceptos (bueno, para esto también), sino para todo lo contrario: para conseguir ponernuestro pensamiento a la altura de un cacho de silicio, que no parece muy listo....

Segundo, la curiosidad no mata al gato, sino que

curiosity Skilled the cat

(por cierto, n.p.i. de de quién es esta frase. Se la he copiado a un miembro delGUL. Así que si esta frase es suya, le pido diculpas por no pagar derechos de autor)

O sea, que siempre, repito, siempre es bueno parar de estudiar y encender elordenador para hacer alguna prueba de lo que estemos estudiando. Si vemos castingserá muy positivo que mandes a tomar por saco los apuntes y escribas un par de clasespara probar “el acceso a los miembros de una calse vía una referencia de tipo lasuperclase”. Parece mentira, pero esta frase tiene sentido. En serio, nunca vas aaprender a programar con un libro, siempre lo aprenderás por tu cuenta. Así que vetehaciendo a la idea de que vas a pasar muncho rato delante de la pantalla, aunque esperoque no sea demasiado tiempo. O que al menos no sea tedioso.

He intentado explicar todo este rollo usando ejemplos de la vida real. Tal vezquede “un poco” asquerosamente pedante explicar las clases metiendo a Platón pormedio, pero creo que haciéndolo vamos a entender los conceptos más fácilmente, ysobre todo, no se van a olvidar. Por supuesto, no creas que todo es Platón, tambiénhablaremos de tu vecina, de la mesa Margarita, de “páginas gué”, la bicicleta Anacleta,y de mil cosas más. Bueno, mil... lo que se dice mil....

Por supuesto, todo ello respaldado por el pez Otilio, el pato Onorato y el pájaroque no sé cómo demonios se llama, que no son más que excusas para apartar un poco laatención y hacer la lectura un pelín más agradable.

Espero haber logrado, aunque sólo sea en pequeña parte, estos objetivos. Ahora,como dice la historia de la sopa de piedra, debes poner tú de tu parte. ¡Ánimo!

Introducción. Cultureta.

Normalmente, para empezar se opta por definir qué es programar, cómo se llevaa cabo, conceptos como “software”, “hardware”,“memoria”, etc etc etc. Vamos a ignorar todo este rollo porque realmente no importa en absoluto. Nosotros, por ahora, nonos vamos a preocupar de la Yo soy un programadorcapacidad de la memoria o de la leche.de la velocidad del proce-sador. A nosotros nos inte-resa programar.

Cuando aprendemos a programar siempre se nos plantea si debemos compaginar la progra-mación con el lenguaje de programación. Parece una tontería,pero podemos aprender OOP sin saber ningún lenguaje. Es cierto: podemossaber sobre clases, objetos, herencia, casting, etc sin saber una maldita palabra deningún lenguaje. Sin embargo, siempre es positivo compaginar nuestro aprendizaje deprogramación con el de un lenguaje propicio para ello.

Además de la OOP, y a modo de curiosidad (cultureta), existen otros tipos deprogramación, cada uno con un lenguaje de programación típico. Esta parte, si quieres,te la puedes saltar.

La programación “lineal” tiene como fundador el antiguo BASIC. A lo largo delos años, el BASIC ha ido cambiando hasta que hoy en día existen compiladores deBASIC orientado a objetos (Visual Basic, por ejemplo, mantiene una filosofía de OOP).La programación lineal se daba con los primeros intérpretes de BASIC. Aquí hay unejemplo de este lenguaje:

10 INPUT “¿Cómo te llamas?”, NOMBRE$20 SALUDO$ = “¡Hola “+NOMBRE$+” ¡”30 PRINT SALUDO$40 END

¿Ves? El programa empieza en un punto, y acaba en otro. Esto, claro, tiene susinconvenientes: no podemos hacer repeticiones, ni nada de eso. Nacieron las “sentenciascondicionales”:

10 INPUT “¿Cómo estás?”,COMO$20 IF COMO$=”bien” GOTO 5030 IF COMO$=”mal” GOTO 70

40 GOTO 1050 PRINT “Vaya, me alegro.”60 GOTO 8070 PRINT “Alégrate!”80 END

El siguiente paso es la programación procedimental: consiste en dividir el código enfragmentos independientes. Lenguaje típico, el Pascal.

var cad:String;

procedure debuti;begin Writeln('me alegro');end;

procedure notandebuti;begin Writeln('alegrate!');end;

begin Writeln('¿Cómo estás?'); readln(cad); if (cad='bien') then debuti else notandebuti;end.

Hay muchos más tipos de programación, y también muchos otros lenguajes muyraros, Smalltalk, ADA, Prolog.... En realidad, hoy en día muchos de estos lenguajes seusan con fines didácticos o experimentales.

A nosotros nos interesa la “Programación Orientada a Objetos” (OOP, deObject-Oriented Programming). Se basa en “encapsular” fragmentos de código en“burbujas” independientes entre sí. Los códigos mostrados antes no tienen sentido enOOP. Vamos a ver por qué.

Platón y la OOP

La pregunta es las siguiente: Tenemos una mesa en la cocina, una en el salón,una mesilla de noche y una en un taller. Estas mesas son diferentes entre sí, pero, sinembargo, hay algo en ellas que hace que todas SEAN mesas. Una es cuadrada, otraredonda, unas con tres patas y otras con cuatro. ¿Por qué, si son tan diferentes, son todasmesas?

Este hombre de aquí dijo que había un mundo aparte delnuestro en el que existían unos “seres” perfectos, inmutables,universales, etc etc etc, a quienes llamó Ideas. Los seres de nuestromundo físico serían “copias” imperfectas de estas Ideas. Imagina portanto que todos los objetos que tenemos alrededor son copias de lasIdeas. De esta forma, al ser copias imperfectas, no serían igualesentre sí, pero seguirían teniendo esa “esencia común”.

Esta teoría sirve para explicar la realidad y dar un poco decabida a la ciencia. Si la ciencia trata sobre las cosas globales, esdecir, los hechos universales, no los específicos, entonces tiene que haber algouniversal.

Bueno, pues nuestra intención es semejante: vamos a tratar de explicar, no larealidad, sino los problemas que nos encontramos, que de una forma u otra, son parte dela realidad. ¿o no?

En OOP definimos un concepto más que fundamental: el concepto de objeto.Un objeto es un conjunto de:

a) Datosb) Métodos

Supongamos dos objetos semejantes, por ejemplo, dos mesas. Datos que puedenconcernir a las mesas, por ejemplo, son su color, número de patas, su forma, etc. Así, sitenemos dos “objetos mesa”, cada uno con datos diferentes, tenemos dos mesasdiferentes, que es lo que planteábamos al principio: dos objetos de la misma naturaleza(“mesa”), pero diferentes entre sí. ¡A Platón esto le habría encantado!

Debido a que los datos de un objeto definen en parte este objeto (lo diferencian delos demás), a veces llamamos a estos datos “Propiedades”.

¿Se te ocurre algún método propio de una mesa? A mí no, las mesas son objetospuramente pasivos, ellas mismas no hacen nada. Sin embargo, vamos a suponer que elcambio de color es una acción propia de la mesa (y no del pintor).

De acuerdo, ya tenemos el diseño de nuestra mesa. Ya conocemos el concepto deobjeto. Vamos a seguir con el señor Platón.

¿Cómo un carpintero puede crear una mesa? Según este griego, su alma, antes denacer, vislumbró las Ideas, y durante la vida de la persona, el alma recuerda algunas deestas Ideas (aunque no todas....) Así, un carpintero recuerda haber visto la “Idea deMesa”, y por ello sabe hacer mesas. Es decir, el carpintero se FIJA en la “Idea de Mesa”para crear una mesa.

Si ya conocemos lo que es un Objeto, ¿Qué es una Idea? Pues, sencillamente, ladefinición de ese objeto, que, por cierto, nosotros llamamos clases. Platón dice que losobjetos físicos son copias de las Ideas. Nosotros decimos que los objetos con instanciasde las clases.

Para Platón, los objetos son copias de unosseres universales llamados Ideas. Las Ideasson, por tanto, la definición de los objetosfísicos, aunque éstos pueden ser diferentes entresí. Para la OOP, los Objetos son instancias deunas definiciones generales que llamamos Clases.Dos objetos con propiedades diferentes (dos mesas con diferente color) siguen siendo instancias de la misma clase (la “clase mesa”).

Éstos son los conceptos fundamentales de la OOP. Es estrictamente necesario comprenderlos a fondo antes de seguir adelante. Párateun momento a pensar si entiendes a fondo...

OBJETOCLASEPROPIEDADESMÉTODOSINSTANCIA

¡Cuidado!Si decimos que dos objetos de la misma clase tienen las mismas propiedades, talvez lo que realmente queramos decir es que dos objetos de la misma clase tienenEL MISMO VALOR PARA TODAS Y CADA UNA.DE SUS PROPIEDADES.Es evidente que dos objetos de la misma clase van a tener las mismaspropiedades: dos mesas tendrán color, forma, número de patas, etc. Pero tal vezdigamos que dos mesas tienen las mismas propiedades cuando queremos decirque ambas mesas tienen la misma forma, el mismo color y el mismo número depatas. Hay que tener cuidado con esto, aunque tampoco es tan importante.

Para comerse el coco.... (1)Tenemos dos objetos de la misma clase, con exactamente las mismaspropiedades ¿Son el mismo objeto?

Java

Java es un lenguaje de programación. La verdad es que no va a recibir ningúnpremio por este simple hecho. Sin embargo, sí va a recibir cierta atención por nuestraparte, porque, sencillamente, es la herramienta que nosotros vamos a utilizar. Que quedemuy claro, Java es un MEDIO para programar en OOP. Podemos programar en OOPcon otros muchos lenguajes, Delphi, Visual Basic, o C++.

Java nació con una intención muy clara: hacer la vida más fácil al programador.C++ es el lenguaje más potente que existe ahora mismo. Pero tiene un grave problema:es lo más complicado que hay. Un ejemplo:

#include <owl.h>

// Define la clase derivada de TApplication

class THelloApp : public TApplication{public: THelloApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {}; virtual void InitMainWindow();};

// el MainWindow de la clase

void THelloApp::InitMainWindow(){ MainWindow = new TWindow(NULL, "Hola Mundo");}

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ THelloApp HelloApp ("HelloApp", hInstance, hPrevInstance, lpCmdLine, nCmdShow); HelloApp.Run(); return HelloApp.Status;}

Bueno, pues este fragmento de código abre una ventana con el título “HolaMundo!”.

Visto lo visto, Java trata de hacer la vida un poco más fácil. Además, unprograma en Java ocupa bastante poco espacio en disco, mientras que uno en C++ ocupatodo lo que quieras y un poco más. Así que, gracias a eso, Java es también propicio paraaplicaciones que corran por Internet y esas cosas. Pero todo eso ya lo veremos.

Java NO lo entiende directamente el procesador. Java es un lenguajeINTERPRETADO, es decir, que se “traduce” para que el procesador pueda entenderlo.C++, una vez compilado, es entendido perfectamente por el procesador, mientras queJava no. Java se compila y se generan los “bytecodes”, que es otro lenguaje mucho mássencillo, pero el procesador sigue sin entenderlo. Para ello, los bytecodes tienen que

INTERPRETARSE por la “Java Virtual Machine” (JVM), que, en realidad, es otroprograma (escrito, por cierto, en C++) que sabe interpretar los bytecodes. Bueno, esto esun poco extraño, pero en realidad es muy fácil. Al escribir un programa en C++, porejemplo, se compila y funciona solito. Pero al escribirlo en Java, se compila y necesitaotro programa que lo haga funcionar. Este otro programa se llama JVM. Ya está. No estan mortal, ¿no?

¿Ventajas de Java sobre los lenguajes no interpretados? muchas, por ejemplo,seguridad: Si un programa en Java intenta hacernos la puñeta, la JVM lo detendrá,mientras que el procesador no podrá detener nunca un virus escrito en C++. Otra ventajaes el ya mencionado reducido tamaño de los programas en Java. Otra, mucho másimportante, un programa en Java funciona en Windows, en Linux, en Mac, en Solaris,etc, porque lo que cambia es la JVM.

Aquí no vamos a extendernos en el funcionamiento de los compiladores de Javay las JVM. Sin embargo, vamos a recordar un poco el proceso.

1.- Creamos el archivo “xxxx.java”2.- lo compilamos con “javac xxxx.java”3.- lo ejecutamos con “java xxxx”

El paso 3 es el que invoca a la JVM. Más explicaciones, ayuda en línea.

Antes de seguir adelante, vamos a pararnos un poco para recapacitar sobre si hasentendido los conceptos de:

LENGUAJE Empiezo a plantearmeLENGUAJE INTERPRETADO esto de programar.... Y COMPILADOCOMPILADORJVMBYTECODES

Para comerse el coco......(2)Teniendo en cuenta que la JVM es un programa escrito en un lenguaje compilado, ¿puede ser entendido por la propia JVM?

El movimiento se demuestra andando.

Vamos a escribir un pequeño programa en Java. ¿Su fin? definir las mesas quetanto tiempo nos han acompañado. Recordemos la CLASE MESA:

Propiedades: color, número de patas, formaMétodos: cambiar el color

Bueno, vamos a pensar un poco. Como sabrás, los nombres oIDENTIFICADORES en Java son una cadena de caracteres que almacenan un valordeterminado, o el nombre de un método, o el nombre de una clase, o yo qué sé.Tenemos que tratar de inventarnos identificadores con nombres sencillos, que no seanrebuscados, sin caracteres raros. A mí se me ocurren los siguientes:

para el color, pues “color”para el número de patas, “numPatas”para la forma, pues “forma”para el método que cambia el color, pues “cambiarColor”

Definición de propiedades

Vamos a centrarnos en las propiedades, y luego veremos los métodos.

Seguimos pensando. El color será una cadena de caracteres (“marrón”, “violeta”,joer, una mesa violeta...), que en Java se denomina “String”, al igual que la forma(“Redonda”, ”cuadrada”). El número de patas será un número entero, que se llama “int”.

La definición de la clase Mesa.java empezaría así:

class Mesa {String color;int numPatas;String forma;...

Esto ya tenemos que ser capaces de entenderlo bien. Una mesa tiene un color, unnúmero de patas y una forma. El número de patas es un número entero, mientras que laforma y el color son cadenas de caracteres. Bueno, pues así se han definido. Ahora noha lugar a pensar cómo se define el color de una mesa determinada, o su forma, o cómosaber qué color tiene otra mesa cualquiera..... todo eso ya lo veremos. Ahora estamosDEFINIENDO la clase Mesa, no hacemos nada más.

En cualquier libro encontrarás los tipos básicos de variables y sus rangos devalores. Tendrás que aprendértelos, aunque sólo para el examen. Luego, puedesolvidarlos. Básicamente son

int, short, long, double, float, char, String y boolean. Este es un buen momento para aprenderte los tipos de datos básicos.

Definición de métodos

¿ya te los has aprendido? ¡Bien! Vamos a por el método cambiarColor. Un método consta, aparte de su nombre (o IDENTIFICADOR), claro está, de

a) valor de retorno.b) parámetros

Un método puede devolver un valor, o puede no hacerlo. Por ejemplo, unmétodo que calcule la suma de dos números debería devolver otro número, o un métodoque abra un fichero del disco debe devolver si ha podido abrirlo o no. Ahora bien, haymétodos que no tienen por qué devolver nada. Por ejemplo, un método que muestre unsaludo en pantalla no tiene por qué devolver nada.

A la hora de definir el tipo de dato que devuelve un método, se antepone alnombre de ese tipo de dato (int, float, boolean, String....) al nombre del método. Porejemplo:

int calculaSuma() // devuelve un enterofloat raizCuadrada() // devuelve un realboolean abrirArchivo() // devuelve un valor lógico

Los métodos que no devuelven nada se declaran como void:

void saludo() // no devuelve nada

Bien. Vayamos ahora a por los parámetros.

Un método que calcule 5*4 está claro que no va a necesitar parámetros, porque elmétodo no puede hacer nada más que calcular 5*4. Sin embargo, un método que calculela multiplicación de dos enteros cualquiera necesitará conocer esos enteros, es decir, selos daremos como parámetro. Es como si queremos saber dónde está determinada calle,y le preguntamos a alguien: tenemos que decirle qué calle buscamos. Imagínate,“Disculpe, ¿podría decirme dónde está la calle?” No tiene sentido, habría que preguntar

“Disculpe (educación ante todo), ¿podría decirme dónde está la calle Butarque?”.Bueno, pues como éste se te pueden ocurrir mil ejemplos

Es MUY IMPORTANTE que diferencies cuándo un método necesita parámetros y cuándo no.

Una cosa sí es cierta: no hay una regla general para saber si un método necesitaparámetros, para saberlo necesitamos la mplementación del código, y el sentido común.

Vamos a ver unos ejemplos:

int suma(int a, int b) recibe un entero a y un entero b y devuelve otro entero

String concatenar(String a, String b) recibe dos cadenas de caracteres y devuelve otra cadena de caracteres

float raizCuadrada(int a) recibe un entero y devuelve un real

Debe quedar MUY MUY MUY claro este rollo de los parámetros y del tipo dedato devuelto por un método. Vamos a ver los métodos anteriores implementados ycomentados para que se vea todo mucho mejor, y ya de paso aprendemos cómo hace unmétodo para devolver un valor usando “return”:

int suma(int a, int b){ return a+b;}

Este método recibe dos enteros, a y b, y devuelve su suma, que será otro entero.Si hacemos en cualquier parte del programa

int numero = suma(3,5);

estamos diciendo que el entero “numero” va a valer lo que devuelva el método“suma” pasándole como parámetros 3 y 5. “suma” devolverá 3+5, y entonces “numero”pasará a valer 3+5.

String concatenar(String a, String b){ return a+“ ”+b; // las comillas encierran un espacio en blanco}

Recibe dos cadenas y las concatena poniendo un espacio en blanco entre medias.Fíjate en la diferencia entre usar “+” con números y usarlo con cadenas. Si en cualquierpunto del programa escribimos

String cad = concatenar(“Hola”,”Mundo”);

estamos diciendo que la cadena (String) “cad” va a valer el resultado que“concatenar” devuelva pasándole como argumentos las cadenas “Hola” y “Mundo”;Como “concatenar” coge las dos cadenas que hemos pasado como parámetros (“Hola” y“Mundo”) y las devuelve juntas con un espacio entre medias (devuelve “Hola Mundo”),la cadena “cad” pasará a valer “Hola Mundo”

void saludo(){ System.out.println(“Holas!”);}

este método no tiene parámetros, y no devuelve nada de nada. Así, se le invocaráen cualquier parte del programa:

saludo();

y ya está. Como en el método no hay definidos parámetros, pues no le pasamosparámetros, y como el método no devuelve nada, pues es ilícito escribir algo como:

int resultado = saludo(); // mal!!!!!

porque “saludo()” no devuelve nada (recuerda: se ha definido como “void” y nose ha escrito ningún “return”), y como no devuelve nada, Java no sabe qué valor meteren “resultado”.

Bueno, pues este es el funcionamiento de un método. A modo de resumen,cuando un método es invocado, puede necesitar o no parámetros. Que los necesite o nodepende de cómo hemos definido dicho método, es decir, si hemos definido variablesentre los paréntesis del método:

... metodo(parametro1, parametro2, ....) por ejemplo:int suma(int a, int b)

o si no las hemos definido:

... metodo() por ejemplo:void saludo()

Un método puede devolver un valor, o bien puede no devolver nada. Depende de cómohemos definido el método: si lo definimos como “void”:

void saludo()

entonces no devuelve nada, pero si lo definimos de otra forma:

int suma(....)

entonces devolverá un dato de un tipo determinado (int, float...), y será OBLIGATORIOescribir un “return” en el cuerpo del método.

int suma(int a, int b){ int resultado = a+b;}

Este método es casi igual al que hemos visto poco más arriba, peeeeeeeeeero tiene ungrave problema: hemos dicho que devuelve un entero ( INT suma(int a, int b) ), pero nohay ningún “return” en el cuerpo del método. Habrá un error de compilación!

Una cosa más, que un método devuelva algún valor NO IMPLICA(curiosamente) que haya alguna variable que reeciba dicho valor. Es decir, las siguienteslíneas son perfectamente legales:

int resultado = suma(5,3);...suma(5,3);

La única pega es que la segunda línea llama al método “suma”, le pasa susparámetros pertinentes, pero nadie recibe el resultado. Esto, parece una chorrada, peroes útil. Supongamos que tenemos un método:

boolean abrirFichero(String nombreFichero)

cuya tarea es abrir un fichero determinado. Este método devuelve un booleanque indica si se ha abierto el fichero con éxito. Bien, puede que en algún momentohagamos:

boolean hemosPodido = abrirFichero(“miFichero.txt”);

para saber si hemos podido abrir el fichero. Esto sería lo más normal, pero en algunasocasiones no necesitamos saber si se ha abierto exitosamente, porque sabemos que va aser así, por ejemplo, al hacer algún programilla tonto en nuestra casa. Si no necesitamosasegurarnos de si el fichero se ha abierto o no, entonces podemos hacer

abrirFichero(“miFichero.txt”);

e ignoramos el valor que abrirFichero devuelve.

Bueno, ¡pues esto es todo sobre los métodos! Antes de seguir adelante, comosiempre, asegúrate de haber entendido bien los conceptos de:

PROPIEDADMÉTODOTIPO DE DATOS (int, float....)PARÁMETROSVALOR DE RETORNO DE UN MÉTODOSENTENCIA RETURNVOIDRecuerda siempre que un valor de retorno puede ser ignorado

Ejercicio

Una vez hayas entendido perfectamente todo este rollo, puedes escribir ladefinición completa de la clase Mesa. Plantéate qué parámetros le pasaríamos al métodocambiarColor() y qué valor devolvería. ¡Vamos!

Solución

A mí se me ocurre que cambiarColor() tendría como parámetros una únicaString, y no devolvería nada. El resto de la clase ya lo hemos definido.

class Mesa {String color;int numPatas;String forma;

void cambiarColor(String nuevoColor){color = nuevoColor; Empieza lo bueno...

}}

Creación y uso de objetos

Ya tenemos definida la clase Mesa. Ahora quiero crear una mesa. ¿Cómo se haceeso?...

primero: las referencias

Cuando creemos un objeto, la JVM genera una “burbujita” que es nuestro objeto.Claro, que para que ese objeto haga cosas necesitamos “llamarlo” de alguna forma. Siquieres que, en medio de una fiesta atestada de gente tu amigo Miguel te diga, porejemplo, la hora, como digas “¡Dime la hora!”, no te van a hacer ni caso, porque cadauno pensará (si te ha oído) que no le estás llamando a él. Tendrás que decir “¡Miguel,dime la hora!”, para que el señor Miguel te haga caso. En definitiva, que si vas dandogritos por la calle ni Dios te va a hacer caso, mientras que si a cada frase le antepones elnombre de la persona a la que imperas, pues ya te puede atender.

En Java esto es exactamente igual, a cada objeto se le debe dar un nombre parapoder “llamarle” de alguna forma cuando le necesites. Bien, pues a estos nombres se lesdenomina Referencias. Si yo creo dos mesas y quiero cambiar el color de una sóla,¿Cómo le digo a la JVM a qué mesa quiero cambiar el color? Pues fácil, si creo dosmesas, a una la llamo “Margarita” y a la otra “Alberto”, y luego digo que cambie elcolor de Margarita.

segundo: el operador “new”

“new“significa “nuevo”. Y este es un ejemplo de otra cosa que por este simplehecho no va a recibir ningún premio. “new” sirve para

a) crear un nuevo objetob) definir la REFERENCIA a ese nuevo objeto.

¿Cómo se usa? Pues muy fácil:

CLASE REFERENCIA = new CLASE();

por ejemplo:

Mesa Margarita = new Mesa();Mesa Alberto = new Mesa(); por ahora, olvida los paréntesis de “new CLASE()”

¿Por qué esos paréntesis en “new Mesa()”? Por ahora, haz caso al pez.

Pues ya sabemos definir objetos e incluso crearlos! Ahora, vamos a aprender autilizarlos.

Supongamos que quiero crear dos mesas, Margarita y Alberto, y quiero cambiarel color de la mesa Margarita. Tendré que llamar al método cambiarColor() de la mesaMargarita. ¿Cómo se hace esto? Pues usando algo tan tonto y tan simple como un punto:

Mesa Margarita = new Mesa();Mesa Alberto = new Mesa();Margarita.cambiarColor(“Rojo”);

¿Quiero cambiar el color de la mesa Alberto?

Alberto.cambiarColor(“Azul”);

Ya está. Hala. ¿Parecía complicado todo esto? Pues ya ves qué complicaciónmás grande. Ya sabemos definir objetos, crearlos y usar sus métodos. Para que teconvenzas, aquí tienes un cachito de mi práctica de Junio:

log.write(" tipoReserva = "+r.getTipoReserva()); log.write(" horaInicio = "+r.getHoraInicio()); log.write(" horaFin = "+r.getHoraFin()); log.write(" fecha = "+r.getStringFecha();

Sabiendo que “log” y “r” son objetos, ¿Hay algo complicado? ¿Hay algo que noentiendas? ¡Claro que no!

Constructores

A primera vista, parece que “new” es un CONSTRUCTOR, porque su misión esconstruir nuevos objetos. Bueno, pues nooooop. “new” INVOCA a un constructor, NOES un constructor. Bueno, no es tan difícil. “new” invoca a un constructor. Vale. ¿Yqué es un constructor?

Un constructor es un método especial, propio de cada clase. Su función esINICIALIZAR el contenido, las propiedades, el estado, etc etc del objeto. Podemoshacer que cuando creemos una mesa cualquiera, comience siendo cuadrada de cuatropatas y azul. Pero eso lo veremos luego.

¿Por qué el constructor es especial? Por varias razones:

Primero: se invoca UNA VEZ para cada objeto. Los métodos de un objeto sepueden llamar todas las veces que quieras:

Margarita.cambiarColor(“rojo”); // y acto seguido....Margarita.cambiarColor(“azul”); // y otra vez...Margarita.cambiarColor(“verde”);

Sin embargo, el constructor va a ser invocado una sóla vez, cuando lo diga“new”.

Segundo: nunca devolverá ningún valor

Tercero: sin embargo, no se define como “void”. Recuerda que cuando unmétodo no devuelve ningún valor, se define como “void”. Bueno, pues elconstructor no.

Cuarto: su nombre es el mismo nombre de la clase a la que pertenece. Nopuedes escoger el nombre del constructor.

¿Recuerdas los paréntesis a los que se refería el pez?

Mesa Margarita = new Mesa();

¿Por qué estos paréntesis? Pues está ya claro: “Mesa()” es el nombre de unmétodo, el CONSTRUCTOR, y por eso lleva paréntesis.

Bueno, pues una vez dicho esto, vamos a cambiar un poco lo que decíamos sobreel uso de “new”, y vamos a cambiarlo por:

CLASE REFERENCIA = new CONSTRUCTOR();

Antes de seguir, asegúrate de entender bien los conceptos de

REFERENCIAOPERADOR PUNTO “.”

NEWCONSTRUCTOR

Definición de constructores

Vamos a definir un constructor para la clase Mesa. Nuestra intención, hacer quecada mesa nueva sea cuadrada, azul y con cuatro patas. Bueno, pues es muy fácil,añadimos a la clase el método en negrita:

class Mesa { String color; int numPatas;

String forma; RECUERDA: el constructor tiene el

void cambiarColor(String nuevoColor){ mismo nombre que su clase, color = nuevoColor; no devuelve ningún valor, } y se define sin “void”

Mesa() { color = “azul”; numPatas = 4; forma = “cuadrada”; }}

Ahora, cuando hagamos

Mesa Margarita = new Mesa();

Margarita será una mesa cuadrada azul de cuatro patas, ¡Una mesa encondiciones, vaya!

Pero hay un problema: yo no quiero mil mesas iguales. Yo quiero crear una mesacomo a mí me dé la gana, yo no quiero que todas las mesas sean azules y cuadradas concuatro patas. ¿Se te ocurre algo para solucionar esto?

¡Podemos definir un constructor con parámetros! Así, cuando creemos una mesale daremos su color, su número de patas y su forma iniciales. A ver, sería algo así:

Mesa(String colorInicial, int numPatasInicial, String formaInicial){color = colorInicial;numPatas = numPatasInicial;forma = formaInicial;

}

Esto es genial. Ahora podemos hacer:

Mesa Margarita = new Mesa(“rojo”, 4, “redonda”);Mesa Catalina = new Mesa(“verde”, 3, “triangular”);

Hala. ¿Qué constructor te gusta más? Podemos prescindir de uno de ellos.Aunque, gracias a algo que llamaremos “Polimorfismo”, podemos quedarnos con losdos constructores A LA VEZ. (¡Vaya! dos constructores diferentes!)

El Polimorfismo permite tener varios métodos diferentes entre sí y con el mismo nombre. Un buen momento para echarle un vistazo!

Si te digo la verdad, yo pocas veces uso los constructores con parámetros (queno significa que sean malos, ¿eh? no te creas......). En su lugar, utilizo los.....

Métodos get/set

Cuando no definimos un constructor en una clase, al invocar “new” la JVMusará el CONSTRUCTOR POR DEFECTO, que inicializa las propiedades del objetocon ceros, referencias nulas, etc (¡que lo de “referencias nulas” no te asuste! ya loveremos). Para inicializar las propiedades usamos un constructor “personalizado”,“propio”, “característico”, o como lo quieras llamar. Estupendo.

supón que en medio del programa quiero cambiar UNA SOLA propiedad de unobjeto. En nuestro caso, puedo cambiar el color. Pero imagina que tengo una mesa roja:

Mesa Margarita = new Mesa(“rojo”, 4, “redonda”);

Y quiero hacer que sea amarilla. Bueno, pues tengo dos opciones:

primera: crear una nueva mesa, casi igual:

Mesa Margarita = new Mesa(“amarillo”, 4, “redonda”);

(Esto parece guai, pero te aseguro que no siempre va a resultar fácil)

segunda: definir una serie de métodos que cambien UNA SOLA propiedad delobjeto. A este tipo de métodos se les denomina “métodos set”, porque suelen comenzarcon la palabra “set” (“poner”):

Vamos a definir tres nuevos métodos para nuestra clase Mesa:

void setColor(String nuevoColor){color = nuevoColor;

}

void setForma(String nuevaForma){forma = nuevaForma;

}

void setNumPatas(int nuevoNumPatas){numPatas = nuevoNumPatas;

}

Fíjate tú qué cosas, oche. Ahora resulta que “setColor” y “cambiarColor” hacenexactamente lo mismo. Prescindiremos de uno de ellos. Por ejemplo, de“cambiarColor”.

Está bien esto, ¿eh?

Bueno, tómate un respiro, y vamos a por los métodos “get”. Su función esobtener (get) el valor de una propiedad determinada. No es difícil adivinar que todométodo “get” se definirá con algún tipo de dato de retorno (int, String...) y que ademástendrá un “return”. Normalmente los métodos “get” no tendrán parámetros. ¿Recuerdastodo eso? Si no, ya sabes....

Vamos a definir los métodos “get” de nuestra clase Mesa. Empecemos con elcolor. Llamaremos al método “getColor”. Ya que el color es una String, getColordevolverá una String:

String getColor(){return color;

}

De forma semejante haremos con getForma:

String getFoma(){return forma;

}

getNumPatas devolverá un valor entero:

int getNumPatas(){return numPatas;

}

Bueno, pues resumimos nuestra clase Mesa; tres propiedades, tres métodos “set”para definir esas propiedades, tres métodos “get” para obtener el valor de laspropiedades, un constructor con parámeros y otro sin parámetros, y pasamos delmétodo “cambiarColor”. La clase Mesa está escrita en la siguiente página. Aquí nocabe....

class Mesa {String color;int numPatas;String forma;

void setColor(String nuevoColor){color = nuevoColor;

}

void setNumPatas(int nuevoNumPatas){numPatas = nuevoNumPatas;

}

void setForma(String nuevaForma){forma = nuevaForma;

}

String getColor(){return color;

}

String getForma(){return forma;

}

int getNumPatas(){return numPatas;

}

Mesa(String colorInicial, int numPatasInicial, String formaInicial){color = colorInicial;numPatas = numPatasInicial;forma = formaInicial;

}

Mesa() {color = “azul”;numPatas = 4;forma = “cuadrada”;

}}

Variables de clase. Modificador static.

Supón que tenemos una empresa que publica páginas web en Internet para otrascompañías. Supón que, como empresa que somos, en cada página queremos anunciarnuestros servicios, por ejemplo, poniendo nuestro número de teléfono. Así, cada vez quealguien visitase la página de uno de nuestros clientes sabría cuál es nuestro teléfono paraasí poder contratar nuestros servicios. Hasta aquí bien, ¿verdad?

Vale. Supón que tenemos una clase paginaGué con las propiedades dirección,contenido y numeroTeléfono. Cada vez que creemos una página, le daremos uncontenido, una dirección y nuestro número de teléfono. Por supuestodefinimos en la clase todos los métodos set y get necesarios. Creo que eresAhora supón que cambiamos nuestra sede y, por tanto, totalmente capaz de nuestro número de teléfono. escribir la clase paginaGué

¡Dios! ¡Hemos creado mil páginas weby ahora tenemos que cambiar el número deteléfono de todas! ¡Mil llamadas al métodosetNumeroTeléfono!

Pues no, si hacemos que todoslos objetos de la clase paginaGué compartanla propiedad numeroTeléfono. Así, si cambiamosel número de teléfono de una sola página, cambiará el de todas las demás páginas. Guai.

Creo que este ejemplo es muy ilustrativo, ¿verdad? Bueno, pues pasemos a laacción.

En Java, una propiedad que se comparte por todos los objetos de una clase sellama “variable (propiedad) de clase” o “estática”. ¿Por qué? La primera denominaciónhace referencia a que podemos entender que una variable compartida NO pertenece a lospropios objetos, sino sólo a su clase. Es como si las Ideas de Platón definiesen no sólolas propiedades y el comportamiento de los objetos físicos, sino que además definiesenel contenido de alguna propiedad. Si todas las mesas fuesen de madera, la propiedad“material” de una mesa estaría definida en la Idea de mesa, no en cada mesa.

Bueno, pues es sólo una idea. Respecto al otro nombre, “variable estática”, ésteviene dado porque en Java, para definir una variable compartida se le antepone elmodificados “static”:

static int numeroTeléfono;

Hala. Pues ya está. Añadiendo un “static” antes de una propiedad hacemos queesa propiedad sea compartida por todos los objetos.

Supón ahora que queremos saber cuántas mesas hemos fabricado. Bueno, puesvamos a añadir una propiedad estática numMesasFabricadas a la clase Mesa.

Inicialmente, numMesasFabricadas valdrá cero, pero cada vez que un constructor seainvocado, aumentará en una unidad. Después definiremos un métodogetNumMesasFabricadas() para saber cuántas mesas llevaremos creadas. Bueno, puesla clase Mesa quedaría definida asín (de nuevo, en una hoja aparte):

class Mesa {String color;int numPatas;String forma; static int numMesasFabricadas = 0;void setColor(String nuevoColor){

color = nuevoColor;}

void setNumPatas(int nuevoNumPatas){numPatas = nuevoNumPatas;

}

void setForma(String nuevaForma){forma = nuevaForma;

}

String getColor(){return color;

}

String getForma(){return forma;

}

int getNumPatas(){return numPatas;

}

Mesa(String colorInicial, int numPatasInicial, String formaInicial){color = colorInicial;numPatas = numPatasInicial;forma = formaInicial;numMesasFabricadas = numMesasFabricadas + 1;

}

Mesa() {color = “azul”;numPatas = 4;forma = “cuadrada”;numMesasFabricadas = numMesasFabricadas + 1;

}

int getNumMesasFabricadas() {return numMesasFabricadas;

}}

Y ya está. Ahora, si hacemos:

Mesa Margarita = new Mesa(“Azul”, 3, “redonda”);int num1 = Margarita.getNumMesasFabricadas();

Mesa Catalina = new Mesa(“Verde”, 4, “triangular”);int num2 = Catalina.getNumMesasFabricadas();int num3 = Margarita.getNumMesasFabricadas();

¿Cuánto valdrán num1, num2 y num3? Pues, respectivamente, 1, 2 y 2.

Tal vez te hagas la preguna siguiente: si podemos definir propiedadescompartidas, ¿Podemos hacer lo mismo con los métodos? ¿Tiene sentido definir unmétodo compartido? ¿Cómo se hace? ¿Una existencia divergente implica un universodivergente?

Bueno, pues sí se puede definir un método estático, y sí que tiene sentido.Además, se hace igual que con las propiedades, anteponiendo un “static” a la definicióndel método. Lo de la existencia lo dejamos para otro momento.

Por ejemplo, podemos saber cuál es el número de mesas fabricadas sin necesidadde “preguntárselo” a una mesa determinada. ¡Podemos preguntar a la propia clase Mesa!Cambiamos el método:

static int getNumMesasFabricadas() {return numMesasFabricadas;

}

y ahora podemos hacer:

Mesa Margarita = new Mesa(“Azul”, 3, “redonda”);int num1 = Mesa.getNumMesasFabricadas();

Mesa Catalina = new Mesa(“Verde”, 4, “triangular”);int num2 = Mesa.getNumMesasFabricadas();int num3 = Mesa.getNumMesasFabricadas();

Fíjate que la llamada a getNumMesasFabricadas() la hacemos sobre Mesa y nosobre un objeto determinado. Bueno, éste hecho no debe traerte de cabeza nunca de losjamáses, ¡de verdad! los métodos y las variables estáticas no es que se usen demasiado,¿eh? Además, los puristas de la OOP (que son personas) no admiten nada estático, nipropiedades ni métodos, salvo en una excepción: las constantes.

Constantes

¡Sí! También podemos definir constantes en Java. Una constante, comocomprenderás, no sólo no puede cambiar de valor: además, debe ser compartida portodos los objetos. Vaya una constante tan estúpida aquélla que no es la misma en todoslos objetos de la clase donde esa constante se define. En Pascal, C, C++, BASIC, etc etcetc las constantes se definen como const (de constant). Bueno, pues en Java, como es unlenguaje tan especialito el jodío, se definen con final.

Es decir, que si yo quiero definir una constante, por ejemplo, pi, hago:static final int pi = 3,1415926535897932384626433832795;

Hala. Ahora pi es una variable compartida por todos los objetos de la clase en lacual hemos definido la propia pi, y además no puede cambiar de valor. Hala.

Antes de seguir adelante, ya sabes...

VARIABLE COMPARTIDAMODIFICADOR STATICMÉTODO COMPARTIDOLLAMADAS A MÉTODOS MEDIANTE EL NOMBRE DE LA CLASE

( Mesa.getNumMesasFabricadas() )MODIFICADOR FINAL

Para comerse el coco..... (3)

La clase Math contiene métodos que hacen cálculos numéricos, comocoseno, seno, etc..... Si miras la definición de estos métodos, verás que ningunose salva, todos son métodos static. ¿Por qué crees que es así?

El método main, arrays y ¡a lanzar programas!

Seguro que te has dado cuenta de que hemos definido mil clases, métodos ypropiedades, pero que realmente todavía no hemos hecho ningún programa. Bueno.Vamos a solucionar eso.

Un programa siempre tiene un punto de arranque, es decir, empieza en unmomento determinado. Bueno, pues en Java, este punto de arranque se llama métodomain.

Un programa suele constar de varios archivos, uno por cada clase que definimos.Bueno, pues en una de estas clases debemos definir el método main. Comocomprenderás, será una buena práctica de programación definir una claseexclusivamente para albergar el main. No es necesario, pero es muy buena práctica, esdecir, que al margen de toda nuestra fabulosa colección de clases definimos otra máscuyo contenido sea un sólo método main. Bueno, pero vamos con el propio método.

El main se define siempre igual, por norma en Java. Es un método:

estático: ya sabes qué es esto.público: si lo sabes, te felicito. Básicamente significa que puede accederse a este

método desde cualquier lugar, a diferencia de otros métodos que puedenser privados. Bueno, ya lo veremos, ¿vale?

no devuelve datos: se define como voidse llama siempre “main”recibe como argumentos un array de Strings: también lo veremos.

main queda definido entonces como:

public static void main(String[] IDENT)

Como comprenderás, IDENT es un identificador al que puedes llamar como tedé la gana. Normalmente recibe el nombre arg o args. ¿Para qué sirve?

Cuando ejecutamos un programa Java, lo que hacemos es escribir

java clase

y esto invoca a la JVM. Pero nosotros somos muy listos, y podemos arrancar elprograma pasándole argumentos:

java clase arg1 arg2 arg3 ... argn

Bueno, pues la JVM coge estos argumentos los mete en una lista. A este tipo delistas se les denomina array, y funciona de la siguiente manera:

Un inciso: arrays

Un array es una lista ordenada de elementos. Cada elemento tiene asociado uníndice. El primer índice es el cero, y el último depende del número de elementos quehaya guardados en el array.

Un array, como una variable cualquiera, tiene un TIPO (int, float, String...) y unIDENTIFICADOR. Veamos cómo se declaran:

tipo[] IDENT = new tipo[tamaño];

por ejemplo, hagamos un array de Strings de 5 posiciones:

String[] miArray = new String[5];

y usamos el array como si fuese una variable normal, pero teniendo en cuenta losíndices en los que guardamos valores:

miArray[0] = “Posición primera...”;miArray[1] = “... segunda...”;miArray[2] = “...tercera...”;miArray[3] = “...cuarta...”;miArray[4] = “y al siguiente día dejé el colegio”;

Para saber el número de posiciones de un array usamos el operador .length¡Fíjate en el punto inicial de .length!:

int tamaño = miArray.length;

Ahora tamaño vale 5.

sacabó el inciso.

Sigamos con el main.

public static void main(String[] args)

Cuando invocamos a la JVM, ésta determina el número de argumentos quehemos introducido en

java clase arg1 arg2 arg3 ...

y crea el array que hemos llamado args. Bueno, Podemos, por ejemplo, escribirun programa al que le pasemos como argumentos un color y la forma, y él nos cree unamesa con cuatro patas y con ese color y esa forma. Usando System.out.printlnpodemos mostrar en pantalla las propiedades de la mesa.

Meteremos el main en una nueva clase MesaMain (archivo MesaMain.java):

class MesaMain{public static void main(String[] args) { Mesa Margarita = new Mesa( args[0], 4, args[1] ); System.out.println(“Hemos creado una mesa”); System.out.println(“con ”+Margarita.getNumPatas()+” patas,”); System.out.println(“de color “+Margarita.getColor()); System.out.println(“y de forma “+Margarita.getForma());}

}

Ahora, si compilamos Mesa y MesaMain con:

javac Mesa.javajavac MesaMain.java

y hacemos:

java MesaMain rojo, redonda

el programa nos dice:

Hemos creado una mesacon 4 patas,de color rojoy de forma redonda

Hala. Nuestro primer programa. Es una pena, normalmente el primer programaque se escribe es mostrar en pantalla el saludo “Hola mundo!”, pero alguna vez hay quesaltarse las reglas, ¿no? De todas formas eres perfectamente capaz de programar talsaludo, ¿no? Haz una clase Saludo que contenga un main que muestre en pantalla elsaludo “¡Hola mundo!”. En total, cinco líneas de código.

¡Cuidado! El programa MesaMain exige que metamos al menos dosargumentos. Si ponemos sólo uno, habrá un error, y si ponemos siete, los últimos cincose ignorarán.

Programando a lo bestia. Estructuras de control.

Hay una serie de estructuras que la mayoría de los lenguajes de programaciónposeen. Son las estructuras del control.

Estas estructuras son fundamentalmente las condicionales y las repetitivas.Empecemos por las primeras.

Sentencias condicionales

sentencia if

if es la estructura condicional por antonomasia en todos los lenguajes. Susintaxis es muy fácil:

if (condición) {bloque1

} else {bloque2

}

Si cualquier bloque consta sólo de una sentencia, entonces las llavescorrespondientes a ese bloque pueden eliminarse. Es cuestión de comodidad.

Expliquemos. la condición es una expresión lógica, es decir, booleana. Si estaexpresión da como resultado TRUE, se ejecuta el bloque1, mientras que si la expresiónes FALSE se ejecuta bloque2. Así de simple. Claro, que queda un poco al aire eso de laexpresión booleana. Veámosla:

Una expresión booleana es cualquier cosa que pueda dar como resultado TRUEo FALSE. Por ejemplo, la comparación de dos variables.Este es un buen momento paraver los comparadores de magnitud:

== igual a!= diferente de> mayor que< menor que >= mayor o igual que<= menor o igual que

Una expresión lógica puede ser combinación de expresiones lógicas máspequeñas combinadas con los Y, O, NO que ya conocemos, ¿verdad? En Java seescriben así:

AND &&OR ||NOT !

Bueno, pues ya no deben asustarte cosas como

((n1 > 5) && (n2 < 3)) || !(n3 >= n4)

Otro tipo de expresión booleana puede ser un valor boolean devuelto por unmétodo. Veamos un ejemplo:

Para saber si dos números son iguales utilizamos el símbolo ==

if (num1 == num2){System.out.prinln(“Son iguales”);

} else {System.out.println(“Son diferentes”);

}

Sin embargo, para saber si dos String son iguales no podemos utilizar elsimbolo de igualdad. Es una peculiaridad de Java que no viene ahora a cuento:

Aparentemente, si tenemos

String string1 = “Hola”;String string2 = “Hola”;String string3 = “Adiós”;

la expresión booleana ( string1 == string2 ) debería ser TRUE, pero no es así.

Para comparar Strings utilizamos el método .equals() Éste es un método quefunciona de la siguiente manera: partiendo de las strings anteriores,

string1.equals(string2) da un resultado de TRUE, mientras questring1.equals(string3) da como resultado FALSE.

En definitiva, .equals() es el método que utilizamos para comparar una Stringcon otra. Como ves, un método puede devolver un valor booleano, por lo que este valor puede ser utilizado en una sentencia if:

if (string1.equals( string2 )) { RECUERDA:System.out.println(“Son iguales”); los números se comparan

} else { con == != > < >= <=System.out.println(“Son diferentes”); pero las Strings se comparan

} con .equals()

por supuesto, dentro de un bloque de un if podemos anidar más ifs:

if (tal y cual) {hacemos esto

if (nosequé){pues esto otro

} else {y si no, esto

}

} else {

if (vaya rollo){ bah, yo me piro

} else {paso de todo

}}

Una sentencia if puede definirse sin su else correspondiente:

if (string1.equals(string2)){System.out.println(“Son iguales”);

}...

Pero hay que tener mucho cuidado con esto, sobre todo si anidamos ifs.Supongamos que queremos comparar dos enteros n1 y n2, y saber si son iguales o si n1> n2. No nos importa saber si n2 > n1. Recuerda que cuando un bloque consta sólo deuna sentencia (que puede ser perfectamente una sentencia if), las llaves puedeneliminarse.

int n1 = 1;int n2 = 10;

if (n1 != n2)if (n1 > n2)

System.out.println(“n1 > n2”);

// no comprobamos si n2 > n1

else System.out.println(“Son iguales”);

Bueno, pues este fragmento es erróneo. Si n1 y n2 son iguales, el programa noavisa. De hecho, tomando los valores 1 y 10, el programa dice que son iguales. La razónes que el else aparentemente pertenece al primer if, pero en realidad pertenece alsegundo if! El fragmento correcto sería el siguiente:

int n1 = 1;int n2 = 10;

if (n1 != n2)if (n1 > n2)

System.out.println(“n1 > n2”);else

// cualquier sentencia que no haga nada, por ejemplon1 = n1;

elseSystem.out.println(“Son iguales”);

¡Bueno, hay que pasar siempre por estas cosas! Mucho cuidado cuando anidesifs, pon siempre sus elses, aunque no hagan nada. Otra opción, tal vez te guste más, esla siguiente:

int n1 = 1;int n2 = 10;

if (n1 != n2)if (n1 > n2)

System.out.println(“n1 > n2”);else { } // bloque de código vacío

elseSystem.out.println(“Son iguales”);

Aquí hacemos uso de un bloque vacío, lo delimitamos con { }, y sin embargo nometemos nada entre esas llaves. Bueno, todo son opciones.

Personalmente te recomiendo que cuando empieces a programar siempreescribas las llaves, aunque encierren una sóla sentencia, o aunque estén vacías:

int n1 = 1;int n2 = 10;

if (n1 != n2) {

if (n1 > n2) {System.out.println(“n1 > n2”);

} else { }

} else {System.out.println(“Son iguales”);

}

Así siempre verás claramente los bloques y la dependencia de ifs y elses.

Como verás en las pruebas de programas, las sentencias condicionales sonsiempre una fuente de errores, debido, por ejemplo, a cosas como estas. Estos errores seeliminan mediante las pruebas de caja blanca, es decir, conociendo el código delprograma. Si tienes que probar un programa y te dan el código, mira siempre ladependencia de ifs y elses, ¿vale?

sentencia switch

Esta sentencia es muy peculiar. Permite ejecutar determinada parte de unfragmento de código en función de un número enteo. Me explico.

switch (expresión) {

case caso1:bloque1

case caso2:bloque2

.

.

.}

Bueno, pues esto es fácil. Vamos a ver. expresión es un número entero. Si hayalgún caso que coincida con ese número entero, entonces se ejecutan todos los bloquesque haya a partir de ese caso, no sólo el bloque que corresponde a ese caso. Unpoco raro, ¿no? Bueno, veamos un ejemplo:

switch (n){

case 1:System.out.println(“uno”);

case 2:System.out.println(“dos”);

case 3:System.out.println(“tres”);

}

Date cuenta de que no es necesario poner llaves, sean los bloques como sean,una sentencia o más.

Si n = 1, por lo que se ejecuta el caso 1 y todos los casos posteriores, es decir,el 2 y el 3. Por eso, si n = 1 se imprimiría en pantalla

unodos tres

mientras que si n = 2 se imprimiría

dostres

y si n = 3, pues se mostraría

tres

Por la razón que hemos visto. Repito. Se ejecuta el bloque que corresponde alcaso y los bloques siguientes. Por eso, si n = 1, se ejecuta el caso 1 y los siguientes, esdecir, los casos 2 y 3.

¿Hay alguna forma de hacer que se ejecute sólo el caso que corresponda, y queno se ejecuten los casos siguientes? ¡Pues claro! usando break:

switch (n){

case 1:System.out.println(“uno”);break;

case 2:System.out.println(“dos”);break;

case 3:System.out.println(“tres”);break;

}

ahora, si n = 1, se muestra en pantalla

uno

a diferencia de antes.

Otra cosa sobre los switches: existe un caso especial, el llamado default. Seejecuta este caso si no hay otro caso que corresponda a la expresión:

switch (n){case 1:

System.out.println(“uno”);case 2:

System.out.println(“dos”);case 3:

System.out.println(“tres”);case default:

System.out.println(“más de tres”);}

Aquí, si n = 4, se mostraría en pantalla

más de tres

mientras que si n = 1, se vería

unodostresmás de tres

Bueno, no es tan mortal.

Para comerse el coco...... (4)¿se te ocurre algún error en el siguiente código de programa?

switch (n){case 1:

System.out.println(“uno”);break;

case 2:System.out.println(“dos”);break;

case 3:System.out.println(“tres”);break;

case default:System.out.println(“más de tres”);

}piensa, piensa............

Sentencias repetitivas (o iterativas)

Adivina por qué se llaman así. Nos permiten repetir determinado fragmentode código un número definido de veces.

En realidad lo que se hace es determinar una condición, una expresión lógica.Así, mientras esta expresión sea TRUE el fragmento se repite, hasta que sea FALSE. Esdecir, que no definimos un número de repeticiones, sino una condición para que se

repita. Naturalmente podemos adecuar una condición para que un fragmento se repitaun número determinado de veces. Bueeeno, poco a poco. Vale.

Ya hemos tomado contacto con las expresiones lógicas, ¿verdad? Fantástico.Apréndetelas bien, porque las vas a usar muncho muncho muncho.

while

permite repetir un bloque mientras una condición sea TRUE. Primero secomprueba la condición, y si es TRUE entonces se ejecuta el bloque:

while (condición){bloque

}

Un ejemplo:

int n = 0;

System.out.println(“a contar”);

while (n <=10) {System.out.println(“Voy por el ”+n);n = n + 1;

}

System.out.println(“¡Ay!, que me canso”);

Bueno, pues está claro, este fragmento inicializa n a cero, y mientras n <= 10hace lo que está entre llaves, es decir, imprimir el mensaje y aumentar n en una unidad.Es decir, cuenta de cero a diez.

Por supuesto puedes meter whiles, ifs y todo lo que quieras dentro de un while.

Esto ya lo sabrás, pero es mi obligación avisarte: Las sentencias repetitivas sonuna fuente inagotable de errores. Tienes que tener mucho cuidado a la hora de usarlas,que va a ser siempre, por cierto. Por favor, ten mucho cuidado en cómo usas las cosas,cómo planteas las condiciones, el orden de las líneas dentro de un bloque.... cualquiercosa puede hacer que tu programa estalle. ¿Qué ocurriría si invertimos el orden de lasdos líneas del bloque del while anterior? ¿y si ponemos como condición n < 10?

Por estas razones suele haber una regla, que no siempre se cumple, ni tienes porqué cumplirla, pero es conveniente:

primero, inicializamos las variables en el primer caso del bucle. Si quierocontar de 0 a 10 empiezo en 0. Parece obvio, pero no lo es.

segundo, la condición tiene que aceptar el primer valor. Es estúpido que nopueda entrar en el bucle en el primer caso.

tercero, las variables se actualizan al final del bloque. Es decir, es aconsejableque las variables cambien de valor justo en el final del bloque, no en la mitad ni alprincipio. Fíjate, el “n = n + 1” está al final.

Repito que no es una regla general, que no tiene por qué ser así, pero queconviene. De hecho, seguir esta regla a veces complica la existencia una barbaridad.

una variante de while: do – while

while, como hemos dicho, primero comprueba la condición y si es TRUEejecuta el bloque. do – while (o “duguail” para los amigos) primero ejecuta el bloque yluego comprueba la condición. De esta forma, while puede no ejecutar nunca un bloque,ya que primero comprueba la condición, pero do – while, al comprobar la condición alfinal, siempre ejecuta el bloque al menos una vez. Típica pregunta de examen.

Bueno, la estructura es semejante a la del while:

do {bloque

} while (condición)

Y esas “reglas” de antes, yo que tú intentaba aplicarlas aquí también.

for

Esta es la más complicada de todas. Se basa en lo siguiente:

Fíjate que while y do – while tenían como tres partes:

inicialización de las variables condición actualización de las variables

¿te suena?

int n = 0; // INICIALIZACIÓN

System.out.println(“a contar”);

while (n <=10) { // CONDICIÓNSystem.out.println(“Voy por el ”+n);n = n + 1; // ACTUALIZACIÓN

}

System.out.println(“¡Ay!, que me canso”);

Bueno, pues for resume estas tres partes en una sola sentencia:

for (inicialización, condición, actualización){bloque

}

Por ejemplo:

System.out.println(“a contar”);

for (int n = 0; n <= 10; n = n + 1){System.out.println(“voy por el ”+n);

}

System.out.println(“¡Ay! que me canso”);

¿Te percatas de cómo for resume las tres partes en una sola sentencia?

Bueno, ¿Crees que hay más sentencias repetitivas? Pues nooooop. En realidadpuedes hacer una diferenciación muy simple: for se usa cuando sabes cuántas veces seva a repetir un bucle, y while en caso contrario. Por ejemplo, si vas a recorrer un arrayusarás un for porque sabes la longitud del array, sabes su tamaño. Si buscas una letra enuna cadena de caracteres usas un for porque sabes cuántos caracteres tiene esa cadena(usando el método .length() de la clase String, no lo confundas con el .length sinparéntesis de un array), pero si esperas a que el usuario introduzca una clave, porejemplo, usarás un while porque no sabes cuántas veces va a teclear una claveincorrecta. Y recuerda, do – while no es más que un caso de while.

¿Sabes que con lo dicho hasta ahora puedes programar cualquier cosa? Bueno,pero no saltes de alegría hasta haberte convencido de que pilotas los conceptos de

SENTENCIAS CONDICIONALESIF / ELSESWITCH / CASE / CASE ELSESENTENCIAS REPETITIVASWHILE / DO – WHILE / FOR

Para comerse el coco.....(5)Ya sabes que for engloba una inicialización, una condición y una actualización.

¿En qué momento del bucle se produce cada una de estas partes?

Debo decirte que todo en programación se aprende primero mediante teoría, yluego mediante horas de práctica. Eso ya lo sabes. Pero en el uso de bucles ycondicionales es especialmente necesario que practiques con ellos. Trata de hacerprogramas simples (que sean un un solo main) que, por ejemplo, cuenten de un númeroa otro, que cuenten pares, impares, que calculen sumatorios, factoriales..... ¿Se te ocurrealguna forma de calcular los 100 primeros primos? Puedes implementar la criba deErastótenes con dos bucles for anidados y un array de enteros..... En fin, que cualquiercosa que se te ocurra, a por ella sin temor. Hazlo por mí....

Existe otra forma de abordar los problemas que se resuelven mediante sentenciasrepetitivas. Es una visión muy diferente y que, desgraciadamente, cuesta muchoentender. Así que trataré de esforzarme. Es el temido tema de...

Recursividad

Como acabo de decir, la recursividad es una forma de solucionar problemas.Siempre se dice que todo algoritmo iterativo puede traducirse a una forma recursiva, yviceversa. Bueno, pues es cierto: si tienes un algoritmo iterativo puedes cambiarlo yconvertirlo en recursivo. De hecho es una pregunta muy propia de los exámenes deLaboratorio de Programación. Bueno, vamos a ver entonces qué es esto de larecursividad.

La recursividad es un concepto muy abstracto. Así que atención. Consiste en queun fragmento de código se usa a sí mismo. Ese es el corazón de la definición. Porejemplo: hay un cuento que narra cómo un príncipe se metió en un gran barrizal, el cualle impedía caminar, ya que el lodo era demasiado denso. Así que lo que hizo para salirfue tirar él mismo de sus botas hacia ariba, primero una, luego la otra, y así conseguía lafuerza suficiente para avanzar por el barrizal, y logró salvarse.

Bueno, es un ejemplo muy simple de cómo algo puede usarse a sí mismo.Desgraciadamente abordaremos este tema de una forma más difícil.

Hay un ejemplo típico del uso de la recursividad. Es el cálculo de factoriales. Yasabes:

n! = n · (n-1) · (n-2) · ... · 3 · 2 · 1

pero, fíjate:

n! = n · (n-1) · (n-2) · ... · 3 · 2 · 1(n+1)! = (n+1) · n · (n-1) · (n-2) · ... · 3 · 2 · 1

entonces,

(n+1)! = (n+1) · n!

y, por tanto,

n! = n · (n-1)!

Vale. Cursillo intensivo de Calculo I. Bueno. Observa que la definición defactorial engloba un factorial. Por eso es recursivo.

Para ver fácilmente cómo funciona la recursividad, vamos a considerar elsiguiente ejemplo. A ver si te gusta.

Supón la cola de la taquilla del cine. Si, antes de entrar a ver la película hay unascuantas personas comprando la entrada. Aquí las tenemos:

En un momento dado, el último de ellos, el de la camiseta amarilla, desea saber aqué hora es la siguiente sesión. Así que lo que hace es preguntárselo al de la camisetaroja:

Pero, claro, resulta que el de la camiseta roja tampoco lo sabe. Un fastidio. Asíque lo que hace es preguntárselo al de las rastas, mientras mantiene al de la camisetaamarilla a la espera.

Pero el de las rastas tampoco lo sabe. Así que hace la misma pregunta al de loszapatos amarillos, mientras mantiene al de la camiseta roja a la espera. Por supuesto, elde la camiseta amarilla sigue a la espera de que le responda el de rojo.

En fin, puedes adivinar que el de los zapatos amarillos no tiene ni idea, así que loque hace es preguntárselo a la taquillera de los pelos rojos. El de las rastas se quedaesperando a que el de los zapatos amarillos le responda. A todo esto, el de rojo estáesperando al de las rastas, y el de la camiseta amrilla está hartándose de esperar.

Pero ¡vaya! resulta que la taquillera de los pelos rojos, a pesar de ser su primerdía de trabajo, está muy puesta en el tema y sabe la respuesta. Claro, que ella responde aquien le ha preguntado, al de los zapatos amarillos:

Ahora que el de los zapatos amarillos sabe la respuesta, se la dice al de las rastas,que le estaba esperando. El de rojo sigue esperando, claro, y el de la camiseta amarilla,ni te cuento.

Ahora el de las rastas ya sabe la respuesta. Pues va y contesta a quien le hapreguntado. El de la camiseta amarilla, todavía sigue esperando.

Una vez que el de rojo sabe la respuesta, por fin, se la dice al de la camisetaamarilla, que es el primero que preguntó, justito antes de que le diera un ataque dehisteria.

En fin, acabas de ver intuitivamente cómo funciona un algoritmo recursivo. Elprimero llama al segundo y espera a que le responda. El segundo llama al tercero yespera a que le responda, mientras el primero sigue esperando. Y así sucesivamente... yasí recursivamente....

Todo método recursivo tiene parámetros y valor de retorno. Es parte del juego.¿Por qué?

Bueno, vayamos poco a poco. Un algoritmo recursivo trata de resolver unproblema, por ejemplo, el método factorial() halla un factorial., por ejemplo, 5!. Siqueremos calcular 5! debemos pasar ese 5 al método:

float resultado = factorial(5);

Lo cual ya es una buena razón para pensar que el método necesita parámetros.Pero, lo mejor de todo, y lo más importante es que el propio método “factorial()”llamará a “factorial()” pero con otro parámetro. factorial(5) llama a factorial(4), yéste a factorial(3), y así sucesivamente. Por tanto, es más que obvio que un métodorecursivo necesita parámetros. Ufff...

Pensar que un método recursivo no ha de tener parámetros es como pensar queen la cola del cine el de la camiseta amarilla pregunta al de rojo “disculpe, ¿podríadecirme?”

Decíamos que un método recursivo siempre devolverá un valor. Claro, ¿Por qué?Pues muy sencillo: cuando factorial(5) llama a factorial(4) lo hace para averiguar elfactorial de cuatro. Así que factorial(4) debe devolver un valor, exactamente 24.

Pensar que un método recursivo no devuelve ningún valor es como pensar queen la cola del cine el de rojo responde al de amarillo “¡claro! la película empieza a las”.Joer, imagina la conversación.

En definitiva, esto es una especie de demostración intuitiva para que te percatesde que un método recursivo necesita, exige, precisa y requiere parámetros, ysiempre devuelve algún valor. Si algún método recursivo no tiene parámetros y/o nodevuelve algún valor, es porque tiene un diseño extraño, poco común.

Mi compañero de la práctica de Programación, primer cuatrimestre, resolvióvarios problemas de la práctica mediante un método recursivo que ni tenía parámetros,ni devolvía valores. Y funcionaba a las mil maravillas. Pero, repito, es un caso muyraro. Yo jamás habría hecho tal método recursivo, sino iterativo. O sea, que la máximade antes no es tal máxima, pero yo te aconsejo que la sigas siempre que puedas.

Todo método recursivo consta de tres partes. Primero veamos esas partes y luegote pondré un ejemplo, vale?

a) caso base: el caso en el que no se necesita una llamada recursiva. Porejemplo, factorial de 1.

b) caso no base: el caso en el que se hace la llamada recursiva. Por ejemplo, elfactorial de 36.

c) conquista: consiste en, después de hacer la llamada recursiva, obtener elresultado que piden al método.

El caso base podríamos relacionarlo con la taquillera de los pelos rojos. Ellapuede contestar a la pregunta sin necesidad de preguntar a nadie más, es decir, sin hacerninguna llamada recursiva. El caso no base es cualquiera de las personas de la cola:para resolver la duda han de planteársela a otra persona, no pueden resolverla por símismos. La conquista sería un poco más rara: el paso de la respuesta que a uno le ha

llegado hacia la persona que le ha preguntado. Es decir, el de rojo lleva a cabo laconquista cuando el de las rastas le responde, y el de rojo toma esa respuesta y se la daal de amarillo.

No confundas caso no base y conquista: el caso no base es la condición, y laconquista es la acción. Huy, qué bonito.

Bueno, lo prometido es deuda. Vamos a implementar el método factorial. Loimplementaremos poco a poco, así que no te hagas un lío con las llaves, ¿vale?

Bueno: primero necesitamos parámetros, un entero, y devolveremos un enterolargo:

long factorial( int numero ) {

Vamos a definir un entero largo, que será la respuesta que el método devolverá:

long respuesta = 0;

Ahora debemos diferenciar entre caso base y caso no base. El caso base será elfactorial de 1, y el caso no base, cualquier otro.

if ( numero == 1 ) { // caso baserespuesta = 1;

} else {

Ahora viene el caso no base. La respuesta se hallará mediante la llamadarecursiva. Ya que n! = n * (n-1)!, haremos:

respuesta = numero * factorial(numero – 1);}

Y por último, la conquista. Debemos devolver la respuesta que hemoshallado a quien nos lo pregunta:

return respuesta;}

Aquí está el método al completo:

long factorial( int numero ) {

long respuesta = 0; // lo que devolveremos

if ( numero == 1 ) { // caso baserespuesta = 1; // devolveremos 1

} else { // caso no base: llamada recursivarespuesta = numero * factorial(numero – 1);

}

return respuesta; // ¡conquista!}

Pues nada, esto compila perfectamente, y funciona. Por cierto, este código notiene tratamiento de errores, así que no le hagas perrerías, tipo factorial(-3), porque se teva a quedar más colgao que el teleférico. Claro, que... ¿Por qué no le haces tú lasmedidas de seguridad? No es difícil... ¡Ánimo!

Bueno, ahora voy a contarte un pequeño truco que nadie cuenta para entenderbien el funcionamiento de un método recursivo.

Verás, cuando un método se llama a sí mismo, imagina que lo que ocurre es queen la memoria del ordenador se hace una copia del método. Así que lo que tú deberíashacer para entender un método recursivo es pensar que existen varias copias del métodoen memoria. Si tienes este código:

long factorial( int numero ) { long respuesta = 0; if ( numero == 1 ) { respuesta = 1; } else { respuesta = numero * factorial(numero – 1); }

return respuesta; }

Trata de pensar que, cuando el programa arranque, por ejemplo, al calcular elfactorial de 3, lo que tendrás es esto:

Uff... no se ve muy bien... he tenido que reducir mucho la letra para que entrenlas tres copias. Sorry. Bueno, pues con esta imagen tú puedes imaginar el proceso que selleva a cabo al calcular factorial(3). El trascurso del programa está marcado con la línearoja.

El dibujo está en la página siguiente, porque es un poco grande. En él puedes vercómo la primera llamada viene desde las alturas, en la parte de arriba a la izquierda. Esallamada “mete” el “3” como parámetro en la primera copia de factorial. Éste, al ver queno es un caso básico, hace la segunda llamada pasando como parámetro “2” a lasegunda copia del método. La segunda copia actúa de forma semejante, pasando “1” a latercera copia. Ésta identifica que es el caso básico y “conquista” la respuesta, en estecaso 1. La respuesta vuelve a la segunda copia, quien lleva a cabo la segunda conquista,devolviendo a la primera copia “2”. La primera copia, a su vez, lleva a cabo suconquista devolviendo al ente en las alturas “6”.

Espero que haya sido una explicación muy gráfica. Creo que no soy capaz deexplicarlo de otra manera mejor, así que, si no lo has pillado bien, releelo tododespacito. Trata de ir muy lentamente, viendo cómo se comporta cada copia defactorial, identificando cada paso con la situación de la cola del cine, ¿vale? Espero quehayas perdido el miedo a la recursividad, y estoy convencido de que cada vez quepreguntes algo a alguien, y este alguien se lo pregunte a otro te acordarás de todo esto.

Hala. Se acabó. ¿Crees que te voy a dejar sin la lista de conceptos? Puesnoooooo...

MÉTODO ITERATIVO / RECURSIVOMETODOLOGÍA DE LA RECURSIÓN: la cola del cine MÉTODO RECURSIVOPARTES DE UN MÉTODO RECURSIVO

caso base, caso no base, conquista

Como curiosidad....¿Sabes por qué se le llama “conquista”? Pues es muy sencillo. Los métodos

recursivos se suelen usar para resolver problemas partiéndolos en cachitos máspequeños. Por ejemplo, buscar a una persona en una cola de gente: primero buscas en lamitad izquierda, y luego en la derecha. Esto lo verás muy profundamente en Laboratoriode Programación. Bueno, pues como ya sabrás, hay un refrán árabe que dice: divide yvencerás. En inglés, “divide and conquer”. De ahí lo de “conquista”.

Bueno, vamos a abordar una de las partes más bonitas de la OOP, aunque traesus dolores de cabeza, no te creas. Algunos lenguajes, como C++ basan gran parte de suingente potencial en esto que llamamos...

Herencia

Bueno, está claro qué es la herencia. Es lo que unos padres dejan a sus hijos. Omejor dicho, lo que unos padres transmiten a sus hijos por vía genética. Las personassomos creadas mediante herencia de genes, a pachas entre papi y mami. En definitiva,que papá y mamá no nos definen desde el principio, sino que toman sus propios genespara crearnos a nosotros. Bueno, afortunadamente esto no es tan fácil en genética comoen programación.

Pero el concepto que te tiene que quedar muy claro es que la herencia es unmecanismo de definición, no un método para suspender a los de primero de Teleco, niun galimatías conceptual, sino que es una forma de definir nuevos objetos a partir delos existentes. La herencia sirve para definir.

En Java una clase sólo puede heredar de otra clase. No se admite que unaclase herede de varias clases, como sí se puede hacer, por ejemplo, en C++. En Java, portanto, no hablamos nunca de herencia múltiple. Además, la herencia en Java sedenomina extensión: decimos que una clase extiende a otra.

Por tanto tenemos que tener en cuenta que, en Java, los objetos sólo tienen unpadre, y además, heredan de él el 100%, no como en las personas que heredan el 50%

Bueno, pues sin más preámbulos nos podemos plantear alguna estructurajerárquica, es decir, algún diagrama de clases en el que dichas clases se relacionenmediante mecanismos de herencia. Por ejemplo, se me ocurre pensar que una moto escomo una bicicleta con motor. De ahí lo de “motocicleta”. Bieeeeen

Bueno, pues pasemos a escribir. Por cierto, veremos muchasel fin de este código que ahora vamos a escribir es clases definidas de formapuramente didáctico, no funcional. muy tonta. A veces incluso sin definir. Eso es porque

Es decir, que vamos a definir una realmente su contenidobicicleta y una moto, pero de una no importa nada.forma muy estúpida. Verás: vamos a definir las clases Rueda y Motor de una forma un tanto peculiar, aunque simpática donde quepa:

class Rueda {void saludar() {

System.out.println(“Soy una rueda”);}

}

class Motor {void saludar() {

System.out.println(“Soy un motor”);}

}

Ahora hacemos que una bicicleta sea, simplemente, dos ruedas:

class Bicicleta {Rueda delantera;Rueda trasera;

Bicicleta(){ // el constructordelantera = new Rueda();trasera = new Rueda();

}

void saludar() {System.out.println(“Soy una bicicleta”);

}}

Bueno, pues vamos a definir la moto. Para hacer que una clase “hijo” extienda aotra “padre”, la primera clase se define así:

class hijo extends padreBueno, pues a ello.

class Moto extends Bicicleta {Motor motor;

Moto() { // el constructormotor = new Motor();

}

void saludar(){System.out.println(“Soy una amoto”);

}}

Estas cuatro clases son lo más fácil del mundo. Si no las entiendes, para y vuelveatrás, porque son de lo más básico. Pero seguro que las entiendes sin problemas,¿verdad?

Fíjate en el uso de la herencia: la clase Moto sólo define un método saludar yuna propiedad Motor, pero hereda de la clase Bicicleta, por lo que también posee todoslos contenidos de Bicicleta. Por tanto, Moto hereda de la clase Bicicleta las dos ruedas.¿Te percatas de cómo se usa la herencia para definir clases? Definimos el contenido deMoto a partir del contenido de Bicicleta.

Respecto al método saludar, fíjate que Motor redefine el método saludar quehereda de Bicicleta. La clase padre tenía un método saludar, pero la clase hija tambiénlo tiene. Se dice que lo redefine (overrides). Sin embargo, debe quedar muy claro queredefinir un método no implica que el método anterior deje de existir, es decir, queel método saludar de Bicicleta sigue existiendo a pesar de haberlo redefinido en laclase moto.

No tendría sentido que una moto saludase como una bicicleta, ¿no? Aunque note creas, que gracias al casting, que en breve veremos, podemos hacer que una motopueda saludar como moto y como bicicleta.

Bueno, pues eso es todo sobre cómo se usa la herencia. Vemos cómo hemosdefinido una moto a partir de la definición de una bicicleta, ¿verdad?. Ahora, encualquier parte del código, por ejemplo, en un main podemos hacer sin problemas:

Bicicleta Antonieta = new Bicicleta();Moto Anacleta = new Moto();

Bueno, pues al crear a Antonieta se crearán las ruedas, y al crear a Anacleta secreará el motor. Podemos hacer sin problemas:

Antonieta.saludar();Anacleta.saludar();

y cada una nos saludaría diciendo lo que son. Hala. Voy a compilar este código aver si da problemas...... no, parece que no los da.

Vamos a plantear una cuestión: una Bici, al crearse, crea las dos ruedas. Unamoto, al crearse, crea un motor. Pero, ¿Se crean las ruedas al crearse la moto? Fíjate enel constructor de la clase Moto:

Moto() { // el constructor

motor = new Motor();}

Pregunta: ¿Crees que al invocar al constructor de Moto se invocaautomáticamente el constructor de su superclase Bicicleta?

Desgraciadamente no. Tal y como estamos, al crear una moto se crea su motor,pero no sus ruedas. Ayayayayyyyyy.... ¿cómo arreglamos esto?

Opción primera: crear específicamente las ruedas en el constructor de la moto:

Moto() { // el constructordelantera = new Rueda();trasera = new Rueda();motor = new Motor();

}

Esto es perfectamente válido. Pero hay otra solución más mejor:

Opción guai: Hacer uso de la palabra super(). Esta palabreja se utiliza en elconstructor de una clase para llamar al constructor de su superclase. Es decir, quesi hacemos:

Moto() { // el constructorsuper();motor = new Motor();

}

entonces, cada vez que creemos una moto se creará “la bicicleta que reside en suinterior” (oh! una lágrima resbala por mi mejilla....) y luego el motor. Es como si

al crear a una persona primero

En definitiva, creas lo que tiene de su cuando una clase extiende padre y luego creas el a otra, el constructor de la resto de cosas. clase hija debe llamar al Una visión muy peculiar, constructor de la clase madre, ¿no crees? y esto se hace mediante Por cierto, conviene super(). que super() sea lo primero que

aparezca en el constructor, antes decualquier otra sentencia. ¿Te has preguntado

por qué super() tiene paréntesis? Deberías adivinarlo,pero por si acaso, te lo digo. super() es el constructor de

la superclase, y recuerda que el constructor no es más queun método un tanto especialito, pero método al fin y al cabo.

Y si no recuerdas mal, los métodos llevan paréntesis siempre....

nota

Cuando una clase hereda de otra no es necesario que llame al constructor de su superclase, perosiempre que crees una clase hija, lo más normal es que sí lo haga. Plantéate la lógica de este hecho: supónun mecánico que sabe que una moto es una bicicleta con motor. Si le piden fabricar una moto, entoncesprimero creará una bicicleta y luego le pondrá un motor. Es decir, primero crea la clase padre y luego lahija. Supón ahora que defines una motopija, que es una moto con aire acondicionado . Pues al crearla,primero crearás una moto y luego le pondrás el aire. Esto implica crear primero una bicicleta, luegoponerle motor para hacer la moto, y luego ponerle el aire para hacer la motopija. Vaya, dos super()....

Weno, pues, como siempre, antes de seguir asegúrate de pilotar:

HERENCIACLASE PADRE / CLASE HIJOUSO DE extendsREDEFINICIÓN (OVERRIDING) DE MÉTODOS

(que a continuación veremos con más detalle)USO DE super()CONCEPTO DE MOTO CON AIRE ACONDICIONADO

¡Animo! ¡ya queda poco de OOP!

Preludio al Casting: las referencias

Bueno, no tiene nada que ver con actores. Qué pena, ¿verdad?

Casting significa algo así como “convertir”. El objetivo del casting es hacer queun objeto que se ha definido mediante herencia se comporte como un objeto de una desus superclases. Es decir, que una moto salude como una bicicleta, o que una moto deje

de tener motor, o cosas por el estilo. En realidad el casting es algo un poco másprofundo, pero empezaremos por lo fácil. No te creas, acabaremos con lo difícil....

Bueno, pues recordemos las definiciones de Moto y de Bicicleta:

class Bicicleta {Rueda delantera;Rueda trasera;

Bicicleta(){ // el constructordelantera = new Rueda();trasera = new Rueda();

}

void saludar() {System.out.println(“Soy una bicicleta”);

}}

class Moto extends Bicicleta {Motor motor;

Moto() { // el constructorsuper(); // llamamos al constructor de Bicicletamotor = new Motor();

}

void saludar(){System.out.println(“Soy una amoto”);

}}

Vamos a crear dos objetos:

Bicicleta Antonieta = new Bicicleta();Moto Anacleta = new Moto();

Si hacemos:

Anacleta.saludar();

veremos en pantalla :

Soy una amoto

Como sabemos, una moto es una bicicleta con motor. Eso significa que unamoto tiene una bicicleta dentro de sí. o lo que es lo mismo, que una moto puedecomportarse como una bicicleta. ¿Cómo? Ahora lo veremos. ¿Para qué sirve? Eso loveremos luego.

Supón que tenéis una vecina que conoce muy bien a tu madre, mucho mejor quea ti. Un buen día te ve y te saluda, y te dice “Vaya, tienes los ojos de tu madre”. ¿Porqué te dice esto? Aparte de porque realmente puede que tengas los ojos de tu madre, lavecina te lo dice porque conoce a tu madre. Si no la conociese no podría decirlo, ¿no?Es decir, que la vecina puede decir lo que has sacado de tu madre si conoce a tu madre.

Bueno, pues una referencia, que se supone que ya sabes a la perfección qué es,es como la vecina. Es capaz de ver en los objetos los rasgos que conoce. Si unareferencia es del tipo bicicleta, entonces verá los contenidos propios de la bicicleta en elobjeto al que apunte. Por ejemplo:

Bicicleta refABicicleta = new Bicicleta();

Estamos cerando una referencia llamada refABicicleta (“referencia a bicicleta”)que es del tipo Bicicleta y que apunta a una nueva Bicicleta ( new Bicicleta() ). Estoes claramente legal, es como si la vecina ve a tu madre, no hay nada que no conozca deella. Pero si hacemos un truco...

Bicicleta refAOtraBicicleta = new Moto();

Hacemos que la referencia refAOtraBicicleta apunte a una nueva moto. ¿Cómoes esto posible? Pues es como la vecina que se encuentra un día contigo. La vecina ve enti lo que has heredado de tu madre, porque conoce a tu madre. La referenciarefAOtraBicicleta ve en la nueva moto lo que ha heredado de bicicleta porqueconoce las bicicletas (es del tipo bicicleta).

Entonces, usando la referencia refAOtraBicicleta podemos hacer que una motosalude como una bicicleta, porque refAOtraBicicleta conoce el método saludar de labicicleta: Si hacemos

refAOtraBicicleta.saludar();

veremos

Soy una bicicleta

¡aunque refAOtraBicicleta apunta a una moto!. ¿Por qué? Pues por lo dicho,porque refAOtraBicicleta no conoce el método que saluda como una moto, sóloconoce el método que saluda como una bicicleta. Pretender que refAOtraBicicletahaga saludar a la moto como si fuese una moto sería como pretender que la vecina te

diga que tienes las manos de tu abuelo, al que nunca conoció. Aquí tienes un pequeñográfico que tal vez te ayude:

Vamos a olvidar por ahora los constructores, ¿vale? Bueno, pues ¡te presento a laseñora referencia de tipo Bicicleta!:

¡¡¡TACHAAAAAAN!!!

no esperarás que tres flechas piensen como lo hacen el pez y los otros, ¿no? Vaya unasideas que tienes...... :)

Bueno, pues ¿Por qué la referencia de tipo Bicicleta tiene esa forma? Pues fjateen cómo funciona esta referencia con un objeto de tipo Bicicleta:

¿Te percatas de cómo de “ajusta” la referencia al contenido del objeto? Unareferencia del tipo Bicicleta verá todo el contenido de una bicicleta, así como tu vecinaconoce a tu madre por completo. Ahora fíjate en esto:

Un objeto de la clase Moto es igual que una bicicleta con dos cosas añadidas: unmotor y un método que saluda de forma diferente. Estos dos miembros de la clase estánarriba marcados en rojo. Fíjate cómo una referencia de tipo Bicicleta puede adaptarse aun objeto de tipo Moto, pero no ve más que el contenido de la bicicleta. En otraspalabras, que la referencia no ve ningún miembro pintado en rojo. Por cierto, perdón porel desenfoque.

Por supuesto, huelga decir que una referencia de tipo Bicicleta no puede apuntara objetos que ni sean bicicletas ni hereden de bicicletas. Es decir, que una referencia detipo bicicleta no puede apuntar a la mesa Margarita. Lástima.

Espero que ahora haya quedado bien explicado, o mejor dicho, bien mostrado:

1- Que una referencia de bicicleta se acopla a un objeto moto. Una referenciade un tipo puede acoplarse a un objeto de otro tipo

2- Que una referencia de bicicleta al acolparse a una moto no ve ni motor ni elsegundo método saludar. Una referencia de un tipo acoplada a un objeto deotro tipo sólo ve parte del contenido objeto

Bueno, acabas de ver cómo funciona una referencia. Como resumen, unareferencia es un conjunto de flechitas que apuntan hacia determinados contenidos de unobjeto. Los contenidos a los que apuntan vienen determinados por el tipo de lareferencia.

Comparación de referencias

Para comprobar si pilotas el sentido de la palabra “referencia”, hazte la siguientepregunta:

Tenemos dos objetos diferentes, con referencias diferentes, pero cuyaspropiedades coinciden. Por ejemplo, dos mesas cuadradas azules de tres patas:

Mesa Margarita = new Mesa(“Azul”, 3, “cuadrada”);

Mesa Catalina = new Mesa(“Azul”, 3, “cuadrada”);

La pregunta es la siguiente: ¿Qué valor lógico (TRUE – FALSE) dará lasiguiente expresión?

Margarita == Catalina

Pues veamos: estamos comprobando si son iguales dos referencias. Cada una deellas apunta a una mesa cuadrada, azul y de tres patas. Así que, como son iguales, estodebería dar TRUE.

Pues no.

Fíjate: las dos mesas son azules, de tres patas y cuadradas. PERO SON DOSMESAS DIFERENTES, no son la misma mesa. Es como decir que dos gemelos, por seridénticos, son la misma persona. Bueno, ten esto muy presente siempre, ¿vale? Puedescomparar dos númeos con ==, pero no dos objetos.

Antes de seguir asegúrate que has alcanzado la Idea platónica de los dos puntosanteriores. Si no es así, en realidad lo único que tienes que hacer es pensar muyprofundamente en ello, vuelve a escribir las clases, prueba a hacer pequeñosprogramas... recuerda lo dicho en el prefacio. Y, por supuesto, si tienes más probelmas,aquí estoy.

Arreglando bicicletas: parámetros que son referencias

Supón ahora que se nos pincha una rueda de la bicicleta. Pues la llevaremos a untaller:

class Taller {void arreglar(Bicicleta bici){

System.out.println(“A arreglar!”);}

}

Bueno, fíjate: definimos un taller con un método arreglar al que le vamos apasar como parámetro una bicicleta. Realmente este método no hace absolutamentenada con la bicicleta que le damos a arreglar, pero repito que el objetivo de este rollo espuramente didáctico.

Pues eso, que ahora podemos hacer sin problemas:

Bicicleta Antonieta = new Bicicleta();Taller elTaller = new Taller();

// después de largas horas de uso...

elTaller.arreglar(Antonieta);

es decir, creamos una bici, un taller, y hacemos que el taller arregle la bicidespués de mucho montar. Bueno, pues esto no parece complicado, ¿verdad?

Bueno, plantéate lo siguiente: Si en el taller arrerglan ruedas de bicicleta, y unamoto es una bicicleta con motor, ¿va a poder el taller arreglar las ruedas de una moto?¡Pues claro que sí! Pero no podemos hacerlo tan a la ligera. Veamos por qué.

El método arreglar requiere como parámetro una Bicicleta. Sin embargo,queremos areglar una moto. Bueno, pues es aquí donde haremos el uso de referencias deantes:

Crearemos primero una moto, pero tendrá una referencia de tipo bicicleta:

Bicicleta laMotoRompida = new Moto(); // moto con ref. Bicicleta

Y..... ¡Si! ya podemos arreglar la moto:

Taller elTaller = new Taller();elTaller.arreglar(laMotoRompida); // arreglamos una moto en realidad

¿Te da cuen? Si arreglar necesita una bicicleta y queremos arreglar una moto,hacemos que una referencia de tipo bicicleta apunte a una moto.

Bueno, pues fíjate para qué sirve esto de las referencias. ¿Te gusta? Pues verásahora.

Un taller que se precie no sólo debe ser capaz de arreglar pinchazos. Tambiéndebería poder cambiar el aceite a los motores, ¿no? Bueno, pues vamos a definir otrométodo de la clase Taller.

class Taller {void arreglar(Bicicleta bici){

System.out.println(“A arreglar!”);}

void cambiarAceite(Moto laMoto){System.out.println(“El aceite estaba echo una miiiiierda”);

}}

Bueno, pues ahora tenemos un peazo taller de la leche. Si tenemos una motocualquiera podemos arreglarle los pinchazos y cambiarle el aceite. Pero fíjate, el método

cambiarAceite requiere que le pasemos una moto (porque cambiar el aceite a una bicise las traería, ¿no?), pero arreglar requiere una bicicleta. Madre mía. ¡Necesitamos unareferencia de tipo Bicicleta para arreglar la moto y otra de tipo Moto para cambiarle elaceite!

Taller elTaller = new Taller();Bicicleta refMoto = new Moto();

Si queremos cambiar el aceite a la moto, es fácil:

elTaller.cambiarAceite(refMoto);

Pero, para arreglar las ruedas necesitábamos una referencia de tipo bicicleta, y lareferencia que tenemos es de tipo Moto. Tendremos que crear una nueva referencia:

Bicicleta refBicicleta = refMoto;

Esta referencia nueva apunta al mismo objeto al que apuntaba refMoto. Ahora síes lícito hacer

elTaller.arreglar(refBicicleta);

Bueno, pues esto es perfectamente legal, funciona. Pero coincidirás conmigo quees un engorro. Tener dos referencias de tipo distinto para un mismo objeto no es sermuy ahorrativo. Ni muy práctico, todo sea dicho.

Casting

Como dijimos hace una eternidad, “casting” es algo así como “convertir”. Elobjetivo es el siguiente:

Hemos visto casos en los que un objeto necesita varias referencias de distintotipo, como con el taller: arreglar las ruedas necesita una bicicleta, pero cambiar el aceitenecesita una moto. Para cambiar el aceite a una moto no hay mucho problema, pero paraarreglarle las ruedas había que hacer una nueva referencia de un tipo diferente.

Bueno, pues existe una manera de hacer esto mismo con una sola referencia.¿Cómo? Pues muy fácil: convirtiéndola.

Convertir una referencia de un tipo inicial a un tipo final se hace así:

(tipo final)referencia

Por ejemplo, si quiero convertir un número entero en uno de coma flotante(¡CUIDADO! no te creas que en este caso hay herencia de algún tipo, ¿eh?)

(float)miEntero

O si quiero convertir una moto en bicicleta...

(Bicicleta)refMoto

Es decir, que usando esta conversión, puedo hacer sin problemas:

Taller elTaller = new Taller();Moto Maroto = new Moto();

y, por fin....

elTaller.cambiarAceite(Maroto);elTaller.arreglar( (Bicicleta)Maroto ); // esto es casting!!!!!!!!!

Tenemos una sola referencia, llamada Maroto que es de tipo Moto, peropodemos usar esta referencia de tipo Moto en métodos que requieran una referencia detipo Bicicleta (como el método arreglar) porque podemos convertirla. ¡BIEN!

Relee el párrafo anterior.Vuelve a leerlo.¿Está claro?¿Seguro?Fabuloso.¿Realmente te parece el casting lo que te parecía antes?

Hala. A modo de resumen:

1. Una moto puede saludar como una bici. Podemos hacer que un objeto de untipo se comporte como un objeto de otro tipo.

2. El método arreglar ve a una moto como si fuese una bici, mientras quecambiarAceite ve la misma moto como lo que realmente es, una moto.Podemos hacer que un método vea a un objeto como si fuese de una clase yque otro método vea el mismo objeto como si fuese de otra clase.

3. Esto lo podemos hacer mediante varias referencias de diferentes tipos queapunten al mismo objeto....

4. O mediante una sola referencia y el “truco” del casting

El Casting se acaba aquí. Con estos conocimientos puedes enfrentarte a unfragmento de código que contenga conversiones de referencias, es decir, casting.

Pensado puedes saber qué sentencias serán correctas y cuales no lo serán. Sólo tienesque pensar qué contenidos del objeto es capaz de ver una referencia.

Antes de seguir (y por supuesto después de realizar tus ejercicios espirituales)plantéate los conceptos de:

REFERENCIATIPO DE UNA REFERENCIACÓMO las referencias apuntan a un objetoCÓMO dos referencias de diferentes tipos ven contenidos diferentes de un

mismo objetoCOMPARACIÓN DE REFERENCIAS: == no funciona como quisiéramos....CÓMO un método requiere referencias de determinado tipo (como parámetros)SENTIDO DE usar distintas referencias para un objetoFINALIDAD DEL CASTING SINTAXIS DEL CASTING

¡Recuerda!

Vimos cómo se usaba el casting para convertir enteros a coma flotante. Aesto se le llama también CASTING, pero no tiene nada que ver con herencia. ElCasting se usa para convertir

a) tipos básicos (de int a float, por ejemplo)b) referencias de objetos (llevamos tol rato haciéndolo)

Para comerte el coco.... (6)

Dadas las siguientes definiciones:

class A {int getn() {

return 1; }

}

class B extends A {int getn() {

return 2; }

}

class ABMain {public static void main(String[] args){

A a = new A();B b = new A();

System.out.println(“numero:”+a.getn());System.out.println(“numero:”+b.getn());

}}

Si lanzamos el programa, ¿Qué vemos en pantalla? Madre mía, típica cuestiónde examen. Bueno, un puntito para ti.

Upcasting y downcasting. Y siguiendo con el inglés, explicit and implicitcasting.

Este apartado es muy corto y sólo sirve para que aprendamos un par de términos.Sólo hay un pequeño problema: es un pelín enrevesado. Trataré de explicarlofácilmente, pero eso no va a ser suficiente. Así que abre bien los ojos y lee cada párrafosiete veces. Para hacerlo más corto aún, vamos a seguir con la bicicleta y la moto comoejemplos, ¿vale?

Bicicleta Anacleta = new Bicicleta();Moto Maroto = new Moto();

Upcasting: convertir una moto en una bicicleta. Es decir, convertir unareferencia de un tipo hijo a un tipo padre:

(Bicicleta)Maroto

Downcasting: lo contrario:

(Moto)Anacleta

Lo recordarás fácilmente si te imaginas la clase padre encima de la clase hijo.“UPcasting” es “ir hacia arriba” y “DOWNcasting” sería “ir hacia abajo”.

Voy a adjuntarte este pequeño fragmento de código para entender genial los dossiguientes conceptos, casting implícito y explícito:

class A {int getn() {

return 10;}

}

class B extends A {int getm() {

return 20; }

}

class C {void pillaUnA ( A j ){

System.out.println("n = "+j.getn());}

void pillaUnB ( B j ) {System.out.println("m = "+j.getm());

}}

Ahora supongamos un main cualquiera con las siguientes declaraciones:

public static void main(String[] args) {A a = new A();B b = new B();C c = new C();...

Weno. Es perfectamente lícito hacer:

c.pillaUnA(a); c.pillaUnA(b);

En el primer caso, a es una referencia de tipo A y por eso puede pasarse almétodo pillaUnA como parámetro.

En el segundo caso, AL LORO, b es una referencia de tipo B. Si queremospasarla al método pillaUnA deberíamos hacer:

c.pillaUnA( (A)b );

es decir, hacer UPCASTING. Sin embargo, este casting no es necesario hacerlo,porque el compilador lo hace directamente. A esto se le llama casting implícito.

Hagamos ahora:

c.pillaUnB(b); c.pillaUnB(a);

En el primer caso, no hay ningún problema. En el segundo caso, estamospasando una referencia de tipo A a un método que requiere una referencia de tipo B. Esdecir, al contrario de antes. Bueno, pues como pillaUnB() necesita un parámetro de tipoB, la referencia a tendremos que convertirla a una referencia de tipo B. Es decir, hay que

hacer DOWNCASTING. Bueno, pues este casting no es implícito, no lo hace elcompilador solito, como antes, sino que necesita que nosotros lo hagamos. A estecasting se le denomina casting explícito.

Por regla general, el upcasting es implícito y el downcasting es explícito.

AVISO: dado el código:

A a = new A();C c = new C();

podemos hacer downcasting así:

c.pillaUnB( (B)a );

per fíjate: la referencia a apunta a un objeto de tipo A que no tiene el métodogetM(). Es decir, que sintácticamente el casting es lícito, pero pillaUnB() jamás podráacceder al método getM() del parámetro, sencillamente porque en este caso no elparámetro no tiene dicho método.

Es un poco engorroso, pero básicamente lo que te planteo es que estedowncasting puede hacerse, puede compilar, pero jamás va a poder ejecutarse.

¡Ya hemos acabado! plantéate de nuevo:

UPCASTINGDOWNCASTINGCASTING IMPLÍCITO CASTING EXPLÍCITO

Ejercicio:

Dado el siguiente main, ¿Qué sentencias son lícitas? ¿cuáles compilan y cuálesno? ¿cuáles tienen upcasting y downcasting? ¿Cuáles tienen casting implícito y cuálesexplícito?

public static void main(String args[]){A a = new A();B b = new B();C c = new C();

c.pillaUnA(a); c.pillaUnA(b);

c.pillaUnA ( (A)b );c.pillaUnA ( (B)a );

c.pillaUnB (a); c.pillaUnB (b);

c.pillaUnB ( (A)b ); c.pillaUnB ( (B)a );

}

Solución:

Es normal fallar en algunas, así que no te desesperes si no aciertas, ¿eh? Porcierto, estoy seguro de que esta solución es wena al 99%, pero no al 100%. Así que si noconcuerda con lo que tú dices, y estás seguro de que no te has equivocado, tal vez lohaya hecho yo... De todas formas, he compilado el código y parece que se ciñe a estosresultados. Por supuesto, lo mejor cuando tengas dudas es encender el ordenador yprobar.....

c.pillaUnA(a); // normalc.pillaUnA(b); // upcasting implícito

c.pillaUnA ( (A)b ); // upcasting explícitoc.pillaUnA ( (B)a ); // compila pero no ejecuta

c.pillaUnB (a); // requiere downcasting explícitoc.pillaUnB (b); // normal

c.pillaUnB ( (A)b ); // requiere downcasting explícitoc.pillaUnB ( (B)a ); // compila pero no ejecuta

Bueno, visto esto, vamos a por la maravillosa...

La Clase Object

La Clase Object es una clase que Java tiene definida en sí mismo con su propiomecanismo. Es decir, que no vas a tener que definirla, así que tranki.

La clase Object se define como superclase de toda clase Java. Es decir, que sidefines una clase cualquiera, será una clase que herede de la clase Object, aunque no lodefinas como tal. La clase Mesa o Bicicleta son, en realidad, extensiones de Object.Fíjate qué cosas.

Bien. ¿Qué contenidos tiene la clase Object? Pues esta clase tiene unos métodosmuy extraños:

clone(), que sirve para hacer clonar objetos,equals(), para comparar objetos, getClass(), para obtener la clase de un objeto,

y algunos más. En definitiva, que la clase Object tiene un contenido bastanterarito. ¿Cuál es el sentido de este contenido? Pues muy fácil: como cualquier objetohereda de Object, Object contiene los métodos que todo tipo de objetos debería tener.Métodos para que un objeto se clone, se compare con otro objeto y cosas por el estilo.De esta forma, si tu objeto necesita tales métodos, pues ya los tiene definidos.

Sin embargo, estos métodos sirven para todo tipo de objetos. Por lo que no esdifícil adivinar que serán todos métodos muy generales. Así que lo más probable es que,si quieres utilizar uno de estos métodos, tendrás que redefinirlo (override).

Pero el auténtico potencial de la clase Objwect no reside en su contenido, sino enel hecho de que es la superclase de toda clase Java. Y dado que ya pilotas la herencia yel casting, te darás cuenta de que cualquier objeto podrá verse referenciado por unareferencia de tipo Object..Para ver un ejemplo,vamos a definir las siguientes clases:

class Florero {void saludar(){

System.out.println(“Soy un florero”);}

}

class Foto {void saludar(){

System.out.println(“Soy una fotografía”);}

}

class Lampara {void saludar(){

System.out.println(“Soy una lámpara”);}

}Bueno, pues el objetivo de nuestro programa es escribir un método que

meteremos en la clase Mesa (¿te acuerdas de ella?) que sirva para colocar cosas encimade una mesa. Recuerda la clase Mesa:

class Mesa {String color;int numPatas;String forma;

static int numMesasFabricadas = 0;

void setColor(String nuevoColor){color = nuevoColor;

}

void setNumPatas(int nuevoNumPatas){numPatas = nuevoNumPatas;

}

void setForma(String nuevaForma){forma = nuevaForma;

}

String getColor(){return color;

}

String getForma(){return forma;

}

int getNumPatas(){return numPatas;

}

Mesa(String colorInicial, int numPatasInicial, String formaInicial){

color = colorInicial;numPatas = numPatasInicial;forma = formaInicial;numMesasFabricadas = numMesasFabricadas + 1;

}

Mesa() {color = “azul”;numPatas = 4;forma = “cuadrada”;numMesasFabricadas = numMesasFabricadas + 1;

}

int getNumMesasFabricadas() {return numMesasFabricadas;

}}

Bueno, pues ahora queremos hacer un método ponerEncima() para colocarencima de una mesa una lámpara, una foto o un florero, es decir, objetos de las clasesque antes hemos definido. Por supuesto, el contenido del método no importa enabsoluto.

A primera vista se nos ocurre hacer un método para cada tipo de objeto acolocar, es decir, escribir un ponerEncimaUnFlorero, PonerEncimaUnaLampara,ponerEncimaUnaFoto, más o menos así:

void ponerEncimaUnFlorero (Florero nuevoFlorero) {...

}

void ponerEncimaUnaFoto (Foto nuevaFoto) {...

}

void ponerEncimaUnaLampara(Lampara nuevaLampara) {...

}

Bueno, normal, ¿no? Un método específico para colocar cada objeto.

Bueno, pues ahora vamos a hacer uso de la clase Object. Como es la superclasede toda clase Java, podemos hacer un método que coloque cualquiera de los objetosanteriores:

void ponerEncima ( Object nuevoObjeto ) {...

}

Hala. Ya podemos hacer:

Mesa Margraita = new Mesa();

Florero f = new Florero();Margarita.ponerEncima(f);

Lampara l = new Lampara();Margarita.ponerEncima(l);

Hala. Revive este pequeño capítulo sobre la clase Object y no sigas adelante sino has entendido a la perfección:

CLASE OBJECTSU CONTENIDOSU USO COMO REFERENCIA GLOBAL (para toda clase Java)

Ejercicio:

Plantéate los siguientes fragmentos de código

Lampara l = new Lampara();Margarita.ponerEncima( (Lampara) l );

Lampara l = new Lampara();Margarita.ponerEncima( (Object) l);

Object l = new Lampara();Margarita.ponerEncima(l);

Object l = new Lampara();Margarita.ponerEncima( (Object) l);

Échales un ojo de nuevo.......... te lo aseguro: ¡usarás la clase Object

¿sabes qué es lo mejor? más de lo que tú te crees!

Que todos funcionan.

¿Has visto lo genial que

es la clase Object?

Verás, ahora debemos parar un minuto para reconsiderar una cosa. En el prefacio he dicho que iba a explicar todo elrollo de Java basándome en la vida real, en ejemplos sencillos e ilustrativos, ydesgraciadamente a partir del casting ese hecho ha empezado a decaer, y hemosalcanzado un punto en el que consideramos métodos ( ponerEncima() ) que ni siquierahemos definido, sólo hemos escrito su cabecera. Hay que entender que del casting enadelante es todo muy abstracto, y por ello poner ejemplos de la vida real, pues ejem.... laverdad, es complicado.

Vamos, lo que pretendo hacer es disculparme si todo esto te ha parecidodemasiado tedioso, que en realidad lo es. Sólo que sepas que he hecho lo que he creídomejor, hemos dejado métodos sim implementar porque hacerlo sería complicar las cosasdemasiado y no vendría a cuento; las explicaciones son más escuetas que al principioporque la intención es mostrar la idea limpiamente: partir de un objetivo, plantear unproblema, aportar soluciones y escoger la mejor.

En definitiva, si esta parte te ha parecido lo peor, siento que haya sido así, yespero y deseo de corazón que encuentres fácilmente una explicación mejor. Por cierto,el pez, el pato y el pájaro que no tengo ni idea de cómo se llama, también te pidendisculpas.

Bueno, pues estos tres bichos también te animan a seguir adelante, ya que quedamuy poco. De verdad. Lo prometo. Bueno, abordemos ahora un tema bastante curioso.Son las...

Interfaces

Vamos a ver.

El objetivo de una interface es definir qué contenidos debe tener una claseobligatoriamente. Es algo así como un contrato: una clase puede implementar unainterface si se compromete a definir determinados contenidos. Veamos.

Si yo soy un trabajador, tengo obligatoriamente que pagar impuestos. Esosignifica que todo trabajador se compromete a pagar impuestos. Bueno, debería.

Las interfaces, repito, definen qué contenidos debe tener una clase. Por ejemplo,qué métodos debe tener obligatoriamente, pero no define esos métodos. Es decir, queuna interface sólo es una colección de cabeceras de métodos. La clase que implementeesa interface debe implementar esos métodos. Lo vemos con un ejemplo: Si definimos:

interface Trabajador {void pagarImpuestos();

}

Entonces, toda persona que sea trabajador, trabaje en lo que trabaje, debeimplementar esta interface:

class Funcionario implements Trabajador {String nombre;String dirección;int edad;int sueldo;...

void pagarImpuestos(){System.out.println(“Como funcionario, pago mis impuestos”);sueldo = sueldo – (0.16*sueldo);

}}

Hala, ahora cada funcionario pagará el 16% de su sueldo. Pero fíjate, unpresentador de televisión paga más impuestos que un funcionario. Eso significa que su

método pagarImpuestos() será ligeramente diferente. Su sueldo se ve reducido en un30%, y además, el mensaje que nos avisa de tal pago es un poco más pijo.

class Presentador implements Trabajador {String nombre;int cuánInsoportableSoy; ...

void pagarImpuestos(){System.out.println(“O sea, yo pago un plussss”);sueldo = sueldo – (0.30*sueldo);

}}

¿Te das cuenta? Tenemos dos personas diferentes, que nada tienen que ver la unacon la otra, excepto una cosa: que ambas son trabajadoras. Así, deben pagar impuestos.Pero fíjate que cada una lleva a cabo ese pago de forma diferente. La InterfaceTrabajador no determina cómo va a llevarse a cabo tal pago, solamente exige quese lleve a cabo.

Bueno, creo que hasta ahora todo va más o menos bien, ¿no? Ahora vamos a porlo mejor de las interfaces.

¿Lo has pillado? En realidad, el objetivo de una interface es que una clase Apueda comunicarse con otra clase B independientemente de cómo B esté escrita. Porejemplo: supón que ahora definimos la clase Hacienda. Esta clase exigirá a todos lostrabajadores que paguen sus impuestos. Pero hay miles de trabajadores distintos, unosson funcionarios, otros presentadores, pero otros son otras cosas. Sin embargo,Hacienda juega con un as en la manga: como hemos exigido que cada trabajador, seacomo sea, implemente a la interface Trabajador, podemos referenciar a cualquierclase que implemente a Trabajador mediante una referencia de tipo Trabajador:

class Hacienda {...void quePagueElCurrante(Trabajador currante) {

currante.pagarImpuestos();}

}

Joer, qué cosa. Resulta que al método quePagueElCurrante le pasamos comoparámetro cualquier objeto que implemente a la interface Trabajador, y éste método seencarga de hacer que pague. ¿Te fijas? Primero: no nos importa quñe tipo de trabajadorsea, sólo nos importa que implemente a Trabajador. Segundo: La referencia a esteobjeto es de tipo Trabajador, no es ni Presentador ni Funcionario ni nada.

El mecanismo de la referencia de tipo Trabajador es semejante a la señoraReferencia que vimos en la Herencia: es una flechita que apunta sólo a los contenidos deTrabajador, el resto de los contenidos ni los ve. Es como si lo único importante de untrabajador fuese que pague impuestos.

Ahora, en un programa podemos hacer:

Funcionario Fulgencio = new Funcionario();Presentador JesusVazquez = new Funcionario();Hacienda malditaHacienda = new Hacienda();

malditaHacienda.quePagueElCurrante( Fulgencio );malditaHacienda.quePagueElCurrante( JesusVazquez );

Bueno, ahora, si lo has entendido todo, te preguntarás la diferencia entreInterfaces y Herencia. Bueno, esta es tal vez la mejor pregunta que puedas hacer.

Cuando una clase hereda de otra, hereda todos sus contenidos. En las Interfacesno se definen contenidos, por lo que no se puede hereda ningún contenido. Una interfaceno es una clase, como lo son las superclases en la herencia, por lo que una interface nose puede instanciar:

Trabajador yop = new Trabajador(); // lo peorcito.

Una clase puede implementar varias interfaces a la vez, pero no puede heredar devarias clases a la vez. NO EXISTE LA (maravillosa) HERENCIA MÚLTIPLE ENJAVA, diga lo que diga tu profesor (vale, pero si te lo pregunta en el examen respondelo que él diga!). Las Interfaces pueden parecer un mecanismo de herencia múltiple, perono es así en realidad.

Supongo que tu profesor de dará más razones para diferenciar interfaces deherencia. Yo sólo te digo las más representativas (para mí).

Hala. Repasa los conceptos de

HERENCIA (ea, fastidiate)INTERFACEUSO DE IMPLEMENTSUSO DE REFERENCIAS DEL TIPO DE UNA INTERFACEDIFERENCIAS ENTRE HERENCIA E INTERFACES

¿Te doy una sorpresa?

Ya hemos acabado.

Epílogo

Es una pena, me gusta pensar en un epílogo como en el final de un libro deaventuras y no de un cursillo rápido de OOP y Java.

Hemos visto cómo es la estructura de la OOP: clases y objetos. Hemos vistocómo se llevan a cabo en Java. Hemos visto programación estructurada, es decir,sentencias de control: bucles y sentencias condicionales, la fatal historia de larecursividad, herencia, casting, interfaces.... y poco más.

Desgraciadamente hay otros puntos que no he tocado, porque realmente son untanto innecesarios porque ocuparían un hueco que no es necesario hacer: clasesabstractas, tipos básicos de datos, clases para acceso a disco (los asquerosos flujos ostreams), la estúpida BufferedString.... en fin, unas cuantas cosas que no son realmentenecesarias: tu profesor te las enseñará durante tres horas cada una de ellas, cuando noson necesarios más de diez minutos.

¿Por qué estas lagunas? Muy sencillo: porque mi intención no es enseñarte Javaa fondo, (eso lo hará el “mastering Java” se la editorial SUN) sino enseñarte aprogramar en OOP. ¿Y eso? Fácil: si sabes programar, entenderás cualquier cosafácilmente. Cuando hayas leído todo este mamotreto de letras y dibujos, y cuando loentiendas a la perfección, no te costrará aprender a usar flujos de entrada y salida endisco, manejo de excepciones, acceso restringido a miembros de clase, o yo qué sé.

Es decir, que aprendas primero a caminar... para luego echar a correr.

Tal vez algún día escribas tú la segunda parte de “Java para aprobar” explicandotodo lo que me he dejado atrás. Sería muy bonito. Si quieres, te paso los JPG del pez, elpato y el pajaro ese que no sé cómo se llama.

Bueno, aquí acabamos. Espero que no se te haya hecho muy tedioso (jeeee, queiluso soy). Pásalo bien, estudia mucho, pregunta lo que quieras y sácale partido a todoesto, ¿vale?

David Muñoz DíazGrupo de Usuarios de Linux de la Universidad Carlos III de Madrid

[email protected]

The Stone Soup Story

Once upon a time, somewhere in Eastern Europe, there was a great famine.People jealously hoarded whatever food they could find, hiding it even fromtheir friends and neighbors. One day a peddler drove his wagon into a village,sold a few of his wares, and began asking questions as if he planned to stayfor the night.

"There's not a bite to eat in the whole province," he was told. "Better keepmoving on."

"Oh, I have everything I need," he said. "In fact, I was thinking of makingsome stone soup to share with all of you." He pulled an iron cauldron from hiswagon, filled it with water, and built a fire under it. Then, with greatceremony, he drew an ordinary-looking stone from a velvet bag and dropped itinto the water.

By now, hearing the rumor of food, most of the villagers had come to thesquare or watched from their windows. As the peddler sniffed the "broth" andlicked his lips in anticipation, hunger began to overcome their skepticism.

"Ahh," the peddler said to himself rather loudly, "I do like a tasty stonesoup. Of course, stone soup with CABBAGE -- that's hard to beat."

Soon a villager approached hesitantly, holding a cabbage he'd retrieved fromits hiding place, and added it to the pot. "Capital!" cried the peddler. "Youknow, I once had stone soup with cabbage and a bit of salt beef as well, andit was fit for a king."

The village butcher managed to find some salt beef...and so it went, throughpotatoes, onions, carrots, mushrooms, and so on, until there was indeed adelicious meal for all. The villagers offered the peddler a great deal ofmoney for the magic stone, but he refused to sell and traveled on the nextday. And from that time on, long after the famine had ended, they reminiscedabout the finest soup they'd ever had.

(tomado de un documento de Monte Davis)