Tutorial Java St

Tutorial Java Contents Lección: Lenguaje básico ......................................................................

Views 70 Downloads 0 File size 2MB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Tutorial Java

Contents Lección: Lenguaje básico .......................................................................................................... 8 Variables .................................................................................................................................. 8 Operadores.............................................................................................................................. 8 Expresiones, declaraciones y bloques ................................................................................ 8 Instrucciones de flujo de control........................................................................................... 8 Variables ...................................................................................................................................... 8 Nomenclatura ........................................................................................................................ 10 Tipos de datos primitivos......................................................................................................... 10 Valores por defecto .............................................................................................................. 12 Literales .............................................................................................................................. 13 Usando caracteres de subrayado en literales de valores numéricos........................... 15 Arreglos ...................................................................................................................................... 16 Declarar una Variable para hacer referencia a un Arreglo ............................................ 18 Crear, inicializar y acceder a una arreglo ......................................................................... 19 Copia de Arrays .................................................................................................................... 20 Manipulación de arreglos .................................................................................................... 21 Resumen de Variables ............................................................................................................ 22 Preguntas: Variables ................................................................................................................ 22 Operadores................................................................................................................................ 22 Asignación, aritmética y operadores unarios ....................................................................... 24 El operador de asignación Simple ..................................................................................... 24 Los operadores aritméticos................................................................................................. 24 Los operadores unarios ....................................................................................................... 25 Operadores de igualdad y relacionales ............................................................................ 27 Los operadores condicionales ............................................................................................ 28 El operador de comparación de tipo instanceof .............................................................. 29 Operadores Bitwise y Bit Shift ................................................................................................ 30 Resumen de operadores ......................................................................................................... 30 Operador de asignación simple.......................................................................................... 30 Operadores aritméticos ....................................................................................................... 30 Operadores unarios ............................................................................................................. 31 Igualdad y operadores relacionales ................................................................................... 31 Operadores condicionales .................................................................................................. 31 Operador de comparación de tipo ..................................................................................... 31 Operadores Bitwise bit a bit y Bit Shift (mover bits) ........................................................ 31

Preguntas y ejercicios: operadores ....................................................................................... 31 Preguntas............................................................................................................................... 31 Ejercicios................................................................................................................................ 32 Expresiones, instrucciones y bloques ................................................................................... 33 Expresiones ........................................................................................................................... 33 Instrucciones o sentencias .................................................................................................. 34 Bloques .................................................................................................................................. 34 Preguntas y ejercicios: expresiones, instrucciones y bloques .......................................... 35 Preguntas............................................................................................................................... 35 Ejercicios................................................................................................................................ 35 Instrucciones de control de flujo............................................................................................. 35 Las instrucciones if-then e if-then-else.................................................................................. 36 La instrucción if-then ...................................................................................................... 36 La instrucción if-then-else .......................................................................................... 37 La instrucción switch ............................................................................................................ 38 El uso de Strings en la instrucción switch ..................................................................... 41 Las instrucciones while y do-while ................................................................................. 43 La instrucción for .................................................................................................................... 44 Instrucciones de ramificación ................................................................................................. 46 La instrucción break ........................................................................................................... 46 La instrucción continue .................................................................................................... 48 La instrucción return......................................................................................................... 49 Resumen de las instrucciones de flujo de Control .............................................................. 50 Preguntas y ejercicios: Control de flujo ................................................................................. 50 Preguntas............................................................................................................................... 50 Ejercicios................................................................................................................................ 50 Lección: Clases y objetos ....................................................................................................... 52 Clases..................................................................................................................................... 52 Objetos ................................................................................................................................... 52 Más tipos ................................................................................................................................ 52 Clases anidadas ................................................................................................................... 52 Tipos de enumeración ......................................................................................................... 52 Clases......................................................................................................................................... 52 Declarar Clases ........................................................................................................................ 54 Declarar las Variables miembro ............................................................................................. 55 Modificadores de acceso..................................................................................................... 55

Tipos ....................................................................................................................................... 56 Nombres de variables .......................................................................................................... 56 Definir Métodos ......................................................................................................................... 57 Nombrando un método ........................................................................................................ 57 Sobrecarga de métodos ...................................................................................................... 58 Proporcionar constructores para tus clases ......................................................................... 58 Pasar información a un método o a un Constructor ........................................................... 59 Tipos de parámetros ............................................................................................................ 60 Número arbitrario de argumentos ...................................................................................... 60 Nombres de parámetros ...................................................................................................... 61 Pasando argumentos de tipo de datos primitivo ............................................................. 62 Pasando argumentos de tipo de datos de referencia ..................................................... 62 Objetos ....................................................................................................................................... 63 Creación de objetos ................................................................................................................. 64 Declarar una Variable para hacer referencia a un objeto .............................................. 64 Crear instancias de una clase ............................................................................................ 65 Inicializar un objeto............................................................................................................... 65 Uso de objetos .......................................................................................................................... 67 Referenciando a los campos de un objeto ....................................................................... 67 Llamar los métodos de un objeto ....................................................................................... 68 El recolector de basura ........................................................................................................ 69 Más sobre clases ...................................................................................................................... 70 Devuelve un valor desde un método ..................................................................................... 70 Devolviendo una clase o una interfaz ............................................................................... 71 Usando la palabra clave this................................................................................................... 72 Usando this con un campo .............................................................................................. 72 Usando this con un Constructor ..................................................................................... 72 Controlar el acceso a los miembros de una clase............................................................... 73 Entendiendo a los miembros de la clase .............................................................................. 74 Variables de clase ................................................................................................................ 75 Métodos de la clase ............................................................................................................. 76 Constantes............................................................................................................................. 76 La clase de Bicycle .......................................................................................................... 77 Inicializar campos ..................................................................................................................... 78 Bloques de inicialización estática ...................................................................................... 78 Inicializar miembros de instancia ....................................................................................... 79

Resumen de crear y utilizar clases y objetos ....................................................................... 79 Preguntas y ejercicios: clases ................................................................................................ 80 Preguntas............................................................................................................................... 80 Ejercicios................................................................................................................................ 81 Preguntas y ejercicios: objetos............................................................................................... 81 Preguntas............................................................................................................................... 81 Ejercicios................................................................................................................................ 82 Clases anidadas ....................................................................................................................... 82 ¿Por qué utilizar clases anidadas? .................................................................................... 82 Clases anidadas estáticas .................................................................................................. 83 Clases internas ..................................................................................................................... 83 Sombreado ............................................................................................................................ 84 Ejemplo de la clase interna ................................................................................................. 84 Clases locales y anónimas.................................................................................................. 86 Modificadores ........................................................................................................................ 86 Clases locales ........................................................................................................................... 86 Declarar clases locales ........................................................................................................ 86 Acceso a miembros de una clase envolvente.................................................................. 88 Clases de sombreado y locales ..................................................................................... 89 Las clases locales son similares a las clases internas ................................................... 89 Clases de anónimas................................................................................................................. 90 Declarar clases anónimas ................................................................................................... 90 Sintaxis de clases anónimas .............................................................................................. 91 Acceder a las Variables locales del ámbito envolvente y declarando y acceder a los miembros de la clase anónima........................................................................................... 91 Ejemplos de clases de anónimos ...................................................................................... 92 Cuándo utilizar clases anidadas, Local clases, clases de anónimas y expresiones Lambda ...................................................................................................................................... 94 Preguntas............................................................................................................................... 95 Ejercicios................................................................................................................................ 95 Las respuestas a las preguntas y ejercicios: clases anidadas .......................................... 96 Preguntas............................................................................................................................... 96 Ejercicio.................................................................................................................................. 97 Tipos enumerados .................................................................................................................... 97 Lección: anotaciones ............................................................................................................. 101 Conceptos básicos de anotaciones ................................................................................. 101

El formato de una anotación ......................................................................................... 101 Donde pueden ser utilizadas las anotaciones ........................................................... 102 Declarar un tipo de anotación ....................................................................................... 102 Tipos de anotación predefinidos ...................................................................................... 104 Tipos de anotación utilizados por el lenguaje Java................................................... 104 Anotaciones que se aplican a otras anotaciones ...................................................... 105 Preguntas y ejercicios: anotaciones ................................................................................ 106 Preguntas......................................................................................................................... 106 Lección: Interfaces y herencia .............................................................................................. 106 Interfaces ............................................................................................................................. 106 Herencia ............................................................................................................................... 106 Interfaces ................................................................................................................................. 107 Interfaces en Java .............................................................................................................. 107 Interfaces como APIs ......................................................................................................... 108 Definir una interfaz ............................................................................................................. 108 El cuerpo de la interfaz ...................................................................................................... 109 Implementar una interfaz....................................................................................................... 109 Una interfaz de muestra, Relatable ................................................................................. 109 Implementa la interfaz Relatable...................................................................................... 110 Usando una interfaz como un tipo ....................................................................................... 111 Evolución de las Interfaces ................................................................................................... 112 Métodos por defecto .............................................................................................................. 112 Extender Interfaces que contienen métodos por defecto............................................. 115 Métodos estáticos............................................................................................................... 116 Integración de métodos por defecto en bibliotecas existentes ................................... 117 Resumen de Interfaces ......................................................................................................... 121 Preguntas y ejercicios: Interfaces ........................................................................................ 121 Preguntas............................................................................................................................. 121 Ejercicios.............................................................................................................................. 121 Herencia ................................................................................................................................... 122 La jerarquía de clases de la plataforma Java ................................................................ 122 Un ejemplo de herencia..................................................................................................... 123 Lo que se puede hacer en una subclase ........................................................................ 124 Miembros privados en una superclase ........................................................................... 124 Casting de Objetos ............................................................................................................. 124 Herencia múltiple de estado, la implementación y el tipo ................................................ 125

Sobreescribir y ocultar métodos....................................................................................... 126 Métodos de instancia ..................................................................................................... 126 Métodos estáticos........................................................................................................... 126 Métodos de interfaz ........................................................................................................ 127 Modificadores .................................................................................................................. 129 Resumen .......................................................................................................................... 129 Polimorfismo............................................................................................................................ 130 Ocultar campos ....................................................................................................................... 132 Usando la palabra clave super ............................................................................................. 132 Acceso a miembros de la superclase.............................................................................. 132 Los constructores de la subclase ..................................................................................... 133 Objeto como una superclase ................................................................................................ 134 El método clone() ............................................................................................................... 134 El método equals() ............................................................................................................. 135 El método finalize()............................................................................................................. 136 El método getClass() ......................................................................................................... 136 El método hashCode() ....................................................................................................... 136 El método toString() ........................................................................................................... 136 Escribir clases y métodos finales ......................................................................................... 137 Clases y métodos abstractos................................................................................................ 137 Las clases abstractas en comparación con las Interfaces........................................... 138 Un ejemplo de clase abstracta ......................................................................................... 139 Cuando una clase abstracta implementa una interfaz ................................................. 140 Miembros de la clase ......................................................................................................... 140 Resumen de la herencia ....................................................................................................... 140 Preguntas y ejercicios: herencia .......................................................................................... 140 Preguntas............................................................................................................................. 140 Lección: Números y cadenas ............................................................................................... 141 Números............................................................................................................................... 141 Strings .................................................................................................................................. 141 Números................................................................................................................................... 141 Las clases de números .......................................................................................................... 142 Formato de impresión numérica .......................................................................................... 144 Los métodos printf y formato ............................................................................................ 144 Un ejemplo........................................................................................................................... 145 La clase DecimalFormat .................................................................................................... 146

Más allá de la aritmética básica ........................................................................................... 147 Constantes y métodos básicos ........................................................................................ 148 Métodos de funciones logarítmicos y exponenciales ................................................... 149 Métodos de funciones trigonométricos ........................................................................... 150 Números aleatorios ............................................................................................................ 152 Resumen de números ........................................................................................................... 152 Caracteres ............................................................................................................................... 152 Secuencias de escape....................................................................................................... 154 Strings ...................................................................................................................................... 154 Creación de strings ............................................................................................................ 154 Longitud de cadena ............................................................................................................ 155 Concatenación de cadenas .............................................................................................. 156 Creación de cadenas de formato ..................................................................................... 157 Conversión entre números y cadenas ................................................................................ 157 Conversión de cadenas a números ................................................................................. 157 Convertir números en cadenas ........................................................................................ 158 Manipulación de caracteres de una cadena ...................................................................... 159 Caracteres y subcadenas Índice ...................................................................................... 159 Otros métodos para manipular cadenas ......................................................................... 160 La búsqueda de caracteres y subseries de caracteres en una cadena .................... 160 Sustitución de caracteres y subseries de caracteres en una cadena ........................ 161 Un ejemplo........................................................................................................................... 162 Comparación de cadenas y porciones de cadenas .......................................................... 163 La clase StringBuilder ............................................................................................................ 165 Longitud y capacidad ......................................................................................................... 165 Operaciones de StringBuilder ........................................................................................... 166 Un ejemplo........................................................................................................................... 167 Resumen de caracteres y cadenas ..................................................................................... 169 Autoboxing y Unboxing .......................................................................................................... 169

Lección: Lenguaje básico Variables Ya has aprendido que objetos almacenan su estado en los campos. Sin embargo, el lenguaje de programación Java también utiliza el término "variable". Esta sección analiza esta relación, más las variables y sus reglas de nomenclatura y convenciones, los tipos de datos básicos (tipos primitivos, matrices y cadenas de caracteres), los valores por defecto y literales.

Operadores Esta sección describe los operadores del lenguaje de programación Java. Primero presenta los operadores más comúnmente utilizados, y por último los operadores menos utilizados. Cada discusión incluye ejemplos de código que se pueden compilar y ejecutar.

Expresiones, declaraciones y bloques Los operadores pueden utilizarse en la construcción de expresiones, que computan los valores; las expresiones son los componentes básicos de las instrucciones; las instrucciones pueden agruparse en bloques. Esta sección analiza expresiones, instrucciones y los bloques usando el código de ejemplo que ya has visto.

Instrucciones de flujo de control Esta sección describe las sentencias de los flujos de control soportados por el lenguaje de programación Java. Cubre la toma de decisiones, bucles y ramificaciones de sentencias que permiten a sus programas ejecutar condicionalmente bloques particulares de código.

Variables Como has aprendido en la lección anterior, un objeto almacena su estado en campos.

int cadence = 0; int speed = 0; int gear = 1; Ya hemos presentado a los campos, pero probablemente tiene todavía un par de preguntas, tales como:    

¿Cuáles son las reglas y convenciones para nombrar un campo? Además de int, ¿qué otros tipos de datos existen? ¿Los campos se tienen que inicializar cuando se declaran? ¿A los campos se les asigna un valor predeterminado si no se inicializan explícitamente?

Exploraremos las respuestas a estas preguntas en esta lección, pero antes de hacerlo, hay algunas distinciones técnicas de las que primero debes ser consciente. En el lenguaje de programación Java, se usan ambos términos "campo" y "variable"; Esto es una fuente común de confusión entre los nuevos desarrolladores, ya que ambas parecen a menudo referirse a lo mismo.

El lenguaje de programación Java define los siguientes tipos de variables:



Variables de Clase (campos estáticos) Una variable de clase es cualquier campo declarado con el modificador static; Esto indica al compilador que hay exactamente una copia de esta variable en existencia, sin importar cuántas veces la clase ha creado una instancia. Un campo define el número de marchas para una clase particular de bicicleta que podría ser marcado como static ya que conceptualmente el mismo número de marchas se aplicará a todas las instancias. El código static int numGears = 6; crearía un campo estático. Además, la palabra clave final podría añadirse para indicar que el número de marchas nunca cambiará.



Variables de Instancia (campos no-estáticos) Técnicamente hablando, los objetos almacenan sus Estados individuales en "campos no estáticos", es decir, los campos se declararan sin la palabra clave static. Los campos no estáticos son también conocidos como las variables de instancia porque sus valores son únicos para cada instancia de una clase (para cada objeto, en otras palabras); el currentSpeed de una bicicleta es independiente de la currentSpeed de otra.



Variables Locales Similar a cómo un objeto almacena su estado en los campos, un método almacenará temporalmente el estado en las variables locales. La sintaxis para declarar una variable local es similar a declarar un campo (por ejemplo, int count = 0;). No hay ninguna clave especial designando una variable como local; la determinación proviene totalmente de la situación en la que se declara la variable —está entre la apertura y cierre de llaves de un método. Por lo tanto, las variables locales sólo son visibles para los métodos en los que se declaran; No son accesibles desde el resto de la clase.



Parámetros Ya has visto ejemplos de parámetros tanto en el método main de la aplicación "Hello World!" y en la clase Bicycle. Recordemos que la firma para el método main es public static void main(String[] args). Aquí, la variable args es el parámetro de este método. Lo importante a recordar es que los parámetros siempre son clasificados como "variables" no como "campos". Esto se aplica a otras construcciones de parámetros aceptados también (como constructores y los controladores de excepciones) que aprenderá más adelante en el tutorial.

Una vez dicho esto, el resto de este tutorial utiliza las siguientes directrices generales cuando se habla de campos y variables: Si estamos hablando de "campos en general" (excluyendo las variables locales y los parámetros), podemos decir simplemente "campos". Si la discusión se aplica a "todas las anteriores", podemos decir simplemente "variables". Si el contexto pide una distinción, usaremos términos específicos (campo estático, variables locales, etc.) según corresponda. Ocasionalmente también puede ver el término "miembro" usado también. Los tipos de campos, métodos y tipos anidados se denominan colectivamente miembros.

Nomenclatura Cada lenguaje de programación tiene su propio conjunto de reglas y convenciones para las clases de nombres que puedes usar, y el lenguaje de programación Java no es diferente. Las reglas y convenciones para nombrar sus variables pueden resumirse como sigue:



Los nombres de variables distinguen mayúsculas de minúsculas. El nombre de una variable puede ser cualquier identificador legal —una secuencia de longitud ilimitada de Unicode de letras y dígitos, comenzando con una letra, el signo de dólar "$" o el carácter subrayado "_". La Convención, sin embargo, es siempre comenzar sus nombres de variables con una letra, no "$" o "_". Además, el carácter de signo de dólar, por Convención, nunca se utiliza en absoluto. Usted puede encontrar algunas situaciones donde se generan automáticamente nombres que contienen el signo de dólar, pero sus nombres de variable siempre deben evitar usarlo. Un convenio similar existe para el carácter de subrayado; Aunque es técnicamente legal para comenzar un nombre de la variable con '_', se desaconseja esta práctica. El espacio en blanco no está permitido.



Los caracteres posteriores pueden ser Letras, números, signos de dólar, o caracteres resaltados. La convención (y el sentido común) se aplican a esta regla también. Al elegir un nombre para sus variables, utilice palabras completas en lugar de abreviaturas crípticas. Hacerlo asi hará su código fácil de leer y comprender. En muchos casos también hará su código auto-documentado; los campos denominados cadence, speed y gear, por ejemplo, son mucho más intuitivos que versiones abreviadas, como s, c y g. También tenga en cuenta que el nombre que usted elige no debe ser una palabra clave o palabra reservada.



Si el nombre que usted elige consta de una única palabra, escriba esa palabra en letras minúsculas. Si consta de más de una palabra, la primera letra de cada palabra subsiguiente será mayúscula. Los nombres gearRatio y currentGear son los principales ejemplos de esta Convención. Si la variable almacena un valor constante, tales como static final int NUM_GEARS = 6, la Convención cambia ligeramente, cada letra será mayúscula y se separa las palabras posteriores con el carácter de subrayado. Por Convención, el carácter de subrayado nunca se utiliza en otros lugares.

Tipos de datos primitivos El lenguaje de programación Java es estáticamente-tipado, lo que significa que: 

todas las variables primero deben ser declaradas antes de que puedan ser utilizadas.

Esto implica declarar el tipo de la variable y el nombre, como ya lo has visto:

int gear = 1; Así dice el programa que un campo llamado "gear" existe, contiene datos numéricos y tiene un valor inicial de "1". El tipo de dato de una variable determina los valores que puede contener, además de las operaciones que pueden realizarse con él. Además de int, el lenguaje de programación Java soporta otros siete tipos de datos primitivos. 

Un tipo primitivo está predefinido por el lenguaje y es nombrado por una palabra clave reservada.

Los valores primitivos no comparten el estado con otros valores primitivos. Los ocho tipos de datos primitivos soportados por el lenguaje Java de programación son:



byte: el tipo de dato byte de 8-bit es un entero con signo en complemento a dos (0 para positivo y 1 para negativo). o o

Tiene un valor mínimo de -128 y un valor máximo de 127 (inclusivo). Útil para guardar memoria en grandes arreglos, donde importa el ahorro de memoria.

Pueden también ser utilizados en lugar de int donde sus límites ayudan a clarificar el código; el hecho de que el rango de una variable es limitado puede servir como una forma de documentación.



short: el tipo de dato short es de 16-bit es un entero con signo en complemento a dos. o o



Tiene un valor mínimo de -32,768 y un valor máximo de 32,767 (inclusivo). Puede utilizar un short para guardar memoria en arreglos grandes, en situaciones donde realmente importa el ahorro de memoria.

int: por defecto, el tipo de datos int es de 32-bit es un entero con signo en complemento a dos, o

o

Tiene un valor mínimo de -231 y un valor máximo de 231-1. Utilice la clase Integer para utilizar el tipo de datos int como un entero sin signo.

En Java SE 8 y versiones posteriores, puede utilizar el tipo de datos int para representar un entero sin signo de 32 bits, que tiene un valor mínimo de 0 y un valor máximo de 232-1. Consulte la sección el número de clases para obtener más información. Métodos estáticos como compareUnsigned, divideUnsigned etc. se han añadido a la clase Integer para apoyar las operaciones aritméticas de números enteros sin signo.



long: el tipo de datos long es de 64-bit complemento a dos con cualquier otro.

o o

La firma de long tiene un valor mínimo de -263 y un valor máximo de 263-1. Utilice este tipo de datos cuando se necesita un rango de valores más amplio que las ofrecidas por int.

En Java SE 8 y versiones posteriores, puede utilizar el tipo de datos long para representar 64 bits sin signo, que tiene un valor mínimo de 0 y un valor máximo de 264-1. La clase Long también contiene métodos como compareUnsigned, divideUnsigned etc. para apoyar operaciones aritméticas de long sin signo.



float: el tipo de datos float es un punto flotante de precisión simple de 32 bits del estandar IEEE 754 (Instituto de Ingeniería Eléctrica y Electrónica para aritmética en coma flotante). Su rango de valores está fuera del alcance de esta discusión, pero se especifica en la sección tipos de coma flotante, formatos y valores de la Java Language Specification. Como con las recomendaciones de byte y short,

o o o



Use un float (en vez de double) si necesita guardar memoria en grandes conjuntos de números de punto flotante. Este tipo de datos no debe utilizarse para valores precisos, como moneda. Para eso, usted necesitará utilizar la clase java.math.BigDecimal en su lugar. Numbers and Strings cubre BigDecimal y otras clases útiles proporcionados por la plataforma Java.

doble: el tipo de datos double es un punto flotante de precisión doble de 64 bits IEEE 754. Su rango de valores está fuera del alcance de esta discusión, pero se especifica en la sección tipos de coma flotante, formatos y valores de la especificación del lenguaje Java.

o o

Para valores decimales, este tipo de datos es generalmente la opción predeterminada. Este tipo de datos no debe utilizarse para valores precisos, como moneda.



booleano: el tipo de datos boolean tiene sólo dos valores posibles: true y false.

o o 

Utilice este tipo de datos para indicadores simples que siguen condiciones del tipo verdadero o falso. Este tipo de datos representa un bit de información, pero su "tamaño" no es algo que se define con precisión.

char: el tipo de datos char es un solo carácter Unicode de 16 bits.

o

Tiene un valor mínimo de '\u0000' (o 0) y un valor máximo de '\uffff' (o 65.535 inclusivo).

Además de los ocho tipos de datos primitivos mencionados anteriormente, el lenguaje de programación Java también proporciona un apoyo especial para cadenas de caracteres mediante la clase java.lang.String . Encerrando tu cadena de caracteres entre comillas dobles creará automáticamente un nuevo objeto String; por ejemplo,

String s = "this is a string";. Los objetos String son inmutables, que significa que una vez creado, no se pueden cambiar sus valores. La clase String no es técnicamente un tipo de datos primitivo, pero teniendo en cuenta el apoyo especial dado por el lenguaje, probablemente tenderán a pensar en él como tal. Usted aprenderá más acerca de la clase String en Objetos de datos simples.

Valores por defecto 

No siempre es necesario asignar un valor cuando se declara un campo.

Los campos que son declarados pero no inicializados establecerán una moratoria razonable por el compilador. 

En términos generales, por defecto será cero o null, dependiendo del tipo de datos.

Confiar en estos valores por defecto, sin embargo, se considera generalmente mal estilo de programación. La siguiente tabla resume los valores por defecto para los tipos de datos anteriores. Tipo de datos

Valor por defecto (de campos)

Byte

0

short

0

int

0

long

0L

float

0.0F

double

0.0d

Char

'\u0000'

String (o cualquier objeto) null Boolean

false

Las variables locales son ligeramente diferentes; El compilador nunca asigna un valor predeterminado a una variable local sin inicializar. Si no puede inicializar la variable local donde se declara, asegúrese de asignarle un valor antes de intentar usarla. 

El acceso a una variable local sin inicializar producirá un error en tiempo de compilación.

Literales Usted puede haber notado que no se utiliza la palabra clave new al inicializar una variable de un tipo primitivo.   

Los tipos primitivos son tipos de datos especiales incorporados en el lenguaje; No son objetos creados de una clase. Una literal es la representación de código fuente de un valor fijo; los literales están representados directamente en el código sin necesidad de cómputo.

Como se muestra a continuación, es posible asignar un literal a una variable de un tipo primitivo:

boolean result = true; char capitalC = 'C'; byte b = 100; short s = 10000; int i = 100000;

Literales enteros 

Un literal entero es de tipo long si termina con la letra L o l; de lo contrario es de tipo int.

Se recomienda utilizar la letra mayúscula L porque la minúscula letra l es difícil distinguir el dígito 1.  

Los valores de los tipos integrales byte, short, int y long pueden crearse desde literales int. Los valores de tipo long que exceden el rango de int pueden crearse de literales de long.

Los literales enteros pueden ser expresados por estos sistemas de numeración:

  

Decimales: Base 10, cuyas cifras consta de los números 0 a 9; Este es el sistema de numeración que utiliza todos los días. Hexadecimal: Base 16, cuyos dígitos consisten en los números 0 a 9 y las letras A F Binario: Base 2, cuyas cifras se compone de los números 0 y 1 (puede crear literales binarios en Java SE 7 y versiones posteriores)

Para la programación de propósito general, es probable que el sistema de numeración único que nunca usará es el sistema decimal. Sin embargo, Si usted necesita usar otro sistema de numeración, el ejemplo siguiente muestra la sintaxis correcta. El prefijo 0x indica hexadecimal y 0b binario:

// The number 26, in decimal int decVal = 26; // The number 26, in hexadecimal int hexVal = 0x1a; // The number 26, in binary int binVal = 0b11010;

Literales de coma flotante 

Un literal de coma flotante es de tipo float si termina con la letra F o f; de lo contrario su tipo es double y opcionalmente puede terminar con la letra D o d.

Los tipos de punto flotante (float y double) también puede expresarse utilizando E o e (para la notación científica), F o f (literal float de 32 bits) y D o d (64 bits double literal; esta es la opción predeterminada y por Convención se omite).

double d1 = 123.4; // mismo valor que d1, pero en notación científica double d2 = 1.234e2; float f1 = 123.4f;

Carácteres y literales String 

Los literales de tipo char y String pueden contener cualquier carácter Unicode (UTF-16).

Si tu editor y sistema de archivos lo permiten, se pueden utilizar tales caracteres directamente en el código. Si no, puede utilizar un "escape Unicode" como '\u0108' (mayuscula C con acento circunflejo), o "S\u00ED Se\u00F1or" (Sí Señor en Español). 

Utilice siempre 'comillas simples' para literales char y "comillas dobles" para literales de String.

Las secuencias de escape Unicode pueden utilizarse en cualquier parte en el programa (como en los nombres de campo, por ejemplo), no sólo en literales char o String. El lenguaje de programación Java también soporta algunas secuencias de escape especial para literales char y String:        

\b (retroceso) \t (tab), \n (avance de línea), \f (forma de alimentación), \r (retorno de carro), \" (comilla doble), \' (comilla simple) y \\ (barra invertida).

También hay una literal especial null que puede utilizarse como un valor para cualquier tipo de referencia. 

null puede asignarse a cualquier variable, excepto las variables de tipos primitivos.

Es poco lo que puede hacer con un valor null más allá de pruebas de su presencia. Por lo tanto,



null es a menudo utilizado en programas como marcador para indicar que un objeto no está disponible.

Finalmente, también hay un tipo especial de literal llamada 

Una clase literal, se forma al tomar un nombre de tipo y anexar (.class);

Por ejemplo, String.class. Esto se refiere al objeto (de tipo Class) que representa el tipo de sí mismo.

Usando caracteres de subrayado en literales de valores numéricos En Java SE 7 y versiones posteriores, cualquier número de caracteres de subrayado (_) puede aparecer en cualquier parte entre los dígitos en un literal numérico. 

Esta caracteristica le permite separar grupos de dígitos en literales numéricos, que pueden mejorar la legibilidad del código.

Por ejemplo, si su código contiene números con muchos dígitos, usarás un carácter de subrayado para separar dígitos en grupos de tres, similar a cómo usarías un signo de puntuación como una coma o un espacio, como un separador. El siguiente ejemplo muestra otras maneras en que puede utilizar el carácter de subrayado en literales de valores numéricos:

long creditCardNumber = 1234_5678_9012_3456L; long socialSecurityNumber = 999_99_9999L; float pi = 3.14_15F; long hexBytes = 0xFF_EC_DE_5E; long hexWords = 0xCAFE_BABE; long maxLong = 0x7fff_ffff_ffff_ffffL; byte nybbles = 0b0010_0101; long bytes = 0b11010010_01101001_10010100_10010010; Usted puede colocar subrayados sólo entre los dígitos; No puede colocar subrayado en los siguientes lugares:

   

Al principio o al final de un número Adyacente a un punto decimal en un literal de coma flotante Antes de un sufijo F o L En las posiciones donde se espera una cadena de dígitos

Los siguientes ejemplos demuestran las colocaciones de subrayado válido y no válido (que destacan) en literales de valores numéricos:

// Invalido: no se puede poner subrayado // adyacente a un punto decimal float pi1 = 3_.1415F; // Invalido: no se puede poner subrayado // adyacente a un punto decimal float pi2 = 3._1415F; // Invalido: no se puede poner subrayado

// antes de un sufijo L long socialSecurityNumber1 = 999_99_9999_L; // OK (literal decimal) int x1 = 5_2; // Invalido: no se puede poner subrayado // Al final de una literal int x2 = 52_; // OK (decimal literal) int x3 = 5_______2; // Invalido: no se puede poner subrayado // en el prefijo 0x int x4 = 0_x52; // Invalido: no se puede poner subrayado // en el comienzo de un número int x5 = 0x_52; // OK (literal hexadecimal) int x6 = 0x5_2; // Invalido: no se puede poner subrayado // al final del numero int x7 = 0x52_;

Arreglos   

Un arreglo es un objeto contenedor que contiene un número fijo de valores de un solo tipo. La longitud de un arreglo se establece cuando se crea el arreglo. Después de la creación, su longitud es fija.

Usted ya ha visto un ejemplo de arreglo, en el método main de la aplicación "Hello World!". Esta sección analiza detalladamente los arreglos.

Una arreglo de 10 elementos.



Cada item de un arreglo se llama un elemento, y cada a elemento se accede por su Índice numérico.

Como se muestra en la ilustración anterior, la numeración comienza con 0. El noveno elemento, por ejemplo, sería por lo tanto para acceder al índice 8.

El siguiente programa, ArrayDemo, crea un arreglo de enteros, pone algunos valores del arreglo e imprime cada valor en salida estándar.

class ArrayDemo { public static void main(String[] args) { // declara una arreglo de enteros int[] anArray; // asigna memoria para 10 números enteros anArray = new int[10]; // inicializa primer elemento anArray[0] = 100; // inicializa segundo elemento anArray[1] = 200; // y así sucesivamente anArray[2] = 300; anArray[3] = 400; anArray[4] = 500; anArray[5] = 600; anArray[6] = 700; anArray[7] = 800; anArray[8] = 900; anArray[9] = 1000; System.out.println("Element at index + anArray[0]); System.out.println("Element at index + anArray[1]); System.out.println("Element at index + anArray[2]); System.out.println("Element at index + anArray[3]); System.out.println("Element at index + anArray[4]); System.out.println("Element at index + anArray[5]); System.out.println("Element at index + anArray[6]); System.out.println("Element at index + anArray[7]); System.out.println("Element at index + anArray[8]); System.out.println("Element at index + anArray[9]); } } La salida de este programa es:

Element Element Element Element Element Element Element Element Element Element

at at at at at at at at at at

index index index index index index index index index index

0: 1: 2: 3: 4: 5: 6: 7: 8: 9:

100 200 300 400 500 600 700 800 900 1000

0: " 1: " 2: " 3: " 4: " 5: " 6: " 7: " 8: " 9: "

En una situación de programación del mundo real, es probable que utilice una de las construcciones de bucle soportados para iterar a través de cada elemento de la matriz, en lugar de escribir cada línea individual como en el ejemplo anterior. Sin embargo, el ejemplo ilustra claramente la sintaxis de la matriz. Usted aprenderá acerca de las diferentes construcciones de bucles (for, while, y do-while) en la sección de Control de flujo .

Declarar una Variable para hacer referencia a un Arreglo El programa anterior declara un arreglo (llamada anArray) con la siguiente línea de código:

// declara un arreglo de enteros int[] anArray; Al igual que las declaraciones de variables de otros tipos, 

una declaración de arreglo tiene dos componentes: tipo de arreglo y el nombre del arreglo.

Tipo de arreglo se escribe como type[], donde type es el tipo de datos de los elementos contenidos; 

los corchetes son símbolos especiales que indica que esta variable contiene un arreglo.

El tamaño del arreglo no es parte de este tipo (razón por la cual los corchetes están vacíos). El nombre de un arreglo puede ser cualquier cosa que quieras, siempre que sigas las reglas y convenciones como se discute en la sección de nomenclatura . Al igual que con las variables de otros tipos, 

la declaración en realidad no crea un arreglo; simplemente indica al compilador que esta variable mantendrá un arreglo del tipo especificado.

Del mismo modo, puede declarar arreglos de otros tipos:

byte[] anArrayOfBytes; short[] anArrayOfShorts; long[] anArrayOfLongs; float[] anArrayOfFloats; double[] anArrayOfDoubles; boolean[] anArrayOfBooleans; char[] anArrayOfChars; String[] anArrayOfStrings; También puede colocar los paréntesis después del nombre de la matriz:

// esta forma se desaconseja float anArrayOfFloats[]; Sin embargo, la convención desalienta esta forma. 

Los corchetes identifican el tipo de arreglo y deben aparecer con la designación del tipo.

Crear, inicializar y acceder a una arreglo 

Otra forma de crear un array es con el operador new.

La siguiente instrucción en el programa ArrayDemo asigna un array con suficiente memoria para 10 elementos de tipo entero y asigna el arreglo a la variable anArray.

// crea un arreglo de enteros anArray = new int[10]; Si falta esta instrucción, entonces el compilador imprime un error como el siguiente, y falla la compilación:

ArrayDemo.java:4: Variable anArray may not have been initialized. Las siguientes líneas asignan valores a cada elemento de la matriz:

anArray[0] = 100; // inicializa el primer elemento anArray[1] = 200; // inicializa el segundo elemento anArray[2] = 300; // y así sucesivamente A cada elemento del array se accede por su índice numérico:

System.out.println("Element 1 at index 0: " + anArray[0]); System.out.println("Element 2 at index 1: " + anArray[1]); System.out.println("Element 3 at index 2: " + anArray[2]); Como alternativa, puede utilizar la sintaxis de método abreviado para crear e inicializar un arreglo:

int[] anArray 100, 200, 400, 500, 700, 800, }; 

= { 300, 600, 900, 1000

Aquí la longitud del arreglo se determina por el número de valores proporcionados entre corchetes y separados por comas.

También puede declarar un arreglo de arreglos (también conocido como un arreglo multidimensional) mediante el uso de dos o más conjuntos de corchetes, tales como

// arreglo multidimensional String[][] names  

Cada elemento, por lo tanto, debe accederse por el número correspondiente de los valores del índice. En el lenguaje de programación Java, un arreglo multidimensional es un arreglo cuyos componentes son ellos mismos, los arreglos.

Esto es a diferencia de los arreglos en C o Fortran. Una consecuencia de esto es que las filas pueden variar en longitud, como se muestra en el siguiente programa MultiDimArrayDemo :

class MultiDimArrayDemo { public static void main(String[] args) { String[][] names = { {"Mr. ", "Mrs. ", "Ms. "},

{"Smith", "Jones"} }; // Mr. Smith System.out.println(names[0][0] + names[1][0]); // Ms. Jones System.out.println(names[0][2] + names[1][1]); } } La salida de este programa es:

Mr. Smith Ms. Jones Finalmente, usted puede utilizar la propiedad incorporada length para determinar el tamaño de cualquier arreglo. El código siguiente imprime el tamaño de la matriz a la salida estándar:

// para determinar el tamaño del arreglo System.out.println(anArray.length);

Copia de Arrays La clase System tiene un método arraycopy que puede utilizar para eficientar 

copiar datos desde un arreglo a otro:

// obj origen, posición inicial del obj origen, // obj destino, posición inicial del obj destino, // numero de elementos a copiar public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) Los dos argumentos Object especifican el arreglo a copiar y el arreglo al que se copiara. Los tres argumentos int especifican la posición de partida en el arreglo de origen, la posición de partida en el arreglo de destino y el número de elementos del arreglo para copiar. El siguiente programa, ArrayCopyDemo, declara un array de elementos char, deletrea la palabra "descafeinado". Se utiliza el método System.arraycopy para copiar un subsecuencia de componentes del arreglo en un segundo arreglo:

class ArrayCopyDemo { public static void main(String[] args) { char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 2, copyTo, 0, 7); System.out.println(new String(copyTo)); } } La salida de este programa es:

caffein

Manipulación de arreglos 

Los arreglos son un concepto potente y útil usado en programación.

Java SE proporciona métodos para realizar algunas de las manipulaciones más comunes relacionadas con arreglos. Por ejemplo, el ejemplo ArrayCopyDemo utiliza el método arraycopy de la clase de System en lugar de recorrer manualmente los elementos del arreglo origen y colocar cada uno en el arreglo de destino. Esto se lleva a cabo detrás de escena, permitiendo a los desarrolladores usar una sola línea de código para llamar al método. Para su conveniencia, Java SE proporciona varios métodos para realizar las manipulaciones de los arreglos (tareas comunes, como copiar, clasificar y búsqueda de arreglos) en la clase java.util.Arrays . Por ejemplo, el ejemplo anterior puede modificarse para utilizar el método copyOfRange de la clase java.util.Arrays , como se puede ver en el ejemplo ArrayCopyOfDemo . La diferencia es que mediante el método copyOfRange no requiere crear el array de destino antes de llamar al método, porque el arreglo de destino es devuelto por el método:

class ArrayCopyOfDemo { public static void main(String[] args) { char[] copyFrom = {'d', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd'}; char[] copyTo = java.util.Arrays.copyOfRange(copyFrom, 2, 9); System.out.println(new String(copyTo)); } } Como puede ver, la salida de este programa es el mismo (caffein), aunque requiere menos líneas de código. Tenga en cuenta que el segundo parámetro del método copyOfRange es el índice inicial del rango a ser copiado, inclusivo, mientras que el tercer parámetro es el índice final del rango que se copiará, exclusivamente. En este ejemplo, el rango a copiar no incluye el elemento del arreglo en el índice 9 (que contiene el carácter a). Algunas otras operaciones útiles proporcionados por métodos de la clase java.util.Arrays, son:

   

Buscar en una matriz un valor específico para obtener el índice en el cual se coloca (el método binarySearch). Comparar dos arreglos para determinar si son iguales o no (el método equals). Llenar una matriz para colocar un valor específico en cada índice (el método fill). Clasificar un arreglo en orden ascendente. Esto puede hacerse ya sea secuencialmente, utilizando el método de sort, o al mismo tiempo, usando el parallelSort método introducido en Java SE 8. La clasificación paralela de grandes arreglos en sistemas multiprocesador es más rápido que la matriz secuencial de clasificación.

Resumen de Variables            

El lenguaje de programación Java utiliza "variables" y "campos" como parte de su terminología. Las variables de instancia (campos no estáticos) son únicas para cada instancia de una clase. Las variables de clase (campos estáticos) son campos declarados con el modificador static; hay exactamente una copia de una variable de clase, sin importar cuántas veces se ha creado una instancia de la clase. Las variables locales almacenan temporalmente el estado dentro de un método. Los parámetros son variables que proporcionan información extra para un método; parámetros y variables locales siempre se clasifican como "variables" (no "campos"). Al nombrar sus campos o variables, hay reglas y convenciones que se deben (o debe) seguir. Los ocho tipos de datos primitivos son: byte, short, int, long, float, double, boolean y char. La clase java.lang.String representa cadenas de caracteres. El compilador asigna un valor razonable por defecto para los campos de los tipos anteriores; para las variables locales, nunca se asigna un valor predeterminado. Un literal es la representación de código fuente de un valor fijo. Un arreglo es un objeto contenedor que contiene un número fijo de los valores de un solo tipo. La longitud de un arreglo se establece cuando se crea el arreglo. Después de la creación, su longitud es fija.

Preguntas: Variables 1. 2. 3. 4. 5. 6. 7.

El término "variable de instancia" es otro nombre para ___. El término "variable de clase" es otro nombre para ___. Una variable local almacena el estado temporal; se declara dentro de un ___. Una variable declarada dentro de la apertura y cierre de paréntesis de la firma de un método se llama un ___. ¿Cuáles son los ocho tipos de datos primitivos, apoyados por el lenguaje de programación Java? Cadenas de caracteres están representadas por la clase ___. Un ___ es un objeto contenedor que contiene un número fijo de los valores de un solo tipo.

Operadores Ahora que ha aprendido a declarar e inicializar variables, probablemente quieras saber cómo hacer algo con ellas. Aprender los operadores del lenguaje de programación Java es un buen lugar para empezar. 

Los operadores son símbolos especiales que realizan operaciones concretas en uno, dos o tres operandos y luego devuelven un resultado.

Mientras exploramos los operadores del lenguaje de programación Java, puede ser útil para usted saber con anticipación qué operadores tienen la mas alta precedencia. Los operadores en la tabla siguiente se enumeran según el orden de precedencia. 

Cuanto más cerca de la parte superior de la tabla un operador aparece, es más alta su procedencia.

Los operadores con mayor prioridad se evalúan antes que los operadores con precedencia relativamente menor. 

Los operadores en la misma línea tienen la misma precedencia.

Cuando los operadores de igual prioridad aparecen en la misma expresión, debe regir una regla de cuál se evalúa primero.  

Los operadores binarios se evalúan de izquierda a derecha; Los operadores de asignación se evalúan de derecha a izquierda. Precedencias de los operadores Operadores

Precedencia

Postfix

expr++ expr--

Unario

++expr --expr +expr -expr ~ !

Multiplicativo

* / %

Aditivo

+ -

Shift (desplazar)

> >>>

Relacionales

< > = instanceof

Igualdad

== !=

bitwise AND

&

bitwise exclusive OR

^

bitwise inclusive OR

|

AND lógico

&&

OR lógica

||

ternario

? :

asignación

= += -= *= /= %= &= ^= |= = >>>=

En la programación de propósito general, ciertos operadores tienden a aparecer con más frecuencia que otros; por ejemplo, el operador de asignación "=" es mucho más común que el operador de desplazamiento a la derecha sin signo ">>>". Con esto en mente, la siguiente discusión se centra primero en los operadores que es más probable que utilice en forma regular y termina enfocándose en aquellas que son menos comunes. Cada discusión va acompañada de código de ejemplo que se puede compilar y ejecutar. Estudiar la salida en consola le ayudará a reforzar lo aprendido.

Asignación, aritmética y operadores unarios El operador de asignación Simple Uno de los operadores más comunes que te vas a encontrar es el operador de asignación simple "=". Viste a este operador en la clase de bicicleta; asigna el valor a su derecha con el operador de la izquierda:

int cadence = 0; int speed = 0; int gear = 1; Este operador puede usarse en objetos para asignar referencias a objetos, como se discute en Crear objetos.

Los operadores aritméticos El lenguaje de programación Java proporciona operadores que realizan la adición, sustracción, multiplicación y división. Hay una buena posibilidad de que les reconocerás por sus homólogos en matemática básica. El único símbolo que puede parecer nuevo para ti es "%", él cual divide un operandor por otro y devuelve el resto como su resultado. Operador

Descripción

+

Operador aditivo (también utilizada para la concatenación de cadenas)

-

Operador de resta

*

Operador de multiplicación

/

Operador división

%

Operador del resto

El siguiente programa, ArithmeticDemo, prueba los operadores aritméticos.

class ArithmeticDemo { public static void main (String[] args) { int result = 1 + 2; // el resultado es ahora 3 System.out.println("1 + 2 = " + result); int original_result = result; result = result - 1; // el resultado es ahora 2 System.out.println(original_result + " - 1 = " + result); original_result = result; result = result * 2; // el resultado es ahora 4 System.out.println(original_result + " * 2 = " + result); original_result = result; result = result / 2; // el resultado es ahora 2 System.out.println(original_result + " / 2 = " + result); original_result = result;

result = result + 8; // el resultado es ahora 10 System.out.println(original_result + " + 8 = " + result); original_result = result; result = result % 7; // el resultado es ahora 3 System.out.println(original_result + " % 7 = " + result); } }

Este programa imprime lo siguiente:

1 + 2 = 3 3 - 1 = 2 2 * 2 = 4 4 / 2 = 2 2 + 8 = 10 10 % 7 = 3 También puedes combinar los operadores aritméticos con el operador de asignación simple para crear asignaciones compuestas. Por ejemplo, x+=1; y x=x+1; ambos incrementan el valor de x por 1. El + operador puede utilizarse también para concatenar (unir) dos cadenas juntas, como se muestra en el siguiente programa ConcatDemo :

class ConcatDemo { public static void main(String[] args){ String firstString = "This is"; String secondString = " a concatenated string."; String thirdString = firstString+secondString; System.out.println(thirdString); } } Al final de este programa, la variable thirdString contiene " This is a concatenated string.", que queda impreso a la salida estándar.

Los operadores unarios Los operadores unarios requieren sólo uno de los operadores; realizan diversas operaciones como un valor de incremento/decremento en uno, negar una expresión, o invertir el valor de tipo booleano. Operador

Descripción

+

operador aditivo unario ; indica el valor positivo (sin embargo, los números son positivos sin esto)

-

Menos; operador unario, niega una expresión

++

Operador de incremento; incrementa un valor de 1

--

Operador de decremento; disminuye un valor de 1

!

Operador complemento lógico; invierte el valor de tipo booleano

El siguiente programa, UnaryDemo, prueba los operadores unarios:

class UnaryDemo { public static void main(String[] args) { int result = +1; // el resultado es ahora 1 System.out.println(result); result--; // el resultado es ahora 0 System.out.println(result); result++; // el resultado es ahora 1 System.out.println(result); result = -result; // el resultado es ahora -1 System.out.println(result); boolean success = false; // false System.out.println(success); // true System.out.println(!success); } } Los operadores de incremento/decremento pueden aplicarse antes del (prefijo) o después del (posfijo) operador. En el código result++; y ++result; ambos terminarán en que result se incrementa en uno. La única diferencia es que la versión prefija  

(++result) evalúa sobre el valor incrementado, (result++) se evalúa sobre el valor original.

Si sólo está realizando un simple incremento/decremento, no importa qué versión elegir. Pero si utiliza este operador en una parte de una expresión más grande, elegir indistintamente puede hacer una diferencia significativa. El siguiente programa, PrePostDemo, ilustra el operador de incremento unario prefijo/postfijo:

class PrePostDemo { public static void main(String[] args){ int i = 3; i++; // imprime 4 System.out.println(i); ++i; // imprime 5 System.out.println(i); // imprime 6 System.out.println(++i); // imprime 6

System.out.println(i++); // imprime 7 System.out.println(i); } }

Operadores de igualdad y relacionales Los operadores de igualdad y relacionales 

determinan si uno de los operadores es mayor, menor, igual, o no es igual a otro operador.

La mayoría de estos operadores probablemente se verá familiar también. Tenga en mente que 

debe utilizar "==", no "=", cuando se prueba si dos valores primitivos son iguales.

== != > >= < value2) System.out.println("value1 > value2"); if(value1 < value2) System.out.println("value1 < value2"); if(value1 >=
>> & ^ |

Unary bitwise complement Signed left shift Signed right shift Unsigned right shift Bitwise AND Bitwise exclusive OR Bitwise inclusive OR

Preguntas y ejercicios: operadores Preguntas 1.

Considere el siguiente fragmento de código.

arrayOfInts[j] > arrayOfInts[j+1]

¿Que operadores contiene el código? 2.

Considere el siguiente fragmento de código.

int i = 10; int n = i++%5; a. b.

3. 4. 5.

¿Cuáles son los valores de i y n después de que se ejecuta el código? ¿Cuáles son los valores finales de i y n si en lugar de utilizar el operador postfijo de incremento (i++), utiliza la versión prefija (++i))?

¿Para invertir el valor de un boolean, que operador usarías? ¿Qué operador se utiliza para comparar dos valores, = o ==? Explica el siguiente ejemplo de código:

result = someCondition ? value1 : value2;

Ejercicios 1.

Cambiar el siguiente programa para utilizar asignaciones compuestas:

class ArithmeticDemo { public static void main (String[] args){ int result = 1 + 2; // result is now 3 System.out.println(result); result = result - 1; // result is now 2 System.out.println(result); result = result * 2; // result is now 4 System.out.println(result); result = result / 2; // result is now 2 System.out.println(result); result = result + 8; // result is now 10 result = result % 7; // result is now 3 System.out.println(result); } }

En el siguiente programa, explique por qué el valor "6" se imprime dos veces seguidas:

class PrePostDemo { public static void main(String[] int i = 3; i++; System.out.println(i); // ++i; System.out.println(i); // System.out.println(++i); // System.out.println(i++); // System.out.println(i); // } }

args){ "4" "5" "6" "6" "7"

Expresiones, instrucciones y bloques Ahora que comprende las variables y los operadores, es tiempo de aprender acerca de las expresiones, instrucciones y bloques. 

Los operadores se utilizan en la construcción de expresiones, que computan los valores; las expresiones son los componentes básicos de las instrucciones; las instrucciones pueden agruparse en bloques.

Expresiones Una expresión es una construcción compuesta por variables, operadores y las invocaciones de método, que fueron construidas según la sintaxis del lenguaje, se evalúa como un valor único. Ya hemos visto ejemplos de expresiones, ilustrados en negrita abajo:

int cadence = 0; anArray[0] = 100; System.out.println("Element 1 at index 0: " + anArray[0]); int result = 1 + 2; // result is now 3 if (value1 == value2) System.out.println("value1 == value2"); El tipo de datos del valor devuelto por una expresión depende de los elementos utilizados en la expresión. La expresión cadence = 0 devuelve un int porque el operador de asignación devuelve un valor del mismo tipo de datos que el de su operador de la izquierda; en este caso, cadence es un int. Como se puede ver en las otras expresiones, una expresión puede devolver otros tipos de valores, tales como boolean o String. El lenguaje de programación Java permite construir expresiones compuestas de varias expresiones más pequeñas, siempre y cuando el tipo de datos requerido por una parte de la expresión coincide con el tipo de datos del otro. Aquí hay un ejemplo de una expresión compuesta:

1 * 2 * 3 En este caso particular, el orden en el cual se evalúa la expresión es importante porque el resultado de la multiplicación es independiente del orden; el resultado es siempre el mismo, no importa en qué orden se aplican las multiplicaciones. Sin embargo, esto no es cierto de todas las expresiones. Por ejemplo, la siguiente expresión da resultados diferentes, dependiendo de si se realiza la adición o la operación de división primero:

x + y / 100

// ambiguo

Puede especificar exactamente cómo una expresión serán evaluadas utilizando paréntesis: (y). Por ejemplo, para hacer la anterior expresión inequívoca, puede escribir lo siguiente:

(x + y) / 100

// no ambiguo, recomendado

Si usted no indica explícitamente el orden para las operaciones a realizar, el orden es determinado por la precedencia asignada a los operadores en el uso dentro de la expresión. Los operadores que tienen una mayor prioridad consiguen ser evaluados primero. Por ejemplo, el operador división tiene una mayor prioridad que el operador de suma. Por lo tanto, los siguientes dos comandos son equivalentes:

x + y / 100 x + (y / 100) // no ambiguo, recomendado Al escribir expresiones compuestas, debe ser explícito e indicar entre paréntesis que los operadores deben ser evaluados primero. Esta práctica hace más fácil leer y mantener el código.

Instrucciones o sentencias Las instrucciones son más o menos equivalentes a las oraciones en lenguas naturales. 

Una instrucción forma una unidad completa de ejecución.

Los siguientes tipos de expresiones se pueden realizar en una instrucción por la expresión de un punto y coma (terminación;).

   

Expresiones de asignación Cualquier uso de ++ o -Invocaciones de método Expresiones de creación de objeto

Tales instrucciones son llamadas instrucciones o sentencias de expresión. Estos son algunos ejemplos de instrucciones de expresión.

// instrucción de asignación aValue = 8933.234; // instrucción de incremento aValue++; // instrucción de invocación de método System.out.println("Hello World!"); // instrucción de creación de objeto Bicycle myBike = new Bicycle(); Además de las instrucciones de expresión, existen otros dos tipos de instrucciones: 1. 2.

declaración de instrucciones e instrucciones de control de flujo.

Una declaración declara una variable. Ya has visto muchos ejemplos de instrucciones de declaración:

// instrucción de declaración double aValue = 8933.234; Finalmente, las instrucciones o sentencias de control de flujo regulan el orden en que se ejecutan las instrucciones.

Bloques 

Un bloque es un grupo de cero o más instrucciones entre corchetes y puede ser utilizado en cualquier lugar que se permite una sola sentencia.

El ejemplo siguiente, BlockDemo, ilustra el uso de bloques:

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

boolean condition = true; if (condition) { // comienza el bloque 1 System.out.println("Condition is true."); } // finaliza el bloque 1 else { // comienza el bloque 2 System.out.println("Condition is false."); } // finaliza el bloque 2 } }

Preguntas y ejercicios: expresiones, instrucciones y bloques Preguntas 1. 2. 3. 4.

Los operadores pueden utilizarse en la construcción de ___, que computan los valores. Las expresiones son los componentes básicos de ___. Las instrucciones pueden agruparse en ___. El siguiente fragmento de código es un ejemplo de una expresión ___.

5. 1 * 2 * 3 6. Las instrucciones son más o menos equivalentes a las oraciones en lenguas naturales, pero en lugar de acabar con un punto, una instrucción termina con un ___. 7. Un bloque es un grupo de cero o más instrucciones entre ___ y puede ser utilizado en cualquier lugar que se permite una sola sentencia.

Ejercicios Identifique los siguientes tipos de instrucciones de expresión:

   

aValue = 8933.234; aValue++; System.out.println("Hello World!"); Bicycle myBike = new Bicycle();

Instrucciones de control de flujo Las instrucciones dentro de los archivos fuente generalmente se ejecutan de arriba hacia abajo, en el orden en que aparecen. Sin embargo, en las instrucciones del control de flujo, la ruptura del flujo de ejecución mediante el empleo de toma de decisiones, bucles y ramificaciones, permite a su programa condicionar la ejecución de determinados bloques de código. Esta sección describe las instrucciones para la toma de decisiones:   

if-then if-then-else switch

Instrucciones de bucle:   

for while do-while

Instrucciones de ramificación:   

break continue return

Las instrucciones if-then e if-then-else La instrucción if-then La instrucción if-then es la más básica de todas las instrucciones de control de flujo. 

Le dice a su programa que ejecute una determinada sección de código sólo si una determinada prueba se evalúa como true.

Por ejemplo, la clase Bicycle podría permitir a los frenos disminuir la velocidad de la bicicleta solamente si la bicicleta ya está en marcha. Una posible implementación del método applyBrakes podría ser como sigue:

void applyBrakes() { // la cláusula "if": la bicicleta debe estar en movimiento if (isMoving){ // la cláusula "then": disminuir la velocidad actual currentSpeed--; } } Si esta prueba se evalúa como false (es decir, que la bicicleta no está en movimiento), el control salta hasta el final de la instrucción if-then. Además, la apertura y cierre de llaves son opcionales, siempre que la cláusula "then" contenga solamente una instrucción:

void applyBrakes() { // lo mismo que el anterior, pero sin llaves if (isMoving) currentSpeed--; } Decidir cuándo omitir las llaves es una cuestión de gusto personal. Omitirlos puede hacer el código más frágil. Si una segunda instrucción más tarde se añade a la cláusula "then", un error común sería olvidar añadir las llaves recién requeridas. El compilador no puede detectar este tipo de error; sólo obtendrá resultados equivocados.

La instrucción if-then-else 

La instrucción if-then-else proporciona un camino secundario a la ejecución cuando una cláusula "if" se evalúa como false.

Puedes usar una instrucción if-then-else en el método applyBrakes para tomar medidas si se aplican los frenos cuando la bicicleta no está en movimiento. En este caso, la acción es simplemente imprimir un mensaje de error indicando que ya se ha detenido la bicicleta.

void applyBrakes() { if (isMoving) { currentSpeed--; } else { System.err.println("The bicycle has already stopped!"); } } El siguiente programa, IfElseDemo, asigna una calificación basada en el valor de una prueba: una A para una calificación de 90% o superior, una B por una puntuación de 80% o superior y así sucesivamente.

class IfElseDemo { public static void main(String[] args) { int testscore = 76; char grade; if (testscore >= 90) { grade = 'A'; } else if (testscore >= 80) grade = 'B'; } else if (testscore >= 70) grade = 'C'; } else if (testscore >= 60) grade = 'D'; } else { grade = 'F'; } System.out.println("Grade =

{ { {

" + grade);

} } La salida del programa es:

Grade = C Usted puede haber notado que el valor de testscore puede satisfacer más de una expresión en la declaración compuesta: 76 >= 70 y 76 >= 60. Sin embargo, una vez que se satisface una condición, se ejecutan las instrucciones apropiadas (grade = 'C';) y no se evalúan las condiciones restantes.

La instrucción switch A diferencia de las instrucciones if-then e if-then-else,  

La instrucción switch puede tener un número de posibles rutas de ejecución. Un switch trabaja con byte, short, char y tipos de datos primitivos int.

También funciona con tipos enumerados (discutido en Tipos Enum), la clase String y algunas clases especiales que contienen ciertos tipos primitivos: Character, Byte, Short e Integer (discutido en números y cadenas).

La sentencia break lo lleva a la siguiente sentencia ejecutable fuera del bloque en el que se ubica. El ejemplo de código siguiente, SwitchDemo, declara un int llamado month cuyo valor representa un mes. El código muestra el nombre del mes, basándose en el valor del month, mediante la instrucción switch.

public class SwitchDemo { public static void main(String[] args) { int month = 8; String monthString; switch (month) { case 1: monthString break; case 2: monthString break; case 3: monthString break; case 4: monthString break; case 5: monthString break; case 6: monthString break; case 7: monthString break; case 8: monthString break; case 9: monthString break; case 10: monthString break;

= "January"; = "February"; = "March"; = "April"; = "May"; = "June"; = "July"; = "August"; = "September"; = "October";

case 11: monthString = "November"; break; case 12: monthString = "December"; break; default: monthString = "Invalid month"; break; } System.out.println(monthString); } } En este caso, August se imprime a la salida estándar. 

El cuerpo de una instrucción switch es conocido como bloque del switch.

Una instrucción en el bloque del switch puede etiquetarse con una o más etiquetas de case o default. 

La instrucción switch evalúa la expresión, luego ejecuta todas las instrucciones que le siguen a la correspondiente etiqueta case.

También se puede mostrar el nombre del mes con declaraciones if-then-else :

int month = 8; if (month == 1) { System.out.println("January"); } else if (month == 2) { System.out.println("February"); } ... // y asi… Decidir si utilizar la instrucción if-then-else o una instrucción switch se basa en la legibilidad y la expresión que está probando la instrucción.  

Una instrucción if-then-else puede probar expresiones basadas en rangos de valores o condiciones. Una declaración switch prueba expresiones basadas solamente en un único número entero, valor enumerado u objeto String.

Otro punto de interés es la instrucción break. 

Cada instrucción break termina la instrucción switch en la que se encuentra.

El Flujo de control continúa con la primera instrucción que sigue en el bloque switch. Las instrucciones de break son necesarias porque sin ellas, las instrucciones dentro del bloque switch fracasan: todas las instrucciones después de la correspondiente etiqueta del case son ejecutadas en secuencia, independientemente de la expresión de etiquetas posteriores case, hasta que se encuentre una instrucción break. El programa SwitchDemoFallThrough muestra las instrucciones en un bloque switch que fracasan. El programa muestra el mes correspondiente al número entero month y los meses que siguen en el año:

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

java.util.ArrayList futureMonths = new java.util.ArrayList(); int month = 8; switch (month) { case 1: futureMonths.add("January"); case 2: futureMonths.add("February"); case 3: futureMonths.add("March"); case 4: futureMonths.add("April"); case 5: futureMonths.add("May"); case 6: futureMonths.add("June"); case 7: futureMonths.add("July"); case 8: futureMonths.add("August"); case 9: futureMonths.add("September"); case 10: futureMonths.add("October"); case 11: futureMonths.add("November"); case 12: futureMonths.add("December"); break; default: break; } if (futureMonths.isEmpty()) { System.out.println("Invalid month number"); } else { for (String monthName : futureMonths) { System.out.println(monthName); } } } } Esta es la salida del código:

August September October November December Técnicamente, el break final no es necesario porque el flujo cae fuera de la declaración switch. Es recomendable utilizar un break para que modificar el código sea más fácil y menos propenso a errores. 

La sección default se encarga de todos los valores que no son explícitamente manejados por una de las secciones del case.

SwitchDemo2, el siguiente ejemplo de código muestra cómo una declaración puede tener varias etiquetas de case. El ejemplo de código calcula el número de días en un mes determinado:

class SwitchDemo2 { public static void main(String[] args) { int month = 2; int year = 2000; int numDays = 0;

switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDays = 31; break; case 4: case 6: case 9: case 11: numDays = 30; break; case 2: if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)) numDays = 29; else numDays = 28; break; default: System.out.println("Invalid month."); break; } System.out.println("Number of Days = " + numDays); } } Esta es la salida del código:

Number of Days = 29

El uso de Strings en la instrucción switch En Java SE 7 y versiones posteriores, puede utilizar un objeto String en la expresión de la instrucción switch. El ejemplo de código siguiente, StringSwitchDemo, muestra el número del mes basándose en el valor de la String denominada month:

public class StringSwitchDemo { public static int getMonthNumber(String month) { int monthNumber = 0; if (month == null) { return monthNumber; } // toLowerCase convierte en minuscula switch (month.toLowerCase()) { case "january": monthNumber = 1;

break; case "february": monthNumber = break; case "march": monthNumber = break; case "april": monthNumber = break; case "may": monthNumber = break; case "june": monthNumber = break; case "july": monthNumber = break; case "august": monthNumber = break; case "september": monthNumber = break; case "october": monthNumber = break; case "november": monthNumber = break; case "december": monthNumber = break; default: monthNumber = break;

2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 0;

} return monthNumber; } public static void main(String[] args) { String month = "August"; int returnedMonthNumber = StringSwitchDemo.getMonthNumber(month); if (returnedMonthNumber == 0) { System.out.println("Invalid month"); } else { System.out.println(returnedMonthNumber); } } } La salida de este código es 8. La String en la expresión switch se compara con las expresiones asociadas con la etiqueta de cada case como si se utilizara el método String.equals. A fin de que el ejemplo

StringSwitchDemo acepte cualquier mes independientemente del caso, month se convierte en minúscula (con el método toLowerCase) y todas las cadenas asociadas con el case son etiquetas en minúsculas. Nota: este ejemplo comprueba si la expresión en la instrucción switch es null. Asegúrese de que la expresión en cualquier instrucción switch no es null para impedir que una NullPointerException sea lanzada.

Las instrucciones while y do-while 

La instrucción ciclica while continuamente ejecuta un bloque de instrucciones mientras una condición particular es true.

Su sintaxis puede expresarse como:

while (expresión) { instrucción(es) }   

La instrucción while evalúa la expresión, que debe devolver un valor boolean. Si la expresión se evalúa como true, la instrucción while ejecuta la instrucción(es) en el bloque de while. La instrucción while continúa probando la expresión y ejecutando su bloque hasta que la expresión se evalúa como false.

Se logra mediante la instrucción while imprimir los valores del 1 al 10 como en el siguiente programa WhileDemo:

class WhileDemo { public static void main(String[] args){ int count = 1; while (count < 11) { System.out.println("Count is: " + count); count++; } } } Puede implementar un bucle infinito mediante la instrucción while como sigue:

while (true){ // aqui va tu codigo } El lenguaje de programación Java también proporciona una instrucción do-while, que puede expresarse de la siguiente manera:

do { instrucción(es) // las instrucciones se ejecutan al menos una vez } while (expresión);



La diferencia entre do-while y while es que do-while evalúa su expresión en la parte inferior del bucle en lugar de la parte superior. Por lo tanto, las instrucciones dentro del bloque do siempre se ejecutan al menos una vez.

Como se muestra en el siguiente programa DoWhileDemo:

class DoWhileDemo { public static void main(String[] args){ int count = 1; do { System.out.println("Count is: " + count); count++; } while (count < 11); } }

La instrucción for 

La instrucción cíclica for proporciona una forma compacta para iterar sobre un rango de valores.

Los programadores a menudo se refieren a él como el "for loop" debido a la forma en la cual el bucle se repite hasta que se satisface una condición particular. La forma general de la instrucción for puede expresarse de la siguiente manera:

for (inicialización; terminación; incremento) { instrucción(es) } Cuando use esta versión de la instrucción for, tenga en cuenta que:



La expresión inicialización, inicializa el bucle; se ejecuta una vez, cuando comienza el bucle. Cuando la expresión terminación se evalúa como false, finaliza el bucle. La expresión de incremento se invoca después de cada iteración a través del bucle; es perfectamente aceptable para esta expresión incrementar o disminuir un valor.

 

El siguiente programa, ForDemo, utiliza la forma general de la instrucción for para imprimir los números del 1 al 10 a la salida estándar:

class ForDemo { public static void main(String[] args){ for(int i = 1; i < 11; i++){ System.out.println("Count is: " + i); } } } La salida de este programa es:

Count is: 1

Count Count Count Count Count Count Count Count Count

is: is: is: is: is: is: is: is: is:

2 3 4 5 6 7 8 9 10

Observe cómo el código declara una variable dentro de la expresión de inicialización. El alcance de esta variable se extiende desde su declaración hasta el final del bloque regido por la instrucción for, así que puede ser utilizado en las expresiones de terminación y de incremento. Si la variable que controla una instrucción for no es necesaria fuera del bucle, es mejor declarar la variable en la expresión de inicialización. 

Los nombres i, j y k se utilizan para el control de los bucles for; declarándolos dentro de la expresión de inicialización limita su vida útil y reduce errores.

Las tres expresiones del bucle for son opcionales; se puede crear un bucle infinito de la siguiente manera:

// loop infinito for ( ; ; ) { // your code goes here } La instrucción for también tiene otra forma diseñada por iteración a través de colecciones y arreglos de esta forma se refiere a veces como 

Instrucción for mejorado y puede ser utilizada para hacer los bucles más compactos y fáciles de leer.

for (parametro : nombrearreglo) { instrucción(es) } Para demostrarlo, considere la siguiente matriz, que contiene los números del 1 al 10:

int[] numbers = {1,2,3,4,5,6,7,8,9,10}; El siguiente programa, EnhancedForDemo, utiliza el bucle for mejorado a través de la matriz:

class EnhancedForDemo { public static void main(String[] args){ int[] numbers = {1,2,3,4,5,6,7,8,9,10}; for (int item : numbers) { System.out.println("Count is: " + item); } } }

En este ejemplo, la variable item retiene el valor actual de la matriz de números. La salida de este programa es la misma que antes:

Count Count Count Count Count Count Count Count Count Count 

is: is: is: is: is: is: is: is: is: is:

1 2 3 4 5 6 7 8 9 10

Se recomienda utilizar este forma de instrucción for en vez de la forma general siempre que sea posible.

Instrucciones de ramificación La instrucción break 

La instrucción break tiene dos formas: con etiqueta y sin etiqueta.

Viste la forma sin etiqueta en la discusión anterior de la instrucción switch. También puede utilizar una etiqueta break para terminar un bucle for, while, o do-while, como se muestra en el siguiente programa BreakDemo:

class BreakDemo { public static void main(String[] args) { int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 }; int searchfor = 12; int i; boolean foundIt = false; for (i = 0; i < arrayOfInts.length; i++) { if (arrayOfInts[i] == searchfor) { foundIt = true; break; } } if (foundIt) { System.out.println("Found " + searchfor + " at index " + i); } else { System.out.println(searchfor + " not in the array"); } } }

Este programa busca el número 12 en una matriz. La instrucción break, que se muestra en negrita, finaliza el bucle for cuando se encuentra ese valor. Luego el flujo de control se transfiere después del bucle for. La salida de este programa es:

Found 12 at index 4 

Una instrucción break sin etiqueta termina las instrucciones switch, for, while, o dowhile mas internas. Un break con etiqueta termina una instrucción externa.



El siguiente programa, BreakWithLabelDemo, es similar al programa anterior, pero utiliza bucles for anidados para buscar un valor en una matriz bidimensional. 

Cuando el valor se encuentra, un break con etiqueta finaliza el bucle for externo (etiquetado como " search "):

class BreakWithLabelDemo { public static void main(String[] args) { int[][] arrayOfInts = { { 32, 87, 3, 589 }, { 12, 1076, 2000, 8 }, { 622, 127, 77, 955 } }; int searchfor = 12; int i; int j = 0; boolean foundIt = false; search: for (i = 0; i < arrayOfInts.length; i++) { for (j = 0; j < arrayOfInts[i].length; j++) { if (arrayOfInts[i][j] == searchfor) { foundIt = true; break search; } } } if (foundIt) { System.out.println("Found " + searchfor + " at " + i + ", " + j); } else { System.out.println(searchfor + " not in the array"); } } } Ésta es la salida del programa.

Found 12 at 1, 0

La instrucción break termina la instrucción etiquetada; No transfiere el flujo de control a la etiqueta. El Flujo se transfiere a la instrucción que sigue inmediatamente a la instrucción con etiqueta (finalizada).

La instrucción continue 

La instrucción continue salta la iteración actual de un bucle for, while, o dowhile.

La forma sin etiqueta salta al final del cuerpo del bucle más interno y evalúa la expresión boolean que controla el bucle. El siguiente programa, ContinueDemo, pasa a través de una String, contando las ocurrencias de la letra "p". Si el carácter actual no es una p, la declaración continue omite el resto del bucle y procede al siguiente carácter. Si es una "p", el programa incrementa el contador de letra.

class ContinueDemo { public static void main(String[] args) { String searchMe = "peter piper picked a " + "peck of pickled peppers"; int max = searchMe.length(); int numPs = 0; for (int i = 0; i < max; i++) { // interesado solo en p's if (searchMe.charAt(i) != 'p') continue; // procesa p's numPs++; } System.out.println("Found " + numPs + " p's in the string."); } } Aquí está la salida de este programa:

Found 9 p's in the string. Para ver este efecto con más claridad, intente quitar la declaración continue y vuelva a compilar. Cuando se ejecuta el programa otra vez, la cuenta será incorrecta, diciendo que ha encontrado 35 p en lugar de 9. Una instrucción con etiqueta continue salta la iteración actual de un bucle externo marcado con la etiqueta dada. El siguiente programa de ejemplo, ContinueWithLabelDemo, utiliza bucles anidados para buscar una subcadena dentro de otra cadena. Se necesitan dos bucles anidados:

 

uno para iterar sobre la subcadena uno para iterar sobre la cadena en donde vamos a buscar.

El siguiente programa, ContinueWithLabelDemo, usa la forma etiquetada de continue para saltar una iteración en el bucle externo.

class ContinueWithLabelDemo { public static void main(String[] args) { String searchMe = "Look for a substring in me"; String substring = "sub"; boolean foundIt = false; int max = searchMe.length() substring.length(); test: for (int i = 0; i = 0) if (aNumber == 0) System.out.println("first string"); else System.out.println("second string"); System.out.println("third string"); a.

¿Qué salida crees que el código producirá si aNumber es 3?

b.

c. d.

Practicas.

Escribe un programa de prueba que contenga el fragmento de código anterior; hacer aNumber 3. ¿Cuál es la salida del programa? ¿Es lo que has predicho? Explicar por qué la salida es lo que es; en otras palabras, ¿cuál es el flujo de control para el fragmento de código? Usando sólo espacios y saltos de línea, reformatear el fragmento de código para que el flujo de control sea fácil de entender. Utilice llaves, { y }, para clarificar el código.

Lección: Clases y objetos Con el conocimiento que ahora tiene de los fundamentos del lenguaje de programación Java, puede aprender a escribir sus propias clases. En esta lección, encontrará información sobre cómo definir sus propias clases, incluyendo declarar miembros, variables, métodos y constructores. Aprenderá a utilizar las clases para crear objetos y cómo utilizar los objetos que crea. Esta lección cubre también clases anidadas dentro de otras clases y enumeraciones.

Clases Esta sección le muestra la anatomía de una clase y cómo declarar campos, métodos y constructores.

Objetos Esta sección cubre la creación y uso de objetos. Usted aprenderá a crear una instancia de un objeto y, una vez instanciado, cómo se utiliza el operador dot para acceder a las variables de instancia y métodos del objeto.

Más tipos Esta sección cubre más aspectos de las clases que dependen del uso de referencias a objetos y sobre el operador dot que has aprendido en la sección anterior: devolver valores desde los métodos, la palabra clave this, clase vs. miembros de instancia y control de acceso.

Clases anidadas Clases anidadas estáticas anónimas internas, clases, clases locales están cubiertas. También hay una discusión sobre cuándo utilizar este enfoque.

Tipos de enumeración Esta sección cubre las enumeraciones, clases especializadas que le permiten definir y utilizar conjuntos de constantes.

Clases La introducción a los conceptos de orientación a objetos en la lección titulada Conceptos de programación orientada a objetos utiliza una clase de bicicleta como ejemplo, con bicicletas de carreras, bicicletas de montaña y bicicletas tándem como subclases. Aquí está el código del ejemplo para una posible implementación de una clase de Bicycle, para darle una visión general de una declaración de clase. Las secciones posteriores de esta lección retroceden y explican las declaraciones de clase paso a paso. Por el momento, no se preocupe por los detalles.

public class Bicycle { // la clase Bicycle tiene // tres campos

public int cadence; public int gear; public int speed; // la clase Bicycle tiene // un constructor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } // la clase Bicycle tiene // cuatro métodos public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } } Una declaración de clase para una clase de MountainBike que es una subclase de la Bicycle podría verse así:

public class MountainBike extends Bicycle { // la subclase MountainBike tiene // un campo public int seatHeight; // la subclase MountainBike tiene // un constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight = startHeight; } // la subclase MountainBike tiene // un método public void setHeight(int newValue) { seatHeight = newValue; } } MountainBike hereda todos los campos y métodos de Bicycle y agrega el campo seatHeight y un método para configurarlo (las bicicletas de montaña tienen asientos que se pueden mover hacia arriba y hacia abajo según la demanda de terreno).

Declarar Clases Has visto clases definidas de la siguiente manera:

class MyClass { // declaraciones de métodos, // campos y constructores } Esto es una declaración de clase. El cuerpo de la clase (el área entre las llaves) contiene todo el código que se proporciona para el ciclo de vida de los objetos creados de la clase:   

constructores para inicializar nuevos objetos, las declaraciones de los campos que proporcionan el estado de la clase y de sus objetos, y métodos para implementar el comportamiento de la clase y de sus objetos.

La declaración de clase anterior es mínima. Contiene sólo aquellos componentes de una declaración de clase que se requieren. Puede proporcionar más información acerca de la clase, como el  

nombre de su superclase, si implementa cualquier interface

y así sucesivamente, en el inicio de la declaración de clase. Por ejemplo,

class MyClass extends MySuperClass implements YourInterface { // declaraciones de métodos, // campos y constructores } significa que MyClass es una subclase de MySuperClass y que implementa la interfaz YourInterface . También puede agregar modificadores como público o privado al principio — así que puedes ver que la primera línea de una declaración de clase puede ser bastante complicada. Los modificadores público y privada, que determinan qué otras clases pueden acceder MyClass, se discuten más adelante en esta lección. La lección de las interfaces y la herencia le explicarán cómo y por qué utilizaría las palabras clave extends e implements en una declaración de clase. Por el momento no necesitas preocuparte por estas complicaciones adicionales. En general, las declaraciones de clase pueden incluir estos componentes: 1. 2.

Modificadores como public, private y otros que encontrará más adelante. El nombre de clase, con la letra inicial mayuscula por la Convención.

3. 4.

5.

El nombre de las clases padres (superclase), si es el caso, va precedido por la palabra clave extends. Una clase (subclase) puede solamente extender de un padre. Una lista separada por comas de interfaces implementadas por la clase, si los hubiere, precedido por la palabra clave implements. Una clase puede implementar más de una interfaz. El cuerpo de la clase, rodeado de llaves, { }.

Declarar las Variables miembro Existen varios tipos de variables:

  

Las variables miembro en una clase — se denominan campos. Las variables en un método o bloque de código, se denominan variables locales. Las variables en las declaraciones de métodos — se denominan parámetros.

La clase Bicycle utiliza las siguientes líneas de código para definir sus campos:

public int cadence; public int gear; public int speed; Las declaraciones de campos se componen de tres componentes, en orden: 1. 2. 3.

Cero o más modificadores, como public o private. El tipo del campo. El nombre del campo.

Los campos de Bicycle se denominan cadence, gear y speed y son todos datos de tipo integer (int). 

La palabra clave public identifica estos campos como miembros públicos, accesibles por cualquier objeto que pueda acceder a la clase.

Modificadores de acceso El primer modificador (extremo izquierdo) utilizado le permite controlar qué otras clases tienen acceso a un campo miembro. Por el momento, considere sólo public y private. Otros modificadores de acceso se discutirán más adelante.

 

modificador public — el campo es accesible desde todas las clases. modificador private — el campo es accesible solamente dentro de su propia clase.

En el espíritu de encapsulación, es común hacer los campos privados. Esto significa que sólo se puede acceder directamente desde la clase Bicycle. Sin embargo, sí todavía necesitamos acceso a estos valores: 

puede acceder indirectamente mediante la adición de métodos públicos que obtengan los valores de los campos para nosotros:

public class Bicycle { private int cadence; private int gear; private int speed; public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } public int getCadence() { return cadence; } public void setCadence(int newValue) { cadence = newValue; } public int getGear() { return gear; } public void setGear(int newValue) { gear = newValue; } public int getSpeed() { return speed; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } }

Tipos Todas las variables deben tener un tipo.  

Puede utilizar los tipos primitivos como int, float, boolean, etc. puede utilizar los tipos de referencia, tales como cadenas, arreglos u objetos.

Nombres de variables Todas las variables, ya sean campos, variables locales o parámetros, siguen las mismas reglas de nomenclatura y convenciones que se cubrieron en la lección de lenguaje básico, Variables — Nomenclatura. En esta lección, tenga en cuenta de que las mismas reglas de nomenclatura y convenciones se utilizan en los nombres de métodos y clases, excepto que

 

debe escribirse con mayúscula la primera letra de un nombre de clase, y la primera (o única) palabra en un nombre de método debe ser un verbo.

Definir Métodos Aquí está un ejemplo típico de una declaración de método:

public double calculateAnswer(double wingSpan, int numberOfEngines, double length, double grossTons) { // hacer el cálculo aquí } Los únicos elementos necesarios de una declaración de método son    

el tipo de retorno del método, nombre, un par de paréntesis () y un cuerpo entre llaves, {}.

Más generalmente, las declaraciones de métodos tienen seis componentes, en orden: 1. 2. 3. 4.

5. 6.

Modificadores — como public, private y otros que aprenderás más adelante. El tipo de retorno: el tipo de dato del valor devuelto por el método, o void si el método no devuelve un valor. El nombre del método — las reglas para nombres de campo se aplican a los nombres de los métodos también, pero la convención es un poco diferente. La lista de parámetros entre paréntesis — una lista delimitada por comas de parámetros de entrada, precedidos por sus tipos de datos, encerrado entre paréntesis, (). Si no hay parámetros, debe utilizar paréntesis vacíos. Una lista de excepciones, que se discutirá más adelante. El cuerpo del método, encerrado entre llaves — el código del método, incluyendo la declaración de variables locales, van aquí.

Los modificadores, tipos de retorno y los parámetros serán discutidos más adelante en esta lección. Las excepciones son discutidas en una lección posterior.

Definición: Dos de los componentes de una declaración de método comprenden la firma del método— el nombre del método y los tipos de parámetro.

La firma del método declarado anteriormente es:

calculateAnswer(double, int, double, double)

Nombrando un método Aunque un nombre de método puede ser cualquier identificador legal, las convenciones de código restringen los nombres de métodos. Por Convención, los nombres de métodos deben ser un verbo en minúscula o un nombre de varias palabras que comiencen con un verbo en minúsculas, seguido de adjetivos, sustantivos, etc. En los nombres de varias palabras, la primera letra de cada segunda y siguientes palabras debe escribirse con mayúscula. Estos son algunos ejemplos:

run

runFast getBackground getFinalData compareTo setX isEmpty Típicamente, un método tiene un nombre único en su clase. Sin embargo, un método podría tener el mismo nombre que otros métodos debido a la sobrecarga de método.

Sobrecarga de métodos El lenguaje de programación Java soporta Métodos de Sobrecarga y Java puede distinguir entre los métodos con diferentes firmas de métodos. Esto significa que los métodos dentro de una clase pueden tener el mismo nombre si tienen listas de parámetros diferentes (hay algunos requisitos a esto que serán discutidos en la lección titulada "Interfaces y herencia"). Supongamos que tiene una clase que puede utilizar la caligrafía para dibujar distintos tipos de datos (cadenas, enteros y así sucesivamente) y que contiene un método para la elaboración de cada tipo de datos. Es incómodo usar un nombre nuevo para cada método — por ejemplo, drawString, drawInteger, drawFloaty así sucesivamente. En el lenguaje de programación Java, usted puede utilizar el mismo nombre para todos los métodos de dibujo pero pase una lista de argumentos diferentes para cada método. Por lo tanto, la clase de dibujo de datos podría declarar cuatro métodos denominados draw, cada uno de ellos tiene una lista de parámetros diferentes.

public class DataArtist { ... public void draw(String ... } public void draw(int i) ... } public void draw(double ... } public void draw(int i, ... } }

s) { { f) { double f) {

Los métodos sobrecargados se diferencian por la cantidad y el tipo de los argumentos que se pasan al método. En el código de muestra, draw(String s) y draw(int i) son métodos distintos y únicos porque requieren diferentes tipos de argumentos. No se puede declarar más de un método con el mismo nombre y el mismo número y tipo de argumentos, ya que el compilador no puede distinguirlos. El compilador no considera el tipo de retorno al diferenciar los métodos, por lo que no puede declarar dos métodos con la misma firma, incluso si tienen un tipo de retorno diferente.

Nota: Los Métodos sobrecargados deben ser usados con moderación, ya que pueden hacer el código mucho menos legible.

Proporcionar constructores para tus clases

Una clase contiene constructores que se invocan para crear objetos desde la clase modelo o plantilla. Las declaraciones de los constructores parecen declaraciones de métodos — excepto que utilizan el nombre de la clase y no tienen tipo de retorno. Por ejemplo, Bicycle tiene un constructor:

public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } Para crear un nuevo objeto Bicycle llamado myBike, se llama a un constructor por el operador new:

Bicycle myBike = new Bicycle(30, 0, 8); new Bicycle(30, 0, 8) crea el espacio en la memoria para el objeto e inicializa sus campos. Aunque Bicycle solamente tiene un constructor, podría tener otros, incluyendo a un constructor sin argumentos:

public Bicycle() { gear = 1; cadence = 10; speed = 0; } Bicycle yourBike = new Bicycle(); invoca el constructor sin-argumentos para crear un nuevo objeto Bicycle llamado yourBike. Ambos constructores se pueden haber declarado en Bicycle porque tienen listas de argumentos diferentes. Como con los métodos, la plataforma Java distingue los constructores sobre la base de la cantidad de argumentos en la lista y sus tipos. No puedes escribir dos constructores que tienen el mismo número y tipo de argumentos para la misma clase, porque la plataforma no sería capaz de distinguirlos. Si lo hace, provoca un error en tiempo de compilación. No tiene que proporcionar ningun constructor para la clase, pero debe tener cuidado al hacerlo. El compilador proporciona automáticamente un constructor por default sinargumentos, para cualquier clase sin constructores. Este constructor predeterminado llamará al constructor sin-argumentos de la superclase. En esta situación, el compilador se quejará si la superclase no tiene un constructor sin-argumentos por lo que debe comprobar que lo tiene. Si tu clase no tiene una superclase explícita, entonces tiene una superclase implícita del Object, que tiene un constructor sin-argumentos Usted puede utilizar un constructor de la superclase. La clase MountainBike al principio de esta lección así lo hizo. Esto se discutirá más adelante, en la lección de las interfaces y la herencia. Usted puede utilizar modificadores de acceso en la declaración de un constructor para controlar qué otras clases pueden llamar al constructor.

Nota: Si otra clase no puede llamar al constructor de MyClass, no puede crear directamente objetos MyClass.

Pasar información a un método o a un Constructor

La declaración de un método o un constructor declara el número y el tipo de los argumentos para el método o constructor. Por ejemplo, el siguiente es un método que calcula los pagos mensuales para un préstamo hipotecario, basado en la cantidad de préstamo, la tasa de interés, la duración del préstamo (el número de períodos) y el valor futuro del préstamo:

public double computePayment( double loanAmt, double rate, double futureValue, int numPeriods) { double interest = rate / 100.0; double partial1 = Math.pow((1 + interest), - numPeriods); double denominator = (1 - partial1) / interest; double answer = (-loanAmt / denominator) - ((futureValue * partial1) / denominator); return answer; } Este método tiene cuatro parámetros: el monto del préstamo, la tasa de interés, el valor futuro y el número de períodos. Los tres primeros son números de punto flotante de precisión doble, y la cuarta es un entero. Los parámetros se utilizan en el cuerpo del método y en tiempo de ejecución tomarán los valores de los argumentos que se pasaron dentro.

Nota: Los parámetros se refieren a la lista de variables en una declaración de método. Los argumentos son los valores reales que se pasan cuando se invoca el método. Cuando se invoca un método, los argumentos utilizados deben coincidir con los parámetros de la declaración de tipo y orden.

Tipos de parámetros Puede utilizar cualquier tipo de dato para un parámetro de un método o un constructor. Esto incluye tipos de datos primitivos, como doubles, floats, e integers, como viste en el método computePayment y tipos de datos de referencia, tales como objetos y arreglos. Aquí hay un ejemplo de un método que acepta un arreglo como argumento. En este ejemplo, el método crea un objeto nuevo Polygon y lo Inicializa desde un arreglo de objetos Point (asuma que Point es una clase que representa una coordenada x, y):

public Polygon polygonFrom(Point[] corners) { // el cuerpo del método va aqui } Nota: Si quieres pasar un método dentro de un método, utilice una expresión lambda o un método de Referencia.

Número arbitrario de argumentos Puede utilizar un constructor denominado varargs para pasar un número arbitrario de valores a un método. Usas varargs cuando no sabes cuantos de un tipo determinado de argumento se pasarán al método. Es un atajo para crear una matriz manualmente (del método anterior podría haber utilizado varargs en lugar de una matriz). Para usar varargs, sigues el tipo del último parámetro con puntos suspensivos (tres puntos,...), y luego un espacio, y el nombre del parámetro. Entonces puede llamarse al método con cualquier cantidad de ese parámetro, incluyendo ninguno.

public Polygon polygonFrom(Point... corners) { int numberOfSides = corners.length; double squareOfSide1, lengthOfSide1; squareOfSide1 = (corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) + (corners[1].y - corners[0].y) * (corners[1].y - corners[0].y); lengthOfSide1 = Math.sqrt(squareOfSide1); // más codigo del cuerpo del método que sigue creando y // retornando un polygon que conecta los Points } Puedes ver que, dentro del método, corners es tratado como una matriz. Puede llamar al método con una matriz o con una serie de argumentos. El código en el cuerpo del método tratará el parámetro como un arreglo en cualquiera de los casos. Comúnmente se verá varargs con los métodos de impresión; por ejemplo, este método printf :

public PrintStream printf(String format, Object... args) le permite imprimir un número arbitrario de objetos. Puede ser llamado así:

System.out.printf("%s: %d, %s%n", name, idnum, address); o como esta

System.out.printf("%s: %d, %s, %s, %s%n", name, idnum, address, phone, email); o con todavía un número diferente de argumentos.

Nombres de parámetros Cuando se declara un parámetro a un método o un constructor, proporcionas un nombre para ese parámetro. Este nombre se utiliza en el cuerpo del método para referirse al argumento que se pasa dentro. El nombre de un parámetro debe ser único en su ámbito de aplicación. No puede ser el mismo que el nombre de otro parámetro para el mismo método o constructor, y no puede ser el nombre de una variable local dentro del método o constructor. Un parámetro puede tener el mismo nombre que uno de los campos de la clase. Si este es el caso, se dice del parámetro que sombrea al campo. Sombrear los campos puede dificultar leer su código y convencionalmente se utiliza solo dentro de los constructores y métodos que fijan un campo particular. Por ejemplo, considere la siguiente clase Circle y su método setOrigin :

public class Circle { private int x, y, radius; public void setOrigin(int x, int y) { ... } } La clase Circle tiene tres campos: x, y y radius. El método setOrigin tiene dos parámetros, cada uno de ellos tiene el mismo nombre como uno de los campos. Cada parámetro del método sombrea el campo que comparte su nombre. Así que usar los nombres simples x o y dentro del cuerpo del método hace referencia al parámetro, no al campo. Para acceder al campo, debe

utilizar un nombre cualificado. Esto será discutido más adelante en esta lección en la sección titulada "Usando la palabra clave this”.

Pasando argumentos de tipo de datos primitivo Los argumentos primitivos, como un int o double, se pasan a los métodos por valor. Esto significa que cualquier cambio en los valores de los parámetros existe sólo en el ámbito del método. Cuando el método devuelve, los parámetros se han ido y cualquier cambio en ellos se pierde. Aquí está un ejemplo:

public class PassPrimitiveByValue { public static void main(String[] args) { int x = 3; // invoca el passMethod() con // x como argumento passMethod(x); // imprime x para ver si este // valor ha cambiado System.out.println("Despues de invocar el passMethod, x = " + x); } // cambia el parametro en passMethod() public static void passMethod(int p) { p = 10; } } Cuando se ejecuta este programa, la salida es:

Despues de invocar el passMethod, x = 3

Pasando argumentos de tipo de datos de referencia Los parámetros de tipo de datos de referencia, tales como objetos, también se pasan a los métodos por valor. Esto significa que cuando el método devuelve, la referencia pasada dentro todavía hace referencia al mismo objeto que antes. Sin embargo, los valores de los campos del objeto se pueden cambiar en el método, si tienen el nivel de acceso adecuado. Por ejemplo, considere un método en una clase arbitraria que mueve objetos Circle:

public void moveCircle(Circle circle, int deltaX, int deltaY) { // código para mover el origen del círculo para x+deltaX, y+deltaY circle.setX(circle.getX() + deltaX); circle.setY(circle.getY() + deltaY); // código para asignar una nueva referencia al círculo circle = new Circle(0, 0); } Deja que el método se invoque con estos argumentos:

moveCircle(myCircle, 23, 56)

Dentro del método, circle inicialmente se refiere a myCircle. El método cambia las coordenadas x y y del objeto de esas referencias circle (es decir, myCircle) por 23 y 56, respectivamente. Estos cambios se mantendrán cuando el método devuelve. Entonces circle es asignado a una referencia a un objeto nuevo Circle con x = y = 0. Esta reasignación no tiene ninguna permanencia, sin embargo, debido a que la referencia fue pasada por su valor y no se puede cambiar. Dentro del método, el objeto apuntado por circle ha cambiado, pero, cuando el método devuelve, myCircle todavía hace referencia al mismo objeto Circle como antes de que se llamará al método.

Objetos Un típico programa Java crea muchos objetos, que como ya sabes, interactúan mediante la invocación de métodos. A través de estas interacciones del objeto, un programa puede realizar diversas tareas, como implementar un GUI, ejecutar una animación, o enviar y recibir información sobre una red. Una vez que un objeto ha completado el trabajo para el cual fue creado, sus recursos son reciclados para su uso por otros objetos. Aquí está un pequeño programa, llamado CreateObjectDemo, que crea tres objetos: un objeto Point y dos objetos Rectangle. Usted necesitará los tres archivos fuente completos para compilar este programa.

public class CreateObjectDemo { public static void main(String[] args) { // Declarar y crear un objeto punto y dos objetos rectángulo. Point originOne = new Point(23, 94); Rectangle rectOne = new Rectangle(originOne, 100, 200); Rectangle rectTwo = new Rectangle(50, 100); // muestra la anchura, altura y área de rectOne System.out.println("Width of rectOne: " + rectOne.width); System.out.println("Height of rectOne: " + rectOne.height); System.out.println("Area of rectOne: " + rectOne.getArea()); // fija la posición de rectTwo rectTwo.origin = originOne; // muestra la posición de rectTwo System.out.println("X Position of rectTwo: " + rectTwo.origin.x); System.out.println("Y Position of rectTwo: " + rectTwo.origin.y); // mueve a rectTwo y muestra su nueva posición rectTwo.move(40, 72); System.out.println("X Position of rectTwo: " + rectTwo.origin.x); System.out.println("Y Position of rectTwo: " + rectTwo.origin.y); } } Este programa crea, manipula y muestra información acerca de diversos objetos. Aquí está la salida:

Width of rectOne: 100

Height of rectOne: 200 Area of rectOne: 20000 X Position of rectTwo: Y Position of rectTwo: X Position of rectTwo: Y Position of rectTwo:

23 94 40 72

Las siguientes tres secciones utilizan el ejemplo anterior para describir el ciclo de vida de un objeto dentro de un programa. De ellos, aprenderá cómo escribir código que crea y utiliza los objetos en sus propios programas. También aprenderás cómo el sistema limpia después un objeto cuando su vida ha terminado.

Creación de objetos Como ya sabes, una clase proporciona el plan de acción para los objetos; crea un objeto de una clase. Cada una de las siguientes instrucciones extraídas del programa CreateObjectDemo crea un objeto y lo asigna a una variable:

Point originOne = new Point(23, 94); Rectangle rectOne = new Rectangle(originOne, 100, 200); Rectangle rectTwo = new Rectangle(50, 100); La primera línea crea un objeto de la clase Point, y la segunda y tercera línea crean cada una un objeto de la clase Rectangle. Cada una de estas instrucciones consta de tres partes (explicadas en detalle más abajo): 1. 2. 3.

Instrucción: el código en negrita son todas las declaraciones de variables que asocian un nombre de variable a un tipo de objeto. Instanciación o creación de instancias: la palabra clave new es un operador de Java que crea el objeto. Inicialización: el nuevo operador es seguido por una llamada a un constructor, que inicializa el objeto nuevo.

Declarar una Variable para hacer referencia a un objeto Previamente, aprendió que para declarar una variable, escribe el tipo y el nombre:

type name; Esto notifica al compilador que usará nombre para referirse a datos cuyo tipo es de un tipo de valor. Con una variable primitiva, esta instrucción también reserva la cantidad adecuada de memoria para la variable. También puede declarar una variable de referencia en su propia línea. Por ejemplo:

Point originOne; Si se declara originOne así, su valor será indeterminado hasta que un objeto es creado y asignado a él. Simplemente declarar una variable de referencia no crea un objeto. Por eso, tienes que utilizar el operador new, tal como se describe en la sección siguiente. Debe asignar un objeto a originOne antes de usarlo en su código. De lo contrario, obtendrá un error del compilador. Una variable en este estado, que actualmente hace referencia a ningún objeto, se puede ilustrar como sigue (nombre de la variable, originOne, además de una referencia apuntando a la nada):

Crear instancias de una clase El operador new crea una instancia de una clase por la asignación de memoria para un nuevo objeto y devuelve una referencia de esa memoria. El operador new también invoca el constructor del objeto.

Nota: La frase "crear instancias de una clase" significa lo mismo que "creando un objeto". Cuando crea un objeto, creará una "instancia" de una clase, por lo tanto es el "ejemplar" de una clase.

El operador new requiere un solo argumento postfijo: una llamada a un constructor. El nombre del constructor proporciona el nombre de la clase a instanciar. El operador new devuelve una referencia al objeto creado. Esta referencia es asignada a una variable del tipo adecuado, como:

Point originOne = new Point(23, 94); La referencia devuelta por el operador new no tiene que ser asignado a una variable. También puede utilizarse directamente en una expresión. Por ejemplo:

int height = new Rectangle().height; Esta declaración se discutirá en la próxima sección.

Inicializar un objeto Aquí está el código para la clase Point:

public class Point { public int x = 0; public int y = 0; //constructor public Point(int a, int b) { x = a; y = b; } } Esta clase contiene un único constructor. Puedes reconocer un constructor porque su instrucción utiliza el mismo nombre que la clase y no tiene ningún tipo de retorno. El constructor de la clase Point toma dos argumentos enteros, declarado por el código (int a, int b). La siguiente instrucción proporciona 23 y 94 como valores para esos argumentos:

Point originOne = new Point(23, 94); El resultado de la ejecución de esta instrucción puede ser ilustrado en la figura siguiente:

Aquí está el código de la clase Rectangle, que contiene cuatro constructores:

public class Rectangle { public int width = 0; public int height = 0; public Point origin; // cuatro constructores public Rectangle() { origin = new Point(0, 0); } public Rectangle(Point p) { origin = p; } public Rectangle(int w, int h) { origin = new Point(0, 0); width = w; height = h; } public Rectangle(Point p, int w, int h) { origin = p; width = w; height = h; } // un método para mover el rectangulo public void move(int x, int y) { origin.x = x; origin.y = y; } // un método para computar el área de un rectangulo public int getArea() { return width * height; } }

Cada constructor permite ofrecer valores iniciales para el origen del rectángulo, anchura y altura, usando ambos tipos primitivos y de referencia. Si una clase tiene varios constructores, deben tener diferentes firmas. El compilador de Java distingue los constructores basados en el número y el tipo de los argumentos. Cuando el compilador de Java se encuentra con el siguiente código, sabe llamar al constructor de la clase Rectangle que es el que requiere un argumento point seguido de dos argumentos enteros:

Rectangle rectOne = new Rectangle(originOne, 100, 200); Esto llama al constructor de Rectangle que inicializa origin a originOne. Además, el constructor establece el ancho (width), la altura (height) de 200 y 100. Ahora hay dos referencias al mismo objeto Point— un objeto puede tener múltiples referencias a ella, como se muestra en la siguiente figura:

La siguiente línea de código llama al constructor de Rectangle que requiere dos argumentos enteros, que proporcionan los valores iniciales para la anchura y altura. Si revisas el código en el constructor, verá que crea un nuevo objeto point cuyo x y valores y se inicializan con 0:

Rectangle rectTwo = new Rectangle(50, 100); El constructor de rectángulo utilizado en la instrucción siguiente no toma ningún argumento, así que se llama un constructor sin argumentos:

Rectangle rect = new Rectangle(); Todas las clases tienen al menos un constructor. Si una clase no declara explícitamente alguno, el compilador de Java proporciona automáticamente un constructor sin-argumentos, llamado constructor por default. Este constructor por default llama al constructor sinargumentos de la clase padre, o el constructor de Object si la clase no tiene ningún otro padre. Si los padres no tienen ningún constructor (Object tiene uno), el compilador rechazará el programa.

Uso de objetos Una vez que haya creado un objeto, probablemente quieras usarlo para algo. Puede necesitar usar el valor de uno de sus campos, cambiar uno de sus campos o llamar a uno de sus métodos para realizar una acción.

Referenciando a los campos de un objeto A los campos del objeto se accede por su nombre. Debe utilizar un nombre que no sea ambiguo.

Usted puede utilizar un nombre simple para un campo dentro de su propia clase. Por ejemplo, podemos agregar una instrucción dentro de la clase Rectangle que imprime la width (ancho) y la height (altura):

System.out.println("Width and height are: " + width + ", " + height); En este caso, width y height son nombres simples. El código que está fuera de la clase del objeto debe utilizar una referencia de objeto o expresión, seguido por el operador punto (.), seguido por un nombre de campo simple, como en:

objectReference.fieldName Por ejemplo, el código de la clase CreateObjectDemo está fuera del código de la clase Rectangle. Así que para hacer referencia a los campos de origin, width, y height dentro del objeto Rectangle llamado rectOne, la clase CreateObjectDemo debe usar los nombres rectOne.origin, rectOne.widthy rectOne.height, respectivamente. El programa utiliza dos de estos nombres para mostrar la width y la height de rectOne:

System.out.println("Width of rectOne: " + rectOne.width); System.out.println("Height of rectOne: " + rectOne.height); Intentar utilizar los nombres simples width y height del código en la clase CreateObjectDemo no tiene sentido — esos campos existen solamente dentro de un objeto — y resulta en un error del compilador. Más tarde, el programa utiliza código similar para mostrar información sobre rectTwo. Los objetos del mismo tipo tienen su propia copia de los mismos campos de instancia. De este modo, cada objeto rectangle tiene campos llamados origin, width y height. Cuando usted accede a un campo de instancia a través de una referencia al objeto, se refiere al campo del objeto particular. Los dos objetos rectOne y rectTwo en el programa de CreateObjectDemo tienen diferentes campos de origin, width y height. Para acceder a un campo, puede utilizar una referencia con nombre a un objeto, como en los ejemplos anteriores, o se puede utilizar cualquier expresión que devuelve una referencia al objeto. Recordemos que el operador new devuelve una referencia a un objeto. Así que se puede utilizar el valor devuelto por new para acceder a los campos de un objeto nuevo:

int height = new Rectangle().height; Esta instrucción crea un nuevo objeto rectángulo e inmediatamente obtiene su altura. En esencia, la instrucción determina la altura por defecto de un rectángulo. Tenga en cuenta que después de que esta instrucción ha sido ejecutada, el programa ya no tiene una referencia al rectángulo creado, debido a que el programa no almacena la referencia en ninguna parte. El objeto no tiene referencia y sus recursos son libres para ser reciclados por la Máquina Virtual de Java.

Llamar los métodos de un objeto También puede utilizar una referencia de objeto para invocar el método de un objeto. Anexe el nombre simple del método a la referencia del objeto, con un operador punto intermedio (.). Además, proporcione, dentro de paréntesis, cualquier argumento al método. Si el método no requiere ningún argumento, utilice paréntesis vacíos.

objectReference.methodName(argumentList); o:

objectReference.methodName(); La clase rectángulo tiene dos métodos: getArea() para calcular el área del rectángulo y move() para cambiar el origen del rectángulo. Aquí está el código CreateObjectDemo que invoca estos dos métodos:

System.out.println("Area of rectOne: " + rectOne.getArea()); ... rectTwo.move(40, 72); La primera declaración invoca el método getArea() de rectOne y muestra los resultados. La segunda línea mueve rectTwo porque el método move() asigna nuevos valores del objeto origin.x y origin.y. Como con campos de instancia, objectReference debe ser una referencia a un objeto. Puede utilizar un nombre de variable, pero también se puede utilizar cualquier expresión que devuelve una referencia al objeto. El operador new devuelve una referencia al objeto, así que puede usar el valor devuelto de new para invocar métodos de un objeto nuevo:

new Rectangle(100, 50).getArea() La expresión new Rectangle(100, 50) devuelve una referencia al objeto que se refiere al objeto Rectangle. Como se muestra, puede utilizar la notación de punto para invocar el método getArea() de new Rectangle para calcular el área del nuevo rectángulo. Algunos métodos, como getArea(), devuelven un valor. Para los métodos que devuelven un valor, puede utilizar la invocación del método en las expresiones. Usted puede asignar el valor devuelto por el método a una variable, usarlo para tomar decisiones o para controlar un bucle. Este código asigna el valor devuelto por el método getArea() a la variable areaOfRectangle:

int areaOfRectangle = new Rectangle(100, 50).getArea(); Recuerda, invocar un método en un objeto particular es lo mismo que enviar un mensaje a ese objeto. En este caso, el objeto que getArea() invoca en el rectángulo es devuelto por el constructor.

El recolector de basura Algunos lenguajes orientados a objetos requieren que usted haga un seguimiento de todos los objetos que crea y que explícitamente los destruya cuando ya no son necesarios. La Gestión de memoria manual o explícita es tedioso y propenso a errores. La plataforma Java te permite crear tantos objetos como tú quieras (limitado, por supuesto, por lo que pueda manejar tu sistema) y no debes preocuparte por destruirlos. El entorno de ejecución de Java (JRE) elimina objetos cuando determina que ya no se están utilizando. Este proceso se denomina recolección de basura. Un objeto es elegible para la recolección de basura cuando no existen más referencias a ese objeto. Las referencias que se llevan a cabo en una variable generalmente se cayeron cuando la variable sale del ámbito. O, usted puede tirar explícitamente una referencia a un objeto estableciendo la variable en el valor especial null. Recuerde que un programa puede tener múltiples referencias al mismo objeto; todas las referencias a un objeto deben “dejarse caer” antes de que el objeto sea elegible para la recolección de basura. El entorno de ejecución Java tiene un recolector de basura que periódicamente libera la memoria utilizada por los objetos a los que ya no se hace referencia. El recolector de basura hace su trabajo automáticamente cuando determina que es el momento adecuado.

Más sobre clases Esta sección cubre más aspectos de las clases que dependen del uso de referencias a objetos y el operador dot que has aprendido en las secciones anteriores sobre los objetos:

   

Devolver valores desde métodos. La palabra clave this. Clase vs. miembros de instancia. Control de acceso.

Devuelve un valor desde un método Un método devuelve al código que lo invoca cuando se

  

completan todas las instrucciones en el método, alcanza una instrucción return , o lanza o emite una excepción (cubierta más adelante),

lo que ocurra primero. Puedes declarar un tipo de retorno de un método en su declaración de método. Dentro del cuerpo del método, utilice la instrucción return para devolver el valor. Cualquier método declarado void no devuelve un valor. No necesita contener una instrucción return, pero puede hacerlo. En tal caso, una instrucción return puede utilizarse para ramificar de un bloque de control de flujo y salir del método, y simplemente se utiliza como este:

return; Si usted intenta devolver un valor de un método que es declarado void, obtendrá un error del compilador. Cualquier método que no sea declarado void debe contener una instrucción return con un valor de retorno correspondiente, así:

return returnValue; El tipo de dato del valor devuelto debe coincidir con el tipo de retorno declarado del método; No se puede devolver un valor entero de un método declarado para devolver un valor booleano. El método getArea() de la clase Rectangle que se discutió en las secciones sobre objetos devuelve un entero:

// un método para calcular el área del rectángulo public int getArea() { return width * height; } Este método devuelve el número entero que la expresión width*height evalúa. El método getArea devuelve un tipo primitivo. Un método también puede devolver un tipo de referencia. Por ejemplo, en un programa para manipular objetos de Bicycle, tenemos un método como este:

public Bicycle seeWhosFastest(Bicycle myBike, Bicycle yourBike, Environment env) { Bicycle fastest; // código para calcular qué moto es // más rápida, dado el engranaje de cada bicicleta // y la cadencia y dado el // medio ambiente (terreno y viento) return fastest; }

Devolviendo una clase o una interfaz Si esta sección te confunde, saltala y regresa después de haber terminado la lección de interfaces y herencia. Cuando un método utiliza un nombre de clase como su tipo de retorno, tales como whosFastest , la clase del tipo de objeto devuelto debe ser una subclase de, o la clase exacta de, el tipo de valor devuelto. Supongamos que usted tiene una jerarquía de clases en la que ImaginaryNumber es una subclase de java.lang.Number, que a su vez es una subclase del Object, como se ilustra en la figura siguiente.

La jerarquía de clases para ImaginaryNumber Ahora, supongamos que tiene un método declarado para devolver un Number:

public Number returnANumber() { ... } El método returnANumber puede devolver un ImaginaryNumber pero no un Object. ImaginaryNumber es un Number porque es una subclase del Number. Sin embargo, un Object no es necesariamente un Number — podría ser una String u otro tipo. Se puede reemplazar un método y definirlo para devolver una subclase del método original, así:

public ImaginaryNumber returnANumber() { ... } Esta técnica, llamada tipo covariante de retorno, significa que el tipo de valor devuelto puede variar en la misma dirección que la subclase.

Nota: También puede utilizar nombres de interfaces como tipos de retorno. En este caso, el objeto devuelto debe implementar la interfaz especificada.

Usando la palabra clave this Dentro de un método de instancia o un constructor, this es una referencia al objeto actual — el objeto cuyo método o constructor se esta llamando. Puede referirse a cualquier miembro del objeto actual desde dentro de un método de instancia o un constructor utilizando this.

Usando this con un campo La razón más común para el uso de la palabra clave this es porque un campo es sombreado por un parámetro de método o constructor. Por ejemplo, la clase Point fue escrita así

public class Point { public int x = 0; public int y = 0; //constructor public Point(int a, int b) { x = a; y = b; } } Pero podría haber sido escrito así:

public class Point { public int x = 0; public int y = 0; //constructor public Point(int x, int y) { this.x = x; this.y = y; } } Cada argumento del constructor sombrea uno de los campos del objeto — dentro del constructor x es una copia local del primer argumento del constructor. Para hacer referencia al campo Point x, el constructor debe utilizar this.x.

Usando this con un Constructor Desde dentro de un constructor, también puede utilizar la palabra clave this para llamar a otro constructor en la misma clase. Así, se le llama una invocación explícita del constructor. Aquí tiene otra clase de Rectangle, con una implementación diferente de la de la sección de objetos .

public class Rectangle { private int x, y; private int width, height; public Rectangle() { this(0, 0, 1, 1); } public Rectangle(int width, int height) { this(0, 0, width, height);

} public Rectangle(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } ... } Esta clase contiene un conjunto de constructores. Cada constructor inicializa todas o algunas de las variables miembro del rectángulo. Los constructores proporcionan un valor por defecto para cualquier variable miembro cuyo valor inicial no es proporcionado por un argumento. Por ejemplo, el constructor sin-argumentos crea un Rectangle de 1 x 1 en las coordenadas 0,0. El constructor de dos-argumentos llama al constructor de cuatro-argumentos, pasando el ancho y alto pero siempre utilizando las coordenadas 0,0. Como antes, el compilador determina qué constructor llamar, basado en el número y el tipo de argumentos. Si se presenta, la invocación de un constructor debe ser la primera línea en el constructor.

Controlar el acceso a los miembros de una clase Los modificadores de nivel de acceso determinan si otras clases pueden utilizar un campo particular o invocar un método en particular. Existen dos niveles de control de acceso:

 

En el nivel superior —public o package-private (sin modificador explícito). En el nivel de miembro —public, private, protected o package-private (sin modificador explícito).

Puede declarar una clase con el modificador public, en el caso de que la clase sea visible para todas las clases de cualquier parte. Si una clase no tiene ningún modificador (es por defecto, y se conoce como paquete privado), que es visible solamente dentro de su propio paquete (los paquetes son nombres de grupos de clases relacionadas — usted aprenderá acerca de ellos en una lección posterior.) En el nivel de miembro, también puede utilizar el modificador public o sin modificadores (paquete privado) así como con clases de nivel superior y con el mismo significado. Para los miembros, hay dos modificadores de acceso adicional: private y protected. El modificador private especifica que sólo se puede acceder al miembro de su propia clase. El modificador protected específica que el miembro sólo puede accederse desde dentro de su propio paquete (como con paquete privado) y, además, por una subclase de la clase en otro paquete. La siguiente tabla muestra el acceso a los miembros permitidos por cada modificador. Niveles de acceso Modificador

Clase Paquete Subclase Mundo

public

Y

Y

Y

Y

protected

Y

Y

Y

N

sin modificador Y

Y

N

N

private

N

N

N

Y

La primera columna de datos indica si la clase tiene acceso a los miembros definidos por el nivel de acceso. Como puedes ver, una clase siempre tiene acceso a sus propios miembros. La segunda

columna indica si las clases en el mismo paquete que la clase (independientemente de su paternidad) tienen acceso al miembro. La tercera columna indica si las subclases de la clase declarada fuera de este paquete tienen acceso al miembro. La cuarta columna indica si todas las clases tienen acceso a los miembros. Los niveles de acceso afectan de dos maneras. En primer lugar, cuando utilizas las clases que vienen de otra fuente, como las clases en la plataforma Java, los niveles de acceso determinan que miembros de las clases pueden usar sus propias clases. En segundo lugar, cuando escribes una clase, tienes que decidir qué nivel de acceso deben tener todas las variables miembro y cada método en su clase. Vamos a ver una colección de clases y ver cómo afectan los niveles de acceso a la visibilidad. La siguiente figura muestra las cuatro clases en este ejemplo y cómo se relacionan.

Clases y paquetes del ejemplo para ilustrar los niveles de acceso La siguiente tabla muestra donde los miembros de la clase Alfa son accesibles para cada uno de los modificadores de acceso que se pueden aplicar a ellos. Visibilidad Modificador

Alfa Beta Alphasub Gamma

public

Y

Y

Y

Y

protected

Y

Y

Y

N

sin modificadores Y

Y

N

N

private

N

N

N

Y

Tips para escoger un nivel de acceso: Si otros programadores utilizan su clase, usted quiere asegurarse de que no pueden ocurrir errores por el uso indebido. Los niveles de acceso pueden ayudarle a hacerlo.

 

Use el nivel de acceso más restrictivo que tenga sentido para un determinado miembro. Use private a menos que tenga una buena razón para no hacerlo. Evite los campos public excepto para las constantes. (Muchos de los ejemplos en el tutorial usan los campos públicos. Esto puede ayudar a ilustrar algunos puntos de forma concisa, pero no se recomienda para el código de producción.) Los campos públicos tienden a vincularte a una implementación en particular y limitar la flexibilidad de modificar su código.

Entendiendo a los miembros de la clase En esta sección, discutimos el uso de la palabra clave static para crear campos y métodos que pertenecen a la clase, en lugar de a una instancia de la clase.

Variables de clase Cuando se crea una serie de objetos desde la misma clase plantilla, cada uno tiene sus propias copias diferentes de las variables de instancia. En el caso de la clase de Bicycle, las variables de instancia son cadence, gear y speed. Cada objeto Bicycle tiene sus propios valores de estas variables, almacenadas en localizaciones de memoria diferentes. A veces, quieres tener variables que son comunes a todos los objetos. Esto se logra con el modificador static. Los Campos que tienen el modificador static en su declaración se denominan campos estáticos o variables de clase. Están asociados con la clase, en lugar de cualquier objeto. Cada instancia de la clase comparte una variable de clase, que se encuentra en una posición fija en la memoria. Cualquier objeto puede cambiar el valor de una variable de clase, pero también se pueden manipular variables de clase sin crear una instancia de la clase. Por ejemplo, supongamos que desea crear un número de objetos de Bicycle y asignar a cada uno un número de serie, empezando por 1 para el primer objeto. Este número de identificación es único para cada objeto y por lo tanto es una variable de instancia. Al mismo tiempo, necesitas un campo para hacer un seguimiento de cuántos objetos de Bicycle han sido creados para que sepas qué ID se le asignará al siguiente. Un campo no está relacionado a ningún objeto individual, sino a la clase como un todo. Para ello es necesario una variable de clase, numberOfBicycles, como sigue:

public class Bicycle { private int cadence; private int gear; private int speed; // añadir una variable de instancia para el ID del objeto private int id; // añadir una variable de clase para el // número de objetos de Bicycle instanciados private static int numberOfBicycles = 0; ... } Las variables de clase están referenciadas por el nombre de la clase misma, como en

Bicycle.numberOfBicycles Esto pone de manifiesto que son variables de clase.

Nota: También puede hacer referencia a campos estáticos con una referencia a un objeto como

myBike.numberOfBicycles Pero esto es desalentado porque no deja en claro que son variables de clase.

Puede utilizar el constructor de Bicycle para establecer la variable de instancia de id e incrementar la variable de clase numberOfBicycles :

public class Bicycle { private private private private

int int int int

cadence; gear; speed; id;

private static int numberOfBicycles = 0; public Bicycle(int startCadence, int startSpeed, int startGear){ gear = startGear; cadence = startCadence; speed = startSpeed; // número de incrementos de Bicicletas // y asignar el número de identificación id = ++numberOfBicycles; } // nuevo método para devolver la variable de instancia ID public int getID() { return id; } ... }

Métodos de la clase El lenguaje de programación Java soporta métodos estáticos, así como con las variables estáticas. Los métodos estáticos, que tienen el modificador static en sus declaraciones, deben ser invocados con el nombre de clase, sin la necesidad de crear una instancia de la clase, como en

ClassName.methodName(args) Nota: También puede hacer referencia a métodos estáticos con referencia a un objeto como

instanceName.methodName(args) Pero esto es desalentado porque no deja en claro que son métodos de la clase.

Un uso común de métodos estáticos es para acceder a los campos estáticos. Por ejemplo, nosotros podríamos añadir un método estático a la clase de Bicycle para acceder al campo estático de numberOfBicycles :

public static int getNumberOfBicycles() { return numberOfBicycles; } No todas las combinaciones de métodos y variables de instancia y clase están permitidas:

   

Métodos de instancia pueden acceder a las variables de instancia y métodos de instancia directamente. Métodos de instancia pueden acceder a variables de clase y métodos de la clase directamente. Métodos de la clase pueden acceder a variables de clase y métodos de la clase directamente. Los métodos de clase no pueden acceder a las variables de instancia o métodos de instancia directamente, -deben utilizar una referencia al objeto. Además, los métodos de clase no pueden utilizar la palabra clave this ya que no hay ninguna instancia para this y referirse a.

Constantes El modificador static, en combinación con el modificador final, también se utiliza para definir constantes. El modificador final indica que no puede cambiar el valor de este campo.

Por ejemplo, la siguiente declaración de variable define una constante llamada PI, cuyo valor es una aproximación de pi (la proporción de la circunferencia de un círculo y su diámetro):

static final double PI = 3.141592653589793; Las constantes definidas en esta forma no pueden ser reasignadas, y es un error en tiempo de compilación si su programa intenta hacerlo. Por Convención, los nombres de valores constantes se escriben en mayúsculas. Si el nombre está compuesto por más de una palabra, las palabras están separadas por un guión bajo (_).

Nota: Si un tipo primitivo o una cadena se define como una constante y el valor es conocido en tiempo de compilación, el compilador sustituye el nombre de la constante en todas partes en el código con su valor. Esto se llama una constante de tiempo de compilación. Si cambia el valor de la constante en el mundo exterior (por ejemplo, si se está legislado que pi en realidad debería ser 3.975), tendrá que volver a compilar las clases que utilizan esta constante para obtener el valor actual.

La clase de Bicycle Después de todas las modificaciones realizadas en esta sección, la clase Bicycle es ahora:

public class Bicycle { private int cadence; private int gear; private int speed; private int id; private static int numberOfBicycles = 0; public Bicycle(int startCadence, int startSpeed, int startGear){ gear = startGear; cadence = startCadence; speed = startSpeed; id = ++numberOfBicycles; } public int getID() { return id; } public static int getNumberOfBicycles() { return numberOfBicycles; } public int getCadence(){ return cadence; } public void setCadence(int newValue){ cadence = newValue; }

public int getGear(){ return gear; } public void setGear(int newValue){ gear = newValue; } public int getSpeed(){ return speed; } public void applyBrake(int decrement){ speed -= decrement; } public void speedUp(int increment){ speed += increment; } }

Inicializar campos Como has visto, a menudo se puede proporcionar un valor inicial para un campo en su declaración:

public class BedAndBreakfast { // inicializar a 10 public static int capacity = 10; // inicializar a false private boolean full = false; } Esto funciona bien cuando el valor de inicialización esta disponible y la inicialización se puede poner en una sola línea. Sin embargo, esta forma de inicialización tiene limitaciones debido a su simplicidad. Si la inicialización requiere un poco de lógica (por ejemplo, manejo de errores o un bucle for para llenar una matriz compleja), la asignación simple es insuficiente. Se puede inicializar las variables de instancia en constructores, donde el manejo de errores o de otra lógica puede ser utilizado. Para proporcionar la misma capacidad para variables de clase, el lenguaje de programación Java incluye bloques de inicialización estática.

Nota: No es necesario declarar campos al principio de la definición de clase, aunque esta es la práctica más común. Sólo es necesario que sean declarados e inicializados antes de que se utilicen.

Bloques de inicialización estática Un bloque de inicialización estática es un bloque normal de código encerrado entre llaves, { } y precedido por la palabra clave static. Aquí está un ejemplo:

static { // cualquier código que se necesita para la inicialización va aquí }

Una clase puede tener cualquier número de bloques de inicialización estática, y pueden aparecer en cualquier parte del cuerpo de la clase. El sistema runtime garantiza que la inicialización estática de los bloques sean llamados en el orden en que aparecen en el código fuente. Hay una alternativa a los bloques estáticos, se puede escribir un método estático privado:

class Whatever { public static varType myVar = initializeClassVariable(); private static varType initializeClassVariable() { // la inicialización del código va aqui } } La ventaja de los métodos estáticos privados es que pueden ser reutilizados más tarde si tienes que reiniciar la variable de clase.

Inicializar miembros de instancia Normalmente, pones código para inicializar una variable de instancia en un constructor. Existen dos alternativas al uso de un constructor para inicializar las variables de instancia: bloques inicializadores y métodos finales. Los bloques inicializadores para variables de instancia se parecen a los bloques inicializadores estáticos, pero sin la palabra clave static:

{ // cualquier código que se necesita para la inicialización va aquí } El compilador de Java copia bloques de inicialización en cada constructor. Por lo tanto, este enfoque puede utilizarse para compartir un bloque de código entre varios constructores. Un método final no puede invalidarse en una subclase. Esto se discute en la lección sobre interfaces y herencia. Aquí está un ejemplo del uso de un método final para inicializar una variable de instancia:

class Whatever { private varType myVar = initializeInstanceVariable(); protected final varType initializeInstanceVariable() { // la inicialización del código va aqui } }

Esto es especialmente útil si las subclases querrían volver a utilizar el método de inicialización. El método es final porque llamar a métodos no-final durante la inicialización de la instancia puede causar problemas.

Resumen de crear y utilizar clases y objetos Una declaración de clase da nombre a la clase y encierra el cuerpo de la clase entre llaves. El nombre de la clase puede estar precedido por modificadores. El cuerpo de clase contiene campos, métodos y constructores de la clase. Una clase utiliza campos que contienen información sobre el estado y los métodos para implementar el comportamiento. Los constructores que inicializan una

nueva instancia de una clase utilizan el nombre de la clase y lucen como métodos sin un tipo de retorno. Controlas el acceso a clases y miembros de la misma manera: mediante el uso de un modificador de acceso como el public en su declaración. Especifica una variable de clase o un método de clase mediante el uso de la palabra clave static en la declaración del miembro. Un miembro que no está declarado como static implícitamente es un miembro de instancia. Las variables de clase son compartidas por todas las instancias de una clase y pueden accederse mediante el nombre de clase, así como una referencia a la instancia. Las instancias de una clase obtienen su propia copia de cada variable de instancia, a las cuales debe accederse a través de una referencia a la instancia. Se crea un objeto de una clase utilizando el operador new y un constructor. El nuevo operador devuelve una referencia al objeto que fue creado. Puede asignar la referencia a una variable o usarlo directamente. Las variables y métodos de instancia que son accesibles al código fuera de la clase que se declaran pueden ser referidos mediante el uso de un nombre cualificado. El nombre de una variable de instancia se ve así:

objectReference.variableName El nombre completo de un método se ve así:

objectReference.methodName(argumentList) o:

objectReference.methodName() El recolector de basura limpia automáticamente los objetos no utilizados. Un objeto no es utilizado si el programa no mantiene más referencias a él. Usted puede eliminar explícitamente una referencia estableciendo la variable que contiene la referencia a null.

Preguntas y ejercicios: clases Preguntas 1.

Considere la siguiente clase:

public class IdentifyMyParts { public static int x = 7; public int y = 3; } a. b. c.

¿Cuáles son las variables de clase? ¿Cuáles son las variables de instancia? ¿Cuál es la salida del siguiente código:

IdentifyMyParts a = new IdentifyMyParts(); IdentifyMyParts b = new IdentifyMyParts(); a.y = 5; b.y = 6; a.x = 1; b.x = 2; System.out.println("a.y = " + a.y);

System.out.println("b.y = " + b.y); System.out.println("a.x = " + a.x); System.out.println("b.x = " + b.x); System.out.println("IdentifyMyParts.x = " + IdentifyMyParts.x);

Ejercicios 1.

Escribir una clase cuyas instancias representan una sola carta de una baraja de cartas. Jugar a las cartas tienen dos características distintivas: rango y palo. Asegúrese de mantener su solución ya que se le pedirá reescribirla en Enum Types.

Sugerencia: Puede utilizar la instrucción assert para comprobar sus asignaciones. Escribe:

assert (boolean expression to test); Si la expresión booleana es false, obtendrá un mensaje de error. Por ejemplo,

assert toString(ACE) == "Ace"; debe devolver true, así que no habrá ningún mensaje de error.

2. 3.

Escribir una clase cuyas instancias representan una baraja completa de cartas. También debe mantener esta solución. Escriba un pequeño programa para poner a prueba tus clases baraja y carta. El programa puede ser tan simple como crear una baraja de cartas y que muestre sus cartas.

Preguntas y ejercicios: objetos Preguntas 1.

¿Qué pasa con el siguiente programa?

public class SomethingIsWrong { public static void main(String[] args) { Rectangle myRect; myRect.width = 40; myRect.height = 50; System.out.println("myRect's area is " + myRect.area()); } } 2.

El código siguiente crea una matriz y un objeto string. ¿Cuántas referencias a esos objetos existen después de que el código se ejecuta? ¿Cualquier objeto es elegible para el recolector de basura?

... String[] students = new String[10]; String studentName = "Peter Parker"; students[0] = studentName; studentName = null; ...

3.

¿Cómo destruye un programa un objeto que crea?

Ejercicios 1. 2.

Arregle el programa llamado SomethingIsWrong que se muestra en la pregunta 1. Dada la siguiente clase, llamada NumberHolder, escriba algo de código que cree una instancia de la clase, inicialice sus dos variables miembro, y muestre el valor de cada variable miembro.

public class NumberHolder { public int anInt; public float aFloat; }

Clases anidadas El lenguaje de programación Java permite definir una clase dentro de otra clase. Dicha clase se llama una clase anidada (nested class) y se muestra aquí:

class OuterClass { ... class NestedClass { ... } } Terminología: Las clases anidadas se dividen en dos categorías: estática y no estática. Las clases anidadas que se declaran static se denominan clases anidadas estáticas. Clases anidadas no estáticas se denominan clases internas (inner classes).

class OuterClass { ... static class StaticNestedClass { ... } class InnerClass { ... } } Una clase anidada es un miembro de la clase a la que pertenece o que la envuelve. Las clases anidadas no estáticas (clases internas) tienen acceso a otros miembros de la clase a la que pertenecen, aunque sean declaradas privadas. Las clases anidadas estáticas no tienen acceso a otros miembros de la clase a la que pertenecen. Como miembro de la OuterClass, una clase anidada puede declararse private, public, protected o package private. (Recordemos que las clases externas sólo pueden ser declaradas public o package private.)

¿Por qué utilizar clases anidadas? Razones convincentes para utilizar clases anidadas incluyen las siguientes:



Es una forma de agrupar lógicamente las clases que se utilizan solamente en un solo lugar: Si una clase es útil sólo a otra clase, entonces es lógico incrustarla en esa clase y mantener las dos juntas. La anidación de tales "Clases ayudantes" hace su paquete más ágil.





Aumenta la encapsulación: considere dos clases de nivel superior, A y B, donde B necesita acceso a los miembros de A que en caso contrario se declararía private. Ocultando la clase B dentro de los miembros de la clase A, A puede ser declarada private y B puede acceder a ellos. Además, la propia B se puede esconder del mundo exterior. Puede generar código más legible y fácil de mantener: Anidar clases pequeñas dentro de clases de nivel superior coloca el código más cerca de donde se utiliza.

Clases anidadas estáticas Al igual que con los métodos de clase y variables, una clase anidada estática se asocia con su clase externa. Y al igual que los métodos estáticos de clase, una clase anidada estática no puede referirse directamente a las variables de instancia o métodos definidos en su clase envolvente o a la que pertenece: puede usarlos sólo a través de una referencia de objeto.

Nota: Una clase anidada estática interactúa con los miembros de la instancia de la clase externa (y otras clases) justo igual que con cualquier otra clase de nivel superior. En efecto, una clase anidada estática su comportamiento es como una clase de nivel superior que se ha anidado en otra clase de nivel superior para conveniencia del empaquetado.

Las clases anidadas estáticas son accedidas usando el nombre de clase a la que pertencece:

OuterClass.StaticNestedClass Por ejemplo, para crear un objeto de la clase anidada estática, use esta sintaxis:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Clases internas Como con métodos y variables de instancia, una clase interna se asocia con una instancia de la clase a la que pertenece y tiene acceso directo a los campos y métodos del objeto. También, debido a que una clase interna esta asociada a una instancia, no se puede definir a cualquier miembro estático por sí mismo. Los objetos que son instancias de una clase interna existen dentro de una instancia de la clase externa. Considere las siguientes clases:

class OuterClass { ... class InnerClass { ... } }

Una instancia de InnerClass puede existir solamente dentro de una instancia de OuterClass y tiene acceso directo a los campos y métodos de su instancia envolvente. Para crear una instancia de una clase interna, primero debe instanciar la clase externa. Luego, crea el objeto interno dentro del objeto externo con esta sintaxis:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Hay dos tipos especiales de clases internas: clases locales y anónimas.

Sombreado Si una declaración de un tipo (por ejemplo, una variable de miembro o un nombre de parámetro) en un ámbito determinado (por ejemplo, una clase interna o una definición de método) tiene el mismo nombre que otra declaración en el ámbito al que pertenece, entonces la declaración sombrea la declaración del ámbito envolvente. Usted no puede hacer referencia a una declaración sombreada solo por su nombre. El ejemplo siguiente, ShadowTest, lo demuestra:

public class ShadowTest { public int x = 0; class FirstLevel { public int x = 1; void methodInFirstLevel(int x) { System.out.println("x = " + x); System.out.println("this.x = " + this.x); System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); } } public static void main(String... args) { ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); } }

La salida de este ejemplo es el siguiente: x = 23 this.x = 1 ShadowTest.this.x = 0

Este ejemplo define tres variables denominadas x: la variable miembro de la clase ShadowTest, la variable miembro de la clase interna FirstLevel y el parámetro en el método methodInFirstLevel. La variable x definido como un parámetro del método methodInFirstLevel sombrea la variable de la clase interna FirstLevel. En consecuencia, cuando se utiliza la variable x en el método methodInFirstLevel, se refiere al parámetro del método. Para hacer referencia a la variable miembro de la clase interna FirstLevel, utilice la palabra clave this para representar el ámbito al que pertenece: System.out.println("this.x = " + this.x);

Se llama a las variables miembro encerradas en ámbitos mayores por el nombre de clase a la que pertenecen. Por ejemplo, la siguiente declaración accede a la variable miembro de la clase ShadowTest desde el método methodInFirstLevel: System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

Ejemplo de la clase interna Para ver una clase interna en uso, considere primero una matriz. En el ejemplo siguiente, se crea un array, llenado con valores enteros y luego da salida a los valores de los índices incluidos en la matriz en orden ascendente.

En el ejemplo de DataStructure.java que sigue consiste en:



La clase externa DataStructure, que incluye un constructor para crear una instancia de DataStructure que contiene un arreglo lleno de valores enteros consecutivos (0, 1, 2, 3 y así sucesivamente) y un método que imprime los elementos del arreglo que tienen un valor de índice incluido. La clase interna EvenIterator, que implementa la interfaz DataStructureIterator, que se extiende de la interfaz de Iterator< Integer>. Los Iteradores se utilizan para pasar a través de una estructura de datos y suelen tener métodos de prueba para el último elemento, recuperan el elemento actual y pasan al siguiente elemento. Un método main que crea una instancia de un objeto DataStructure (ds), luego invoca al método printEven para imprimir los elementos del arreglo arrayOfInts con los valores de índice incluidos.





public class DataStructure { // Crea un arreglo private final static int SIZE = 15; private int[] arrayOfInts = new int[SIZE]; public DataStructure() { // llena la matriz con valores enteros ascendentes for (int i = 0; i < SIZE; i++) { arrayOfInts[i] = i; } } public void printEven() { // imprime los valores de los indices incluidos en el arreglo DataStructureIterator iterator = this.new EvenIterator(); while (iterator.hasNext()) { System.out.print(iterator.next() + " "); } System.out.println(); } interface DataStructureIterator extends java.util.Iterator { } // la clase interna implementa la interfaz DataStructureIterator, // que se extiende de la interfaz Iterator private class EvenIterator implements DataStructureIterator { // inicia pasando a través de la matriz desde el principio private int nextIndex = 0; public boolean hasNext() { // Comprueba si el elemento actual es el último de la serie return (nextIndex otherRect.getArea()) return 1; else return 0; } } Porque RectanglePlus implementa Relatable, se puede comparar el tamaño de los dos objetos RectanglePlus .

Nota: El método isLargerThan, tal como se define en la interfaz de Relatable, toma un objeto de tipo Relatable. La línea de código, que se muestra en negrita en el ejemplo anterior, castea o arroja other a una instancia RectanglePlus. Este tipo de casting indica al compilador qué objeto realmente es. Invocando getArea directamente en la instancia other (other.getArea()) fallaría la compilación porque el compilador no entiende que other es actualmente una instancia de RectanglePlus.

Usando una interfaz como un tipo Cuando define una nueva interfaz, está definiendo un nuevo tipo de dato de referencia. Puede utilizar nombres de interfaces en cualquier lugar puede utilizar cualquier otro nombre de tipo de dato. Si define una variable de referencia cuyo tipo es una interfaz, cualquier objeto que se asigna debe ser una instancia de una clase que implementa la interfaz. Como ejemplo, aquí esta un método para encontrar el objeto más grande en un par de objetos, para cualquier objeto que es instanciado desde una clase que implementa Relatable:

public Object findLargest(Object object1, Object object2) { Relatable obj1 = (Relatable)object1; Relatable obj2 = (Relatable)object2; if ((obj1).isLargerThan(obj2) > 0) return object1; else return object2; } Por casting del object1 a un tipo Relatable, puede invocar al método isLargerThan. Si haces un punto de la implementación de Relatable en una amplia variedad de clases, los objetos instanciados desde cualquiera de esas clases pueden ser comparados con el método findLargest() — siempre que ambos objetos sean de la misma clase. Asimismo, pueden todos ser comparados con los siguientes métodos:

public Object findSmallest(Object object1, Object object2) { Relatable obj1 = (Relatable)object1; Relatable obj2 = (Relatable)object2; if ((obj1).isLargerThan(obj2) < 0) return object1; else return object2; } public boolean isEqual(Object object1, Object object2) { Relatable obj1 = (Relatable)object1; Relatable obj2 = (Relatable)object2; if ( (obj1).isLargerThan(obj2) == 0) return true; else return false; } Estos métodos funcionan para cualquier objeto "relatable", no importa cuál sea su herencia de clases. Cuando implementan Relatable, pueden ser de su propio tipo de clase (o superclase) y un tipo de Relatable. Esto les da la algunas de las ventajas de herencia múltiple, donde pueden tener comportamiento desde una interfaz y una superclase.

Evolución de las Interfaces Considere una interfaz que has desarrollado llamada DoIt:

public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); } Supongamos que, en un momento posterior, desea agregar un tercer método para DoIt, para que la interfaz se convierta en:

public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); boolean didItWork(int i, double x, String s); } Si se realiza este cambio, todas las clases que implementan la interfaz vieja DoIt romperán porque ya no implementan la interfaz antigua. Los programadores confiando en esta interfaz protestarán en voz alta. Trate de anticipar todas las aplicaciones para su interface y definirla completamente desde el principio. Si desea agregar métodos adicionales en una interfaz, usted tiene varias opciones. Se puede crear una interfaz DoItPlus que se extiende de DoIt:

public interface DoItPlus extends DoIt { boolean didItWork(int i, double x, String s); } Ahora los usuarios de su código pueden optar por seguir utilizando la interfaz vieja o para actualizar a la nueva interfaz. Alternativamente, usted puede definir sus nuevos métodos como métodos por defecto. El ejemplo siguiente define un método por defecto denominado didItWork:

public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); default boolean didItWork(int i, double x, String s) { // Method body } } Tenga en cuenta que usted debe proporcionar una implementación de métodos por defecto. También puede definir nuevos métodos estáticos para interfaces existentes. Los usuarios que tienen las clases que implementan las interfaces mejoradas con nuevo valor por defecto o métodos estáticos no tienen que modificarlos o recompilarlos para acomodar los métodos adicionales.

Métodos por defecto

La sección Interfaces describe un ejemplo que involucra a fabricantes de coches controlados por computadora que publican las interfaces estándar de la industria que describen los métodos que pueden invocarse para operar sus coches. ¿Qué pasa si los fabricantes de coches controlados por computadora añaden nuevas funciones, tales como vuelo, a sus coches? Estos fabricantes tendrían que especificar nuevos métodos para permitir que otras empresas (como los fabricantes de instrumentos de posicionamiento electrónico) adapten su software para autos voladores. ¿Dónde declararían estos fabricantes de automóviles estos nuevos métodos relacionados con los vuelos? Si los añaden a sus interfaces originales, los programadores que han implementado las interfaces tendrían que reescribir sus implementaciones. Si los añaden como métodos estáticos, entonces los programadores los considerarían como métodos de utilidad, no como esenciales, como métodos básicos. Los Métodos por defecto permiten añadir nuevas funciones a las interfaces de sus bibliotecas y asegurar la compatibilidad binaria con código escrito para las versiones más antiguas de las interfaces. Considere la siguiente interfaz, TimeClient, como se describe en respuestas a las preguntas y ejercicios: Interfaces:

import java.time.*; public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); } La clase siguiente, SimpleTimeClient, implementa TimeClient:

package defaultmethods; import java.time.*; import java.lang.*; import java.util.*; public class SimpleTimeClient implements TimeClient { private LocalDateTime dateAndTime; public SimpleTimeClient() { dateAndTime = LocalDateTime.now(); } public void setTime(int hour, int minute, int second) { LocalDate currentDate = LocalDate.from(dateAndTime); LocalTime timeToSet = LocalTime.of(hour, minute, second); dateAndTime = LocalDateTime.of(currentDate, timeToSet); } public void setDate(int day, int month, int year) { LocalDate dateToSet = LocalDate.of(day, month, year); LocalTime currentTime = LocalTime.from(dateAndTime); dateAndTime = LocalDateTime.of(dateToSet, currentTime); } public void setDateAndTime(int day, int month, int year, int hour, int minute, int second) {

LocalDate dateToSet = LocalDate.of(day, month, year); LocalTime timeToSet = LocalTime.of(hour, minute, second); dateAndTime = LocalDateTime.of(dateToSet, timeToSet); } public LocalDateTime getLocalDateTime() { return dateAndTime; } public String toString() { return dateAndTime.toString(); } public static void main(String... args) { TimeClient myTimeClient = new SimpleTimeClient(); System.out.println(myTimeClient.toString()); } } Suponga que desea añadir nuevas funciones a la interfaz TimeClient, como la capacidad de especificar una zona horaria a través de un objeto ZonedDateTime (que es como un objeto LocalDateTime excepto que almacena información de zona horaria):

public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); ZonedDateTime getZonedDateTime(String zoneString); } A raíz de esta modificación a la interfaz TimeClient , también tendrías que modificar la clase SimpleTimeClient e implementar el método getZonedDateTime. Sin embargo, en lugar de dejar getZonedDateTime como abstract (como en el ejemplo anterior), en su lugar se puede definir una implementación por defecto. (Recuerde que un método abstracto es un método declarado sin una implementación).

package defaultmethods; import java.time.*; public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); static ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } }

default ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } } Especifica que una definición de método en una interfaz es un método por defecto con la palabra clave default al principio de la firma del método. Todas las declaraciones de método en una interfaz, incluyendo métodos por defecto, implícitamente son public, puede omitir el modificador public . Con esta interfaz, usted no tiene que modificar la clase SimpleTimeClient, y esta clase (y cualquier clase que implemente la interfaz TimeClient), tendrá el método getZonedDateTime ya definido. El ejemplo siguiente, TestSimpleTimeClient, invoca al método getZonedDateTime desde una instancia de SimpleTimeClient:

package defaultmethods; import java.time.*; import java.lang.*; import java.util.*; public class TestSimpleTimeClient { public static void main(String... args) { TimeClient myTimeClient = new SimpleTimeClient(); System.out.println("Current time: " + myTimeClient.toString()); System.out.println("Time in California: " + myTimeClient.getZonedDateTime("Blah blah").toString()); } }

Extender Interfaces que contienen métodos por defecto Cuando se extiende una interfaz que contiene un método por defecto, puede hacer lo siguiente:

  

No mencione en absoluto el método por defecto, deje que su interfaz extendida herede el método por defecto. Vuelva a declarar el método por defecto, que lo convierte en abstract. Redefina el método por defecto, que lo reemplaza.

Supongamos que se extiende la interfaz TimeClient como sigue:

public interface AnotherTimeClient extends TimeClient { } Cualquier clase que implemente la interfaz AnotherTimeClient tendrá la aplicación especificada por el método por defecto TimeClient.getZonedDateTime. Supongamos que se extiende la interfaz TimeClient como sigue:

public interface AbstractZoneTimeClient extends TimeClient { public ZonedDateTime getZonedDateTime(String zoneString); }

Cualquier clase que implemente la interfaz AbstractZoneTimeClient tendrá que implementar el método getZonedDateTime; Este método es un método abstract como todos los demás que no son métodos por defecto (y no estáticos) en una interfaz. Supongamos que se extiende la interfaz TimeClient como sigue:

public interface HandleInvalidTimeZoneClient extends TimeClient { default public ZonedDateTime getZonedDateTime(String zoneString) { try { return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString)); } catch (DateTimeException e) { System.err.println("Invalid zone ID: " + zoneString + "; using the default time zone instead."); return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault()); } } } Cualquier clase que implemente la interfaz HandleInvalidTimeZoneClient utilizará la implementación de getZonedDateTime especificado por esta interfaz en lugar del especificado por la interfaz TimeClient.

Métodos estáticos Además de los métodos por defecto, se pueden definir métodos estáticos en las interfaces. (Un método estático es un método que se asocia con la clase en la que se define en lugar de con cualquier objeto. Cada instancia de la clase comparte sus métodos estáticos). Esto hace más fácil para que usted pueda organizar métodos auxiliares en sus bibliotecas; Puedes quedarte con métodos estáticos específicos en una interfaz en la misma interfaz en lugar de una clase aparte. El ejemplo siguiente define un método estático que recupera un objeto ZoneId correspondiente a un identificador de zona horaria; utiliza la zona horaria del sistema por defecto si no hay ningún objeto ZoneId correspondiente al identificador determinado. (Como resultado, puede simplificar el método getZonedDateTime):

public interface TimeClient { // ... static public ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default public ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } } Como los métodos estáticos en clases, se especifica que una definición de método en una interfaz es un método estático con la palabra clave static al principio de la firma del método. Todas las declaraciones de método en una interfaz, incluyendo métodos estáticos, implícitamente son public, puede omitir el modificador public.

Integración de métodos por defecto en bibliotecas existentes Los Métodos por defecto permiten añadir nuevas funciones a las interfaces existentes y asegurar la compatibilidad binaria con código escrito para las versiones más antiguas de las interfaces. En particular, métodos predeterminados permiten agregar métodos que aceptan expresiones lambda como parámetros para interfaces existentes. Esta sección muestra cómo ha mejorado la interfaz Comparator con por defecto y métodos estáticos. Considere las clases de Card y la Deck que se describe en preguntas y ejercicios: clases. En este ejemplo reescribe las clases Card y Deck como interfaces. La interfaz de la Card contiene dos tipos de enum (Suit y Rank) y dos métodos abstractos (getSuit y getRank):

package defaultmethods; public interface Card extends Comparable { public enum Suit DIAMONDS (1, CLUBS (2, HEARTS (3, SPADES (4,

{ "Diamonds"), "Clubs" ), "Hearts" ), "Spades" );

private final int value; private final String text; Suit(int value, String text) { this.value = value; this.text = text; } public int value() {return value;} public String text() {return text;} } public enum Rank { DEUCE (2 , "Two" ), THREE (3 , "Three"), FOUR (4 , "Four" ), FIVE (5 , "Five" ), SIX (6 , "Six" ), SEVEN (7 , "Seven"), EIGHT (8 , "Eight"), NINE (9 , "Nine" ), TEN (10, "Ten" ), JACK (11, "Jack" ), QUEEN (12, "Queen"), KING (13, "King" ), ACE (14, "Ace" ); private final int value; private final String text; Rank(int value, String text) { this.value = value; this.text = text; } public int value() {return value;} public String text() {return text;} } public Card.Suit getSuit(); public Card.Rank getRank(); }

La interfaz de Deck contiene varios métodos que manipulan las cartas de una baraja:

package defaultmethods; import java.util.*; import java.util.stream.*; import java.lang.*; public interface Deck { List getCards(); Deck deckFactory(); int size(); void addCard(Card card); void addCards(List cards); void addDeck(Deck deck); void shuffle(); void sort(); void sort(Comparator c); String deckToString(); Map deal(int players, int numberOfCards) throws IllegalArgumentException; } La clase PlayingCard implementa la interfaz de Card, y la clase StandardDeck implementa la interfaz Deck. La clase StandardDeck implementa el método abstracto Deck.sort como sigue:

public class StandardDeck implements Deck { private List entireDeck; // ... public void sort() { Collections.sort(entireDeck); } // ... } El método Collections.sort ordena una instancia de List cuyo tipo de elemento implementa la interfaz Comparable. El miembro entireDeck es una instancia de List cuyos elementos son del tipo de Card, que se extiende a Comparable. La clase PlayingCard implementa el método Comparable.compareTo de la siguiente manera:

public int hashCode() { return ((suit.value()-1)*13)+rank.value(); } public int compareTo(Card o) { return this.hashCode() - o.hashCode(); }

El método compareTo hace que el método StandardDeck.sort() ordene primero la baraja de cartas por pallo y luego por la rango. ¿Qué pasa si desea ordenar la baraja primero que el rango, luego por palo? Necesitaría implementar la interfaz Comparator para especificar nuevos criterios de clasificación y utilice el método sort(List list, Comparator