La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Introducción a Java (I)

Presentaciones similares


Presentación del tema: "Introducción a Java (I)"— Transcripción de la presentación:

1 Introducción a Java (I)

2 Índice Tipos de datos y operadores Entradas y Salidas básicas
Sentencias de control Clases

3 Tipos de datos y operadores

4 Variables Una variable no es algo muy diferente de lo que hemos aprendido en matemáticas. Pensemos en las siguientes operaciones: El largo de la parcela es 60 metros El ancho de la parcela es 70 metros El área es el producto del ancho por el largo: 4200 ¿Por qué son necesarias las variables? Porque necesitamos etiquetas o identificadores para cosas tales como ancho, largo, etc. Porque necesitamos almacenar datos asociados a dichos identificadores (60, 70, 4200) Un ejemplo en Java: public static void main(String[] args) { System.out.println( "Ha entrado en la aplicación"); float largo; float ancho; float area; largo = 60; ancho = 70; area = ancho * largo; // ¿ Cómo visualizar el área de la parcela }

5 Variables: las reglas básicas
Regla básica: toda variable debe ser declarada antes de ser utilizada En el formato de la declaración hay que tener en cuenta: Lo básico, especificar: El tipo de dato El nombre o identificador de la variable Lo opcional es: Dar valor a la variable por primera vez (inicializar) Declarar otras variables en la misma línea (ojo: del mismo tipo) Formato: Tipo nombre [ = valor ] [, nombre [ = valor ] ... ]; Ejemplos: int alto, ancho = 0, edad; char x = ‘s’, b; El programador tiene completa libertad a la hora de dar nombre a una variable. Por ejemplo, no hay obligación de llamar a las variables enteras con nombres como “número”, “entero”, etc. Lo mejor a la hora de dar un nombre es dejarse llevar por el sentido común: claridad, es decir, tratar de ser “significativo” sin alargarse en exceso. Por ejemplo, el nombre “edad” es más significativo que usar simplemente “e”. La costumbre de dar nombres no significativos es uno de los vicios que conduce a crear código “solipsista”: sólo lo comprende el programador que lo creó (siempre que no haya pasado mucho tiempo, en cuyo caso lo normal es que no lo comprenda ni la persona que lo hizo)

6 Los tipos de datos: enteros y coma flotante
Del mismo modo que existen diferentes tipos de vehículos existen diferentes tipos de variables El tamaño en bits, a diferencia de C/C++, es fijo, es decir, no varía en función de la máquina. Esto facilita la portabilidad Enteros: byte: 8 bits (-128 a 127) short: 16 bits ( a ) int: 32 bits ( a ) long: 64 bits (+/- 9x1018) En coma flotante, también llamados reales. Se utilizan cuando se precisan posiciones decimales: float: 32 bits (3.4e-038 a 3.4e+038) double: 64 bits (1.7e-308 a 1.7e+308)

7 Elegir un tipo de datos En principio parece que lo más fácil sería trabajar con un único tipo de dato. ¿Parece lógico tener diferentes tipos de datos? La respuesta más sencilla es responder con una pregunta: ¿parece sensato tener el mismo tipo de vehículo para transportar 5 personas, transportar 3 toneladas de carga o para llevar a 55 personas? Tenemos diferentes tipos de datos con la finalidad de optimizar. Del mismo modo que no es sensato usar el motor de un autobus para un turismo, no es sensato emplear 64 bits si queremos contar del 1 al 10 Por tanto, parece que el primer criterio para elegir el tipo es la optimización: no malgastar memoria. Pero hay un criterio más importante, el sentido común, que nos indica que resulta prudente actuar con holgura. De hecho, en nuestra vida cotidiana no llevamos nuestros coches siempre llenos y perfectamente optimizados. Sino que con frecuencia, transportan menos personas que su límite máximo

8 Un ejemplo con double Un ejemplo para calcular el área de un círculo (PI*r2) public class j01_radio { public static void main(String[] args) throws IOException { double PI = ; double radio = 3.2, area; area = radio * radio * PI; // Calculo el área System.out.println( "El área es: " + area); } Ejercicio: hacer un programa que calcule volumen de un contenedor a partir de su largo, ancho y altura (pueden admitir dos decimales).

9 Booleanos Es un tipo de dato propio de una lógica binaria: sólo tiene como valores true o false. int edad = 0; boolean mayor_de_edad = false; edad = 18; mayor_de_edad = true; Es el tipo utilizado para evaluar los condicionales: if (edad >= 18) // Si es verdad que la edad es > ó = que 18 mayor_de_edad = true; // entonces es mayor de edad if (mayor_de_edad == true) // Si es verdad que es mayor de edad ... System.out.println( “Puede obtener el carnet B1” ); El último condicional se puede escribir de manara más cómoda (y más usual): if (mayor_de_edad) // Si es verdad que es mayor de edad ...

10 Caracteres (char) En Java los caracteres se almacenan en variables de 16 bits. Se utiliza un formato estándar e internacional denominado Unicode que admite caracteres, de esta forma podemos utilizar desde el latín hasta el arábigo. Unicode es el formato más utilizado en Internet. En el siguiente ejemplo cambiamos el valor de una variable char: char cuadricula = ‘A’; System.out.println( “La cuadrícula del mapa es ” + cuadricula ); cuadricula = ‘b’; El siguiente ejemplo nos muestra como funciona internamente el ordenador: asocia a cada carácter un número. Puesto que con 16 bits podemos representar números enteros de 0 a , entonces podemos representar caracteres. En nuestro ejemplo asociamos a un char el número 126, que se representa en formato de carácter como ‘~’: char a = 126; System.out.println( “El carácter es ” + a ); Observar que una cadenas de caracteres (String) se delimita por comillas dobles y los caracteres aislados (char) se delimitan por comillas simples.

11 String String no es un tipo simple (como float, char, etc.), sino una clase que nos ayuda a manejar de forma sencilla cadenas de caracteres. Ejemplos de instancias: String j = “Hola mundo”; String k = new String( “Hola mundo” ); Podemos concatenar cadenas: String k = "Hola“, String m = "Adios"; String h = "Saludos: " + k + " y " + m; System.out.println( h ); Podemos saber su ancho: String k = “Antonio”; System.out.println( k.length() ); Mediante compareTo() podemos ordenar diferentes cadenas (ver más adelante) Conversión de númerico a cadena mediante el método static valueOf(): int anio = 1999; String p = String.valueOf( anio); System.out.println( p ); La conversión inversa se hace con métodos static que están en las clases Double, Float, etc: radio = Double.parseDouble( cadena ); // Convierto el String en double Se puede acceder a un carácter de la cadena: char car = c.charAt(1);

12 Ámbito de vida El ámbito de una variable u objeto es el espacio del programa en el que esa variable existe. Por ello, se habla de “ámbito de vida” De forma general (hay excepciones que veremos más adelante), la vida de una variable comienza con su declaración y termina en el bloque en el que fue declarada (los bloques de código se delimitan por llaves: {}). Por ejemplo, ¿cuál es el ámbito de la variable ‘radio’ y del vector ‘args’?: public static void main(String[] args) { double PI = ; double radio = 3; System.out.println( “El área es” + (PI*radio*radio) ); } Más adelante profundizaremos en los diferentes tipos de ámbito

13 Conversión de tipos Hemos visto que los datos tienen un tipo. Pero en ocasiones nos conviene convertir un dato de su tipo original a otro Tipos de conversión: Automática o implícita. El tipo destino es más grande (mayor número de bits) que el tipo origen (ensanchamiento o promoción): int Origen = 65; float Destino = 4.35f; Destino = Origen; // ¿Cuál es el valor de ‘Destino’? También hay conversión automática ante tipos compatibles. Por ejemplo, la asignación de un int a un char que vimos anteriormente Explicita. La conversión se produce cuando el tipo destino es más pequeño que el origen (estrechamiento). Para ello debemos realizar un moldeado (cast): double Origen = 65.13; int Destino = 4; Destino = (int) Origen; // ¿Cuál es el valor de ‘Destino’? La conversión por medio de métodos es en realidad una aplicación de los tipos de conversión anteriores. Para ver ejemplos (transparencia dedicada a la clase String): String p = String.valueOf( anio); double radio = Double.parseDouble( cadena );

14 Comprender la conversión de tipos
Supongamos que tenemos en una variable (int) el precio de un producto. Queremos incrementarlo en un 20%: int precio = 10000; precio = precio * 1.2; Este código parece correcto, sin embargo el compilador nos informa de un error: “Error num.: 355 : puede perderse precisión: double, hacía falta int”. ¿Cuál es la razón? Para entenderlo, conviene comprender como trabaja el ordenador: El ordenador trata de realizar el producto (precio*1.2) entre un int y un double (1.2), para lo cual el ordenador convierte de forma automática el int en un double. Hasta aquí todo va bien, el resultado de multiplicar dos números double es un double: precio = precio * 1.2; (int) (double) (conversión automática a double) (double) El problema viene a continuación: no hay conversión automática de un double (el resultado del producto) a un int (la variable a la izquierda del operador =) Para que se produzca esta conversión es necesario realizar un moldeado (cast): precio = (int) (precio * 1.2); // Esto si es correcto

15 Matrices (I) Una matriz es un conjunto ordenado de variables u objetos, con las siguientes características: Tienen el mismo tipo Tienen el mismo nombre (aunque hay casos poco usuales de matrices anónimas) Si tienen el mismo nombre, ¿cómo se diferencia un elemento de otro? La respuesta es por el índice Formatos: Con new: Tipo nombre[] = new tipo[tamaño] Sin new: Tipo nombre[] = {x, y, ...} Un ejemplo: int m[] = new int[3]; m[0] = 5; m[1] = 9; m[2] = 2; System.out.println( m[1] ); Matriz Valor: 5 9 2 Posición: 1 2

16 Matrices (II) ¿Por qué necesito hacer casting?
Un ejemplo en el que incremento en un 50% el tercer elemento de la matriz: public static void main(String[] args) { int depositos[]; int num_depositos = 4; depositos = new int[num_depositos]; // Igual que: int depositos[] = new int[4]; depositos[0] = depositos[1] = 300; depositos[2] = depositos[3] = 700; System.out.println( "Litros del segundo deposito:" + depositos[1]); depositos[2] = (int) (depositos[2] * 1.5); // Incremento de un 50% System.out.println( "Litros del tercer deposito:" + depositos[2]); } ¿Por qué necesito hacer casting?

17 Matrices (III) Es importante destacar una diferencia a la hora de crear una matriz: Si trabajamos con tipos simples (int, char, float, double, etc.) tenemos que usar el operador new una vez, al crear la matriz: int botes[] = new botes[4]; Botes[0] = 325; Si trabajamos con tipos compuestos (todos los demás, es decir, clases de Java como String, o cualquier otra creada por el programador), entonces hay que usar dos veces dicho operador: una al crear la matriz y luego tantas veces como objetos queramos almacenar en ella: public static void main(String[] args) { Vehiculo mios[] = new Vehiculo[2]; mios[0] = new vehiculo(); mios[1] = new vehiculo(); mios[0].definir_precio_bajo(); mios[1].definir_precio_bajo(); mios[1].mostrar(); } Vehiculo.java: package xxx; public class Vehiculo { private int precio; void definir_precio_bajo() { precio = 12000; } void mostrar() { System.out.println( " Precio:" + precio);

18 Matrices (IV) Para obtener el ancho de una matriz: Nombre.length. Ejemplo: String nombres[] = new String[3]; nombres[0] = new String(“Antonio”); System.out.println( nombres.length ); // Muestra el número 3 En comparación con C/C++ la copia de matrices completas resulta muy sencilla: int Origen[] = { 200, 400, 600 }; int Destino[] = { 10, 20, 30 }; Destino = Origen; System.out.println( Destino[0] ); System.out.println( Destino[1] ); Al intentar acceder a un elemento que está fuera del rango de la matriz se genera un ArrayIndexOutOfBoundsException 200 400

19 Matrices multidimensionales
Utilizamos una pareja de corchetes ([]) para cada dimensión. En el caso de una matriz bidimensional un ejemplo sería: int Lista[][] = new int[filas][columnas]; Java le permite no tener que especificar todas las dimensiones al principio (con el primer new). Al menos tiene que especificar la dimensión más significativa (más a la izquierda). Además puede hacer que las dimensiones siguientes (menos significativas) difieran. El siguiente ejemplo crea una matriz en la que la primera fila tiene tres columnas y la segunda fila tiene cinco: int M[][] = new int[2][]; M[0] = new int[3]; M[1] = new int[5];

20 Operadores aritméticos
Suma: + Resta: - Producto: * División: / Módulo: % (se puede aplicar a coma flotante y a int) Incremento: ++ (a++ es equivalente a: a=a+1) Decremento: -- (a-- es equivalente a: a=a-1) Suma y asignación: += (a+=3 es equivalente a: a=a+3) Resta y asignación: -= (a-=3 es equivalente a: a=a-3)

21 Operadores relacionales
El resultado de los operadores relacionales es un valor boolean (true o false): Igual a: == (no confundirlo con el operador de asignación) Distinto de: != Mayor que, mayor o igual: >, >= Menor que, menor o igual: <, <= Ejemplo 1: int a = 5, b = 2; boolean c = a >= b; Ejemplo 2: float a = 3; if (a == 3) System.out.println( “El valor es:” + a);

22 ¿Qué ocurre con String? A menudo necesitamos comparar cadenas de caracteres, para saber si una es lexicográficamente igual, mayor o menor que otra. El ejemplo típico es ordenar una lista de nombres Ya sabemos que String no es un tipo simple, sino que es una clase. Para ayudarnos en la comparación tenemos los métodos compareTo y compareToIgnoreCase. Podemos saber el orden de las cadenas en función de lo que devuelvan los métodos: String j = "Belén", k = "Susana", m = "Belén", n = "Antonio"; if (j.compareTo(m) == 0) System.out.println( j + " es igual a " + m); if (j.compareTo(k) < 0) System.out.println( j + " es menor que " + k); if (j.compareTo(n) > 0) System.out.println( j + " es mayor que " + n); Existe también el método equals( String ), que devuelve true si las cadenas son iguales. Hay otra versión equalsIgnoreCase(String) Belén es igual a Belén Belén es menor que Susana Belén es mayor que Antonio

23 Operadores lógicos Operan solamente con valores booleanos: Ejemplo:
Conjunción (Y): && Disyunción inclusiva (O): || Negación: ! Ejemplo: int edad = 17; float nota = 6f; boolean mayoria_edad = edad >= 18; if (mayoria_edad && nota >= 5) System.out.println( "aprobado" ); if (!mayoria_edad) System.out.println( "Le falta(n) " + (18-edad) + " año(s)" );

24 Entradas y Salidas básicas

25 Streams (I) Cualquier programa realizado en Java que necesite llevar a cabo una operación de I/O lo hará a través de un stream. Un stream, cuya traducción literal es "flujo", es una abstracción de todo aquello que permite introducir o extraer información. Así, un stream de teclado es un flujo de entrada para el programa y un stream de pantalla es un flujo de salida del programa Input: Teclado Output: Pantalla La vinculación de este stream al dispositivo físico (teclado, pantalla, impresora, etc.) la hace el sistema de entrada y salida de Java.

26 Streams (II) El paquete System define tres clases:
in (entrada estándar) out (salida estándar) err (salida de errores estándar) La escritura hacia pantalla se hace con System.out System.out.println(“Hola Mundo”); // Añade nueva línea al final System.out.print(“Adios”); // NO añade nueva línea al final La lectura desde teclado se hace con System.in

27 Stream de entrada por teclado
Para manejar entradas por teclado tenemos que crear un BufferedReader a partir de System.in: import java.io.*; public class inicio { public static void main(String[] args) throws IOException { String cadena; BufferedReader entrada; entrada = new BufferedReader(new InputStreamReader(System.in)); // Crear objeto de entrada System.out.println("Escribe tu nombre:"); cadena = entrada.readLine(); //leemos cadena de caracteres mediante readLine() } Condiciones previas a la creación de un BufferedReader: Tengo que importar las clases que uso (BufferedReader y InputStreamReader), que están en el paquete java.io, por medio de import. Tengo que poner “throws IOException” en la función que usa BufferedReader (ya se explicará más adelante el manejo de excepciones). Una vez creado el objeto de entrada para teclado, mediante BufferedReader, puedo leer la entrada por teclado mediante una llamada a objeto.readLine() (la entrada termina al pulsar Enter). No olvidar que esta función devuelve un String, es decir, cualquier cosa que el usuario teclea se almacena como una cadena, sea “pedro” o “3420”. Java es un lenguaje fuertemente tipado y si queremos que lo tecleado se convierta en un número habrá que hacer posteriormente una conversión mediante métodos, como veremos en el siguiente ejemplo.

28 Un ejemplo entrada por teclado y conversión
public static void main(String[] args) throws IOException { double PI = , radio; int area_int; String c; /* Creo el objeto 'entrada', es un lector de entradas por teclado */ BufferedReader entrada = new BufferedReader( new InputStreamReader(System.in)); System.out.print( "Escriba el radio: " ); c = entrada.readLine(); // Leo un String de la entrada de teclado radio = Double.parseDouble( c ); // Convierto el String en double radio System.out.println( "El área es: " + radio * radio * PI); area_int = (int) (radio * radio * PI); // Calculo el área entera del círculo. Hago casting System.out.println( "El área (entera) es: " + area_int); } Desde un String existen conversiones a otros tipos: Integer.parseInt( cadena ) o Float.parseFloat( cadena). La conversión inversa utiliza String.valueOf( numero). Para que todo funcione: una vez que se ha dado la orden de ejecución, se debe hacer click en la ventana de mensajes, de esta forma la ventana de mensajes obtiene el foco de teclado. A partir de aquí todo lo que se teclea va a dicha ventana.

29 Sentencias de control

30 Introducción Las sentencias de control nos ayudan a que el flujo de ejecución del programa deje de tener un carácter lineal. Ejemplos de sentencias de control en la vida cotidiana: Ejemplo 1: Si el cheque es correcto y hay fondos Entonces pagar Si no: No pagar Ejemplo 2: Mientras la salsa no este densa: Calentar y remover Ejemplo 3: Siga adelante Cuando llegue a la plaza: Si es hora punta Entonces tuerza a la derecha Siga todo recto Vamos a ver los siguientes tipos de sentencias de control: Selección Iteración Salto

31 La tabulación es fundamental para realizar código legible
if / else (I) La sentencia básica para realizar bifurcaciones o ramificaciones. Formato: if (condición) sentencia 1; [else sentencia 2] La condición es una expresión booleana. Si es true, se hace la sentencia 1; si es false, se hace la sentencia 2 (si existiese) Ejemplo: int a = 3, b = 9, c; if (a < b && a != 0) c = b – a; else c = a – b; Precaución: La tabulación es fundamental para realizar código legible

32 if / else (II) Si hay más de una sentencia debemos delimitar los bloques por llaves {}. En el siguiente ejemplo vamos a determinar las ventajas que tiene un cliente en función de los puntos de su tarjeta de compra: if (puntos > 1000) { tipo_cliente = "VIP"; descuento = 0.05f; } else { tipo_cliente = "Normal"; descuento = 0.02f; System.out.println( "Tipo: " + tipo_cliente + "\tDescuento: " + descuento*100 + "%"); Los condicionales pueden ser anidados, es decir, que uno este dentro de otro. En nuestro ejemplo vamos a añadir otra condición: para los clientes de más de 1000 puntos, si su antigüedad es mayor de 1825 días, les haremos un descuento del 6%: if (antiguedad > 1825) descuento = 0.06f;

33 switch Formato: No olvidar ‘break’. Pero a veces es adecuado omitirlo:
switch ( expresión ) { // expresión: no tiene que ser booleano case constante1: secuencia de sentencias break; case constante2: ... default: } No olvidar ‘break’. Pero a veces es adecuado omitirlo: switch ( categoria ) { case 1: case 2: porcen = 0.2; // Tanto para 1 como para 2 case 3: porcen = 0.15; porcen = 0.1;

34 while Sentencia Bucle Formato:
while (condición) Sentencia La sentencia puede ser un bloque delimitado por llaves ({}). El bucle se realiza mientras la condición sea cierta Ejemplo en el que modificamos un vector de números, de tal modo que ponemos el cuadrado del número que antes estuviese: double serie[] = {23, 4, 36, 9}; int i = 0; while ( i < serie.length ) { System.out.print( "Posición: " + i + "\t Anterior: " + serie[i] ); serie[i] = serie[i] * serie[i]; System.out.println( "\t Cuadrado: " + serie[i] ); i++; } Bucle Posición: 0 Anterior: 23.0 Cuadrado: 529.0 Posición: 1 Anterior: Cuadrado: 16.0 Posición: 2 Anterior: 36.0 Cuadrado: Posición: 3 Anterior: 9.0 Cuadrado: 81.0

35 for (I) En la vida cotidiana hay numerosos casos de iteraciones (repeticiones). Por ejemplo, si alguien tiene que asignar un número a las cinco personas que hay en una habitación haría algo así: for (el número es 1; mientras que el número sea < 6; incremento el número) Digo en voz alta el número, señalando a la persona correspondiente De forma semejante, el formato de for es: for ( inicialización; condición; variación ) Sentencia Con un ejemplo puede aclararse. Supongamos que queremos mostrar por pantalla los cuatro primeros números enteros, empezando por el 3: La inicialización sería: empezar con el número 3 Condición: mientras que el número sea menor que 7 (es aquello que debe cumplirse para poder volver a repetir la sentencia) Variación: incrementar en uno el número Sentencia (aquello que se debe iterar o repetir, en nuestro ejemplo 4 veces): mostrar el número por pantalla Ejemplo: int i; for ( i = 3; i < 7; i++) System.out.println( i ); Nos podemos saltar la inicialización (empieza en el valor previo) int i = 3; for ( ; i < 7; i++)

36 for (II) Vamos a ver paso a paso como actua la iteración Ejemplo:
int i; for ( i = 1; i < 3; i++) System.out.println( i ); Al observar la ejecución paso a paso es importante recordar: Siempre se evalúa la condición ANTES de ejecutar la sentencia DESPUÉS de la sentencia siempre se realiza la variación Se pueden iterar varias variables, para lo cual necesitamos comas: for(i=0, k=5; i < 5; i++, k=k+5) INICIO: la variable i se inicia a 1 CONDICIÓN: se comprueba la condición: ¿ i<3 ? SI SENTENCIA: se ejecuta la sentencia println VARIACIÓN: al terminar el bucle, se incrementa i. Ahora vale 2 VARIACIÓN: al terminar el bucle, se incrementa i. Ahora vale 3 CONDICIÓN: se comprueba la condición: ¿ i<3 ? NO, fin del bucle IMPORTANTE: al salir del bucle el valor de i es 3. ¿Cuál sería su valor si la condición fuese i<=3?

37 for (III) Igual que los casos anteriores: utilizan {} para acotar conjuntos de sentencias y además son anidables. Ejemplo en el que se calcula la media y el máximo de un vector de números: public static void main(String[] args) { float serie[] = {-8, -12, -4, -14}; float media, sumatorio = 0; int contador; float maximo = serie[0]; // ¿Funcionaria si asignamos el 0? /*** Hallamos el máximo y sumamos todos los números ***/ for ( contador = 0; contador < serie.length; contador++ ) { if (serie[contador] > maximo) maximo = serie[contador]; sumatorio = sumatorio + serie[contador]; } /*** Calculamos media. Mostramos la media y el maximo ***/ media = sumatorio / contador; System.out.println( "La media es " + media + " y el max es " + maximo); Se pueden clasificar las variables en virtud de su función o uso (hasta ahora las hemos clasificado en virtud del tipo de dato). Entre estos tipos de usos hay dos que son muy comunes y aparecen en nuestro ejemplo: Variables contador Variables sumatorio

38 do-while Formato: do { Sentencia } while (condición); A diferencia de while, analiza la condición al final del bucle. Por tanto, la sentencia se realiza al menos una vez Ejemplo. ¿Qué hace?: int i = 1; System.out.println( i*i*i ); i++; } while ( i < 3 ); do-while es muy útil en la gestión de menús. El diseño sería: Muestro las opciones de menú Solicito la opción por teclado switch (opcion) { En función de la opción elegida realizo una u otra acción } } while (la opción no sea “Salir”); A continuación puede verse un ejemplo de gestión de menú para una calculadora

39 Calculadora public static void main(String[] args) throws IOException { char opcion; String cadenaTeclado; double operando1 = 0, operando2 = 0; /* Creo el obj. 'entrada', es un lector de entradas por teclado */ BufferedReader entrada = new BufferedReader( new InputStreamReader(System.in)); do { /********* Mostrar menu y pedir opcion por teclado ****/ System.out.print("\r\n S - Suma\r\n R - Resta\r\n P - Producto" + "\r\n D - División\r\n Q - Salir\r\n Su opción:"); cadenaTeclado = entrada.readLine(); // Teclado opcion = cadenaTeclado.charAt( 0 ); // Conv a char /********* Si la opción no es salir, solicito operandos ***/ if ( opcion != 'Q' && opcion != 'q') { System.out.print( "Número 1: " ); cadenaTeclado = entrada.readLine(); // Teclado operando1 = Double.parseDouble( cadenaTeclado ); // Conv System.out.print( "Número 2: " ); operando2 = Double.parseDouble( cadenaTeclado ); // Conv } /**** En función de la opción: opero o salgo ***/ switch (opcion) { case 's': case 'S': System.out.print( operando1 + operando2 ); break; case 'r': case 'R': System.out.print( operando1 - operando2 ); case 'p': case 'P': System.out.print( operando1 * operando2 ); case 'd': case 'D': System.out.print( operando1 / operando2 ); case 'q': case 'Q': System.out.print( "Adios" ); default: System.out.print( "Opción no disponible" ); } /////////////////////////////// Fin de switch } while (opcion != 'Q' && opcion != 'q'); } //////////////////////////////// Fin de función

40 Salto Hay sentencias que controlan el flujo de ejecución, de tal forma que realizan saltos fuera del bloque en el que se encuentran: break: salta fuera del bucle o switch return: salta fuera del método Un ejemplo con break. Busca un nombre en una lista y, si lo encuentra, sale del bucle: private static void funcion() { int i = 0; String nombre[] = { "Ana", "Belen", "Juan", "Pedro"}; String nombrBuscado = “Belen"; boolean encontrado = false; while (i < nombre.length) { if (nombre[i].equals(nombreBuscado)) { System.out.println(nombre_buscado + " está en la posición " + i); encontrado = true; break; } i++; if (!encontrado) System.out.println("No encontrado");

41 Clases

42 Introducción (I) Hasta ahora las clases las hemos usado como soporte al método main. A partir de aquí vamos a adentrarnos en el manejo de clases Una clase puede entenderse como un modelo o patrón: la representación abstracta de un conjunto Un conjunto en la vida cotidiana puede ser definido por sus atributos y/o por acciones (comportamiento). Por ejemplo: El conjunto de los mamíferos con aletas El conjunto de los profesionales en extinción del fuego Un bombero en concreto sería una instancia del conjunto de los bomberos Cuando definimos el conjunto de los bomberos no hacemos referencia a ningún bombero en concreto, de la misma manera, cuando definimos una clase no hacemos referencia ni creamos un objeto o instancia de la clase

43 Introducción (II) Del mismo modo que ocurre con los conjuntos de la vida cotidiana, las clases se definen por sus atributos y/o métodos (funciones que definen el comportamiento de la clase). Por ahora vamos a empezar con los atributos. Veamos el siguiente ejemplo en el que la clase Inicio hace una instancia de la clase Circulo: Creamos la clase Circulo. Es importante entender que la sentencia “Circulo a;” NO CREA un objeto, sino que crea una referencia o etiqueta (vacía o nula). Por ello, si queremos acceder al atributo “radio” para asignarle un valor (23), el compilador nos dará un mensaje de error. SOLO se crea un objeto si se utiliza new. Lo correcto sería: Circulo a; a = new Circulo(); // O bien: Circulo a = new Circulo(); a.radio = 23; /******** Circulo.java ********/ package figuras.dominio; public class Circulo { public double radio; public double PI = ; } /********* Inicio.java *****/ package figuras.inicio; import figuras.dominio.Circulo; public class Inicio { public static void main(String[] args) { Circulo a; // ERROR a.radio = 23; }

44 Introducción (III) El error anterior era un error en tiempo de compilación. La mayor parte de IDEs nos darán un mensaje del estilo “variable no inicializada” antes de compilar, es decir, el entorno de desarrollo ha detectado que no hay un objeto, que la etiqueta no hace referencia a un objeto. Podemos “engañar” a la mayor parte de los IDEs con el siguiente código, que se puede compilar sin errores: Circulo a = null; a.radio = 23; // Línea número 7 Decimos “engañar” ya que este código hará que el IDE no nos muestre el error en tiempo de compilación. Pero el problema es el mismo: no hay objeto para la etiqueta “a”. El error surge en tiempo de ejecución: java.lang.NullPointerException at figuras.inicio.Inicio.main(Inicio.java:7) Este es el error más frecuente en programación Java (y en otros lenguajes como C/C++) y siempre indica lo mismo: tratamos de acceder a un atributo o método del objeto, pero ocurre que no hay objeto

45 Introducción (IV) Una clase es un patrón o modelo, no crea un objeto. Se crea un objeto con new Cada objeto tiene sus atributos o variables miembro (hay una excepción a esta regla: los atributos static). En el siguiente ejemplo, el primer círculo tiene un atributo radio que es diferente al mismo atributo del segundo círculo. Es más, ocupan posiciones de memoría diferentes public static void main(String[] args) { Circulo a = new Circulo(); Circulo b = new Circulo(); a.radio = 23; b.radio = 35.6; }

46 El primer método Vamos a introducir un método en nuestra clase “Circulo”, que simplemente muestra el área: Una llamada al método implica un SALTO: el ordenador pasa a ejecutar el código del método y una vez que este termina se devuelve el control a main Las flechas muestran los saltos que da el control de ejecución del programa El método muestra los atributos de SU OBJETO public class Inicio { public static void main(String[] args) { Circulo a = new Circulo(); Circulo b = new Circulo(); a.radio = 23; b.radio = 35.6; a.mostrarArea(); b.mostrarArea(); } public class Circulo { public double radio; public double PI = ; public void mostrarArea() { System.out.println( radio*radio*PI ); }

47 Formato de los métodos El formato de los métodos es:
Tipo_acceso tipo_devuelto Nombre_método( parámetros ) { Cuerpo del método } El tipo de acceso puede ser: Para clases que están en el mismo paquete (por defecto: public): public: se puede llamar al método desde fuera de la clase protected: se puede llamar al método desde fuera de la clase private: no se accede desde fuera de la clase Para clases que están en diferentes paquetes (por defecto: protected): protected: no se accede desde fuera de la clase El “tipo devuelto” es el tipo de dato que devuelve el método

48 Devolviendo valores En nuestro ejemplo calculamos el área en println, pero esto no es muy inteligente. Ya que si necesitamos de nuevo el área, tenemos que volver a calcularla. Lo lógico es realizar el cálculo EN UN ÚNICO MÉTODO y que este método devuelva el resultado. En el siguiente ejemplo vamos a crear un método público que devuelve el área: public class Circulo { public double radio; public double PI = ; public void mostrarArea() { System.out.println( getArea() ); } public double getArea() { return radio*radio*PI; La flecha muestra como se transfiere el control de ejecución. La sentencia return es una orden de salto. Error de principiante: no hay coherencia entre el tipo que declaramos que vamos a devolver y el tipo efectivamente devuelto. En nuestro ejemplo hay coherencia: Declaramos que vamos a devolver double al escribir “public double obtener_area() ...” Efectivamente devolvemos double, el resultado de multiplicar variables de tipo double como radio y PI

49 Introducción a los parámetros
Veamos el siguiente ejemplo de función que calcula y devuelve el cuadrado de un número: double cuadrado() { return 5*5; } Esto es evidentemente un absurdo, sólo nos sirve si el número es 5. Resulta más lógico que el método calcule con independencia de cual es el número base. Para ello, el método debe tener parámetros: public class Param { public static void main(String[] args) { double h = cuadrado(3); // Argumentos System.out.println( h ); /*** Devuelve el cuadrado ***/ public static double cuadrado( double base ) { // Parámetros return ( base * base ); El parámetro “base” recibe el argumento 3

50 Parámetros: los nombres son lo de menos
El principiante poco informado puede pensar que los nombres de los parámetros dependen de los nombres de los argumentos. Puede creer que si el argumento se llama “X”, el parámetro debe llamarse “X”: public static void main(String[] args) { double largo = 3, ancho = 2; double h = getArea( largo, ancho); System.out.println( h ); } public static double getArea(double largo, double ancho) { return (largo * ancho); Este personaje desconoce que los nombres son indiferentes, lo que importa es que el parámetro, se llame como se llame, recibe el contenido del argumento (más adelante distinguiremos llamadas por valor de llamadas por referencia). La aprueba es que el método anterior actúa igual si se escribiese así: public static double getArea(double PinPanPun, double segundo) { return (PinPanPun * segundo);

51 Una pequeña excepción a la regla anterior
Hemos visto que los nombres son lo de menos en el ejemplo de las variables “ancho” y “largo” (no hay conflicto porque tienen ámbitos de vida independientes) Bien, pero la excepción es: “salvo cuando hay conflicto de nombres con un atributo de la clase”, aquí hay conflicto con los ámbitos de vida. Supongamos que usamos de parámetros para almacenar los valores en atributos de un objeto: public class Camino { private double largo; public void setLargo( double largo ) { largo = largo; } } Esto es un error absurdo: almacenamos el valor de la variable parámetro “largo” en ella misma (no en el atributo). Con el agravante de que ese valor se pierde al terminar el método. Lo que queremos es almacenar el valor en el atributo, para lo cual usaremos la palabra reservada “this”: public void setLargo( double largo ) { this.largo = largo; } “this” es una forma de hacer referencia al objeto, es la forma que tiene el propio objeto de decir “yo”. Este nombre se usa para hacer referencia a atributos o métodos del objeto. Resumiendo, en nuestro ejemplo: this.largo: variable atributo de la clase largo: variable parámetro Volveremos más adelante sobre “this” y veremos por qué es incompatible con su uso dentro de métodos static

52 Parámetros: encapsulando
En nuestro ejemplo del círculo podemos acceder a los atributos de “Circulo” directamente desde fuera de la clase: Circulo a = new Circulo(); a.radio = 3; Cambiemos de forma de trabajar. Vamos a hacer que sólo se pueda acceder a los datos por medio de los métodos. Esto implica que debemos poner métodos que devuelvan valores (usan return, get) y otros que asignen valores (usan parámetros, set): public class Circulo { private double radio; private double PI = ; public double getArea() { return radio * radio * PI; } public void setRadio(double nuevoRadio) { radio = nuevoRadio; public double getRadio() { return radio; Reglas importantes: Encapsular: desde fuera de la clase sólo se accede a los métodos públicos. No se accede directamente a los datos Modularizar: separar procesamiento de datos de su presentación. Un ejemplo es que los cálculos se hacen en métodos diferentes a la presentación de datos (incluso, lo que es aún mejor, en clases diferentes). También es una forma de hacer software cohesivo

53 Los métodos públicos de la clase son el interfaz de la clase
Encapsular En la ingeniería del software se especifican reglas que deben seguirse para ayudarnos a realizar software robusto (no proclive a fallos), fácilmente entendible y de fácil mantenimiento (modificaciones poco costosas) El principio de “Encapsulamiento” (ocultamiento de información) nos indica (entre otras cosas) que debemos hacer que los detalles de la clase estén ocultos para el exterior (también se denomina implementación encapsulada). Una aplicación de este principio implica que los atributos serán privados y sólo se puede acceder a ellos desde los métodos de la clase Ventaja: desde el código de la clase controlamos el acceso a los atributos. En caso de fallo o modificación del código, el programador comprueba los métodos de la clase y no tiene que revisar todo el código de los otros archivos Los métodos públicos son el intermediario entre los datos y los otros objetos Método 1 Método 2 Datos Objeto Llamada Los métodos públicos de la clase son el interfaz de la clase

54 Un ejemplo de encapsulamiento
Supongamos que tenemos una clase que representa los productos de un comercio, en el que hay un precio normal y un precio rebajado: public class Producto { private float precio; private float precioRebajado; public void setPrecioRebajado( float porcentajeRebaja ) { precioRebajado = precio * (1-porcentajeRebaja); } ¿Por qué decimos que es una implementación encapsulada? Por dos razones ligadas: Encapsular datos: sólo se accede al atributo privado “precioRebajado” por medio de un método público de la clase Encapsulamos el cálculo: la forma de calcular el dato queda oculta al exterior de la clase. Supongamos que debemos cambiar la forma de calcular el precio rebajado (bien por corregir un error de programación o bien por cambiar la política de rebajas), entonces sólo tendremos que cambiar el método “setPrecioRebajado()”.

55 Un ejemplo de NO encapsulamiento
Tomemos el ejemplo anterior y supongamos que la clase es así: public class Producto { public float precio; public float precioRebajado; Estoy permitiendo el acceso externo a los datos del producto. Por tanto en una clase externa se podría escribir algo como esto: static public void main(…) { Producto a = new Producto(); a.precio = 25.5; a.precioRebajado = a.precio *0.80; Producto b = new Producto(); b.precio = 19; b.precioRebajado = b.precio *0.80; La irracionalidad suele ser costosa. Si tenemos que cambiar nuestra política de rebajas tendremos que cambiar todas las líneas de código donde calculamos el precio rebajado para cada producto, en una implementación encapsulada sólo tenemos que cambiar el método setPrecioRebajado() de la clase Producto En una implementación encapsulada tendríamos que modificar un bloque de código, no N bloques de código.

56 Modularizar Un diseño modular se basa en la conocida estrategia de “divide y vencerás”. Descomponer de forma lógica la aplicación Para conseguir la modularidad debemos hacer que nuestros componentes de software sean especialistas En un ejemplo básico y típico separaremos: Inicio de aplicación: paquete y clase donde está main() Clases del dominio de problema: por ejemplo, paquete figuras.dominio con las clases Circulo, Rectangulo, etc Clases de presentación: paquete para el interfaz de la aplicación (menú de opciones, presentación de clases de dominio, etc.) Clases para persistencia o almacenamiento en base de datos, archivos, etc.

57 Un ejemplo de modularización
En el siguiente ejemplo separamos las clases del dominio (en este caso Circulo.java) de la clase responsable de la presentación: package figuras.dominio; public class Circulo { private double radio; private double PI = ; public Circulo() { } public Circulo( double nuevoRadio ) { setRadio( nuevoRadio ); } public double getArea() { return radio * radio * PI; public void setRadio( double radio ) { this.radio = radio; public double getRadio() { return radio; public String toString() { return "Radio: " + radio + " Area: " + getArea(); package figuras.presentacion; import figuras.dominio.*; public class VistaFiguras { public static void mostrar( Circulo cir ) { System.out.println( cir.toString() ); } public static void mostrar( Rectangulo rec ) { System.out.println( rec.toString() ); ¿Cómo se haría un main() que use estas clases?

58 Constructores Un constructor es un método al que se llama cuando se crea un objeto con new: Sólo son llamados inmediatamente después de la creación del objeto Tienen el mismo nombre que la clase y no devuelven valores Son públicos En nuestro ejemplo vamos a crear un constructor que inicia el radio con 1: Circulo() { radio = 1; } Pero en muchas ocasiones al crear un objeto nos interesa inicializar atributos (en nuestro caso el radio). Para ello, los constructores admiten parámetros: class Circulo { private double radio; private double PI = ; public Circulo( double nuevoRadio ) { setRadio( nuevoRadio ); public void setRadio( double radio ) { this.radio = radio; Utilizamos el nombre de “constructores” por ser el más extendido, pero no confundirse: el constructor no construye el objeto; sino que es invocado inmediatamente después de la construcción Si no implementamos un constructor, Java pone uno por defecto (constructor vacío) Circulo a = new Circulo(); ... Circulo a = new Circulo(21); ...

59 finalize() En lenguajes como C++ la memoria ocupada por los objetos creados por new es liberada manualmente, mediante el operador delete . En Java la orientación es diferente: tiene un procedimiento automático de “recogida de basura”. Este procedimiento examina las referencias y el ámbito, cuando considera que un objeto no va a ser utilizado lo elimina, es decir, libera la memoria que ocupa Inmediatamente antes de que se libere la memoria se invoca automáticamente al método finalize(). El programador puede implementarlo cuando desee realizar una acción antes de la eliminación del objeto: protected void finalize() { System.out.println( “Adios” ); } Téngase en cuenta que no se puede garantizar el momento exacto en el que el programa invocará al método: El procedimiento de recogida de basura no se ejecuta siempre que se deja de utilizar un objeto, sino que se ejecuta de manera esporádica Además cada interprete de Java tiene su procedimiento de recogida de basura Por tanto, no se puede confundir con los destructores de C++. Java no tiene el concepto de destructor

60 Sobrecarga de métodos Java nos permite tener métodos con el mismo nombre y que se diferencian por sus argumentos: package figuras.presentacion; import figuras.dominio.*; public class VistaFiguras { public static void mostrar( Circulo cir ) { System.out.println( cir.toString() ); } public static void mostrar( Rectangulo rec ) { System.out.println( rec.toString() ); ¿Por qué hace falta hacer import de las clases del paquete “figuras.domino”? Porque están en un paquete diferente que “VistaFiguras” Al llamar a un método, Java busca la versión del método que coincide con los argumentos de la llamada

61 Sobrecarga de constructores
Los constructores, como cualquier otro método, pueden ser sobrecargados: class Circulo { private double radio; private double PI = ; /****** Constructores sobrecargados ***/ public Circulo() { } public Circulo( double nuevoRadio ) { setRadio( nuevoRadio ); } public Circulo( Circulo circulo ) { setRadio( circulo.getRadio() ); ... Observe que el último constructor define el radio a partir del radio de otro círculo, que se ha pasado como argumento ¿ Cómo sería la llamada que ejecutase dicho constructor?

62 El proyecto de las figuras. Los puntos
package figuras.dominio; public class Punto { private int x; private int y; public Punto(int x, int y) { setPunto(x, y); } public Punto(Punto p) { setPunto(p ); public void setPunto(int x, int y) { this.x = x; this.y = y; public void setPunto(Punto p) { x = p.getX(); y = p.getY(); public int getX() { return x; } public int getY() { return y; } public String toString() { return "(" + x + "," + y + ")"; Aspectos a resaltar: Encapsulamiento Sobrecarga de constructores Constructor “de copia”: Punto(Punto p). Con este constructor se hace un punto que es una copia (tiene la misma posición) que el objeto que se pasa como argumento (p)

63 El proyecto de las figuras. Los círculos (I)
Aspectos a resaltar: Encapsulamiento Un atributo (posicion) es un objeto de otra clase (Punto) PI es static (lo comentaremos más adelante) PI es final: es una constante, no puede cambiarse. Esto evita modificaciones accidentales por parte del programador Sobrecarga de constructores Constructor “de copia”: Circulo(Circulo circulo). Con este constructor se hace un círculo que es una copia del objeto que se pasa como argumento (circulo) ¿Por qué no hace falta import de la clase “Punto”? Porque está en el mismo paquete package figuras.dominio; public class Circulo { private Punto posicion; private double radio; static final public double PI = ; public Circulo() { } public Circulo( double nuevoRadio, Punto nuevaPosicion ) { setRadio( nuevoRadio ); setPosicion( nuevaPosicion ); } public Circulo( double nuevoRadio, int posicionX, int posicionY ) { posicion = new Punto( posicionX, posicionY ); public Circulo( Circulo circulo ) { setRadio( circulo.getRadio() ); setPosicion( circulo.getPosicion()); public void setRadio( double radio ) { this.radio = radio; } public void setPosicion( Punto posicion ) { this.posicion = posicion; } public Punto getPosicion() { return posicion; } public double getRadio() { return radio; } public double getArea() { return radio * radio * PI; } public String toString() { return "Radio: " + radio + " Posicion: " + posicion.toString() + " Area: " + getArea();

64 El proyecto de las figuras. Los círculos (II)
Interesa distinguir dos constructores: public Circulo( double nuevoRadio, Punto nuevaPosicion ) { setRadio( nuevoRadio ); setPosicion( nuevaPosicion ); } public Circulo( double nuevoRadio, int posicionX, int posicionY ) { posicion = new Punto( posicionX, posicionY ); En el primer caso recibimos un objeto (nuevaPosicion), que “almacenamos” en el atributo “posicion”. No tiene nada de extraño En el segundo caso no se recibe un objeto, sino que recibimos dos variables (“posicionX” y “posicionY”), sin embargo la clase de los círculos requiere tener un objeto para el atributo “posicion”. Por ello, se tiene que crear (new) el objeto de la clase Punto.

65 El proyecto de las figuras. La visualización
package figuras.presentacion; import figuras.dominio.*; public class VistaFiguras { public static void mostrar( Circulo cir ) { System.out.println( cir.toString() ); } public static void mostrar( Rectangulo rec ) { System.out.println( rec.toString() ); Aspectos a resaltar: Modularidad: separamos la presentación (“VistaFiguras”) de las clases de dominio de problema (puntos, círculos, etc.) Sobrecarga de constructores ¿Por qué hace falta import de las clases del paquete “figuras.dominio”? Porque dichas clases están en un paquete diferente al de “VistaFiguras”

66 El proyecto de las figuras. El inicio
package figuras.inicio; import figuras.dominio.*; import figuras.presentacion.*; class Inicio { public static void main(String[] args) { Circulo primero = new Circulo( 23, 2, 3 ); Circulo copia = new Circulo( primero ); Circulo tercero = new Circulo( 17, new Punto(8,9) ); VistaFiguras vista = new VistaFiguras(); vista.mostrar( primero ); vista.mostrar( copia ); vista.mostrar( tercero ); } Aspectos a resaltar: Sobrecarga de constructores Usamos constructor de copia ¿Por qué hacen falta imports? Si hubiera que hacer la clase Rectangulo, ¿cómo sería?

67 Llamadas por valor Cuando hacemos una llamada a un método, que tiene argumentos que son tipos simples, se hace una copia del valor y se traslada al parámetro del método. Para que se entienda: public static void main(String[] args) { /******** Llamada por valor (copia del valor) *****/ double d = 11.5; cuadrado( d ); System.out.println( d ); } public static void cuadrado( double num ) { num = num * num; El programa muestra el número 11.5, es decir, la función no ha modificado la variable argumento (d). Esto significa que la función “cuadrado()” no modifica el valor de la variable “d”. Modifica una copia de “d”. Copia del valor: 11.5

68 Llamadas por referencia
Cuando los argumentos son objetos (no usamos tipos simples) no se pasa una copia del objeto, sino que se pasa el propio objeto. Los parámetros del método reciben el objeto (llamada por referencia): public static void main(String[] args) { Circulo primero = new Circulo( 23, 2, 3 ); trasladar( primero, new Punto(111,111) ); // Llamada por referencia vista.mostrar( primero ); } public static void trasladar( Circulo c, Punto nuevaPosicion ) { c.setPosicion( nuevaPosicion ); Pasamos a la función trasladar() el circulo “primero” con su nueva posición La función modifica el argumento (“primero”)

69 String es una excepción
Hemos dicho que todas las clases (no los tipos simples) son pasadas en llamadas por referencia. String es una excepción: las llamadas son por copia. En el siguiente ejemplo el método no cambia el argumento, sigue teniendo el valor “Adios”: public static void main(String[] args) { String despedida = "Adios"; cambiarDespedida( despedida ); // String es una excepción: llamada por valor System.out.println( despedida ); } public static void cambiarDespedida( String mensaje ) { mensaje = "Hasta luego";

70 Devolución de objetos Hemos visto que return puede servir para devolver el valor de una variable de tipo simple. También puede servir para devolver un objeto (no una copia del objeto, sino un objeto). En el siguiente ejemplo los objetos de la clase “Persona” son capaces de clonarse a si mismos. public class Persona { private String nombre; private int edad; public Persona( String nuevoNombre, int nuevaEdad ) { setPersona( nuevoNombre, nuevaEdad ); mostrarSaludo(); } public void setPersona( String nuevoNombre, int nuevaEdad ) { nombre = nuevoNombre; edad = nuevaEdad; public persona clonar( ) { Persona p = new Persona( nombre, edad ); System.out.println( nombre + " se ha clonado a si misma/o"); return p; public void mostrarSaludo() { System.out.println( "Hola, acaba de crear una nueva persona: " + nombre); public static void main(String[] args) { Persona ana = new Persona( "Ana", 18 ); Persona clon_de_ana = ana.clonar(); // Error, no existe el constructor: // Persona juan = new Persona(); } Hola, acaba de crear una nueva persona: Ana Ana se ha clonado a si misma/o

71 Tipos de ámbito Ya vimos que el ámbito de una variable u objeto es el espacio del programa en el que esa variable existe. Por ello, se habla de “ámbito de vida” Los principales tipos de ámbitos son: Ámbito de objeto. Los atributos de un objeto (que no son static) viven en el espacio de vida del objeto y son accesibles por cualquier método del objeto (siempre que el método no sea static). Por ello, a veces se llaman variables de objeto o variables de instancia Ámbito de método. Variables y objetos declarados en un método. Su ámbito de vida se ciñe al método en el que fueron declaradas, por ello a veces se llaman variables de método o función Ámbito de clase. Las variables static viven con independencia de que hayamos hecho instancias de la clase. Podemos acceder a ellas (si son públicas) usando el nombre de la clase y viven desde que se declara la clase, por ello se llaman variables de clase

72 Ambitos de objeto y de método
package figuras.dominio; public class Circulo { private Punto posicion; private double radio; static final public double PI = ; public Circulo() { } public Circulo( double nuevoRadio, Punto nuevaPosicion ) { setRadio( nuevoRadio ); setPosicion( nuevaPosicion ); } public Circulo( double nuevoRadio, int posicionX, int posicionY ) { posicion = new Punto( posicionX, posicionY ); public Circulo( Circulo circulo ) { setRadio( circulo.getRadio() ); setPosicion( circulo.getPosicion()); public void setRadio( double radio ) { this.radio = radio; } public void setPosicion( Punto posicion ) { this.posicion = posicion; } public Punto getPosicion() { return posicion; } public double getRadio() { return radio; } public double getArea() { return radio * radio * PI; } public String toString() { return "Radio: " + radio + " Posicion: " + posicion.toString() + " Area: " + getArea(); En el ejemplo de los círculos, hay variables de objeto como: posicion radio Y variables de clase (PI). También hay variables de método (locales a la función):

73 Ámbito de clase. static Las variables static viven con independencia de que hayamos hecho instancias de la clase Podemos acceder a ellas (si son públicas) usando el nombre de la clase (no hay que hacer instancias) y viven desde que se declara la clase, por ello se llaman variables de clase. Ejemplo: Todas las instancias de la clase comparten la misma variable static. Cosa que no ocurre con las variables no static, en estas cada objeto tiene su variable En el ejemplo es lógico que el atributo “PI” sea static: el número PI es único y el mismo sea cual sea el círculo Con los métodos static ocurre algo semejante. Son accesibles desde la clase, sin necesidad de hacer instancias. Ejemplo que convierte una cadena en un double: String c = new String( “123.72” ); double r; r = Double.parseDouble( c ); // Double es una clase, no un objeto Ahora podemos explicarnos por qué main debe ser static: debe ser accesible por el interprete Java antes de crear ningún objeto Tienen restricciones: no pueden utilizar atributos de objeto (variables no static) ni pueden llamar a métodos de objeto (métodos no static) Por ello un método static no puede usar la expresión “this”, ya que un método static tiene ámbito de clase y this por definición tiene ámbito de objeto class Circulo { private punto posicion; private double radio; static public double PI = ; ... public static void main(String[] args) { System.out.println( circulo.PI); }

74 final Cuando se declara una variable como final estamos dando la orden de que no se modifique. Es como definir una constante Debe ser inicializada en la declaración, ya que cualquier intento de modificarla provoca un error de compilación Utilidad: no permitir que un error de programación altere el valor de una constante. Ejemplo: class circulo { private punto posicion; private double radio; static final public double PI = ; El uso de final en métodos tiene otro sentido: no permitir que una clase hija sobreescriba un método de la clase padre


Descargar ppt "Introducción a Java (I)"

Presentaciones similares


Anuncios Google