Your SlideShare is downloading. ×
  • Like
Presentacion 4
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Presentacion 4

  • 1,069 views
Published

 

Published in Art & Photos
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
1,069
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
28
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Introducción a Java (I)Indice
  • 2. Índice • Tipos de datos y operadores • Entradas y Salidas básicas • Sentencias de control • ClasesIndice 2
  • 3. Tipos de datos y operadoresIndice
  • 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 }Indice 4
  • 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)Indice 5
  • 6. Los tipos de datos: enteros y coma flotantetipos de vehículos existen • Del mismo modo que existen diferentes 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 (-32.768 a 32.767) – int: 32 bits (-2.147.483.648 a 2.147.483.647) – 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)Indice 6
  • 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áximoIndice 7
  • 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 = 3.1416; 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).Indice 8
  • 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: int edad = 0; boolean mayor_de_edad = false; 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 ... System.out.println( “Puede obtener el carnet B1” );Indice 9
  • 10. • Caracteres (char)16 bits. Se utiliza un En Java los caracteres se almacenan en variables de formato estándar e internacional denominado Unicode que admite 65.537 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’; System.out.println( “La cuadrícula del mapa es ” + cuadricula ); • 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 65.536, entonces podemos representar 65.537 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.Indice 10
  • 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);Indice 11
  • 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 = 3.1416; double radio = 3; System.out.println( “El área es” + (PI*radio*radio) ); } • Más adelante profundizaremos en los diferentes tipos de ámbitoIndice 12
  • 13. • Conversión deen ocasiones nos conviene Hemos visto que los datos tienen un tipo. Pero tipos 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 );Indice 13
  • 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 correctoIndice 14
  • 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 2Indice Posición: 0 1 2 15
  • 16. Matrices (II) • 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?Indice 16
  • 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]; Vehiculo.java: mios[0] = new vehiculo(); package xxx; mios[1] = new vehiculo(); public class Vehiculo { mios[0].definir_precio_bajo(); private int precio; mios[1].definir_precio_bajo(); mios[1].mostrar(); void definir_precio_bajo() { precio = 12000; } } void mostrar() { System.out.println( " Precio:" + precio); } }Indice 17
  • 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 200 matrices completas resulta muy sencilla: 400 int Origen[] = { 200, 400, 600 }; int Destino[] = { 10, 20, 30 }; Destino = Origen; System.out.println( Destino[0] ); System.out.println( Destino[1] );Indice 18 • Al intentar acceder a un elemento que está fuera del rango de la matriz se
  • 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)Indice difieran. El siguiente ejemplo crea una matriz 19
  • 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)Indice 20
  • 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:Indice 21
  • 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); Belén es igual a Belén if (j.compareTo(k) < 0) Belén es menor que Susana System.out.println( j + " es menor que " + k); if (j.compareTo(n) > 0) Belén es mayor que Antonio 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)Indice 22
  • 23. Operadores lógicos • Operan solamente con valores booleanos: – 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)Indice System.out.println( "aprobado" ); 23 if (!mayoria_edad)
  • 24. Entradas y Salidas básicasIndice
  • 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.Indice 25
  • 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.inIndice 26
  • 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.Indice 27
  • 28. Un ejemplo entrada por teclado y conversión public static void main(String[] args) throws IOException { double PI = 3.1416, 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.Indice 28
  • 29. Sentencias de controlIndice
  • 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 – Si no: » Siga todo recto • Vamos a ver los siguientes tipos de sentencias de control: – Selección – IteraciónIndice – Salto 30
  • 31. 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) Precaución: La tabulación es • Ejemplo: fundamental para realizar código legible int a = 3, b = 9, c;Indice if (a < b && a != 0) 31
  • 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 (puntos > 1000) { tipo_cliente = "VIP"; descuento = 0.05f; if (antiguedad > 1825) descuento = 0.06f;Indice 32 }
  • 33. switch • Formato: switch ( expresión ) { // expresión: no tiene que ser booleano case constante1: secuencia de sentencias break; case constante2: secuencia de sentencias break; ... default: secuencia de sentencias } • No olvidar ‘break’. Pero a veces es adecuado omitirlo: switch ( categoria ) { case 1: case 2: porcen = 0.2; // Tanto para 1 como para 2 break; case 3: porcen = 0.15; break; default:Indice 33 porcen = 0.1; }
  • 34. • Formato: while 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]; Bucle System.out.println( "t Cuadrado: " + serie[i] ); i++; } Posición: 0 Anterior: 23.0 Cuadrado: 529.0 Posición: 1 Anterior: 4.0 Cuadrado: 16.0 Posición: 2 Anterior: 36.0 Cuadrado: 1296.0 Posición: 3 Anterior: 9.0 Cuadrado: 81.0Indice 34
  • 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++)Indice System.out.println( i ); 35
  • 36. for (II) • Vamos a ver paso a paso como actua 1. INICIO: la variable i se inicia a 1 la iteración 2. CONDICIÓN: se comprueba la condición: ¿ i<3 ? SI • Ejemplo: 3. SENTENCIA: se ejecuta la sentencia int i; println for ( i = 1; i < 3; i++) System.out.println( i ); 4. VARIACIÓN: al terminar el bucle, se incrementa i. Ahora vale 2 5. CONDICIÓN: se comprueba la • Al observar la ejecución paso a paso es condición: ¿ i<3 ? SI importante recordar: 6. SENTENCIA: se ejecuta la sentencia – Siempre se evalúa la condición ANTES println de ejecutar la sentencia 7. VARIACIÓN: al terminar el bucle, se – DESPUÉS de la sentencia siempre se incrementa i. Ahora vale 3 realiza la variación 8. CONDICIÓN: se comprueba la condición: ¿ i<3 ? NO, fin del • bucle Se pueden iterar varias variables, para lo cual necesitamos comas: for(i=0, k=5; i < 5; 9. IMPORTANTE: al salir del bucle el i++, k=k+5) valor de i es 3. ¿Cuál sería su valor siIndice la condición fuese i<=3? 36
  • 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 sumatorioIndice 37
  • 38. • Formato: do-while 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; do { 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: do { 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 calculadoraIndice 38
  • 39. Calculadora public static void main(String[] args) throws IOException { /**** En función de la opción: opero o salgo ***/ char opcion; switch (opcion) { String cadenaTeclado; case s: double operando1 = 0, operando2 = 0; case S: System.out.print( operando1 + operando2 ); /* Creo el obj. entrada, es un lector de entradas por teclado */ break; BufferedReader entrada = new BufferedReader( new case r: InputStreamReader(System.in)); case R: System.out.print( operando1 - operando2 ); do { break; /********* Mostrar menu y pedir opcion por teclado ****/ case p: System.out.print("rn S - Sumarn R - Restarn P - Producto" + "rn case P: D - Divisiónrn Q - Salirrn Su opción:"); System.out.print( operando1 * operando2 ); cadenaTeclado = entrada.readLine(); // Teclado break; opcion = cadenaTeclado.charAt( 0 ); // Conv a char case d: case D: /********* Si la opción no es salir, solicito operandos ***/ System.out.print( operando1 / operando2 ); if ( opcion != Q && opcion != q) { break; System.out.print( "Número 1: " ); case q: cadenaTeclado = entrada.readLine(); // Teclado case Q: System.out.print( "Adios" ); operando1 = Double.parseDouble( cadenaTeclado ); // Conv break; System.out.print( "Número 2: " ); default: cadenaTeclado = entrada.readLine(); // Teclado System.out.print( "Opción no disponible" ); operando2 = Double.parseDouble( cadenaTeclado ); // Conv } } /////////////////////////////// Fin de switch } while (opcion != Q && opcion != q);Indice 39 } //////////////////////////////// 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");Indice } 40
  • 41. ClasesIndice
  • 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 claseIndice 42
  • 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: /******** Circulo.java ********/ /********* Inicio.java *****/ package figuras.dominio; package figuras.inicio; import figuras.dominio.Circulo; public class Circulo { public double radio; public class Inicio { public double PI = 3.1416; public static void main(String[] args) { } Circulo a; // ERROR a.radio = 23; } } • 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();Indice a.radio = 23; 43
  • 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 objetoIndice 44
  • 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) {Indice 45 Circulo a = new Circulo();
  • 46. El primer método • Vamos a introducir un método en nuestra clase “Circulo”, que simplemente muestra el área: public class Inicio { public class Circulo { public static void main(String[] args) { public double radio; Circulo a = new Circulo(); public double PI = 3.1416; Circulo b = new Circulo(); public void mostrarArea() { a.radio = 23; System.out.println( radio*radio*PI ); b.radio = 35.6; } a.mostrarArea(); } b.mostrarArea(); } } • 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 programaIndice 46 • El método muestra los atributos de SU OBJETO
  • 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): • public: se puede llamar al método desde fuera de la clase • protected: no se accede desde fuera de la clase • private: no se accede desde fuera de la clase • El “tipo devuelto” es el tipo de dato que devuelve el métodoIndice 47
  • 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 = 3.1416; 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 PIIndice 48
  • 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 }Indice 49
  • 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); }Indice 50
  • 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 staticIndice 51
  • 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 = 3.1416; Reglas importantes: public double getArea() { return radio * radio * PI; • Encapsular: desde fuera de la clase sólo } se accede a los métodos públicos . No se public void setRadio(double nuevoRadio) { accede directamente a los datos radio = nuevoRadio; • Modularizar: separar procesamiento de } datos de su presentación . Un ejemplo es que public double getRadio() { los cálculos se hacen en métodos diferentes a la return radio; presentación de datos (incluso, lo que es aún } mejor, en clases diferentes). También es una forma } de hacer software cohesivoIndice 52
  • 53. • Encapsular que deben seguirse En la ingeniería del software se especifican reglas 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 Objeto Los métodos Método 1 públicos de la Llamada Datos clase son el Método 2 interfaz de la claseIndice 53
  • 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()”.Indice 54
  • 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.Indice 55
  • 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,Indice paquete figuras.dominio con las clases Circulo, 56
  • 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; package figuras.presentacion; public class Circulo { import figuras.dominio.*; private double radio; private double PI = 3.1416; public class VistaFiguras { public Circulo() { } public static void mostrar( Circulo cir ) { public Circulo( double nuevoRadio ) { System.out.println( cir.toString() ); setRadio( nuevoRadio ); } } public double getArea() { public static void mostrar( Rectangulo rec ) { return radio * radio * PI; System.out.println( rec.toString() ); } } public void setRadio( double radio ) { } this.radio = radio; } public double getRadio() { ¿Cómo se haría un main() que use estas return radio; clases? } public String toString() { return "Radio: " + radio + " Area: " + getArea(); Indice } 57 }
  • 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() { Circulo a = new 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 = 3.1416; public Circulo( double nuevoRadio ) { Circulo a = new Circulo(21); 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)Indice 58
  • 59. • finalize() los objetos creados por new es En lenguajes como C++ la memoria ocupada por 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 destructorIndice 59
  • 60. Sobrecarga de métodos • Java nos permite tener métodos con el mismo nombre y que se diferencian por sus package figuras.presentacion; argumentos: ¿Por qué hace falta hacer import de las clases del paquete “figuras.domino”? Porque import figuras.dominio.*; están en un paquete diferente que “VistaFiguras” 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() ); } } Al llamar a un método, Java busca la versión del método que coincide con los argumentos de la llamadaIndice 60
  • 61. Sobrecarga de constructores • Los constructores, como cualquier otro método, pueden ser sobrecargados: class Circulo { private double radio; private double PI = 3.1416; /****** 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?Indice 61
  • 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) { Aspectos a resaltar: setPunto(p ); } • Encapsulamiento public void setPunto(int x, int y) { • Sobrecarga de constructores this.x = x; this.y = y; • 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 public void setPunto(Punto p) { argumento (p) x = p.getX(); y = p.getY(); } public int getX() { return x; } public int getY() { return y; } public String toString() { return "(" + x + "," + y + ")"; } }Indice 62
  • 63. El proyecto de las figuras. Lospackage figuras.dominio; círculos (I) Aspectos a resaltar: • Encapsulamientopublic class Circulo { • Un atributo (posicion) es un objeto de otra private Punto posicion; clase (Punto) private double radio; static final public double PI = 3.1416; • PI es static (lo comentaremos más adelante) public Circulo() { } • PI es final: es una constante, no puede public Circulo( double nuevoRadio, Punto nuevaPosicion ) { cambiarse. Esto evita modificaciones setRadio( nuevoRadio ); accidentales por parte del programador setPosicion( nuevaPosicion ); } • Sobrecarga de constructores public Circulo( double nuevoRadio, int posicionX, int posicionY ) { • Constructor “de copia”: Circulo(Circulo setRadio( nuevoRadio ); circulo). Con este constructor se hace un posicion = new Punto( posicionX, posicionY ); círculo que es una copia del objeto que se } pasa como argumento (circulo) public Circulo( Circulo circulo ) { • ¿Por qué no hace falta import de la clase setRadio( circulo.getRadio() ); “Punto”? Porque está en el mismo paquete 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(); } Indice 63}
  • 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 ) { setRadio( nuevoRadio ); 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.Indice 64
  • 65. El proyecto de las figuras. La visualización package figuras.presentacion; Aspectos a resaltar: import figuras.dominio.*; • Modularidad: separamos la presentación (“VistaFiguras”) de las clases de dominio public class VistaFiguras { de problema (puntos, círculos, etc.) • Sobrecarga de constructores public static void mostrar( Circulo cir ) { • ¿Por qué hace falta import de las clases System.out.println( cir.toString() ); del paquete “figuras.dominio”? Porque } dichas clases están en un paquete diferente al de “VistaFiguras” public static void mostrar( Rectangulo rec ) { System.out.println( rec.toString() ); } }Indice 65
  • 66. El proyecto de las figuras. El inicio package figuras.inicio; Aspectos a resaltar: import figuras.dominio.*; • Sobrecarga de constructores import figuras.presentacion.*; • Usamos constructor de copia • ¿Por qué hacen falta imports? class Inicio { • Si hubiera que hacer la clase public static void main(String[] args) { Rectangulo, ¿cómo sería? 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 ); } }Indice 66
  • 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 ); Copia del valor: 11.5 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”.Indice 67
  • 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”)Indice 68
  • 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 ); }Indice public static void cambiarDespedida( String mensaje ) { 69 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 { public static void main(String[] args) { private String nombre; Persona ana = new Persona( "Ana", 18 ); private int edad; Persona clon_de_ana = ana.clonar(); public Persona( String nuevoNombre, int nuevaEdad ) { // Error, no existe el constructor: setPersona( nuevoNombre, nuevaEdad ); mostrarSaludo(); // Persona juan = new Persona(); } } public void setPersona( String nuevoNombre, int nuevaEdad ) { nombre = nuevoNombre; edad = nuevaEdad; Hola, acaba de crear una nueva persona: Ana } Hola, acaba de crear una nueva persona: Ana public persona clonar( ) { Ana se ha clonado a si misma/o 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); } }Indice 70
  • 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 claseIndice 71
  • 72. Ambitos de objeto y de método package figuras.dominio;En el ejemplo de los círculos, public class Circulo {hay variables de objeto como: private Punto posicion; private double radio; – posicion static final public double PI = 3.1416; – radio public Circulo() { }Y variables de clase (PI). public Circulo( double nuevoRadio, Punto nuevaPosicion ) { setRadio( nuevoRadio );También hay variables de setPosicion( nuevaPosicion );método (locales a la función): } public Circulo( double nuevoRadio, int posicionX, int posicionY ) { setRadio( nuevoRadio ); 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(); }Indice 72 }
  • 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: class Circulo { public static void main(String[] args) { private punto posicion; System.out.println( circulo.PI); private double radio; } static public double PI = 3.1416; ...• 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) •Indice 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 73
  • 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 {Indice private punto posicion; 74