Está en la página 1de 195

Ana Belén Moreno

Grado en Diseño y Desarrollo de


Videojuegos
2017-2018
Ana Belén Moreno

Estructuras de Datos
Índice
Parte I. Introducción
• Tema 1. Complejidad.
• Tema 2. Conceptos de Java.

Parte II.- Estructuras de datos lineales


• Tema 3. Listas.
• Tema 4. Pilas.
• Tema 5. Colas.

Parte III.- Estructuras de datos no lineales


• Tema 6. Árboles.
• Tema 7. Conjuntos.
• Tema 8. Grafos.
• Tema 9. Mapas. 2
Ana Belén Moreno

Tema 2: Conceptos de Java


Índice
• Objeto
• Clase
• Modificador de visibilidad de una clase
• Variables instancia
• Modificadores de los miembros de una clase
• Métodos
• Identificadores
• Palabras reservadas
• El programa “Hola Mundo” en java
• Compilación en la línea de comandos
• Ejecución en la línea de comandos
• Constructores
3
Ana Belén Moreno

Tema 2: Conceptos de Java


Índice
• El operador new
• El operador “.”
• El recolector de basura.
• Asignación de referencias
• Asignación de datos de un objeto
• Referencia al objeto que envía el mensaje: this
• Clases anidadas
• Paquetes (packages)
4
Ana Belén Moreno

Tema 2: Conceptos de Java


Índice
• Creación de una aplicación
• Diseño de una aplicación
• Codificación
• Compilación
• Ejecución
• Testeo
• Depuración o debugging
• Legibilidad y estilo
• Tipos básicos o primitivos, variables y constantes
• Expresiones
• Reglas de precedencia de los operadores
5
Ana Belén Moreno

Tema 2: Conceptos de Java


Índice
• Instrucciones de selección
• Instrucciones de repetición
• Arrays
• Arrays unidimensionales
• Redimensionamiento de arrays
• Asignación de arrays
• Arrays bidimensionales
• Cadenas
• Caracteres
• Números aleatorios
• Recursividad
• Clases envoltorio o contenedoras (wrappers)
• Comparaciones 6
Ana Belén Moreno

Tema 2: Conceptos de Java


Índice
• Métodos de salida por pantalla
• Entrada por teclado: métodos de la clase Scanner
• Excepciones
• Ficheros
• Ficheros de texto
• Entrada por teclado usando BufferedReader
• Ficheros binarios
• Escritura en ficheros binarios
• Lectura de ficheros binarios
• Evolución de los lenguajes de programación

7
Ana Belén Moreno

Objeto
Objeto en el mundo real
• En el mundo real un objeto es una cosa que puede ser percibida con los
sentidos y que tiene:
– una identidad,
– propiedades específicas (p.e. color, posición, tamaño, forma,…) que definen su estado, y
– un comportamiento.

• P.e., una batidora es un objeto que tiene:


Una identidad:
– Basada en que cada instancia de batidora es única, p.e. tiene un nº de serie único.
Un estado:
– Posición de encendido (on/off): on
– Velocidad máxima: 600 rpm
– Velocidad actual: 300 rpm
– Temperatura: 40º
Un comportamiento, que incluye acciones como:
– Arrancar o parar la máquina
– Obtener su temperatura
– Cambiar la velocidad

8
Ana Belén Moreno

Objeto
Objeto en Programación Orientada a Objetos (POO)
• En POO cada objeto tiene identidad (es único), y
• almacena datos (propiedades) que definen su estado en
cada momento de la ejecución del programa, y
• puede recibir mensajes, que son instrucciones u
órdenes para ejecutar alguna acción (operación)
permitida sobre sus datos p.e. modificarlos,
comunicarlos, etc. El envío de mensajes a un objeto es
la manera en que el objeto interacciona con el mundo
exterior. Las acciones que realiza el objeto al recibir un
mensaje determinan su comportamiento.
• En POO cada objeto es una instancia de una clase (la
cual define el tipo de objeto). 9
Ana Belén Moreno

Clase
Concepto de clase y de miembros de una clase
• Una clase es el tipo de un objeto, definido por el
programador. Consiste en la definición de sus miembros,
que son:
– Datos de los objetos, almacenados en variables instancia
(también llamadas propiedades o atributos o campos). Estas
pueden ser:
• variables de algún tipo primitivo, u
• objetos de otras clases.
– Métodos u operaciones que actúan sobre esos datos. Cuando
un objeto recibe un mensaje, ejecuta un método. Así, los métodos
expresan o definen cómo responde el objeto a cada mensaje (es
decir, cómo se comporta el objeto). Tipos de métodos:
• constructor, procedimiento o función...

10
Ana Belén Moreno
Clase: Definición de una clase
Ejemplo: Clase llamada Punto que contiene las coord. x e y de un punto:
public class Punto{
//datos o variables instancia:
private int x; //coordenada x
private int y; //coordenada y

//métodos:
public Punto(int coordX, int coordY){ //constructor Métodos especiales llamados
x = coordX; constructores: inicializan las
y = coordY;
variables cuando un objeto nuevo
}
public Punto(){ //constructor sin argumentos de esta clase es creado
x = 0; //inicializa a valores por defecto (instanciado con el operador new).
y = 0;
Su nombre es igual al de la clase.
}
public int leerX(){ //devuelve el valor de x
return x;
} Métodos de acceso a los datos
public int leerY(){ //devuelve el valor de y para obtenerlos (leerlos)
return y; denominados “getters”.
}
public void fijarX(int valorX){ //asigna un valor a x
x = valorX; Métodos de acceso a los datos
} para modificarlos (escribirlos)
public void fijarY(int valorY){ //asigna un valor a y denominados “setters”.
y = valorY;
} Métodos de acceso a los datos
public void trasladar(float dx, float dy){
x = x + dx; para procesarlos o hacer cálculos
y = y + dy; con ellos.
}
} NOTA: El nombre de la clase(Punto), los nombres de las variables (x e y), y los nombres
los métodos (leerX, fijarX, etc.) y de sus argumentos (valorX…), son identificadores.
11
Ejemplo: Ana Belén Moreno
public class Coche{
// propiedades:
private double velocidad;
private boolean enMarcha;

// método constructor:
public Coche(){
velocidad = 0;
enMarcha = false;
}
//getters
public double leerV(){
return v;
}
public boolean estaEnMarcha(){
return enMarcha;
}
// otros métodos:
public void acelerar (int incremento){
velocidad = velocidad + incremento;
enMarcha = true;
}
public void frenar() {
if (enMarcha)
velocidad--;
if (velocidad == 0)
enMarcha = false;
}
} 12
Ana Belén Moreno

Clase
• Los principales actores en un programa en
Java son los objetos.
• Los objetos almacenan datos y
proporcionan métodos para acceder a
ellos.
• Cada objeto es una instancia de una
clase, la cual define el tipo del objeto
(nombre de la clase), sus propiedades
(atributos o variables instancia) y las
operaciones que esta ejecuta (métodos). 13
Ana Belén Moreno

Modificador de visibilidad de una clase

Modificador public
• Los modificadores de clase son palabras clave y su uso es
opcional.
• El único modificador de acceso que se puede especificar en
la cabecera de una clase es public:
– public: una clase definida con el modificador public (p.e. public
class Rectangulo….) indica que dicha clase puede usarse (p.e.
instanciarse) en cualquier fichero del mismo paquete y en cualquier
fichero que importe la clase mediante import.
• Cada clase con modificador public se declara en un fichero propio
separado de las demás, llamado nombreClase.java
– Por defecto, cuando una clase no tiene modificador public,
significa que la clase es amigable (friendly), y sólo podrá utilizarse
por cualquier clase de su mismo paquete (package).

14
Variables instancia
• Las variables instancia (o campos o propiedades)
dentro de un objeto deben tener un tipo, que puede
ser:
– un tipo base, en caso de datos simples (int,float…),
• Una variable instancia de un tipo base guarda un valor
de ese tipo base.
– un tipo “referencia a objeto”. El tipo del objeto viene
determinado por su clase.
• Una variable instancia declarada con un nombre de
clase almacena una referencia (o dirección de
memoria) que apunta a un objeto de esa clase.
NombreClase varReferencia;
P.e.:
Rectangulo rect;
Punto p1, p2;
15
Ana Belén Moreno

Visibilidad de los miembros de una clase


• La visibilidad de las variables instancia y de los métodos puede controlarse
mediante algunos modificadores, que se escriben al principio de la
declaración de la variable o del método, para permitir ocultarla o no. Son:
– private: una variable instancia declarada con este modificador es sólo
accesible por métodos definidos dentro de esa clase (miembros de la
clase) y no es visible (no se puede acceder a ella) desde métodos de
otras clases ni desde métodos de una subclase (clase derivada, que no
se va a dar en la asignatura).
– protected: sólo accesible desde métodos miembros de la misma
clase, o de clases derivadas de esta, o de otras clases del mismo
paquete.
– public: desde cualquier método de fuera de la clase puede accederse
a la variable instancia.
– Si no se usa ningún modificador, la variable instancia o el método es
friendly, y puede accederse a ellos desde los métodos de su misma
clase y desde cualquier clase del mismo paquete en el que se
encuentra. Las variables sin modificador y las protected tienen la
misma visibilidad respecto a las clases del paquete.
16
Visibilidad de los miembros de una clase

Tipo de Miembro de Miembro de Miembro de Miembro de


miembro la misma una clase una clase del clase de otro
clase derivada paquete paquete
Private

sin
modificador
SÍ SÍ
Protected
SÍ SÍ SÍ
Public
SÍ SÍ SÍ SÍ

17
Ana Belén Moreno

Métodos
• En otros lenguajes se llaman funciones o procedimientos.
• Un método es un trozo de código definido dentro de una clase
de la que es miembro.
• Los métodos aceptan parámetros (o datos de entrada) como
argumentos.
• Su definición tiene dos partes:
– Cabecera: Especifica lo que se debe conocer para su uso, es decir,
define el nombre del método, los parámetros y sus tipos, así como el
tipo del valor de retorno si lo hay (void si no lo hay).
– Cuerpo: define lo que hace el método cuando recibe un mensaje para
que este se ejecute.
• Sintaxis de la definición de un método:
//cabecera:
modificadores tipo nombreMetodo (tipo1 parametro1,…,tipoN parametroN){
// cuerpo del método
} 18
Ana Belén Moreno
Métodos
• A continuación se describen los elementos que intervienen en
la cabecera:
–modificadores:
• de visibilidad (son los mismos que para variables instancia):
–public: puede accederse a ellos desde cualquier método, sea del
mismo paquete o no.
–protected: sólo los métodos del mismo paquete o de sus
subclases (no se van a ver en la asignatura) pueden acceder a ellos.
–private: sólo métodos de la misma clase (no métodos de una
subclase) pueden acceder.
–Si no hay modificador es friendly, puede accederse desde cualquier
clase del mismo paquete.
• Otros modificadores:
–static: el método está asociado con la clase, no con una instancia
individual de la clase, es decir, no con un objeto, p.e. la clase Coche
podría contener un método estático static int numCoches {…}
que devuelve el número de objetos coches instanciados. .
Ana Belén Moreno

Métodos
• Continuamos describiendo los elementos que intervienen en la
cabecera:
–tipo: es el tipo del valor que devuelve el método.
–Si el método no devuelve ningún valor, el método es un
procedimiento y se indica escribiendo void como tipo del valor de
retorno. En caso contrario el método es una función.
–nombreMetodo: nombre del método, es un identificador
válido de Java.
–lista de parámetros (precedidos por sus tipos):
•Van entre paréntesis y separados por comas tras el nombre del
método.
•los parámetros son variables que sólo pueden usarse dentro del
método. Reciben los valores necesarios para la ejecución del método.
•tipoi es cualquier tipo base o cualquier clase de objeto.
•parametroi es un identificador.
•la lista de parámetros puede estar vacía, en ese caso también es
preciso escribir los paréntesis.
•los métodos de una clase pueden ser llamados desde dentro del
cuerpo de cualquier método de la misma clase. 20
Ana Belén Moreno

Métodos
Llamada a un método
• Salvo que sea estático, un método es invocado o
llamado para su ejecución sobre una instancia
específica (objeto) de esa clase, usando el
operador punto ‘.’ y como resultado puede cambiar
el estado de ese objeto.
• Para ejecutar un método se envía un mensaje al
objeto:
nombre_objeto.nombre_metodo(param1,..., paramN);
• Ejemplo:
//Creación de una instancia de Coche:
Coche clioAlicia = new Coche();
..
clioAlicia.acelerar(20);
21
Ana Belén Moreno

Métodos
Valor de retorno de un método
• Las funciones devuelven un único valor.
• Para devolver el valor de una expresión se usa la
instrucción
return expresión;
situada dentro del cuerpo de la función, antes de
salir de salir de la misma:
• El tipo de la expresión coincide con el tipo del valor
de retorno indicado en la cabecera.
• Cuando se ejecuta la sentencia return ya no se
ejecutan más sentencias del método.

22
Ana Belén Moreno

Métodos
Parámetros
• Los parámetros se pasan a los métodos por valor:
– Significa que se pasa una copia del parámetro que se envió
en la llamada, y dentro del método se trabaja con la copia.
– El método puede cambiar la copia pero no el original.
– Si se pasa una referencia a un objeto, el método recibe una
copia de la referencia también. Esta apunta (o referencia) al
mismo objeto original (no a una copia del objeto).
• La copia de la referencia, referencia al mismo objeto que la original.
• Cambiar la copia de la referencia dentro del método no cambiará a la
referencia original que fue pasada.
• Sin embargo, en el método se puede usar la copia para acceder a
las variables instancia del objeto y cambiar su estado, pues tanto la
referencia original como la copia apuntan (o referencian) al mismo
objeto en memoria, al que se puede acceder con cualquier referencia
que lo apunte.
23
Métodos Ana Belén Moreno

Cuerpo de un método
• Sea un bloque un conjunto de instrucciones delimitadas por llaves:
{bloque}.
• El cuerpo de un método es un bloque de sentencias (entre llaves), con una
secuencia de:
– declaraciones de variables locales y
– sentencias.
• declaraciones de variables locales.
• Se declaran generalmente al principio del bloque del método, aunque también pueden declararse
en algún bloque más interno donde se vayan a usar.
• Sólo existen mientras se ejecuta el bloque donde están declaradas.
• Son o bien de un tipo base o referencias a objetos
• Sintaxis:
tipo nombre1; // declaración
tipo nombre2 = valor_inicial; // declaración e inicialización
• Ejemplo:
{
//declaración de variables locales
double r;
int i = 512;
Punto p1 = new Punto(8, 2); // declaración e instanciación
// secuencia de sentencias

}
• Las sentencias simples y las declaraciones terminan con “;”. 24
Ana Belén Moreno
Métodos
Ámbito de las variables
{
• Un ámbito se inicia con llave int a;
abierta “{“ y termina con a = 25;
llave cerrada “}”. int c = 15;
// aquí a vale 25 y c vale 15.
• En un ámbito se encuentran
las sentencias afectadas por {
int b;
las declaraciones realizadas
b = 2;
en ese ámbito. int c = 12;
• Los ámbitos pueden /* aquí a vale 25, b vale 2
y c vale 12 */
anidarse, y las variables son }
locales al ámbito en el que
se declaran. /* aquí a vale 25, c vale 15
y b no existe */
}

25
Ana Belén Moreno
Identificadores
Identificador
• Son identificadores los nombres de:
– las clases (por convenio, 1ª letra mayúscula), p.e. Barco
– los objetos (minúscula y si hay varias palabras, las iniciales excepto la
primera, en mayúsculas) p.e. p1, barcoPasaje, …
– las variables instancia (idem): p.e. barcosHundidos, numJugadores,…
– los métodos definidos por el programador (idem, salvo los constructores
que se llaman igual que la clase y tienen inicial mayúscula), ej.:
acelerar, Coche…
– los argumentos y las variables internas de los métodos definidos por el
programador (idem), ej.: i, punto, coche, etc…
– las constantes, declaradas con el atributo final (por convenio,
identificador completo en mayúsculas), p.e. NUM_COCHES etc…
• Sintaxis: Está permitido como identificador cualquier cadena de
caracteres de Unicode (excepto palabras reservadas), que empiece con una
letra seguida una secuencia de caracteres en la que puede haber letras
(a..z, A..Z), números (0,1,..,9) o el carácter subrayado (“_”). 26
Palabras reservadas
Son palabras reservadas de Java:

abstract boolean case catch char class


default do double else extends false
final float for if implements import
Int interface long new null package
private protected public return short static
super switch this throw throws true
try void while …

27
Ana Belén Moreno

El programa “Hola Mundo” en java


• Todo programa en Java tiene una clase con un método main, que
es el método en el que comienza la ejecución del programa.

28
Ana Belén Moreno

Tipos de clases
Podemos decir que una clase puede ser de uno de
estos tipos:

– Clase con un método main (programa principal): esta


clase no corresponde a un tipo de objeto.

– Clase correspondiente al tipo de un objeto: no contiene


método main, sólo contiene datos y métodos del objeto.

• En Netbeans a la hora de crear una clase nos


pregunta si va a contener método main o no, para
crear la plantilla (o el esqueleto) del código
correspondiente a esa clase. 29
Ana Belén Moreno

Compilación en la línea de comandos


• Una vez creado el código fuente con un editor de texto, se
salva en el fichero Universe.java, en un directorio.
• Desde la línea de comandos puede compilarse invocando al
compilador javac.

• Y se crea Universe.class (que contiene bytecodes) en el


directorio donde estaba Universe.java. 30
Ana Belén Moreno

Ejecución en la línea de comandos

• Puede ejecutarse el programa invocando


a la máquina virtual de java, y aparece la
salida por pantalla:

F:\ejemplosJava\> java Universe


Hello Universe!

31
Ana Belén Moreno

Constructores
Concepto de constructor
• Un constructor es un método que se ejecuta
automáticamente cuando se crea un objeto de una
clase.
• Sirve para inicializar las propiedades o variables
instancia miembros de la clase.
• Tiene el mismo nombre que la clase.
• No devuelve ningún valor de retorno, y tampoco hay
que indicarlo con void.
• Puede definirse más de una vez, p.e. con cero
argumentos y con más argumentos es decir, puede
estar sobrecargado.
32
Ana Belén Moreno
Constructores
Definición de un constructor dentro de una clase
public class Rectangulo{
private int izdo;
private int superior;
private int dcha;
private int inferior;

// constructor:
public Rectangulo(int iz, int sup, int d, int inf){
izdo = iz;
superior = sup;
dcha = d;
inferior = inf;
}
// constructor por defecto (sin argumentos):
public Rectangulo(){
izdo = 0; (0,0) (0,100)
superior = 0;
dcha = 100;
inferior = 100;
} (100,0) (100,100)
//.. Definiciones de otros métodos miembro
} 33
Ana Belén Moreno

Constructores
Llamada a un constructor
• Al crear un objeto se realiza una llamada al constructor
después del operador new:

Rectangulo rect = new Rectangulo(25,25,75,75);

• Se ha creado un objeto rect que es una instancia de la


clase Rectangulo, que ha quedado inicializado con los
valores pasados al constructor.
rect 25 25 75 75

• Además de definir un constructor que inicialice los datos del


objeto, conviene incluir además como miembro de una
clase, un constructor que no tiene parámetros y que se
llama constructor por defecto, que permite inicializar los
miembros dato (variables instancia) a valores por defecto.
34
Ana Belén Moreno
Constructores
Constructores sobrecargados
• Los constructores, al igual que los demás métodos de una
clase, se pueden sobrecargar. Esto significa que se pueden
definir varios constructores que se llaman igual pero que
contienen distinto número de argumentos.
• P.e. el constructor Rectangulo puede contener o cero
parámetros o cuatro. Así, puede crearse un objeto rectángulo
de una de estas formas:
Rectangulo rec1 = new Rectangulo();
Rectangulo rec2 = new Rectangulo(10, 10, 30, 30);

• Así, en java puede que una clase tenga como miembros varios
métodos con el mismo nombre y con distinto número de
parámetros. En este caso, el método que se ejecutará con la
llamada es aquél en el que haya coincidencia en el número de
parámetros y en el tipo de los mismos.
• Nota: en la asignatura sólo usaremos la sobrecarga para
métodos constructores, no para otros 35
Referencias
• Las referencias reciben el nombre de punteros en otros
lenguajes como C o Pascal. También se llaman enlaces en el
ámbito de las estructuras de datos dinámicas.
//Declaración de una referencia con identificador p:
Punto p; // Esta declaración reserva memoria para una
// variable p, que puede contener una
// dirección de memoria. En este caso p es una variable que puede
// contener la dirección de memoria
// de un objeto de la clase Punto, es decir,
// puede contener una referencia a un objeto
// de clase Punto.

NOTA: Las direcciones de memoria se representan gráficamente con una


flecha en vez de con un número, pues el número no es relevante, ya que al
programador sólo le interesa a qué objeto referencia p, no en qué posición
de la memoria está. 36
Referencias
Identificador de referencia vacía: null
null: es un valor constante de tipo referencia a objeto
(o puntero a objeto). null se asigna a una variable
referencia para indicar que no contiene ninguna
dirección de memoria es decir, que “no apunta a
ningún objeto”.
Ejemplo:
Punto p; //p no está inicializada

p = null; //asignación de la cte literal null a la variable p.
//p contiene null, gráficamente se representa así:
p 37
Ana Belén Moreno

El operador new
• Un objeto en java se crea con el operador new.
• El operador new crea un objeto nuevo de una clase
especificada y devuelve una referencia a ese objeto
(que es la dirección donde está ese objeto en la
memoria).
• Para crear un objeto, new debe ir seguido de una
llamada a algún constructor de la clase del objeto a
crear. Sintaxis:
varReferencia = new NombreClase(argumentos_constructor); MP
p1 0
Ejemplo:
0
Punto p1, p2;
p1 = new Punto();
p2 3
p2 = new Punto(3,4);
4
38
Ana Belén Moreno

El operador new. Ejemplo.


public class Ejemplo{ . . .
public void nombreMetodo ( ){
Punto p1; Declara la variable p1, p1
Punto p2 = new Punto(); que puede contener
p1 = new Punto(1,2); cualquier referencia a un
p2 = p1; objeto de clase Punto.
... Declara la variable p2 y p2
} le asigna la referencia
} 0 0
(o dirección) del nuevo
objeto creado con new. x y

p1
Asigna a la variable p1 la referencia
1 2
al nuevo objeto creado con new.
x y
p2
Asigna a la variable p2 la referencia al objeto p1. Ahora p2
referencia al mismo objeto que p1. El viejo objeto al que 0 0
apuntaba p2 ahora no tiene ninguna variable que lo refiera p1 x y
=> por eso desaparecerá y la memoria que ocupa quedará
1 2
libre (de ello se encargará el recolector de basura).
x y 39
Ana Belén Moreno
El operador new
• La llamada al operador new hace lo siguiente:
1º) Reserva memoria dinámica en t de ejecución para guardar
un nuevo objeto, y todas sus variables instancia se
inicializan a los valores estándar por defecto (null para
variables referencia a objeto, false para booleanos y 0
para tipos base).
2º) Llama al constructor para el nuevo objeto (que sigue a
new) y este se ejecuta con los parámetros especificados.
3º) Tras ejecutarse el constructor, el operador new devuelve
una referencia es decir, una dirección de memoria al
nuevo objeto creado. Si la expresión de llamada a new
está a la derecha del = en una instrucción de asignación,
esta dirección es almacenada en la variable objeto tal que
esta apunta o referencia al objeto creado. Así, una variable
referencia es vista como un puntero a un objeto, es decir,
apunta al objeto, y permite acceder a él y a sus datos.
Variable
referencia a objeto Objeto apuntado
p 1 2
x y 40
Ana Belén Moreno

El operador new
• El operador new permite reservar memoria
dinámicamente, es decir, en tiempo de
ejecución, para guardar objetos según las
necesidades del programa.
• Al trabajar con memoria dinámica, recuerde que
declarar una variable de tipo referencia a objeto
no es suficiente para reservar memoria para la
referencia al objeto, sino que se debe llamar al
procedimiento new para reservar memoria para
el objeto, llamando al constructor adecuado que
lo inicialice.

41
El operador punto “.” Ana Belén Moreno

• Sólo se puede acceder a un objeto mediante su referencia.


• El acceso a los miembros de un objeto desde métodos de otras clases
distintas a la del objeto, se hace mediante su referencia (identificador
del objeto) seguida del operador “.”, seguido del miembro que se desee
usar.
• Ej.: Para llamar a un método de un objeto se escribe el identificador
del objeto (o referencia) seguido del operador punto (“.”) , el nombre del
método y unos paréntesis que contienen a los parámetros actuales a
enviar. Ej.: Variable
Coche miCoche = new Coche(); referencia al
Punto p1 = new Punto(4, 5) ; objeto Objeto
miCoche.acelerar(10); p1 apuntado
p1.trasladar(3,6);//el objeto apuntado
1 2
// por p1 toma valores (4,8).
• En esto consiste el envío de mensajes a objetos. Se ha enviado x y
un
mensaje al punto referenciado por p1 para que cambie su estado,
trasladando las coord x e y en magnitudes 3 y 6 respectivamente.
• Si se desea acceder a un método de una clase desde otro método de
la misma clase, se puede invocar al nombre del método directamente,
sin anteponer ningún nombre de objeto y sin anteponer el operador ‘.’,
p.e., dentro de la clase Punto puedo hacer esta llamada:
trasladar(5,8); 42
Ana Belén Moreno

El operador punto “.”


• Si se desea acceder a propiedades (datos) de un
objeto desde dentro de un método de la propia clase
del objeto, tampoco es necesario hacer referencia al
propio objeto, ni usar el operador ‘.’ sino que se
puede invocar el nombre de la propiedad
directamente. class Coche {
// datos:
private int num_puertas;

// métodos:
public void ponerPuertas() {
num_puertas = 4;
}

}

43
El operador punto “.”
Ana Belén Moreno

• Desde métodos de otras clases, esto es, desde fuera de una


clase de un objeto, es conveniente usar “.” para acceder a sus
métodos, pero no es recomendable para acceder a variables
instancia aunque sea posible.
• Si desde algún método de una clase distinta a la del punto p1
se desea cambiar el estado o valor de las variables instancia
de p1, en lugar de usar “.” para acceder a esas variables
directamente, es conveniente hacerlo llamando a métodos de
p1 que las modifiquen. Ej.:
// Las siguientes sentencias acceden a variables instancia directamente
// con el operador “.”
p1.x = 3; // acceso a la variable x de p1 para asignarle valor 3 desde
// otra clase distinta de Punto. NO ES ADECUADO.
coord_y = p2.y; //acceso a la variable instancia y de p2 para leer su
//valor. NO ES ADECUADO.
// Para realizar estos accesos a las variables x e y desde métodos de
// otras clases que usen la clase Punto, en lugar de dichas instrucciones
// es conveniente acceder a las variables instancia solamente mediante
// llamadas a métodos la clase Punto, así:
P1.fijarX(3); // ES ADECUADO
coord_y = p2.leerY(); // ES ADECUADO
44
El operador punto “.”
Ana Belén Moreno

• Para impedir el acceso a los datos de un objeto desde otra


clase distinta a la suya directamente con el operador punto
‘.’, los datos se declararán con el modificador private.
• Así se obligará a que el acceso a los datos de una clase
(desde otra), sólo pueda realizarse a través de llamadas a
sus métodos.

• Ventajas:
– No será necesario conocer cómo están declaradas las
variables instancia de los objetos, será suficiente con
conocer las cabeceras de los métodos del objeto para
saber qué acciones podemos hacer con él, es decir,
para saber qué mensajes podemos enviarle o a qué
mensajes responde.

– Se evitarán errores como p.e. asignar un valor erróneo


a una variable. En los métodos esto se podrá controlar. 45
Ana Belén Moreno
El recolector de basura
• Es el recolector de objetos no referenciados, es decir, no apuntados por
ninguna referencia.
• En Java es preciso que un objeto esté referenciado por una variable
referencia para poder acceder a él.
• En el momento en que un objeto deja de estar referenciado, la rutina de
recolección de memoria no usada (llamada recolector de basura), libera
la memoria ocupada y no referenciada, para que esta pueda ser
reservada más adelante cuando se necesite.
Variable referencia
al objeto Objeto
Punto p1 = new Punto(1,2); p1 apuntado
1 2
x y
Objeto sin referencia, no apuntado por nadie. El
recolector de basura lo liberará.
p1 = null; 1 2
p1 x y
p1 ya no apunta a nada. Dejó de apuntar al obj.
46
Ana Belén Moreno
El recolector de basura
• El propio sistema recolecta los objetos en desuso (no referenciados), para
aprovechar la memoria ocupada.
• Para ello, hay un proceso que se ejecuta periódicamente y toma los objetos
que no están referenciados por ninguna variable y libera su memoria. El
proceso lo realiza el método System.gc (garbage collection o recolección
de basura). En otros lenguajes esto no existe y hay que llamar
explícitamente a las instrucciones adecuadas para liberar la memoria
cuando ya no se va a usar más.
• En java, si no se quiere esperar a que lo haga el sistema automáticamente y
periódicamente, se puede hacer una llamada a este método mediante
mediante “System.gc();” en el programa.
• Ejemplo: sea el método:
void objetos() {
Contador k, g, r, s; // creamos referencias a 4 objetos contador
// Creamos 4 objetos de clase Contador:
k = new Contador();
g = new Contador();
r = new Contador();
s = new Contador();
g = k; // g referencia al mismo objeto que k. El objeto original
// de g será recolectado.
k = null; // el objeto al que apuntaba k sigue referenciado (por g).
r = new Contador(); // el recolector libera el objeto original de r;
} // se liberan los objetos actuales apuntados por g y r.
47
Asignación de referencias
1) Sea el estado inicial de dos referencias 2) Si realizamos la asignación p1 = p2;
a objetos de clase Punto, p1 y p2, en p1
las direcciones de memoria 50 y 60: 50 2 | 3

p1 50 2 | 3
p2 2 | 5
60

p2 60 2 | 5
Al asignar un valor de un puntero a
otro puntero, ambos apuntan a la
En este estado se cumple:
misma información, pero esta no se
duplica. Se cumple:

Expresión Devuelve Expresión Devuelve


p1 == p2 (¿50 == 60?) false p1 == p2 true
(p1.leerX()==p2.leerX()) && false (p1.leerX() == p2.leerX()) && true
(p1.leerY()==p2.leerY()) (p1.leerY() == p2.leerY())

48
Asignación de datos de un objeto
1) Sea el estado inicial de dos
objetos p1 y p2 de clase Punto, en 2) Si realizamos la asignación de
las direcciones de memoria 50 y 60: los valores del objeto apuntado:
p1.fijarX(p2.leerX());
p1 50 2 | 3 p1.fijarY(p2.leerY());

p1 50 2 | 5
p2 60 2 | 5

En este estado se cumple: p2 60 2 | 5

En este estado se cumple:

Expresión Devuelve Expresión Devuelve


p1 == p2 (¿50 == 60?) false p1 == p2 (¿50 == 60?) false
(p1.leerX()==p2.leerX()) && false (p1.leerX()==p2.leerX()) && true
(p1.leerY()==p2.leerY()) (p1.leerY()==p2.leerY())

49
Comentarios

• Los comentarios en un programa sirven para un lector humano,


no son procesados por el compilador.
• Hay dos modalidades: el bloque de comentarios y el
comentario en una línea.

– Bloque de comentarios:
/*
* Los dos primeros caracteres “/*” abren el bloque de comentarios
* Este es un bloque de comentarios.
* Los dos siguientes símbolos cierran el bloque:
*/

– Comentario en una línea:

// Tras estas 2 barras, lo que haya en la línea es comentario.

50
Ana Belén Moreno

Referencia al objeto que envía un mensaje: This

• This es una referencia al mismo objeto desde el que se envía


un mensaje. P.e.:
class Triangulo{
private double base;
private double altura;
...
public Triangulo(double base, double altura){
this.base = base;//para diferenciar la variable instancia del parámetro.
this.altura = altura;
}
...
}
• this.base es el miembro base del objeto de clase Triangulo.
Desde el que se envía el mensaje. En este caso evita el conflicto con el
argumento que se llama igual, y no sería necesario this si los
parámetros tuviesen nombres diferentes a las variables instancia.
• Otro ejemplo de uso: cuando un método devuelve el mismo objeto que
lo llamó puede hacerse mediante return this;.
51
Clases anidadas Ana Belén Moreno

• En Java cada clase pública definida se escribe en un fichero


separado tal que:
– El nombre del fichero es el nombre de la clase con extensión .java,
p.e., la clase:
public class BarcoGrande{

}
se guarda en un fichero llamado BarcoGrande.java
• Java permite definir clases anidadas, es decir, permite anidar o
situar la definición de clases dentro de otras clases.
– Sirve para definir una clase que está fuertemente unida o relacionada con otra
clase. P.e. la clase EditorDeTexto puede contener anidada dentro de ella la
clase Cursor.
– Permite mantener ambas clases en un mismo fichero.
– Permite que una de las clases acceda a métodos no públicos de la otra
– La clase anidada debe ser declarada como static, porque la clase anidada
(interna) está asociada con la clase externa, no con una instancia u objeto de la
clase externa.
• En esta asignatura no vamos a usar clases anidadas. 52
Ana Belén Moreno
Paquetes (packages)
• Un paquete en Java (llamado package) es un conjunto de clases
definidas en un subdirectorio común. Para definir un paquete, se
escribe la sentencia:
package nombre_paquete;
en la primera línea de cada archivo fuente de cada clase del
paquete. Ejemplo de paquete llamado escritorio con 3 archivos:
//archivo fuente Lapiz.java // archivo Boligrafo.java // archivo Folio.java
package escritorio; package escritorio; package escritorio;
public class Lapiz { public class Boligrafo { public class Folio {
//... miembros de la clase // ... miembros de la clase // ...miembros de la
// ... // ... // clase ...
} } }

• El subdirectorio que contiene al paquete debe llamarse igual que el


paquete. P.e. Los ficheros Lapiz.java, Boligrafo.java y
Folio.java se ubicarán en el subdirectorio escritorio (Netbeans lo
crea automáticamente) 53
Ana Belén Moreno

Paquetes (packages)

• Para usar una clase situada en un paquete distinto al


actual, puede escribirse al principio del fichero actual la
palabra clave import seguida de las clases externas o
de los paquetes externos que se desean incluir.
• Una clase que se encuentra en un paquete externo, se
identifica mediante el nombre del paquete seguido del
selector punto “.” y a continuación el nombre de la clase.
• Así, para importar una clase individual de un paquete
específico, hay que escribir a continuación de la
sentencia package, lo siguiente:
import nombre_paquete.nombreClase;

54
Ana Belén Moreno

Paquetes (packages)
• Ejemplo:
package proyectofisica;
import ta.medidas.Termometro; //importa la clase Termometro
//del paquete ta.medidas
import ta.medidas.Escala; //importa la clase Escala del paquete
// ta.medidas
// con estas líneas al principio, se importan esas clases y
// ya se pueden usar esos identificadores de clases para
// instanciar objetos de esas clases y llamar a sus métodos.

• Ejemplo: puede importarse un paquete completo (con todas


sus clases) así:
import nombrePackage.*; //importa todas las clases del
// paquete nombrePackage.

• Aunque aparezca esta sentencia, el compilador genera


bytecode sólo para las clases utilizadas en el programa.
55
Ana Belén Moreno

Paquetes (packages)
• Si dos paquetes importados tienen clases que se llaman igual,
hay que indicar el paquete que contiene a cada una de las
clases cuando esta se va a nombrar. Ej.:
• Sean los paquetes cocina y pescaderia que contienen una
clase Mejillon cada uno. Si importamos ambos y usamos la
clase Mejillon, es preciso especificar el paquete de la clase a
la que nos referimos. Si no se indica el paquete, dará un error
por clase ambigua.
package alimentacion;
import cocina.Mejillon; //importa la clase Mejillon
// del package cocina.
import pescaderia.Mejillon;//importa la clase Mejillon
// del package pescaderia.
cocina.Mejillon m = new cocina.Mejillon(“fresco”);
pescaderia.Mejillon mej = new pescaderia.Mejillon(“purpura”);

• Java incorpora varios paquetes p.e. java.lang, java.io, etc.. con


las clases básicas System, String, Integer… 56
Ana Belén Moreno

Creación de una aplicación

• Fases:
Diseño

Codificación
Error de
sintaxis
Compilación
Generación de un fichero .class

Ejecución Error de
semántica (o
de ejecución)
Testeo y
depuración

57
Ana Belén Moreno
Diseño de una aplicación
• Se decide:
– cómo dividir el programa en clases,
– qué datos almacena cada clase,
– qué acciones realiza cada clase, cómo se comporta cada clase para
cada acción, y
– cómo interactúan estas clases.
• Se determina cómo definir cada clase (variables instancia y métodos):
– Se divide el trabajo en actores, cada uno con una responsabilidad. Se
describen las responsabilidades usando verbos de acciones. Estos
actores serán las clases del programa.
– El trabajo de cada clase debe ser lo más independiente de otras clases
que sea posible, t. q. cada clase tenga autonomía sobre algunos
aspectos del programa. Asignar cada dato (variables instancia) a la
clase que tenga jurisdicción sobre las acciones que acceden a ese dato.
– Se define de forma precisa el comportamiento de cada clase al recibir un
mensaje al que debe responder. Los comportamientos se traducen en
métodos que la clase ejecuta. Los comportamientos de una clase
forman una unidad cohesiva, es decir, están muy relacionados.
• La experiencia enseña a diseñar, al aparecer reiteradamente
patrones parecidos a los que ya se han visto alguna vez. 58
Ana Belén Moreno

Codificación
• Tras el diseño, se crea el código fuente (p.e.
en lenguaje Java) para las clases y
paquetes.
• Para ello se usa un editor, p.e.:
– en un editor de texto independiente, o
– en un editor integrado en un IDE (Integrated
Development Environment) como p.e. NetBeans
o Eclipse.

59
Ana Belén Moreno

Compilación
• Es la traducción del código fuente (en java) al
lenguaje que es capaz de interpretar la máquina
virtual de java.
• El código fuente en Java se compila invocando a
un compilador:
– p.e. llamando a un programa javac para que compile
nuestro fichero.
• En un IDE se compila haciendo clic en el botón de
compilación.
• Si hay errores, se corrigen los errores de sintaxis.
• Si no hay errores de sintaxis, el proceso de
compilación crea un fichero con extensión .class.
60
Ana Belén Moreno

Compilación
• Un compilador de Java no produce código
máquina ejecutable en un procesador específico,
sino que genera un código simplificado
denominado bytecodes, que precisa un intérprete
para ejecutarse.
• Este intérprete se denomina la Máquina Virtual de
Java.
• Una sola compilación genera bytecodes que
pueden ejecutarse en máquinas virtuales de
diferentes plataformas (Unix, Windows…).

61
Ana Belén Moreno

Ejecución
• El programa se ejecuta:
– invocando al comando java, fuera del IDE, o
– haciendo clic en el botón run del IDE.
• Las clases referenciadas en el programa se localizan en
alguno de los directorios especificados en la variable de
entorno del sistema operativo llamada CLASSPATH, que
contiene en orden los directorios en los que buscarlas:
– separados por “;” (en DOS/Windows) o
SET CLASSPATH=.; C\java;C:\Program Files\Java\
– Separados por “:” (en Unix/Linux)
SET CLASSPATH “.:/usr/local/java/lib:/usr/netscape/classes”
Donde el primer directorio de la lista denotado por un punto “.” es el
directorio actual desde el que la máquina virtual de java es
invocada.

62
Ana Belén Moreno

Testeo
• Testar es chequear si el programa es correcto.
– Se ejecuta el programa para un conjunto de entradas
representativo, entre ellas los casos especiales.
- P.e. para testar un método de ordenación de un array de enteros
deberíamos probar los siguientes casos:
- Array sin elementos
- Array de un elemento
- Array con todos los elementos iguales
- Array ya ordenado
- Array ordenado en orden inverso
- P.e. para testar un array para guardar datos, hay que probar los
casos insertar y borrar al principio y al final del array.
- Testar el programa con un gran número de entradas generadas
aleatoriamente.
- Cada método debe testarse como mínimo una vez.
- Cada sentencia del código conviene testarse una vez.
63
Ana Belén Moreno

Debugging o depuración de errores

• Debugging o depuración es el proceso de seguir la ejecución


del programa para descubrir dónde están los errores de
semántica detectados en el testeo.
• La técnica más simple es mediante sentencias print
(System.out.println(string)) para seguir los valores
de las variables durante la ejecución del programa.
– Al finalizar debemos borrar o comentar esos print.
• Otra técnica es usando un debugger, que es un entorno que
controla y monitoriza la ejecución del programa. Permite:
– Inserción de puntos de ruptura (breakpoints) en el código: cuando se
ejecuta el programa con el debugger, este se para en cada
breakpoint. Mientras el programa está parado, el valor actual de las
variables puede inspeccionarse.
64
Ana Belén Moreno

Legibilidad y estilo
• Los programas deben ser fáciles de leer y entender. Se recomienda:
– Usar nombres de identificadores con significado,
• que reflejen la acción para los métodos
• que reflejen el contenido de los datos
• Para los métodos y datos, se escribirán en minúsculas, y si se componen de
varias palabras, la primera letra de cada una será mayúscula, excepto la
primera letra del identificador que será minúscula.
– Ej.: insertarElemento(); isFull();
– Ej.: alturaAlumno, nombreEstudiante
• Idem para los nombres de clases salvo que en estos la 1ª letra será mayúsc.
– Ej.: Fecha, Vector, ControladorDispositivo.
– Usar constantes con identificador en lugar de constantes literales, para
obtener legibilidad, robustez y fácil modificación (en un solo punto del
programa). Los identificadores de constantes se escribirán en
mayúsculas:
public class Student{
public static final int MIN_CREDITS = 12;
public static final int MAX_CREDITS = 24;
public static final int SENIOR_CODE = 4;
// …Variables instancia, constructores y métodos …
} 65
Ana Belén Moreno

Legibilidad y estilo
• Indentar los bloques de sentencias
• Organizar cada clase en el orden siguiente:
– Constantes
– Variables instancia
– Constructores
– Métodos
• Escribir comentarios en línea para explicar
construcciones o explicaciones de forma rápida.
• Escribir bloques de comentarios para explicar el
propósito de un método y secciones de código
complejo.
66
Tipos básicos o primitivos, variables y constantes

• Los tipos básicos o primitivos están predefinidos en el lenguaje:


• Es posible declarar variables de Tipos Valores de las variables
primitivos
estos tipos y asignarles valores
boolean Verdadero o falso
mediante el operador de char Caracteres unicode 16 bits
asignación. byte Enteros con signo 8 bits
short Enteros con signo 16 bits

int Enteros con signo 32 bits

long Enteros con signo 64 bits


float Reales 32 bits
double Reales 64 bits

67
Tipos básicos o primitivos, variables y constantes

• Constantes con identificador (no literales)


Si el valor de una variable no puede modificarse
durante la ejecución del programa, esta se declara
con el modificador final, y se inicializa en la
declaración. Ej.:
final double NUM_JUGADORES = 11; //declaración de cte.

int a, b; //declaración de variables, reserva de memoria.


int c = 3; // declaración e inicialización

a = 8; // el valor de a es 8.
b = 5*c - a - NUM_JUGADORES; // el valor de b es -4;
Ana Belén Moreno

Expresiones
• Las expresiones pueden contener constantes
literales, variables, operadores…
– Constantes literales:
• null: es el único literal objeto, puede asignarse a
cualquier ref. o identificador de cualquier tipo de objeto.
• true, false (boolean)
• 176, -52, etc… (int de 32 bits)
• 176L, 52l, etc…(long de 64 bits)
• 3.1415, 135.23, 3.14E2, 19e10, etc…(double)
• 32.45F, 54.46f, etc ... (float)
• ‘a’, ’A’, ‘?’, ‘7’, ‘8’, ‘0’, ‘\n’, ‘\t’, ‘\\’, ‘\’’, ‘\”’,… (char)
• “María Pérez Álvarez” 69
Expresiones
– Operadores.
Operador asignación
= Variable = expresión;
a = 4;
Asigna el valor de expresión a la variable
Operadores aritméticos
(binarios)
+ Suma

- Resta

* Multiplicación

/ División. Resultado entero para operandos enteros,


resultado real para operandos reales
% Módulo, n%m es el resto de la división entera n/m

Operador aritmético
(monario)
- Negación, -expresión invierte el signo de expresión.
70
Expresiones
– Operadores
Operadores de
relación
< menor que

Son binarios. <= Menor o igual que


Los operandos son
expresiones
numéricas.
== Igual a

El resultado de la != Distinto
operación es
booleano. >= Mayor o igual que

> Mayor que

Operadores
booleanos
! No (monario)

(Operandos y
resultado booleanos)
&& y (binario)

|| o (binario) 71
Ana Belén Moreno

Expresiones
Casting
• Permite cambiar el tipo de un valor.
• Sintaxis:
(tipo_nuevo) expresión;
• Ejemplo:
double d1 = 3.2;
double d2 = 3.9999;
int i1 = (int)d1; //i1 toma el valor 3
int i2 = (int)d2; //i2 toma valor 3
double d3 = (double)i2; //d3 toma el valor 3.0

72
Ana Belén Moreno

Reglas de precedencia de los


operadores

73
Ana Belén Moreno

Instrucciones de selección
If simple
//expresión booleana entre paréntesis
if (expresión_booleana)
sentencia_o_bloque_si_true // si es un bloque va entre llaves
else
sentencia_o_bloque_si_false // esta parte es opcional

Ifs en cascada // si es un bloque va entre llaves

if (primera_expresión_booleana)
primera_sentencia_o_bloque_si_true // si son bloques van entre
else if (segunda_expresión_booleana) // corchetes
segunda_sentencia_o_bloque_si_true

else if (enesima_expresión_booleana)
enesima_sentencia_o_bloque_si_true
else
sentencia_o_bloque_si_false 74
Ana Belén Moreno

Instrucciones de selección
switch
Permite evaluar una expresión aritmética y ejecutar las
expresiones que coinciden o corresponden con su resultado:
switch(day) {
case 24:
System.out.println(“Es Nochebuena”);
break;
case 25:
System.out.println(“Es Navidad”);
break;
case 31:
System.out.println(“Es Nochevieja”);
break;
default:
System.out.println(“Hoy no hay fiesta”) ;
break;
}

break permite evitar que si se cumple una condición, se chequeen las demás.
En lugar de esto break hace que se termine de ejecutar switch.
Ana Belén Moreno

Instrucciones de repetición
• for permite repetir una sentencia o un
bloque de sentencias un número concreto de
veces.
Expresión booleana. Si se ejecuta el
inicialización bloque se incrementa
Si se cumple se
ejecuta el bloque el contador.

for (cont=0; cont < 100; cont++){


a = a*b/cont;
}

76
Ana Belén Moreno

Instrucciones de repetición
• While suele utilizarse cuando el número de
iteraciones no es concreto sino que depende
del resultado de evaluar una condición.
Expresión booleana.
Si se cumple se
ejecuta el bloque

While (a > b) {
b = b*3;
a = a-1;
}
77
Ana Belén Moreno

Instrucciones de repetición
• do while similar al anterior salvo que
obliga a ejecutar una primera iteración antes
de evaluar la condición.
Expresión booleana. Si
se cumple se ejecuta
el bloque otra vez

do{
b = b*3;
a = a–1;
} while (a>b);
78
Ana Belén Moreno

Arrays

– Un array o tabla es una estructura de datos


(ED), cuyos elementos se almacenan
formando una secuencia.
– Los elementos de un array se almacenan en
posiciones de memoria contiguas.
– Todos los elementos de un array son del
mismo tipo, normalmente de un tipo primitivo,
p.e. char, int, double…
Ana Belén Moreno

Arrays unidimensionales

– El acceso a los elementos de un array es


directo: permiten almacenar y recuperar cada
elemento directamente, especificando su posición
(índice) en el array.
– El índice es una expresión de tipo int, siendo 0 el
índice del primer elemento, 1 el del segundo, etc…

Acceso: a[0] a[1] a[2] a[3] a[4]

a 89 23 42 11 43

índice 0 1 2 3 4

Array a de 5 elementos enteros. 80


Ana Belén Moreno

Arrays unidimensionales
Declaración de un array: puede hacerse de dos formas:
tipo identificadorArray[ ];
tipo[ ] identificadorArray;

Ejemplos:
int v[ ];
float[ ] w;
// Un array (p.e. v, w) es una referencia a un objeto. Con esta
// declaración el array no está creado (instanciado). Se ha reservado
// espacio para las referencias a los objetos arrays v y w, pero no se ha
// reservado espacio en la memoria para guardar sus elementos.
// Para que se cree o instancie el array se usa el operador new
// junto al tipo de los elementos del array y su número (longitud
// del array) entre corchetes. Ej,:
float velocidades[]; // declaración
velocidades = new float[26]; //estas dos sentencias equivalen a:
float velocidades[] = new float[26]; // declaración e instanciación.
81
Ana Belén Moreno

Arrays unidimensionales
Constructor:
nombreArray = new tipo[tamaño];

Ejemplo:
a = new int[5]; //reserva espacio en la
//memoria para el array a de 5
//enteros (tamaño 5).
Declaración y creación de la tabla en una única sentencia:
int a[ ] = new int[5];

int datos[] = new int{2, -3, 0, 7, 1};


//esta última declara, instancia e inicializa
Ana Belén Moreno

Arrays unidimensionales
• Tamaño o longitud de un array: número de elementos que
caben en la tabla. El atributo length lo contiene:

double v[] = new double[15];


System.out.print(v.length); // escribe 15

• Uso del atributo length de un array para calcular la suma de


los elementos de un array de tipo double, dentro de la función
suma:
double suma (double[] w){
double s = 0.0;
for (int i=0; i < w.length; i++) //recorrido por los elem.
s = s + w[i]; // en cada iteración se accede a w[i]
return s;
}
Ana Belén Moreno

Redimensionamiento de arrays
• Los arrays son ED Estáticas: su tamaño se
establece de forma fija cuando se instancia el array,
y este tamaño no puede cambiarse dinámicamente
(en t de ejecución).
• Una forma de “aumentar” el tamaño de un array u:
– crear un segundo array v de mayor tamaño,
– asignar todos los datos del primer array u a las primeras
posiciones de v, y
– hacer que la referencia u pase a referenciar al nuevo array
v así: u = v
– El recolector de basura liberará la memoria ocupada por u
anteriormente al dejar de estar referenciada.
84
Ana Belén Moreno

Asignación de arrays
• Si se hace una asignación entre 2 variables array, estas
referenciarán al mismo array.

double [] r, w;
r = new double[5];
w = new double[7];

for (int j = 0; j < r.length; j++)


r[j] = (double) 2*j-1;

w = r; // w y r apuntan al mismo array, no se ha


// creado uno nuevo. Los 7 elementos que al
// principio se referenciaban desde w se
// pierden, ya no se puede acceder a ellos y su
// memoria se liberará.
Ana Belén Moreno

Arrays bidimensionales
• También llamados matrices. Sea una matriz de
N filas y M columnas, se accede a sus elementos
por 2 índices:
– índice de fila, i donde 0  i < N
– índice de columna, j donde 0  j < M.
Declaración:
tipo nombreMatriz[][];

Ejemplo:
int b[][]; // declaración
b = new int[7][5]; //instanciación o reserva de
// memoria para los 7x5 datos int.
//Estas 2 instrucciones pueden hacerse en una sola:
int b[][] = new int [7][5]; 86
Ana Belén Moreno
Arrays bidimensionales
Índice de
b
Tienen dos dimensiones (filas y Índice columna
columnas) de fila 0 j M-1
0 6.4 … 6.4 … 6.4
Consisten en una matriz de elementos
todos de un mismo tipo. 1 9.0 … 9.0 … 6.4
Se accede a cada uno mediante una . … ... … ... …
expresión que viene dada por el i 2.2 … 2.2 … 6.4
nombre del array, y dos índices (el de . … ... … ... …
fila y el de columna), que son 3.7 … 2.2 … 9.0
expresiones enteras que indican su
posición en el array. Los índices se N-1 5.5 … 1.3 … 2.9

escriben entre corchetes.


Expresión para el acceso a una
posición:
b[i][j]
Acceso a las b[i][0]
identificArray[ind_fil][ind_col] componentes:
b[1][0]

Array bidimensional b, de NxM


elementos reales
87
Ana Belén Moreno
Ejemplo
Array bidimensional de 7x3 elementos booleanos denominado casasVendidas

Columnas:
Filas: 0 1 2
0
True False True
1 True False True
2 True True False
3 True False False
4 False True True casasVendidas[4][2]

5 True False True Indice


de fila Indice
6 True True False de col

88
Ana Belén Moreno

Arrays bidimensionales
Para recorrer una matriz se usan dos bucles
anidados.
– Uno va variando el índice de fila (i) para
posicionarse en cada fila en cada iteración:
• i va incrementándose en cada iteración en una unidad,
desde 0 hasta el nº filas - 1.

– Otro va variando el índice de columna (j) para


posicionarse en cada columna en cada iteración:
• j va incrementándose en cada iteración en una unidad,
desde 0 hasta el nº de columnas – 1..
89
Ana Belén Moreno

Arrays bidimensionales
• Recorrido de una matriz por filas, pasando por
todos sus elementos. Sea el tamaño de la matriz
NUM_FILAS X NUM_COLUMNAS:

// Se fija el índice de fila a un valor y se recorren


// todas las columnas variando el índice de columna
// desde cero hasta el número de columnas. Se repite
// esta operación para cada fila.

for (int i=0; i < NUM_FILAS; i++)


for (int j=0; j < NUM_COLUMNAS; j++){
//Procesar elem b[i][j], p.e.:
b[i][j] = expresión;
}
Ana Belén Moreno

Arrays bidimensionales

• Recorrido por columnas por todos los elementos de


una matriz. Sea el tamaño de la matriz NUM_FILAS X
NUM_COLUMNAS:

// Se fija el número de columna y se recorren


// todas las filas (variando el índice de fila).
// Se repite esta operación para cada columna.

for (int j=0; j < NUM_COLUMNAS; j++)


for (int i=0; i < NUM_FILAS; i++){
// Se procesa el elemento b[i][j], p.e.:
variable = ... b[i][j] . . .
} 91
Ana Belén Moreno

Cadenas
La clase String
• Una cadena es una secuencia de caracteres delimitada entre dobles
comillas p.e. “Amigo mío”.
• “Amigo mío” es una constante o literal cadena, compuesta por 10
char (en Unicode).
• Java no tiene el tipo cadena como tipo primitivo.
• Para el manejo de cadenas hay varias clases, p.e. la clase String.
Otra es la clase StringBuffer (esta no se va a dar).
• En Java, una cadena es un objeto de la clase String.
• Declaración:
String cadena1, cadena2; // se crean 2 referencias.

// Para crear el objeto String no es necesario usar el operador


// new. En vez de esto puede hacerse inicializando a una cte
// cadena:

String cadena1 = “”; // Se asigna cadena vacía.


String cadena2 = “\n \t Lista de pasajeros \n”
92
Ana Belén Moreno

Cadenas
La clase String. Asignación
• Las cadenas asignadas (objetos) no pueden ser modificadas, ni
expandirse ni eliminarse caracteres, son inmutables.
• Sí puede asignarse otra cadena a una referencia a un objeto de la
clase String, para que tome otro valor.
Ejemplo:
String cadena1 = "Madrid";
String cadena2 = "Segovia";

System.out.println(cadena1 + ", " + cadena2);


// Escribe en pantalla:
Madrid, Segovia
cadena2 = "Valladolid";
System.out.println(cadena2);
// Escribe en pantalla:
Valladolid
// Ahora cadena2 referencia a la cte “Valladolid” y la otra
// cadena “Segovia” ha dejado de ser referenciada (será liberada la
// memoria que ocupa por el recolector de basura).
93
Ana Belén Moreno

Cadenas
Inicialización con un constructor de String.

• Además de inicializarse con la asignación de un literal, puede


hacerse con el operador new seguido de constructores de la
clase String:

String cadena1 = new String(); // Constructor que inicializa a


// cadena vacía

// Construcción a partir de otra cadena ya creada:


String cadena2 = ...;
String cadena3 = new String(cadena2);

94
Ana Belén Moreno

Cadenas
Comparación de cadenas
• El operador != aplicado a identificadores de Strings
compara las referencias, no el contenido:
String cadena1 = "Sábado";
String cadena2 = new String(cadena1);

if (cadena1.equals(cadena2)) //esta condición resulta true


System.out.println("el contenido es el mismo");

if (cadena1 != cadena2) // esta condición resulta true


System.out.println("Las referencias son distintas");

• Esto es debido a que las referencias (direcciones) son


distintas.
• El método equals() compara el contenido de las cadenas y
éstas son iguales. 95
Ana Belén Moreno

Cadenas
Asignación de cadenas de la clase String.
• Las cadenas son objetos. Las variables de tipo String
son referencias a estos objetos.
• La asignación de variables String no copian los objetos
(las cadenas), sino que copian las referencias:
String cadena1 = new String ("Sábado");
String cadena2 = new String ("Sábado");

if (cadena1 == cadena2) //la condición es false, las ref. son distintas


System.out.println("la condición es false");

cadena1 = cadena2; // ahora ya referencian al mismo objeto. El anterior


// objeto referenciado por cadena1 será liberado.

if (cadena1 == cadena2) // la condición es true.


System.out.println(cadena1 + cadena2);
96
Ana Belén Moreno

Cadenas
Algunos métodos de la clase String.
• Las cadenas asignadas a objetos String no pueden modificarse, en vez
de esto, los métodos devuelven otra referencia a una nueva cadena.
• Existe una clase StringBuffer cuyos valores sí pueden modificarse, pero
está fuera del alcance de esta asignatura.
Algunos métodos de la clase String
int length(); Devuelve el nº de caracteres de la cadena
invocante
String concat(String cad2); Devuelve un String resultado de añadir cad2 al
final de la cadena invocante.
charAt(int posicion); Devuelve el carácter cuyo índice es posicion
String substring(int inicial, int Devuelve la cadena formada por los caracteres
final); comprendidos entre inicial y final.
int indexOf(char car); (a) Busca un carácter car desde la posición 0 y
int indexOf(char car, int pos); devuelve el índice de su primera aparición.
int indexOf(String cad, int pos); (b) Lo busca a partir de una posición pos.
(c) Busca la primera ocurrencia de una cadena
cad a partir de pos. 97
Ana Belén Moreno
Cadenas
Algunos métodos de la clase String (continúa)
int compareTo(String cad2); Compara alfabéticamente la cadena invocante
(cad1) con la que se pasa como argumento
(cad2). Devuelve:
- 0 si cad1 y cad2 son iguales.
- un nº < 0 si cad1 está delante de cad2 (cad1 es
menor alfabéticamente que cad2).
- un nº > 0 si cad1 está detrás de cad2.
boolean equals(String cad2); Devuelve true si la cadena que llama al método
coincide con cad2 (tiene en cuenta mayúsculas y
minúsculas).
boolean equalsIgnoreCase(String cad2); Devuelve true si la cadena que llama al método
coincide con cad2 (sin diferenciar mayúsculas y
minúsculas).
String replace(char c1, char c2); Devuelve la nueva cadena con todas las
ocurrencias de c1 sustituidas por el carácter c2.
String toUpperCase(); Convierte la cadena en otra cadena con todas las
letras en mayúscula.
String toLowerCase(); Convierte la cadena en otra cadena con todas las
letras en minúscula.
98
Ana Belén Moreno

Cadenas
Algunos métodos de la clase String (cont.)
Algunos métodos de la clase String
String valueOf(tipo_dato_primitivo dato); Convierte un dato de un tipo
primitivo en una cadena.
P.e:
String valueOf(char c);
String valueOf(char datos[]);
String valueOf(double d);
String valueOf(int i);
etc…

99
Ana Belén Moreno

Cadenas
Ejemplo
String cad1 = “Hola ”;
String cad2 = “Mundo”;
String cad3;

cad3 = cad1.concat(cad2); // construye e inicializa


// cad3 mediante una
// asignación de una cadena
System.out.println(cad3); // Escribe “Hola Mundo”

Ejemplo
String cad1 = “Zorro”;
String cad2 = “Ave”;
System.out.println(cad1.compareTo(cad2));
// Escribe un nº > 0 pues Zorro va después de Ave en
// el alfabeto. 100
Ana Belén Moreno

Cadenas
El operador + con cadenas.
• Da como resultado otro objeto cadena que es la
concatenación de ambas. Ejemplo:

String cadena1 = “Pepita”;


String cadena2 = “Jiménez”;
String cadena3 = cadena1 + “ ” + cadena2;
// Se ha generado la nueva cadena “Pepita Jiménez”

• Se puede aplicar el operador + para concatenar una cadena


con cualquier dato. Primero se convierte el dato a una cadena
y a continuación se unen las cadenas. Da como resultado otro
objeto cadena que es la concatenación de ambas. Ejemplo:

String cadena4 = 34 + “ Estaciones”;


// Se ha generado la nueva cadena “34 Estaciones”.
101
Ana Belén Moreno

Cadenas
De String a array de caracteres y viceversa
Algunos métodos de la clase String
char[] toCharArray(); Crea y devuelve un array de caracteres con
el contenido de la cadena invocante, con un
carácter en cada elemento del array.
static String copyValueOf(char[] Método estático de la clase String que
tabla); devuelve un String con los caracteres
que se encuentran en el array de caracteres
tabla.
void getChars(int p1, int p2, Devuelve en un array de caracteres ar, con
char[] ar, int inicial); los caracteres comprendidos entre p1 y p2,
copiados en ar a partir de un índice
inicial.

Nota: las funciones con el modificador static son de la clase, no de los


objetos, por tanto se llaman con el nombre de la clase a la que
pertenecen (no de un objeto instancia de la misma), seguido de . y
seguido de la llamada al método. 102
Ana Belén Moreno

Cadenas

De String a array de caracteres y viceversa


Ejemplo
String cad = “Hola mundo”;
char c[];
c = cad.toCharArray();
// c vale [‘H’,‘o’,‘l’,‘a’,’ ‘,’m’,’u’,’n’,’d’,’o’]

Ejemplo
String cad;
char c[] = {‘H’,‘o’,‘l’,‘a’};
cad = String.copyValueOf(c); // cad vale “hola”

103
Ana Belén Moreno

Caracteres
Algunos métodos de la clase Character.
Algunos métodos de la clase Character.
static String toString(char c); Crea y devuelve una cadena de longitud 1
que contiene el carácter c.
static char toUpperCase(char c); Convierte el carácter c a mayúscula.
static char toLowerCase(char c); Convierte el carácter c a minúscula.

Nótese que los tres métodos son static, es decir de la clase, no


están asociadas a un objeto particular.
Ejemplo
char c = ‘H’;
char d;
d = Character.toLowerCase(c); // d vale h

Ejemplo
char c = ‘b’;
String cad = Character.toString(c); // cad vale “b”
104
Ana Belén Moreno

Números aleatorios
• Existen varias formas de generar números aleatorios en java.
• Una de ellas es instanciando un objeto de la clase Random,
que se encuentra definida en el paquete java.util. Para
usarla es preciso importar:
import java.util.*;

• Métodos de los objetos de la clase Random:


nextInt() // devuelve un entero aleatorio
nextDouble() // “ “ double “
nextFloat() // “ “ float “
nextBoolean(), // “ “ booleano “
etc...
para crear distintos tipos de datos aleatoriamente.
105
Ana Belén Moreno

run:
10 enteros Ejemplo
aleatorios:

-1463122994
-1552155740
-797089706
-1561137818
1802539988
-347546187
1125385909
137234987
-1333859992
-123030488

10 enteros
aleatorios
positivos:

1547912996
340272380
157508778
1229294245
1672788974
681630928
287385870
306875731
436415001
1551869895
Ana Belén Moreno

run:
Ejemplo
10 enteros
aleatorios
positivos
menores que
55:
39
44
13
14
4
43
7
45
48
23
10 enteros
positivos entre
20 y 30:
25
26
20
22
25
28
24
26
26
30 107
Ana Belén Moreno
Ejemplo

run:
10 reales double
aleatorios:
0.121497492293692
0.275647525859549
0.6787341772001579
0.29933563201366375
0.6886522546340924
0.4181293304103626
0.42424402180590004
0.11122768754553491
0.48192922661870397
0.7035660920719496
10 booleanos aleatorios:
false
true
true
true
false
true
false
true
false
true
108
Ana Belén Moreno

Recursividad

• Una función puede ser invocada desde


cualquier lugar:
– Desde el programa principal o método main
– Desde otra función o método
– Desde dentro de su propio cuerpo de
instrucciones
• En este último caso, cuando una función
se invoca a sí misma, se dice que la
función es recursiva.
109
Ana Belén Moreno

Recursividad
int funcionRecursiva(){
...
...funcionRecursiva() ... ; // llamada recursiva
...
}

• Dentro de funcionRecursiva() se hace una


llamada a funcionRecursiva(), entonces, se
volverá a llamar a funcionRecursiva(), y así
sucesivamente.

• Hay que introducir un mecanismo que detenga en


algún momento la serie de llamadas recursivas,
evitando un ciclo infinito de llamadas. 110
Ana Belén Moreno
Recursividad
• Se introduce una sentencia if que utilice una condición
llamada caso base, que en algún momento se ha de cumplir:
– cuando se cumple se dice que se ha llegado al caso base, y se impide
que se continúe con una nueva llamada recursiva.
• Solo se hace una nueva llamada recursiva cuando la condición
del caso base sea false (en el bloque else):

int funcionRecursiva(<datos>){
int resultado;

if (<caso base>) {
resultado = valorBase; // asignación al llegar al caso base
} else {
resultado =...funcionRecursiva(<nuevos datos>)...; // llamada
//recursiva
}
return resultado;
} 111
Ana Belén Moreno

Recursividad

• Para procesar un conjunto de datos en las sucesivas


llamadas recursivas, el tamaño (o número) de los
datos a procesar en cada llamada recursiva se va
haciendo cada vez menor, tendiendo hacia lo
requerido para que se ejecute el caso base, donde el
tamaño de los datos es tan pequeño, que la solución
es una constante que se asigna al resultado final.
– <nuevos datos> debe ser de menor tamaño que <datos>
para garantizar el cumplimento del caso base.

112
Ana Belén Moreno

Recursividad
Sea el factorial de 6: 6! = 6*5*4*3*2*1 = 6*5!.
En general: n! = n * (n-1)!
factorial(n) = n * factorial(n-1)

Es un ejemplo de cómo el tamaño de la entrada va


disminuyendo en las sucesivas llamadas recursivas. Para
calcular el factorial de un número podemos utilizar el factorial
de un número más pequeño, y así sucesivamente hasta llegar
al caso base en el que el factorial será una constante (0! = 1),
y no se necesitará volver a realizar una llamada al método
recursivo para calcularlo.
factorial(0) = 1 // el factorial en el caso base (cuando n == 0), es
// una cte que se asigna => no hay llamada recursiva.
Ana Belén Moreno

Recursividad
int factorial(int n){
int resultado;
if (n == 0){
resultado = 1; // caso base
}
else{
resultado = n*factorial (n-1);//llamada recursiva
}
return(resultado);
}
Ejemplo de ejecución para n = 3: (8º)return 6
(1º)Llamada a factorial(3). Se ejecuta resultado = 3 * factorial (2) (7º)=3*2 = 6
(2º)Llamada a factorial(2) se ejecuta resultado = 2*factorial(1) (6º)= 2*1=2
(3º)Llamada a factorial(1) se ejecuta resultado = 1*factorial(0) (5º) =1.1 =1
(4º)Llamada a factorial(0) se ejecuta el caso base: resultado = 1
Ana Belén Moreno

Clases envoltorio o
contenedoras (wrappers)

• Hay estructuras de datos como las colecciones (que veremos


más adelante), que no trabajan con tipos primitivos, sino con
objetos.
• También hay funciones cuyos argumentos son objetos, por
tanto, no pueden recibir datos de un tipo primitivo, sino que
tienen que ser objetos de una cierta clase.
• En esos casos no se pueden usar datos de tipo int, double...
• Por ello Java tiene implementadas unas clases que
“envuelven” datos primitivos dentro de un objeto llamado
envoltorio o wrapper.

115
Ana Belén Moreno

Clases envoltorio o
contenedoras (wrappers)
• Para cada tipo primitivo hay definida una clase envoltorio.
Ejemplos:

Tipo Primitivo Clase envoltorio


int Integer
boolean Boolen
float Float
double Double
short Short
char Character
etc… etc...

116
Clases envoltorio o Ana Belén Moreno

contenedoras (wrappers)
• Construcción a partir de un valor primitivo pasado al constructor.

Integer x = new Integer(3); // x es un objeto de la clase Integer


//que guarda un 3 en su interior.

• Pueden manipularse como si fueran primitivos, p.e. instanciarse sin


recurrir al constructor (válido para cualquier otra pareja primitivo-wrapper
distinta de int-Integer):

Integer x = 3; // el compilador envuelve al 3 automáticamente


// antes de asignarlo a x (esto se llama autoboxing);
Integer y = new Integer(5);
Integer z = x + y; //Se suman Integer como si fueran int.
System.out.println(z); // mostrará un 8 en pantalla.

int w = z; // del mismo modo, al asignar un Integer a un int


// lo desenvuelve automáticamente antes de
// asignarlo a una variable entera.
Integer v = x + 9; // se desenvuelve x, se suma con el 9 y envuelve el
//resultado para asignarlo a v.
117
Clases envoltorio o Ana Belén Moreno

contenedoras (wrappers)
• Todas las clases envoltorio excepto Character heredan de la
clase abstracta Number, es decir, tienen las mismas operaciones
que sus tipos primitivos (se pueden aplicar sobre ellas las
operaciones aritméticas, comparaciones, etc…). Ejemplo:
Double x1 = 1.32;
Double x2 = 4.21;

if (x1 < x2) // operador de comparación


System.out.println(x1 + " < " + x2);

• Java envuelve y desenvuelve para colocar un tipo primitivo donde


se espera un primitivo, y un wrapper donde se espere un wrapper.
Ejemplo: Dada la función donde se espera un Integer:
void nombre_función(Integer x){
…}
Puede ser llamada enviando un parámetro int:
nombre_funcion(5); //java lo envuelve antes de pasarlo.
118
Ana Belén Moreno
Clases envoltorio o
contenedoras (wrappers)
• Además de poder operar igual que con valores primitivos, los
envoltorios, al ser objetos, disponen además de una serie de
métodos.
• Entre ellos, los que convierten cadenas de caracteres, p.e.
leídas de teclado, a valores de la clase envoltorio. Ejemplo:
la clase Double dispone del siguiente método.
static double parseDouble(String cadena);
// Este método convierte a Double una cadena que representa a
// un número real, y que se le pasa como argumento.
• Ejemplo:
String cad = "23.546";
double t = Double.parseDouble(cad);
System.out.println(t); // la variable t contiene 23.546
• Los demás wrappers disponen de métodos análogos.
119
Ana Belén Moreno

Comparaciones
• Para comparar datos primitivos en Java usamos operadores
relacionales:
<, >, <=, >=, ==, !=
• Estos sirven también para comparar clases envoltorio.
• Sin embargo, no sirven para comparar objetos.
• Ejemplo:
– Si deseamos saber si dos objetos son iguales (p.e. para
realizar una búsqueda de un objeto), el operador ==
compararía las referencias de los dos objetos, es decir, la
dirección de memoria a la que referencian, y devolvería
true si se tratase del mismo objeto. Pero esto no es lo
que buscamos cuando deseamos comparar el contenido,
esto es, los datos de los objetos.
120
Ana Belén Moreno

Comparaciones
Comparaciones: el método equals()
• Para saber si dos objetos son iguales se usa el método equals().
• Está implementado en la clase Object, de la que heredan todos
los objetos, que por tanto cuentan con esta operación. Sin embargo,
no conviene usar esta implementación, pues funciona como == en
cuanto al contenido de los objetos.
• Si se desea que la comparación esté basada en el contenido de los
datos de los objetos, debe implementarse este método en la
definición de la clase del objeto sobreescribiendo así la versión
heredada de Object.
• Ej.: Si queremos comparar objetos de la clase Persona utilizando el
dni como criterio de comparación, debemos crear un método
equals() dentro la clase Persona e implementarlo, de tal manera
que devuelve true si el objeto invocante contiene el mismo valor de
dni que el objeto pasado como argumento. 121
Ana Belén Moreno

Comparaciones
Comparaciones: el método equals()
Algunas clases definidas por Java como String, y las clases
envoltorio traen bien implementada la función equals(), lo
que permite hacer comparaciones de forma eficiente.

• Ejemplos:
String cad1 = “sancho”;
String cad2 = “sancho”;

if (cad1.equals(cad2)) // la condición es true


System.out.println(cad1+ “ es igual a ” +cad2);

122
Ana Belén Moreno

Comparaciones
Comparación de arrays: método equals de la clase Arrays
• Las tablas o arrays (que son objetos implementados ya en java) no
hacen overriding de equals().
• Para comparar tablas sin tener que recorrerlas explícitamente se puede
emplear el método Arrays.equals(), que es un método static de
la clase Arrays, que admite como argumentos las dos tablas a
comparar.
• Devuelve true si las dos tablas tienen el mismo tamaño y los mismos
elementos y en el mismo orden.
• Este método está sobrecargado, para admitir tablas de tipos primitivos,
así como de elementos Object.

• Ejemplo:
int t1[] = {1,2,3};
int t2[] = {1,2,3};
System.out.println(t1.equals(t2));//devuelve false, compara refs.
System.out.println(Arrays.equals(t1,t2));//devuelve true 123
Ana Belén Moreno

Comparaciones
Creación del método equals()en las clases
definidas por el programador
• Si necesitamos comparar dos objetos de una clase definida por
el programador , tendremos que implementar el método
equals() en la definición de la clase, haciendo overriding (es
decir, sobre-escribiendo) el que tiene heredado de la clase
Object.
• Ejemplo: implementamos la clase Persona, con los atributos
dni, nombre y edad. Elegimos dni para comparar 2
personas.

124
Comparaciones Ana Belén Moreno

Creación del método equals() en las clases definidas por el


programador. Ejemplo:
NOTA: Se implementa el método equals con la misma cabecera que el de la
clase Object que se va a sobreescribir:
public class Persona{
int dni;
String nombre;
int edad;

Persona(int dni, String nombre, int edad){


this.dni = dni; // public para tener el mismo permiso
// de acceso que el método heredado.
this.nombre = nombre; // Parámetro Object pues tiene que
this.edad = edad; // coincidir con el de la función
} // sobre la que se va a hacer overriding
public boolean equals(Object otro){
boolean iguales;
iguales = (dni == ((Persona)otro).dni);
return iguales; // cast para la conversión de Object a
} // Persona.
// NOTA: si dni fuese un String
} // podríamos usar el método equals de la
// clase String para la comparación 125
Comparaciones: creación del método equals()Anaen las
Belén Moreno

clases definidas por el programador. Ejemplo:


package ejemplocomparaciones;
public class Persona{
String dni;
String nombre;
int edad;

Persona(String dni, String nombre, int edad){


this.dni = dni;
this.nombre = nombre;
this.edad = edad; // NOTA:
} // si dni fuese int, podría hacerse:
@Override // return dni == ((Persona) otro).dni;
public boolean equals(Object otro){
return dni.equals(((Persona) otro).dni);
}
package ejemplocomparaciones;
}
public class EjemploComparaciones {

public static void main(String[] args) {


// TODO code application logic here

Persona p1, p2, p3;


p1 = new Persona("aaa", "Ramón", 27);
p2 = new Persona("bbb", "Ramón", 27);

System.out.println(p1.equals(p2));//devuelve false
}
} 126
Ana Belén Moreno

Métodos de Salida por pantalla


• En Java hay clases y métodos para E/S a través de interfaces gráficas
(ventanas, menús, campos de texto…), pero están fuera del alcance de esta
asignatura.
• Usaremos métodos de E/S por pantalla (salida estándar).
• System.out es un objeto estático, instancia de la clase
java.io.PrintStream, que define métodos para un flujo de salida por
buffer, en el que los caracteres se llevan a una localización temporal
llamada buffer, que es vaciada cuando la ventana consola está preparada
para imprimirlos.
• Por ello, para usar System.out incluiremos “import java.io.*;” al
principio del fichero (debajo de package…;).
• System.out posee los siguientes métodos:
print (tipoBase b); // tipoBase puede ser int, double, char, boolean…
print(String s); // escribe un String.
println(String s); // escribe el String seguido de salto de línea
print(Object o); //escribe el objeto o usando su método toString.

127
Ana Belén Moreno

Métodos de Salida por pantalla


• Ejemplo:
import java.io.*; // importa la clase del objeto System.out.
public class EntradaSalidaApp {
public static void main(String[] args) {
int a = 3;
double b = 4.5;
char c = 'r';
String cad = "hola";
System.out.println(a + " " + b + " " + c + " " + cad);
System.out.print("Valores: ");
System.out.print (3.1415 + " ");
System.out.print(',');
System.out.print(15 + " ");
System.out.println("double, char, int");
}
}
• Salida:
3 4.5 r hola
Valores: 3.1415 ,15 double, char, int 128
Ana Belén Moreno
Entrada por teclado usando
métodos de la clase Scanner
• También hay un objeto especial para realizar la
entrada por teclado, llamado System.in.
• Este objeto se usa para crear un objeto Scanner, así:
Scanner s = new Scanner(System.in);
• La clase Scanner de java.util tiene métodos para
leer datos de un flujo de entrada (en inglés, input
stream).
– La clase Scanner lee el flujo de entrada y lo divide en datos
separados por delimitadores (por defecto espacios en
blanco o tabuladores o saltos de línea).
– Los datos pueden leerse como strings o pueden
convertirse a un tipo base usando el método apropiado. 129
Ana Belén Moreno
Entrada por teclado usando
métodos de la clase Scanner
Métodos de la clase java.util.Scanner
Métodos Valor que devuelven
hasNext() Devuelve true si hay otro dato en el flujo de entrada
next() Devuelve el siguiente dato string en el flujo de
entrada. Da error si no hay más datos en él.
hasNextType() Devuelve true si hay otro dato en el flujo de entrada
y este corresponde a un tipo base Type, donde
Type puede ser Boolean, Double, Float, Int,..
nextType() Devuelve el siguiente dato del flujo de entrada, con
tipo base Type. Da error si no hay más datos o si el
siguiente dato no es de tipo Type.
hasNextLine() Devuelve true si el flujo de entrada tiene otra línea
de texto.
nextLine Avanza la entrada hasta pasar la línea actual, y
devuelve la entrada que fue saltada.
130
Ana Belén Moreno
Entrada por teclado usando métodos
de la clase java.util.Scanner
• Ejemplo:
import java.util.Scanner; //La clase Scanner lee el flujo de entrada.
public class EntradaSalidaApp {
public static void main(String[] args) {
double v, t;

//lectura con Scanner


Scanner s = new Scanner (System.in);
System.out.println("Introduce tu velocidad media en coche en km/h: ");
v = s.nextDouble();
System.out.println("Introduce el tiempo que quieres tardar en h");
t = s.nextDouble();
System.out.println("Puedes ir a una ciudad a " + (v*t) + " kms");
}
}

• Salida:
Introduce tu velocidad media en coche en km/h:
120
Introduce el tiempo que quieres tardar en h
6
Puedes ir a una ciudad a 720.0 kms 131
Ana Belén Moreno
Entrada por teclado usando métodos de
la clase java.util.Scanner
Ejemplo:
Lectura de 5
enteros cada uno
introducido en una
línea distinta,
almacenamiento en
un array, y
escritura por
pantalla.

132
Ana Belén Moreno
Entrada por teclado usando métodos de
la clase java.util.Scanner
Salida por pantalla
para una entrada Escriba 5 enteros cada uno en una línea
ejemplo: 1
2
a
No es un entero; por favor, escriba un entero
3
NOTA: en la 4
asignatura, la b
introducción de datos No es un entero; por favor, escriba un entero
por teclado se hará 5
generalmente con
cada dato en una Los números leídos son:
línea distinta. 1
2
3
4
5 133
Ana Belén Moreno
Entrada por teclado usando métodos de
la clase java.util.Scanner
Ejemplo:
Lectura de 5
cadenas de
caracteres, cada
uno introducido en
una línea distinta,
almacenamiento
en un array de
Strings y escritura
por pantalla.

Lectura de 5
caracteres, cada
uno introducido en
una línea distinta.
Almacenamiento
en un array, y
escritura por
pantalla. 134
Ana Belén Moreno

Excepciones
• Java permite la ejecución en redes de ordenadores con
diferentes sistemas operativos, acceso remoto a objetos
en otras máquinas de la red…
– Esto supone perder el control sobre los periféricos
sobre los que actúa.
• Cuando se ejecuta un programa pueden producirse
errores, causados p.e. por:
– código deficiente
– entrada de datos incorrectos
– parámetros incorrectos
– archivos inexistentes
– discos defectuosos, etc.
135
Ana Belén Moreno
Excepciones
• Estas circunstancias pueden provocar desastres en la
ejecución del programa que suponen la finalización de la
aplicación de forma descontrolada, dejando ficheros
abiertos, pérdida de datos por falta de su archivo,…
• Java dispone de un mecanismo robusto de control de
errores mediante excepciones para evitar estos desastres.
• Una excepción es un objeto que se genera
automáticamente cuando se produce un acontecimiento
dañino para el normal funcionamiento del programa, y que
puede ser previsto y controlado.
• Este objeto generado o excepción, contiene información
sobre el acontecimiento producido y transmite esta
información al método que le ha llamado o al usuario a
través de su correspondiente mensaje. 136
Ana Belén Moreno
Excepciones
• Cuando ocurre una circunstancia no deseada para el
funcionamiento normal, en el método que se está
ejecutando en ese momento se crea una excepción
(objeto de la clase Throwable, arrojable) que
contiene información del error.
• Manejar esta excepción evita la finalización anormal
del programa. Para ello:
– 1º (a) Se captura la excepción por el programa o (b) se
envía al método que llamó a la ejecución del método donde
se produce el incidente (expulsión de la excepción) y
– 2º) Se interrumpiendo el flujo normal de la ejecución del
programa (que produciría fallos), obligando a que se
ejecuten otras sentencias (en lugar de las implicadas en el
incidente). 137
Excepciones Ana Belén Moreno

Errores y excepciones (errores de ejecución):


• Algunos no dependen del código, sino que derivan de
problemas de hardware (p.e. disco defectuoso…)
– arrojan objetos de la clase Error (una subclase de
Throwable). De ellos no nos vamos a ocupar.
• Otra clase de errores que sí tienen que ver con el
código, denominados excepciones, son más
habituales (p.e., entrada de datos de tipo equivocado,
apertura de un fichero con ruta de acceso errónea, operaciones
aritméticas no permitidas, parámetros no permitidos, etc.),
– producen un objeto de la clase Exception (otra subclase
de Throwable). Se manipulan en el código, usando:
• bloques como try - catch, o
• Haciendo que el método donde ocurre una excepción, lance la
excepción al método que lo invocó para que sea este el que la trate.
Excepciones Ana Belén Moreno

Estructura try-catch
• Cuando sabemos que en un determinado fragmento de código
se puede producir una excepción, lo encerramos dentro del
bloque try. P.e., si en una división entre a y b el divisor b
podría ser cero:
try {
//bloque de sentencias a ejecutar en circunstancias normales
c = a/b;
} catch (ArithmeticException e){
//bloque que se ejecuta si se ha producido una excepción de
//la clase AritmeticException.
System.out.println(“Error: división por cero”);
}
• Esto somete a observación el código encerrado entre llaves en
el bloque try. Si saltase una excepción por denominador cero,
esta deberá ser capturada por un bloque catch.
139
Excepciones Ana Belén Moreno

Estructura try-catch
• Si salta una excepción en el bloque try:
– Se genera un objeto de la clase Exception o de otra, que en el
ejemplo se ha llamado e, y que contiene información sobre el error
producido.
– Se interrumpe la ejecución del bloque try, saltando a ejecutarse la
primera línea del bloque catch.
– Cuando se termina de ejecutar el bloque catch, continúa el
programa por la línea posterior a la estructura try-catch.
– catch va seguida de un parámetro declarado entre paréntesis (e
en el ejemplo), de la clase de excepción que se quiere atrapar.
– El parámetro e puede usarse como variable local dentro del bloque
catch. Hace referencia al objeto de la excepción generada que
contiene toda la información sobre el error producido. Entre sus
métodos está getMessage(), que devuelve un mensaje
descriptivo del error. Podría usarse así:
Excepciones Ana Belén Moreno

Estructura try-catch
Ejemplo:
try {
c = a/b;
System.out.println("a/b = " + c);
} catch (ArithmeticException e){
System.out.println(e.getMessage());
}
También puede hacerse así:
try {
c = a/b;
System.out.println("a/b = " + c);
} catch(ArithmeticException e){
System.out.println(e); // esto hace una llamada a toString
//de la clase de la excepción y muestra la descripción del error.
} 141
Ana Belén Moreno

Excepciones
Estructura try-catch
• Es posible capturar más de un tipo de excepción con
un solo bloque catch:
catch (TipoExcepcion1 | TipoExcepción2 e){

}
– La barra vertical equivale a un OR.
– Se pueden añadir tantos tipos de excepción como se quiera
separados por barras verticales
– Significa “si salta una excepción del tipo TipoExcepcion1 o
TipoExcepcion2 o …, ejecutar este bloque catch, donde la
excepción será referenciada con la variable e.
– También se pueden escribir varios catch. 142
package aplicacionexcepciones; Ana Belén Moreno

import java.io.*;

public class AplicacionExcepciones {


public static void main(String[] args) {
BufferedReader teclado = new BufferedReader(new
InputStreamReader(System.in));
boolean error = false;
do {
try {
error = false;
System.out.println("Escriba un número");
String texto = teclado.readLine();
int i = Integer.parseInt(texto);

System.out.println("Escriba un número");
texto = teclado.readLine();
int j = Integer.parseInt(texto);

System.out.println("La división es " + i/j);


}
//sigue en la página siguiente; 143
Ana Belén Moreno
// si la excepción no es de la clase del primer catch se comprueba
// el siguiente y así hasta que algún catch lo capture.
// El último catch captura cualquier clase de excpción ya que todas
// derivan de Exception

catch (IOException e){


System.out.println("Error en la lectura");
error = true;
}
catch (ArithmeticException e){
System.out.println("Error por división por cero");
error = true;
}
catch (Exception e){
System.out.println("Error desconocido");
error = true;
}
} while (error);
}
}

144
Ana Belén Moreno
Excepciones
Excepción lanzada por el método: throws NombreExcepción
• Hay otra forma alternativa a try-catch para
manejar la excepción:
– Sea método1 un método en el que puede producirse una
excepción o error.
– Sea método2 un método que llama a método1 para que este
se ejecute.
– Cuando se produzca la excepción en método1, este puede
lanzarla hacia el método que lo llamó (método2) siendo este el
que atrape la excepción y actúe en consecuencia.
– La línea de código del método2 donde se llama al método1 se
encierra dentro de un try-catch.
– Se añade throws NombreExcepción al final de la cabecera
del método1 donde puede ocurrir la excepción.
145
Ana Belén Moreno
Excepción lanzada por el método: throws NombreExcepción
• En la cabecera se indica que método1 puede lanzar una
excepción aritmética al método que lo llame:
void metodo1(int a, int b) throws ArithmeticException {
int c;
c = a / b;
System.out.println(“a/b = ” + c);
}
• El método que llame a método1 deberá hacerse cargo de la
excepción que lance método1 si esta se produce.
void metodo2(){
int x, y;

try {
metodo1(x, y);
} catch (ArithmeticException e){
System.out.println(“Error en método1: div. por cero”);
}// nota: en vez de try-catch, método2 podría pasar la excepción a un 3º
método que lo invoque mediante throws ArithmeticException , etc…
146
Ana Belén Moreno

Excepciones

• Generación de excepciones por el


programador: la sentencia throw.
• El programador puede lanzar excepciones
específicas para sus aplicaciones. P.e.
– El método void establecerEdad(int edad)
de la clase Persona() genera una excepción
cuando la edad que recibe como parámetro es
menor que cero o mayor que 120 y genera una
excepción con el mensaje “Edad no válida”.

147
Ana Belén Moreno

Excepciones
• Método que lanza una excepción personalizada
generada con throw, a través de throws.

148
Excepciones Ana Belén Moreno

• En el método que hizo la llamada se captura la excepción con


un try-catch:

149
Ana Belén Moreno

Excepciones
• Existen muchas clases de excepciones ya definidas
en Java. Podemos usar la que más se parezca al
error que se va a producir, entre todas las que hay
– Si buscamos en Google “Java algo”, p.e. “Java
Exception” o “Java RuntimeException”, el
primer enlace que aparece es la ayuda de oracle
sobre Java para ese término. Véase la cantidad de
excepciones que hay. Las RuntimeException
son las más habituales en la ejecución normal de
programas.
• También pueden crearse nuevas clases con nuevas
excepciones, pero no lo haremos en esta asignatura.
150
Ana Belén Moreno
Algunas Excepciones
Las siguientes son clases de excepciones frecuentes.
Todas derivan de Exception:
Excepción Motivos por los que se produce la excepción
IOException En la apertura de un fichero
BufferedWriter out = new BufferedWriter(new
(Excepción de
entrada/salida de FileWriter (“salida.txt”));
datos por fichero o El fichero no se abre por alguna razón (no existe el
por consola) fichero, o no es la ruta de acceso indicada, etc.)
- Al leer una línea de teclado
cad = Teclado.readLine();
- No se ha podido leer la cadena.
- Al leer un dato de un fichero, error de lectura porque no
corresponde el tipo del dato con el tipo esperado.
ArithmeticException Error en una operación aritmética, p.e. división por cero
(*)
c = a/b
ArrayIndexOutOfBoun Acceder fuera de los límites de una tabla
dsException (*)
151
Ana Belén Moreno
Algunas Excepciones
Excepción Motivos por los que se produce la excepción
EOFException Se produce al leer un dato de un fichero, cuando no se
(Excepción End Of puede leer porque el cursor de lectura ha llegado al final
File o final del del fichero y no hay más datos en él.
fichero) num = in.readInt();
ClassNotFoundExcept Al leer un objeto (clase Object) de un fichero binario y
ion
hacer un cast para que lo referencie una variable
referencia a tabla o a String… cuando el tipo de la
referencia no coincide con el de los datos leídos.
datos_leidos = (int[]) in.readObject();
cadena = (String) in.readObject();
FileNotFoundExcepti Se produce al no encontrar un fichero.
on

NOTA: Netbeans indica cuáles y dónde pueden producirse excepciones y


obliga a manejarlas con try-catch o con throws NombreException, de
otro modo, da error de compilación.
Las excepciones permiten repasar el código y corregirlo para que no se
vuelvan a producir. 152
Ana Belén Moreno

Ficheros
• Los datos pueden guardarse o almacenarse de forma
duradera en ficheros (o archivos) de cualquier unidad
(de disco, pendrive, etc...)
– La salida de un programa puede ir a ficheros además de a
la pantalla.
– La entrada de un programa puede proceder de ficheros
además del teclado.
Datos de Datos de
entrada salida pantalla
teclado

Programa

ficheros ficheros

153
Ana Belén Moreno

Ficheros
Flujos (Streams)
• Java implementa una serie de clases llamadas
flujos (Streams en inglés), que se encargan de
comunicarse con los dispositivos de
almacenamiento.
Según el sentido Flujos de entrada Para leer o
de la recuperar datos
comunicación Flujos de salida Para escribir o
guardar datos
Según el tipo de Flujos de caracteres Son los asociados
datos que a ficheros de texto.
transmiten Flujos de bytes (enteros entre 0 y 255, lo Asociados a
que permite manipular cualquier tipo de ficheros binarios.
dato)
154
Ana Belén Moreno
Ficheros de texto
Flujo de entrada de la clase FileReader
• Los flujos de entrada de tipo texto heredan de la clase
InputStreamReader (tienen en común los métodos de esa
clase).
• Para leer ficheros usaremos la clase de flujo de entrada de
texto FileReader. Su constructor es:
FileReader(nombreFichero String);
– Se pasa nombreFichero como argumento, que es el nombre del fichero
al que se quiere asociar el flujo para su lectura.
– Si el fichero no está en el directorio de trabajo (el actual, donde está el
programa) nombreFichero debe ir precedido de la ruta de acceso. Ej.:
FileReader in = new FileReader(“F:\\programas\\prueba.txt”);
• En Windows la barra invertida en un String se escribe doble (\\) .
• En Linux la barra es ‘/’ y se escribe simple, p.e.:
FileReader in = new FileReader(“/home/programas/prueba.txt”);

155
Ana Belén Moreno

Ficheros de texto
Flujo de entrada de la clase FileReader
• La apertura del fichero puede arrojar una excepción
del tipo IOException, cuando el archivo no se abre
por cualquier razón, p.e. porque no se encuentra el
fichero en esa ubicación, el disco está deteriorado,
etc…

• La operación de apertura del fichero debe ir:


– dentro de una estructura try-catch, o bien,
– en un método cuya cabecera contenga “throws
nombreException”.

156
Ana Belén Moreno
Ficheros de texto
Flujo de entrada de la clase FileReader
• Cuando se abre el fichero, el cursor para su lectura se
sitúa al principio, apuntando al primer carácter.
• Puede leerse el flujo asociado al fichero usando el método:
int read();
de FileReader. Este método lee un carácter del fichero y lo
devuelve en un entero (hay que hacer cast para devolver el
carácter).
• Cada vez que se lee un carácter, el cursor avanza al carácter
siguiente.
• Cuando no hay más caracteres en el fichero read devuelve -1.
• Cuando no se va a leer más del fichero, hay que cerrar el
fichero mediante el método close() que completa las lecturas
pendientes y libera el fichero. 157
Ficheros de texto Ana Belén Moreno

Ejemplo:
Programa
que lee el
fichero fuente
Saludo.java,
almacena su
contenido en
una variable
String cuyo
valor muestra
en pantalla.

158
Ana Belén Moreno

Ficheros de texto
Flujo de entrada de la clase BufferedReader
• FileReader permite leer cualquier texto plano
carácter a carácter.
• Existen flujos de la clase BufferedReader que
consisten en un FileReader al que se asocia un
buffer en memoria para agrupar los caracteres que
van llegando donde se colocan en una cola a la
espera de que el programa los vaya reclamando. Se
reduce el número de accesos a disco, por lo que es
más eficiente.
• Permite leer el fichero línea a línea, no sólo carácter a
carácter. 159
Ana Belén Moreno

Ficheros de texto
Flujo de entrada de la clase BufferedReader
• Para crear un BufferedReader hay que pasar a su
constructor un objeto FileReader:

BufferedReader in = new BufferedReader(new FileReader (“nombreFich”));

• Ahora el flujo in dispone de los métodos:


int read(); Lee y devuelve un carácter
individual en un entero.
String readLine(); Lee y devuelve un línea
completa. Cuando llega al final
del fichero y no hay más
líneas devuelve null.

160
Ana Belén Moreno

Ficheros de texto

Programa que lee


el fichero fuente
Saludo.java línea
a línea, y
almacena su
contenido en una
variable String
cuyo valor
muestra en
pantalla.

161
Ana Belén Moreno
Ficheros de texto
Flujo de salida de la clase FileWriter
• Para escribir en un fichero debemos crear un flujo de
salida de texto.
• Para ello, se crea un objeto de clase FileWriter cuyos
Constructores son:
FileWriter (String nombreArchivo); // Recibe el nombre del archivo
// con su ruta. Al abrirlo, lo destruye y crea uno nuevo
//escribiendo en él desde el principio, es decir, se sobreescribe.

FileWriter (String nombreArchivo, boolean append);


// Recibe el nombre del archivo con su ruta. Al abrirlo,
// si append es true añade el texto al final del archivo.

• La apertura de un FileWriter puede generar una


IOException que puede tratarse con un try-catch o con
un throws nombreExcepcion en la cabecera del método.
Ana Belén Moreno
Ficheros de texto
Flujo de salida de la clase BufferedWriter
• Para mejorar el rendimiento se usa un flujo con un
buffer asociado, de la clase BufferedWriter a cuyo
constructor hay que pasar un objeto flujo de salida,
p.e. de la clase FileWriter:
BufferedWriter out = new BufferedWriter(new FileWriter (“salida.txt”));

• Dispone de los métodos :


void write(int caracter); //escribe un carácter en el fichero
void write(String cadena);// escribe una cadena en el fichero
void newLine(); //escribe un salto de línea (independiente s.o.)
void flush(); //vacía el buffer escribiendo los caracteres
// pendientes en el fichero.
void close(); // vacía el buffer, cierra el flujo de salida y
// libera el recurso correspondiente. 163
Ana Belén Moreno

Ficheros de texto

Programa que
genera un
fichero
“El Quijote.txt”
con las dos
primeras
frases, una
escrita
carácter a
carácter y la
otra mediante
la escritura de
la línea
completa.

164
Programa que genera
un fichero
Ficheros de texto
package escriturafichero;
Ana Belén Moreno

import java.util.*;
“Resultados.txt” con import java.io.*;
la cadena
“Resultados:” en la 1ª
línea, 3 enteros que
se piden al usuario
en la segunda línea y
el real 22.3 en la 3ª
línea. La salida por
pantalla es:

Escriba los 3 resultados:


43
22
10

Fichero generado:

165
Ana Belén Moreno
Entrada por teclado usando
BufferedReader
Entrada usando un flujo de la clase BufferedReader
• Para leer de teclado usaremos un flujo de la clase
BufferedReader, a cuyo constructor pasaremos
como argumento un flujo de la clase
InputStreamReader.
• Al constructor de InputStreamReader le pasamos
como argumento system.in que indica que los
datos provienen del teclado.
InputStreamReader flujo = new InputStreamReader(System.in);
BufferedReader entrada = new BufferedReader(flujo);

166
Ana Belén Moreno

Entrada por teclado usando BufferedReader

Lectura de
un entero del
teclado (un
año) y
escritura en
la pantalla.
La salida por
pantalla es:

Escriba el año
2014
Se ha leído el entero: 2014

167
Ana Belén Moreno

Entrada por teclado usando BufferedReader

Lectura de
un real del
teclado
(velocidad) y
escritura en
la pantalla.
La salida por
pantalla es:
Escriba la velocidad:
22.3
La velocidad leída es: 22.3

168
Ana Belén Moreno
Entrada por teclado usando BufferedReader

Lectura de
una cadena
y de un
carácter del
teclado, y
escritura en
la pantalla.
La salida
por pantalla
es:
Escriba su nombre:
Ana Belen
Su nombre es: Ana Belen
Escriba una letra:
R
Ha escrito la letra: R

169
Ficheros binarios Ana Belén Moreno

• Permiten guardar y recuperar datos de todo tipo desde un


programa.
• Al abrirlos con un editor de texto no son legibles por las
personas, pues sólo contienen ristras de caracteres “raros”, a
diferencia de los ficheros de texto que son legibles.
• Para usar cualquier flujo en Java, ya sea de entrada o de salida
a ficheros de texto o binarios, requiere importar las clases del
paquete java.io mediante: import java.io.*;
• Los flujos básicos para escribir y leer bytes de fichero son de
las clases FileOutputStream y FileInputStream
respectivamente.
• Para manejar datos más complejos que los bytes, p.e. tipos
primitivos, tablas u objetos, utilizaremos flujos capaces de
convertir estos datos en bytes (proceso llamado serialización
de datos) y bytes en datos (deserialización de datos). Son los
flujos ObjectOutputStream y ObjectInputStream. 170
Ana Belén Moreno

Escritura en ficheros binarios


• Para escribir datos en un fichero binario creamos un
flujo de tipo byte de salida, asociándolo a un fichero
(p.e. “resultados.dat”):
FileOutputStream archivo = new FileOutputStream(“enteros.dat”);
• Si el fichero no estuviera en el directorio actual, habría que
indicar la ruta desde el directorio raíz o desde el directorio
actual.
• Una vez creado este flujo, lo “envolvemos en un objeto de la
clase ObjectOutputStream, que tiene más métodos además de
los de escritura de bytes:
ObjectOutputStream out = new ObjectOutputStream(archivo);

• Este constructor puede arrojar una IOException


171
Ana Belén Moreno

Escritura en ficheros binarios


• La clase ObjectOutputStream tiene una serie de métodos
que permiten la escritura de datos de cualquier tipo o clase.
• Para poder escribir un objeto en un fichero binario su clase
debe tener implementada la interfaz Serializable, que es
una marca que declara al objeto como susceptible de ser
serializado (convertible en una serie plana de bytes).
• Así, las clases definidas por el usuario deben declararse como
serializables en su definición, así:
Class miClase implements Serializable{
//con esto miClase ya es serializable y los objetos de esta clase
//pueden ser enviados por flujo binario a ficheros binarios.
<cuerpo de la clase>
}
y esto no obliga a implementar ningún método especial en su
definición.
172
Ana Belén Moreno

Escritura en ficheros binarios


• Las clases implementadas por Java como p.e.
String, las Collections y las tablas, traen ya
implementada la interfaz Serializable y no hay
que hacer nada.
• Lo mismo ocurre con los tipos primitivos.
• ObjectOutputStream dispone de los siguientes
métodos para la escritura de datos en un flujo de
salida:

173
Ana Belén Moreno

Escritura en ficheros binarios

• Métodos de ObjectOutputStream
void writeBoolean(boolean b); Escribe un valor boolean en el flujo.
void writeChar(int c); Escribe el valor char que ocupa los dos
bytes menos significativos del valor entero
que se le pasa.
void writeInt(int n); Escribe un entero.
void writeLong(long n); Escribe un entero largo.
void writeDouble(double d); Escribe un número de tipo double.
void writeObject(Object o); Escribe un objeto serializable

174
Escritura en ficheros binarios
Ana Belén Moreno

Programa
que pide al
usuario 10
enteros y los
escribe en
un fichero
binario
llamado
“datos.dat”

175
Ana Belén Moreno

Escritura en ficheros binarios


• Puesto que una tabla o array es un objeto en Java, el
segundo for del ejemplo anterior puede sustituirse
por:
out.writeObject(datos);

• En este caso la tabla se graba como objeto, que es


distinto a grabar los enteros por separado. Esto es
importante a la hora de recuperarla o leerla.
• Igualmente se hace para grabar un String.

String cadena = “Sancho Panza”;


out.writeObject(cadena);
176
Ana Belén Moreno

Lectura de ficheros binarios


• Para leer datos de un fichero binario usaremos
flujos de entrada de la clase:
ObjectInputStream in = new ObjectInputStream(new
FileInputStream(“datos.dat”));

• Esta sentencia puede producir una IOException.


• Al leer los datos hay que leer los mismos tipos de
datos que fueron grabados:
– para cada uno de los métodos de escritura hay un método
de lectura correspondiente, con el que recuperar el/los
datos.
177
Ana Belén Moreno

Lectura de ficheros binarios


• Métodos de ObjectInputStream
boolean readBoolean(); Lee un booleano del flujo de entrada.
char readChar(); Lee un carácter.
int readInt(); Lee un entero.
long readLong(); Lee un entero largo.
double readDouble(); Lee un número de real double.
final Object readObject(); Lee un objeto

178
Ana Belén Moreno

Lectura de ficheros binarios


• Si se escribieron 10 enteros con writeInt() hay que
recuperarlos por separado con el método readInt().
– puede arrojar una IOException si hay un error de lectura, o
EOFException si se ha llegado al final del fichero.
• También puede producir una IOException la sentencia
in.close().

179
Ana Belén Moreno

Lectura de ficheros binarios


Podemos recuperar los 10 enteros escritos separadamente en el
fichero datos.dat y almacenarlos en un array llamado
datos_leidos. Los datos leídos se escriben en pantalla para
comprobar que se han leído correctamente.
int[] datos_leidos = new int[10];

180
Ana Belén Moreno

Lectura de ficheros binarios


• Las cadenas de caracteres son objetos y se deben recuperar
utilizando el método readObject().
• Al objeto devuelto (de clase Object) hay que hacerle un cast
para asignarlo a una referencia de tipo String. Esto puede
generar una ClassNotFoundException si el valor leído no
era de esa clase:
try{
String cad = (String) in.readObject();
} catch (ClassNotFoundException ex){
System.out.println(ex.getMessage());
}
NOTA: Cada sentencia que pueda arrojar una excepción puede introducirse
dentro de un try. Puede haber una estructura try-catch dentro de otra.
Puede haber también varios catch después de un try para capturar distintas
excepciones..Otra forma es que el método lance la excepción al método que
lo llamó. 181
Lectura de ficheros binarios
Ana Belén Moreno

Programa
que
escribe en
el fichero
binario los
10 enteros
del array y
después
escribe
“Hola” en
dicho
fichero.
Por último
lee el
fichero
generado
y escribe
sus datos
en
pantalla.

182
Ana Belén Moreno

Lectura de ficheros binarios

• Las tablas son objetos. Si se ha guardado una


tabla en un fichero con writeObject(), el
bucle for usado en la lectura se debe sustituir
por:

try{
datos_leidos = (int[]) in.readObject();
} catch (ClassNotFoundException ex){
System.out.println(ex.getMessage());
}

Donde el cast es (int[])


183
Ana Belén Moreno

Lectura de ficheros binarios


• A veces se desconoce el número de datos guardados
en un fichero => no se pueden recuperar mediante un
for controlado por contador.
– Es preciso leer hasta el final del fichero, es decir, hasta que
salte la excepción EOFException.
• Ejemplo: si un fichero contiene una lista de enteros y
no sabemos cuántos hay, usamos un bucle infinito del
que sólo nos puede sacar una excepción
EOFException, que indica que se ha llegado al
final del fichero:

184
Ana Belén Moreno

Lectura de ficheros binarios


try {
while (true){
System.out.println(in.readInt());
//cuando llega al final del fichero hay excepción.
}
} catch (EOFException ex) {
< bloque que se ejecuta cuando se sale
del bucle while y del bloque try

System.out.println(ex.getMessage());
etc… >
}

185
Ana Belén Moreno

Evolución de los lenguajes de programación


• La evolución de los lenguajes de programación ha ido
incorporando los siguientes conceptos:
– Abstracción
– Jerarquía
– Modularidad
– Encapsulación
• Estas características facilitan:
– la comprensión y legibilidad de los programas,
– la reusabilidad
– el mantenimiento y la adaptación del software a nuevos
requerimientos,
Ello reduce el coste de programación y de mantenimiento.
186
Ana Belén Moreno

Evolución de los lenguajes de programación

Abstracción
– Es el mecanismo que tiene el ser humano para
extraer sólo las características relevantes de
algo (ignorando los detalles irrelevantes en ese
nivel de abstracción), para comprender mejor
fenómenos que involucren gran cantidad de
detalles. Ej.:
• En biología, para clasificar seres vivos hablamos de
especies, género, clases,… con el fin de comprender
similitudes y diferencias. Cada una es una abstracción
que destaca ciertas características relevantes de esa
clase ignorando en ese momento las restantes.
• Mapas, planos de viviendas, plano del metro (en los que
se elimina
187 detalle)…
187
Ana Belén Moreno
Evolución de los lenguajes de programación

Abstracción
• La abstracción procedimental consiste en describir
partes del código mediante un nombre y la descripción
de su funcionalidad ocultándose los detalles, p.e. un
método puede llamarse conociendo su cabecera
(interfaz del método) y su funcionalidad (qué hace),
evitando conocer los detalles de su código interno
(cómo lo hace). Es posible cambiar la implementación
sin modificar la interfaz.
• La abstracción de datos: aplicar la abstracción al diseño
de estructuras de datos se materializa en la creación de
Tipos Abstractos de Datos (TADs).
188
Ana Belén Moreno

Evolución de los lenguajes de programación


Tipos Abstractos de Datos (TADs)

• Además de los tipos de datos predefinidos de un lenguaje,


los lenguajes modernos permiten crear nuevos tipos
definidos por el programador. P.e.:
• Tipo Punto, que almacena las coordenadas x e y.
• Tipo Lista, que almacena una secuencia de elementos…

189
Ana Belén Moreno

Evolución de los lenguajes de programación


Tipos Abstractos de Datos (TADs)
• Un tipo abstracto de datos es un tipo creado por el programador
que consiste en una colección de datos junto con sus operaciones
para actuar sobre ellos.
• Es opaco para quien usa. Quien usa el tipo, declara datos del mismo
y llama a sus operaciones, y sólo precisa conocer:
• el nombre del tipo (Punto, Lista… para declarar variables del
mismo),
• el conjunto de valores que puede tomar un dato (objeto) de
ese tipo, y
• la interfaz (cabecera y funcionalidad de las operaciones
visibles).
pero no conocen ni la declaración de los datos ni el código interno
de las operaciones. 190
Evolución de los lenguajes de Ana Belén Moreno

programación
Tipos Abstractos de Datos (TADs)
• Es lo mismo que ocurre con double, etc. No se sabe cómo
está definido el tipo double ni cómo se realizan las
operaciones de datos double, sólo sabemos que podemos
declarar variables double y llamar a sin(x), cos(x)…
• Un tipo definido por el programador se materializa en una
clase en los lenguajes de programación orientada a objetos
(POO) como java, donde los datos se hallan en sus campos
o variables instancia y sus operaciones son los métodos.
• Una vez creado un TAD (en una clase en java), se va poder
usar en más programas, importando dicha clase.
191
Ana Belén Moreno
Evolución de los lenguajes de programación
Concepto de Tipo Abstracto de Datos (TAD)
• Un TAD tiene una interfaz visible y una implementación privada:
– La interfaz visible consta de las cabeceras de los métodos visibles, que pueden
ser llamados desde cualquier parte.
– Implementación privada: la representación de los datos del TAD (definiciones de
tipos) y los algoritmos de los métodos se ocultan.
• Un programa que usa un TAD, lo hace sólo a través de llamadas a las
operaciones del TAD, sin conocer la representación de los datos
(definiciones de tipos) ni cómo están implementadas las operaciones.
• Podría modificarse la implementación manteniendo la interfaz pública sin
modificar, lo que permitirá el mantenimiento del TAD sin tener que
cambiar los programas que usan el TAD.
• En Java un TAD se materializa (implementa) en una clase, donde los
datos son privados y las operaciones de acceso a los datos desde fuera
de esa clase se hacen visibles.
• Cada TAD se implementa en una clase, y cada clase pública se guarda
en un fichero independiente. 192
Ana Belén Moreno

Evolución de los lenguajes de programación


• Jerarquía
– Estructuración que organiza un conjunto de elementos en
diferentes niveles, siguiendo unos criterios determinados.
– Se aplica para descomponer algo complejo en partes menos
complejas y manejables. Los programas grandes serían
inviables si no se aplicara, por las limitaciones de la mente
humana para manejar tantos detalles.
– La abstracción permite trabajar siguiendo un método
jerárquico por sucesivos niveles de detalle:
• Dirección descendente: de niveles de menos detalle a los de más
detalle.
• Dirección ascendente: al revés.
– En la POO los datos también se estructuran de manera
jerárquica a través de la herencia, pero esta está fuera del
alcance de esta asignatura. 193
Ana Belén Moreno

Evolución de los lenguajes de programación


• Modularidad
– Organización del código en diferentes componentes
que:
• Tienen significado propio
• Sus conexiones con el resto del programa son pocas y
simples, lo que facilita la independencia en el desarrollo.
– Es necesaria para abordar problemas extensos.
– Permite repartir el trabajo entre programadores y facilita
la reusabilidad y el mantenimiento (cambios en un
módulo implican modificar un sólo módulo y a veces
muy pocas partes de otros).
– En java cada clase correspondiente a un TAD se
escribe en un módulo (fichero), y las clases se agrupan
en paquetes.
194
Ana Belén Moreno

Evolución de los lenguajes de programación

• Encapsulación u ocultación
– Proceso por el que se ocultan los detalles de una
abstracción.
• Permite reutilizar código en otros programas conociendo sólo
la interfaz visible, sin saber cómo está implementado.

195

También podría gustarte