7 . c l a se s y o b j e t o s - fismat

22
7. Clases y objetos Objetivos Explicar el significado del término orientado al objeto ; explicar y distinguir entre los términos clase y objeto ; crear objetos en Java; llamar los métodos de un objeto; usar algunos métodos de la clase String ; crear y usar arreglos de objetos; crear un ArrayList y usar sus métodos add() y get() . 7.1 Introducción En la década de 1990 se convirtió en norma para los lenguajes de programación usar construcciones especiales llamadas clases y objetos . Esos lenguajes son referidos como lenguajes de programación orientados al objeto . En este capítulo y el siguiente se explica el significado de estos términos y se muestra como se puede usar la potencia de un lenguaje orientado al objeto como Java. 7.2 Clases y Tipos de Datos Se han estado usando tipos de datos como char , int o double . Estos son tipos de datos simples que guardan una sola pieza de información. En ocasiones se quiere que una variable tenga más de una pieza de información relacionada. Por ejemplo, un libro podría tener título, autor, número ISBN y precio, o un estudiante podría tener nombre, matrícula y claves para cursos. Los tipos simples de datos son inadecuados para tener toda la información necesaria de un libro o un estudiante. Un arreglo tampoco lo sería porque las diferentes partes de datos no son necesariamente todas del mismo tipo. Los primeros lenguajes de programación como C y Pascal resolvieron este problema permitiendo crear un tipo que guarda más de una pieza de información, estos tipos son conocidos estructuras o registros . En Java y C++ fueron un paso más adelante. Estos permiten no solo crear tipos que guardan varias piezas de datos, pero también permiten definir dentro de estos tipos los métodos mediante los cuales procesan los datos. Por ejemplo un 98

Upload: others

Post on 23-Nov-2021

1 views

Category:

Documents


0 download

TRANSCRIPT

7. Clases y objetos

Objetivos

● Explicar el significado del término orientado al objeto ;

● explicar y distinguir entre los términos clase y objeto ;

● crear objetos en Java;

● llamar los métodos de un objeto;

● usar algunos métodos de la clase String ;

● crear y usar arreglos de objetos;

● crear un ArrayList y usar sus métodos add() y get() .

7.1 Introducción

En la década de 1990 se convirtió en norma para los lenguajes de programación usar construcciones especiales llamadas clases y objetos . Esos lenguajes son referidos como lenguajes de programación orientados al objeto . En este capítulo y el siguiente se explica el significado de estos términos y se muestra como se puede usar la potencia de un lenguaje orientado al objeto como Java.

7.2 Clases y Tipos de Datos

Se han estado usando tipos de datos como char , int o double . Estos son tipos de datos simples que guardan una sola pieza de información. En ocasiones se quiere que una variable tenga más de una pieza de información relacionada. Por ejemplo, un libro podría tener título, autor, número ISBN y precio, o un estudiante podría tener nombre, matrícula y claves para cursos. Los tipos simples de datos son inadecuados para tener toda la información necesaria de un libro o un estudiante. Un arreglo tampoco lo sería porque las diferentes partes de datos no son necesariamente todas del mismo tipo. Los primeros lenguajes de programación como C y Pascal resolvieron este problema permitiendo crear un tipo que guarda más de una pieza de información, estos tipos son conocidos estructuras o registros .

En Java y C++ fueron un paso más adelante. Estos permiten no solo crear tipos que guardan varias piezas de datos, pero también permiten definir dentro de estos tipos los métodos mediante los cuales procesan los datos. Por ejemplo un

98

'tipo' libro podría tener un método que agregue el impuesto al precio de venta; un 'tipo' estudiante podría tener un método para calcular el promedio de los cursos.

El siguiente programa le pide al usuario que proporcione la base y la altura de un rectángulo, luego calcula el área y el perímetro del rectángulo usando métodos y muestra los cálculos.

import java.util.Scanner; public class CalculosRectangulo { public static void main(String[] args) {

double base, altura, area, perimetro; Scanner teclado = new Scanner(System.in); System.out.println("Introducir del rectángulo su"); System.out.print(" base: "); // pedir la base base = teclado.nextDouble(); // obtener la base System.out.print("altura: "); // pedir la altura altura = teclado.nextDouble(); // obtener la altura

// llamadas a métodos para cálculos de área y perímetro area = calcularArea(base, altura); perimetro = calcularPerimetro(base, altura); System.out.println("Área es " + area); // mostrar área y System.out.println("Perímetro es " + perimetro); // perimetro

} // método para calcular área static double calcularArea(double base, double altura) {

return base * altura; } // método para calcular perímetro static double calcularPerimetro(double base, double altura) {

return 2 * (base + altura); } }

Se puede observar lo útil que podría ser si, cada vez que se escribió un programa que maneja rectángulos, en vez de tener que declarar varias variables y escribir métodos para calcular el área y el perímetro de un rectángulo, se pudiera solo usar un tipo rectángulo para crear una sola variable, y luego usar sus métodos escritos. De hecho no se necesitaría saber cómo estos cálculos son hechos.

Lo anterior es lo que un lenguaje orientado al objeto permite hacer. Esta construcción especial que guarda datos y métodos es llamada una clase. Ya se ha visto una clase como la unidad básica la cual contiene el método main() y otros métodos adicionales. Se pueden también usar las clases para definir nuevos tipos.

Se puede ver que hay dos aspectos para una clase:

99

● Los datos que esta tiene; ● y las tareas que esta realiza.

En el siguiente capítulo se verá que los diferentes elementos de datos que una clase tiene son referidos como los atributos de la clase; las tareas que esta puede realizar son referidos como los métodos de la clase. Se vio en el capítulo 5 como los métodos fueron llamados solamente desde adentro de la propia clase. Ahora se revisará cómo llamar a los métodos de otra clase. De hecho ya se ha realizado esto sin haberlo indicado desde el segundo capítulo, cuando se han llamado a los métodos de la clase Scanner .

7.3 Objetos

Para usar los métodos de una clase se necesita crear un objeto de esa clase. Para entender la diferencia entre clases y objetos, se puede pensar una clase como un plano, o plantilla, de la cual los objetos son generados, mientras un objeto se refiere a una instancia individual de esa clase. Por ejemplo, imaginar un sistema que es usado por una librería. La tienda podría contener cientos de libros, pero no se necesita definir un libro cientos de veces. Se podría definir un libro una vez, en una clase, y luego generar tantos objetos como se quiera desde el plano, cada uno representando un libro individual, como se ve en la siguiente figura:

En un programa se podrían tener varias clases, tantas como los diferentes tipos de objetos que se quieran generar. Un sistema de una biblioteca podría tener

100

libros, clientes, proveedores, etc. Una administración universitaria podría tener estudiantes, cursos, profesores, etc.

La programación orientada al objeto por lo tanto consiste en definir una o más clases que podrían interactuar entre ellas.

Enseguida se ilustra todo lo anterior creando y usando objetos de clases predefinidas, definidas por el usuario o por los desarrolladores Java y proporcionadas como una parte estándar del Kit de Desarrollo Java o JDK. Se usa el ejemplo discutido en la sección 7.2 dónde se propuso un tipo individual para manejar el cálculo del área y el perímetro de un rectángulo. La nueva clase será llamada Rectangulo . En el diseño de Rectangulo se considerará que la base y la altura deben ser diferentes, a pesar de que un rectángulo pueda tener sus cuatro lados iguales, un cuadrado.

7.4 Clase Rectangulo

La clase Rectangulo ya está escrita. La clase creada está guardada en un archivo llamador Rectangulo.java , disponible en la página de códigos del curso .

En el siguiente capítulo se revisará esta clase y cómo fue escrita. En este capítulo sólo será usada. Cuando ya se tenga la clase Rectangulo se podrá hacer una declaración como:

Rectangulo miRectangulo;

Esta declaración crea una variable que guarda una referencia a un objeto, en vez del propio objeto. Una referencia es un nombre para una localidad de memoria. En esta etapa no se ha reservado espacio para el objeto nuevo Rectangulo .

Se ha indicado que, un objeto también es referido como una instancia de una clase; el proceso de crear un objeto es referida como una instanciación . Para crear un objeto se usa un método especial de la clase llamado constructor .

El constructor es un método que siempre tiene el mismo nombre que la clase . Cuando se crea un objeto nuevo este método especial es llamado siempre; su función es reservar espacio suficiente en la memoria de la computadora para guardar el objeto requerido, en este caso un objeto de la clase Rectangulo .

El constructor de la clase Rectangulo ha sido definido para que cada vez que un objeto Rectangulo nuevo es creado, la base y la altura sean puestas, estas son puestas a los valores que el usuario de la clase manda. Así que cada vez que se crea un objeto Rectangulo se tiene que especificar su base y su altura al mismo tiempo. Enseguida se muestra como se podría llamar al constructor para crear un rectángulo con base 7.5 y altura 12.5:

101

miRectangulo = new Rectangulo(7.5, 12.5);

Esta sentencia reserva espacio en memoria para un Rectangulo nuevo. Usando el constructor con la palabra reservada new , se reserva memoria para un objeto Rectangulo nuevo. Para la clase Rectangulo se definió el constructor para que requiera dos elementos de datos, ambos de tipo double , mandados como parámetros. En el ejemplo se mandó 7.5 y 12.5. La localidad del objeto nuevo está guardado en la localidad llamada miRectangulo .

Cada vez que se quiera referir al objeto Rectangulo nuevo se usa el nombre de variable miRectangulo .

Al igual que con la declaración e inicialización de tipos simples, Java permite declarar una referencia y crear un objeto nuevo en una sola línea:

Rectangulo miRectangulo = new Rectangulo(7.5, 12.5);

Hay todo tipo de formas para definir constructores, por ejemplo, en una clase CuentaBancaria se podría querer poner el límite de sobregiro a un valor particular cuando la cuenta es creada. Ya se ha visto otro ejemplo de la declaración de una referencia y creación de un objeto con la clase Scanner :

Scanner teclado = new Scanner(System.in);

La clase está escrita para asegurarse de que ningún programa pueda asignar valores a los atributos directamente. De esta forma los datos en la clase están protegidos. La protección de datos de esta forma es conocida como encapsulación . La única forma para interactuar con los datos es vía los métodos de la clase.

En la siguiente tabla se listan todos los métodos de la clase Rectangulo con sus entrada y salidas, esta lista también se refiere como la interfaz de los métodos, incluyendo el constructor.

Método Descripción Entradas Salida

Rectangulo() Constructor Dos elementos de datos, ambos tipo double para la base y la altura.

No aplica

setBase() Poner el valor de la base

Un elemento tipo double

Ninguno

setAltura() Poner el valor de la altura

Un elemento tipo double

Ninguno

getBase() Regresar la base Ninguno Un dato tipo double

102

getAltura() Regresar la altura Ninguno Un dato tipo double

calcularArea() Calcular y regresar el área

Ninguno Un dato tipo double

calcularPerimetro() Calcular y regresar el perímetro

Ninguno Un dato tipo double

Se observa que se proporcionan métodos para regresar el valor del área y el perímetro del rectángulo. Los valores de la base y la altura son proporcionados inicialmente vía el constructor, pero se pueden cambiar los valores de estos atributos con los métodos setBase() y setAltura() . Para mostrar los valores de los atributos base y altura se proporcionan los métodos getBase() y getAltura() los cuales regresan, o leen esas propiedades.

Se han usado métodos de la clase Scanner varias veces, por ejemplo:

x = teclado.nextInt()

Se puede observar que para llamar un método de una clase desde otra clase se usa el nombre del objeto, en este caso teclado , junto con el nombre del método, nextInt() , separado por una parada completa, también referido como el operador punto .

En el caso de la clase Rectangulo , se podría llamar al método setBase() con una sentencia como la siguiente:

miRectangulo.setBase(6.0);

Cuando se llaman los métodos dentro de una clase, se usa solo el nombre del método. Lo que se está haciendo es una forma abreviada. Cuando se escribe una línea como

metodoDemo(x);

se está diciendo que se llame a metodoDemo() , el cual es un método de esta clase. En Java la palabra reservada this es usada dentro de una clase para cuando se quiere referir a un atributo de la propia clase, en vez de un atributo de alguna otra clase, así la línea anterior es una abreviatura para:

this.metodoDemo(x);

Se debe tener cuidado de que, así como no se puede usar una variable que no ha sido inicializada, no se puede llamar un método de un objeto si no se ha reservado memoria para el objeto, esto podría ser la causa para un problema en tiempo de ejecución. En Java, cuando una referencia es creada sin asignarle un

103

objeto nuevo en la misma línea, se le puede dar el valor null ; un valor null indica que no se ha reservado espacio. Se puede asignar un valor null a una referencia en cualquier parte del programa, como se muestra enseguida:

Rectangulo miRectangulo; // miRectangulo tiene valor null miRectangulo = new Rectangulo(5.0, 7.5); // crear Rectangulo // más código aquí miRectangulo = null; // reasignar valor nul l if(miRectangulo == null) { // probar por valor null System.out.println("Sin memoria reservada para el objeto"); }

En la siguiente sección se escribe un programa que crea un objeto Rectangulo y luego se usan sus métodos.

7.5 Programa ProbadorRectangulo

El siguiente programa muestra cómo la clase Rectangulo puede ser usada por otra clase, en este caso una clase llamada ProbadorRectangulo .

import java.util.Scanner; public class ProbadorRectangulo { public static void main(String[] args) {

Scanner teclado = new Scanner(System.in); // declarar 2 variables para guardar base y altura double base, altura; // declarar una referencia para un objeto Rectangulo Rectangulo miRectangulo; System.out.print("Ingresar base del rectángulo: "); base = teclado.nextDouble(); System.out.print("Ingresar altura del rectángulo: "); altura = teclado.nextDouble(); // crear un objeto Rectangulo nuevo miRectangulo = new Rectangulo(base, altura); /* usar los métodos de la clase Rectangulo para mostrar

base, altura, área y perímetro del Rectangulo */ System.out.println("Base del rectángulo: " +

miRectangulo.getBase()); System.out.println("Altura del rectángulo: " +

miRectangulo.getAltura());

104

System.out.println("Área del rectángulo: " + miRectangulo.calcularArea());

System.out.println("Perímetro del rectángulo: " + miRectangulo.calcularPerimetro());

} }

En el programa ProbadorRectangulo no se han usado los métodos setBase() y setAltura() porque no se quiere cambiar la base y la altura del rectángulo una vez que ha sido creado.

Enseguida se revisan otras clases. La primera que se revisa es la clase incorporada String disponible en todas las versiones de Java.

7.6 Cadenas

Una cadena es una secuencia de caracteres, como un nombre, una dirección, un registro de una placa vehicular, etc. Java proporciona la clase String que permite usar y manipular cadenas.

La clase String tiene varios constructores, pero Java permite declarar un objeto cadena de la misma forma como se declaran variables de tipo simple como int o char . Se podría hacer la siguiente declaración:

String nombre;

y se le podría dar a la cadena un valor:

nombre = "Miguel";

También se podría hacer en una sola línea:

String nombre = "Miguel";

Sin embargo, se debe tener en cuenta que esta es una forma conveniente de declarar un objeto String sin llamar a su constructor, lo cual se podría hacer como sigue para obtener el mismo resultado:

String nombre = new String("Miguel");

Se debe recordar que solo la clase String es la única clase que permite crear nuevos objetos usando el operador de asignación de esta forma.

7.6.1 Obtener Cadenas desde el Teclado

Para obtener una cadena desde el teclado, se debería usar el método next() de Scanner . Sin embargo, cuando se hace esto no se deben ingresar cadenas que

105

incluyan espacios, ya que podría dar resultados inesperados. En la siguiente sección se muestra una forma de resolver esta restricción.

Enseguida está un programa que usa la clase String.

import java.util.Scanner; public class PruebaString { public static void main(String[] args) {

Scanner teclado = new Scanner(System.in); String nombre; // declaración de una String int edad; System.out.print("¿Cuál es tu nombre? "); nombre = teclado.next(); System.out.print("¿Cuál es tu edad? "); edad = teclado.nextInt(); System.out.println(); System.out.println("Hola " + nombre);

// enseguida la broma System.out.println("Cuando tenía tu edad tenía " +

(edad+1) + " años"); } }

Observar que el operador + es usado para dos propósitos diferentes. Es usado con cadenas para concatenar ( "Hola " + nombre ) y también es usado para sumar números ( edad+1 ).

7.6.2 Métodos de la Clase String

La clase String tiene varios métodos interesantes y útiles, se listan algunos de ellos en la siguiente tabla.

Método Descripción Entradas Salida

lenght() Regresa la longitud de la cadena.

Ninguno Dato de tipo int

charAt() Acepta un entero y regresa el carácter en esa posición. El índice inicia en cero.

Dato de tipo int

Dato de tipo char

substring() Acepta dos enteros (sean m y n ) y regresa una copia de un pedazo de la copia iniciando en m y terminando en n-1

Dos datos tipo int

Un objeto String

106

concat() Acepta una cadena y devuelve una cadena nueva con la cadena enviada unida al final de la cadena original

Un objeto String

Un objeto String

toUpperCase() Regresa una copia de la cadena original, toda en mayúsculas

Ninguno Un objeto String

toLowerCase() Regresa una copia de la cadena original, toda en minúscula

Ninguno Un objeto String

compareTo() Acepta una cadena y la compara con la cadena del objeto. Devuelve cero si las cadenas son idénticas, un número negativo si la cadena del objeto está antes que la pasada en el alfabeto, y positivo si viene después

Un objeto String

Un dato tipo int

equals() Acepta un objeto, como un String , y compara este con otro objeto, como String . Regresa true si estos son idénticos, y false caso contrario.

Un objeto de cualquier clase

Un valor boolean

equalsIgnoreCase() Acepta una cadena y compara esta con la cadena original. Regresa true si las cadenas son idénticas, insensible a mayúsculas y minúsculas, y false caso contrario.

Un objeto String

Un valor boolean

startsWith() Acepta una cadena y regresa true si la cadena original empieza con esta y false caso contrario.

Un objeto String

Un valor boolean

endsWith() Acepta una cadena y regresa true si la

Un objeto String

Un valor boolean

107

cadena original termina con esta y false caso contrario.

trim() Regresa un objeto String , con los espacios removidos al inicio y al final.

Ninguno Un objeto String

Hay otros métodos útiles de la clase String que se pueden revisar. El siguiente programa proporciona un ejemplo de cómo se pueden usar varios de los métodos listados previamente.

import java.util.Scanner; public class MetodosString { public static void main(String[] args) {

Scanner teclado = new Scanner(System.in); // crear un String String str; // pedir al usuario ingresar una cadena System.out.print("Ingrese cadena sin espacios: "); str = teclado.next(); // mostrar el tamaño de la cadena ingresada System.out.println("Tamaño de la cadena: " +

str.length()); // mostrar el tercer carácter System.out.println("Carácter en la posición 3: " +

str.charAt(2)); // mostrar una parte de la cadena ingresada System.out.println("Caracteres posiciones 2 a 4: " +

str.substring(1,4)); // mostrar la cadena ingresada unida con otra cadena System.out.println(str.concat(" fue la cadena introducida")); // mostrar la cadena ingresada en mayúsculas System.out.println("Mayúsculas: " +

str.toUpperCase()); // mostrar la cadena ingresada en minúsculas System.out.println("Minúsculas: " +

str.toLowerCase()); } }

7.6.3 Comparación de Cadenas

Cuando se comparan dos objetos, tales como String , se debería hacer usando el método llamado equals() . No se debería usar el operador de igualdad ( == ); este

108

deberá ser usado para comparar tipos primitivos solamente. Por ejemplo, si se han declarado dos cadenas, primeraCadena y segundaCadena , se compararían estas en una sentencia if como sigue:

if (primeraCadena.equals(segundaCadena)) { // más código aquí }

Un error común hecho por los programadores es usar el operador de igualdad ( == ) para comparar cadenas. Lo anterior no resulta en un error de compilación, pero no dará el resultado esperado. Lo que se estaría revisando es si los objetos ocupan el mismo espacio de dirección en memoria, en vez de comparar el valor actual de los atributos cadena de los objetos.

Observar que un objeto de tipo String también puede ser usado dentro de una sentencia switch para revisar si esta es igual a uno de varios valores posibles String . El programa RevisarCadenaConSwitch ilustra esto dando un significado para tres símbolos en un controlador de juego para un juego particular:

import java.util.Scanner; public class RevisarCadenaConSwitch { public static void main(String[] args) { Scanner teclado = new Scanner (System.in); String figura; // obtener la figura del usuario System.out.print( "Ingresar figura (cuadrado/círculo/triángulo) "); figura = teclado.next(); // usar objeto String en switch switch(figura) { case "cuadrado": System.out.println("ATACAR"); break; case "círculo": System.out.println("BLOQUEAR"); break; case "triángulo": System.out.println("BRINCAR"); break; default: System.out.println("Opción no válida"); } } }

La clase String también tiene un método útil llamado compareTo() . Este método acepta una cadena y compara esta con el valor cadena del propio objeto.

109

Regresa cero si las cadenas son idénticas, un número negativo si la cadena original viene antes que la cadena pasada en el alfabeto, y un número positivo si viene después.

El siguiente programa proporciona un ejemplo de cómo usar el método compareTo() .

import java.util.Scanner; public class ComparacionCadenas { public static void main(String[] args) { Scanner teclado = new Scanner(System.in); String cadena1, cadena2; int comparacion; // obtener dos cadenas del usuario System.out.print("Ingresar una cadena: "); cadena1 = teclado.next(); System.out.print("Ingresar otra cadena: "); cadena2 = teclado.next(); // comparar las cadenas comparacion = cadena1.compareTo(cadena2); if(comparacion < 0) { // compareTo() regresó núm. negativo System.out.println(cadena1 + " viene antes que " + cadena2 + " en el alfabeto"); } else if(comparacion > 0){ //compareTo() regresó núm. positivo System.out.println(cadena1 + " viene después de " + cadena2 + " en el alfabeto"); } else { // compareTo() regresó cero System.out.println("Las cadenas son idénticas"); } } }

Al igual que con el método equals() el método compareTo() es sensible a mayúsculas y minúsculas, y las letras mayúsculas vienen antes que las minúsculas porque su código Unicode es menor. Si no importa la capitalización de las letras, se podrían convertir ambas cadenas a mayúsculas, o minúsculas, antes de compararlas.

Si solo interesa saber si las cadenas son idénticas es mejor usar el método equals() . Si no importa la capitalización se puede usar equalsIngoreCase() .

110

7.6.4 Ingresar Cadenas con Espacios

Hay un problema con el uso del método next() de la clase Scanner cuando se ingresan cadenas que contienen espacios. Si se intenta esto se observa que la cadena resultante se detiene en el primer espacio, así que si se ingresó la cadena "Hola mundo" por ejemplo, la cadena resultante será "Hola".

Para ingresar una cadena que contiene espacios se necesita usar el método nextLine() . Desafortunadamente hay un problema con este. Si el método nextLine() es usado después del método nextInt() o nextDouble() , entonces es necesario consumir el salto de línea que dejan pendiente los métodos anteriores usando nextLine() . La manera de realizarlo se muestra enseguida:

import java.util.Scanner; public class UsoNextLine { public static void main(String[] args) { double d; int i; String s; Scanner teclado = new Scanner(System.in); // obtener número real, entero y cadena System.out.print("Ingresar un número real: "); d = teclado.nextDouble(); System.out.print("Ingresar un número entero: "); i = teclado.nextInt(); System.out.print("Ingresar una cadena: "); teclado.nextLine(); //comer salto de línea dejado x nextInt() s = teclado.nextLine(); System.out.println(); System.out.println("Datos Ingresados"); System.out.println(" Double: " + d); System.out.println("Integer: " + i); System.out.println(" String: " + s); } }

7.7 Clase Scanner Propia para Entrada del Teclado

Podría ocurrir que usar la clase Scanner para obtener la entrada del teclado sea un poco molesto.

● Es necesario crear un objeto Scanner nuevo en cada método que use la clase Scanner ;

● no hay un método simple como nextChar() para obtener un solo carácter como sí lo hay para el tipo int o double ;

111

● como se ha visto hay un problema cuando se ingresan cadenas conteniendo espacios.

Para facilitar la programación, se ha creado una clase nueva llamada ScannerFacil, la cual se puede descargar desde la página de los códigos . En el siguiente capítulo se revisará para ver como está escrita, por ahora se mostrará y se usará. Los métodos de ScannerFacil se describen en la siguiente tabla.

Tipo Java Método ScannerFacil

int nextInt()

double nextDouble()

char nextChar()

String nextString()

Cuando se usa ScannerFacil ya no se tienen que crear objetos Scanner para poderla usar, de eso se encarga la propia clase, y solo se tiene que escribir el nombre de la clase cuando se llama a un método. El siguiente programa muestra cómo se usan estos métodos.

public class ProbadorScannerFacil { public static void main(String[] args) { System.out.print("Ingresar un número real: "); double d = ScannerFacil.nextDouble(); // leer un double System.out.println("Ingresó: " + d); System.out.println(); System.out.print("Ingresar un número entero: "); int i = ScannerFacil.nextInt(); // leer un entero System.out.println("Ingresó: " + i); System.out.println(); System.out.print("Ingresar una cadena: "); String s = ScannerFacil.nextString(); // leer una cadena System.out.println("Ingresó: " + s); System.out.println(); System.out.print("Ingresar un carácter: "); char c = ScannerFacil.nextChar(); // leer un carácter System.out.println("Ingresó: " + c); System.out.println(); } }

112

7.8 Clase Console

La clase Console , de la biblioteca java.io , es proporcionada como una alternativa a Scanner . La clase Console no es adecuada para ejecutar programas dentro de un IDE.

El siguiente programa muestra como la entrada del teclado es obtenida con la clase Console :

import java.io.Console; public class ProbadorConsole { public static void main(String[] args) { System.out.println(); System.out.println("Probador de Console"); System.out.println(); Console con = System.console(); String nombre; // declaración de una cadena nombre=con.readLine("Ingresar nombre: "); // permitir entr. System.out.println("Hola " + nombre); // mostrar mensaje } }

Se puede ingresar una cadena conteniendo espacios; sin embargo, si se quiere usar la clase Console para ingresar un double o un int , se tiene que ingresar una cadena y luego convertirla al tipo deseado.

7.9 Clase CuentaBancaria

Se ha creado una clase llamada CuentaBancaria , la cual se puede descargar usando este enlace . Nuevamente no se necesitan revisar los detalles de cómo esta clase está codificada para poderla usar. Sin embargo, se necesita saber que la clase guarda tres piezas de información de la cuenta: número, nombre y balance. Los primeros dos son objetos String y el último es una variable de tipo double .

Enseguida se muestran los métodos.

Método Descripción Entradas Salida

CuentaBancaria() Constructor. Acepta dos cadenas y las asigna al número de cuenta y al nombre. También pone el saldo a cero

Dos objetos String

No aplica

getCuenta() Regresa el número de Ninguno Objeto

113

cuenta String

getNombre() Regresa el nombre de la cuenta

Ninguno Objeto String

getBalance() Regresa el balance Ninguno Dato de tipo double

depositar() Acepta un dato de tipo double y lo agrega al balance

Dato de tipo double

Ninguno

retirar() Acepta un dato de tipo double y revisa si hay fondos suficientes para hacer un retiro. Si hay se resta el monto del balance y regresa true . Si no hay el método termina y regresa false

Dato de tipo double

Dato de tipo boolean

El programa ProbadorCuentaBancaria crea un objeto CuentaBancaria y luego pide al usuario ingresar un monto a depositar. Luego confirma que el depósito fue hecho y muestra el balance nuevo.

Enseguida hace lo mismo con un retiro. El método r etirar() regresa un valor boolean indicando si el retiro fue exitoso o no, él cuál se asigna a una variable que es usada para mostrar el mensaje adecuado.

import java.util.Scanner; public class ProbadorCuentaBancaria { public static void main(String[] args) { Scanner teclado = new Scanner(System.in); double monto; boolean estado; CuentaBancaria cuenta1 = new CuentaBancaria("53927005982","JOSE PEREZ LOPEZ"); System.out.print("Ingresar monto a depositar: "); monto = teclado.nextDouble(); cuenta1.depositar(monto); System.out.println("Depósito fue hecho"); System.out.println("Balance = " + cuenta1.getBalance()); System.out.println(); System.out.print("Ingresar monto a retirar: ");

114

monto = teclado.nextDouble(); estado = cuenta1.retirar(monto); // obtener valor devuelto if(estado) { System.out.println("Retiro hecho"); } else { System.out.println("Fondos insuficientes"); } System.out.println("Balance = " + cuenta1.getBalance()); System.out.println(); } }

7.10 Arreglos de Objetos

En el capítulo 6 se revisa cómo crear arreglo de tipos simples como int y char . También es posible crear arreglos de objetos pero se debe tener cuidado. Para mostrar esto el programa ProbadorCuentaBancaria2 creará varias cuentas bancarias usando un arreglo.

public class ProbadorCuentaBancaria2 { public static void main(String[] args) { // crear un arreglo de referencias CuentaBancaria[] listaCuentas = new CuentaBancaria[3]; // crear 3 cuentas, c/u referida por un elemento del arreglo listaCuentas[0] = new CuentaBancaria("53927005982","JOSE PEREZ LOPEZ"); listaCuentas[1] = new CuentaBancaria("64938116093","JUAN SOTO TENA"); listaCuentas[2] = new CuentaBancaria("75049227104","MARIA REAL VACA"); // realizar varios depósitos y retiros listaCuentas[0].depositar(1000); listaCuentas[2].depositar(200); listaCuentas[0].retirar(500); // mostrar detalles de las tres cuentas for(CuentaBancaria cuenta : listaCuentas) { System.out.println(" Número: "+cuenta.getNumero()); System.out.println(" Nombre: "+cuenta.getNombre()); System.out.println("Balance: "+cuenta.getBalance()); System.out.println(); } } }

115

La siguiente sentencia es muy similar a las usadas para declarar y crear arreglos de tipos primitivos. Pero no prepara un arreglo de referencias de tales objetos.

CuentaBancaria[] listaCuentas = new CuentaBancaria[3];

La sentencia reserva espacio para las tres referencias CuentaBancaria solamente, no los tres objetos CuentaBancaria . Cuando una referencia es creada esta apunta a la constante null , así que en este punto cada referencia en el arreglo apunta a null .

Lo anterior significa que todavía se necesitará reservar memoria para objetos CuentaBancaria y enlazarlos al arreglo. Ahora se pueden crear objetos CuentaBancaria y asociarlos con elementos en el arreglo como se hace en las siguientes líneas:

listaCuentas[0] = new CuentaBancaria("53927005982","JOSE PEREZ LOPEZ"); listaCuentas[1] = new CuentaBancaria("64938116093","JUAN SOTO TENA"); listaCuentas[2] = new CuentaBancaria("75049227104","MARIA REAL VACA");

Una vez creadas estas cuentas, se hacen algunos depósitos y retiros.

listaCuentas[0].depositar(1000); listaCuentas[2].depositar(200); listaCuentas[0].retirar(500);

Para llamar un método de un elemento particular del arreglo, se coloca el operador punto después del corchete de cierre del índice del arreglo.

Para mostrar los detalles de las tres cuentas se tiene que acceder el arreglo entero, para realizarlo se usa el ciclo for avanzado, y como se está manipulando un arreglo de objetos CuentaBancaria , el tipo de los elementos es indicado como CuentaBancaria .

7.11 Clase ArrayList

Trabajar con arreglos puede ser en ocasiones un poco incómodo. Lo anterior se debe a que los arreglos son lo que se denomina una construcción de bajo nivel, lo que significa que estos están más cercanos a la manera como trabaja la computadora, y empatan la forma como los datos están guardados en memoria. Como programador es importante entender los arreglos y como trabajan; sin embargo es habitual que un lenguaje de programación orientado al objeto proporcione clases de alto nivel cuyos métodos están más cercanos a la forma como se hacen las cosas en la vida real; estas clases manejan el detalle de bajo

116

nivel que ocurre detrás de escena, permitiendo al usuario tener a la mano tales detalles.

Un ejemplo de una clase de alto nivel son las conocidas como clase colección. Estas clases permiten al programador manipular colecciones tales como listas simples con métodos que agregan un nuevo elemento al final de lista, o quitan un elemento de una posición específica.

Clases colección son ejemplos de clases conocidas como clases genéricas . Para entender las clases genéricas se requieren algunos conceptos avanzados que serán abordados en el segundo semestre. Por el momento se revisa la clase colección llamada ArrayList , del paquete java.util , y se proporciona información suficiente para poder usarla.

En el siguiente programa se verá que hay una notación nueva involucrada. Esto es porque cuando se declara un objeto de una clase colección se necesita indicar el tipo de objeto que será guardado, por lo que se verán declaraciones como esta:

ArrayList<CuentaBancaria> ListaCuentas;

El tipo de objeto guardado es indicado entre los corchetes angulares; así ListaCuentas guardará una lista de CuentaBancaria . De igual forma, si se quiere declarar un objeto ArrayList llamado nombres el cual es para guardar String , se hará lo siguiente:

ArrayList<String> nombres;

El programa siguiente, ProbadorCuentaBancaria3 usa un ArrayList en vez de un arreglo.

import java.util.ArrayList; public class ProbadorCuentaBancaria3 { public static void main(String[] args) { // crear un arreglo de referencias ArrayList<CuentaBancaria> listaCuentas = new ArrayList<>(); // crear 3 cuentas, c/u referida por un elemento del arreglo listaCuentas.add( new CuentaBancaria("53927005982","JOSE PEREZ LOPEZ")); listaCuentas.add( new CuentaBancaria("64938116093","JUAN SOTO TENA")); listaCuentas.add( new CuentaBancaria("75049227104","MARIA REAL VACA")); // realizar varios depósitos y retiros listaCuentas.get(0).depositar(1000); listaCuentas.get(2).depositar(200);

117

listaCuentas.get(0).retirar(500); // mostrar detalles de las tres cuentas for(CuentaBancaria cuenta : listaCuentas) { System.out.println(" Número: "+cuenta.getNumero()); System.out.println(" Nombre: "+cuenta.getNombre()); System.out.println("Balance: "+cuenta.getBalance()); System.out.println(); } } }

La declaración completa de listaCuentas es como sigue:

ArrayList<CuentaBancaria> listaCuentas = new ArrayList<>();

Cuando se llama al constructor de una clase genérica no se necesita reafirmar el tipo de objeto guardado, así los paréntesis angulares son dejados vacíos, en ocasiones referidos como diamante. El compilador deduce el tipo de la primera parte de la declaración, este es un ejemplo de inferencia de tipo .

Se debe observar que no se necesita indicar cuantos elementos un ArrayList guardará. Este se expande y contrae dinámicamente conforme se agregan y quitan elementos.

Para agregar elementos se usa el método add() de ArrayList , el cual toma como parámetro el objeto que se está agregando.

listaCuentas.add( new CuentaBancaria("53927005982","JOSE PEREZ LOPEZ")); listaCuentas.add( new CuentaBancaria("64938116093","JUAN SOTO TENA")); listaCuentas.add( new CuentaBancaria("75049227104","MARIA REAL VACA"));

Para hacer depósitos y retiros, se necesita recuperar el elemento individual que se requiere usando el método get() de ArrayList , el cual toma como parámetro el índice particular, iniciando con cero, al igual que los arreglos:

listaCuentas.get(0).depositar(1000); listaCuentas.get(2).depositar(200); listaCuentas.get(0).retirar(500);

Para mostrar los elementos se usa un ciclo for avanzado el cual trabaja adecuadamente con clases como ArrayList , así el código para mostrar las cuentas bancarias es el mismo del programa original.

118

7.12 Preguntas

1. Escribir el código que haga lo siguiente: a. Crear dos objetos CuentaBancaria , referidos por cuenta1 y cuenta2 .

El número de cuenta y el nombre serán puestos al momento de que el objeto sea creado.

b. Depositar la cantidad de 200 en cuenta1 y 100 en cuenta2 . c. Intentar un retiro de 150 de cuenta1 y mostrar el mensaje "RETIRO

EXITOSO" si la cantidad se pudo retirar y "FONDOS INSUFICIENTES" caso contrario.

d. Mostrar el balance de cuenta1 y cuenta2 . 2. ¿Cómo difieren las llamadas a los métodos de ScannerFacil respecto a las

llamadas de los métodos de CuentaBancaria , String o Scanner ? 3. ¿Cómo difieren los arreglos de objetos de los arreglos de tipos primitivos?

Indicar la diferencia en la memoria y en su creación. 4. Escribir el código que permita realizar lo siguiente:

a. Declarar un arreglo llamado recamaras para guardar tres objetos Rectangulos . Cada objeto Rectangulo representará las dimensiones de una recámara en un apartamento.

b. Las tres recámaras del departamento tienen las siguientes dimensiones en metros: i) 5.2x4.7; ii) 5.2x5.7; iii) 8.1x5.0. Agregar tres objetos Rectangulo al arreglo recamaras para representar estas tres recámaras.

c. Hacer uso del arreglo recamaras para mostrar el área de las tres recámaras en la pantalla.

119