Copyright (C) 2010 Rosario Baena, Roberto Aragón.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".
- 1.1 Declarar clases (40), declarar interfaces (49):
- Desarrollar código que declare clases (incluidas clases abstractas y todas las formas de clases anidadas), interfaces y enums, y que incluya el uso apropiado de instrucciones package e import (incluidas importaciones estáticas).
- 1.2 Declarar interfaces (49):
- Desarrollar código que declare una interfaz. Desarrollar código que implemente o amplíe una o más interfaces. Desarrollar código que declare una clase abstracta. Desarrollar código que amplíe una clase abstracta.
- 1.3 Identificadores y JavaBeans (34), declarar miembros de clases (54):
- Desarrollar código que declare, inicialice y use primitivas, arreglos, enums y objetos como variables estáticas, de instancia y locales. Asimismo, utilizar identificadores válidos para los nombres de variable.
- 1.4 Identificadores y JavaBeans (34), declarar miembros de clases (54):
- Desarrollar código que declare métodos tanto estáticos como no estáticos, si resulta adecuado, que utilice nombres de método con nomenclatura de JavaBeans. Además, desarrollar código que declare y utilice una lista de argumentos de longitud variable.
- Los identificadores pueden comenzar con una letra, un guión bajo o un carácter de moneda ($).
- Después del primer carácter se pueden incluir dígitos.
- Los identificadores pueden ser de cualquier longitud.
- Los métodos de JavaBeans deben nombrarse utilizando CamelCase y, en función del propósito de método, debe empezar con set, get, is, add o remove (estos dos últimos sólo para Listeners).
- Un archivo de código fuente sólo puede tener una clase public.
- Si el archivo contiene una clase public, el nombre del archivo debe coincidir con el nombre de la clase public.
- Un archivo sólo puede tener una sentencia package y varias import.
- Las sentencias package (si las hubiera) deben ser las primeras líneas no comentadas del fichero fuente.
- Las sentencias import (si las hubiera) deben venir después de las package y antes de la declaración de la clase.
- Si no hay ninguna sentencia package, las sentencias import deben ser las primeras líneas (no comentadas) del archivo fuente.
- package e import afectan a todas las clases del archivo.
- Un archivo puede tener más de una clase privada.
- Los archivos sin clases public no tienen restricción de nomenclatura.
- El orden de ocurrencia de package, import y clases es el siguiente: [comentarios]* [package]? [import]* [clases o interfaces]+
- Hay tres modificadores de acceso: public, protected y private.
- Hay cuatro niveles de acceso: public, protected, por defecto y private.
- Las clases (no internas) sólo pueden tener acceso public o por defecto.
- Una clase con acceso por defecto (sin modificador de acceso) puede ser vista solamente por las clases del mismo paquete.
- Una clase con acceso public puede ser vista por todas las clases de todos los paquetes.
- La visibilidad de una clase se traduce en si puede:
- Crearse una instancia de ella en otra clase.
- Extender/heredar de (o subclasificar) otra clase.
- Accederse a sus métodos y variables desde otra clase.
- A efectos de acceso, los subpaquetes son paquetes diferentes. El paquete por defecto también es un paquete diferente de todos los demás, aunque no puede importarse desde ningún archivo de clases.
- Las clases también pueden modificarse con final, abstract o strictfp.
- Una clase no puede ser a la vez final y abstract.
- Una clase final no se puede subclasificar.
- Una clase abstract no puede ser instanciada.
- Un solo método abstract en una clase implica que la clase completa debe ser abstract.
- Una clase abstract puede tener métodos abstractos y no abstractos.
- La primera clase concreta que se extienda/herede de una clase abstract debe implementar todos sus métodos abstractos.
- Las interfaces son los contratos de lo que puede hacer una clase, pero no dicen nada acerca de la forma en que la clase debe hacerlo.
- Las interfaces pueden ser implementadas por cualquier clase de cualquier árbol de herencia.
- Una interfaz es como una clase 100% abstracta y es implícitamente abstracta tanto si lleva el modificador abstract como si no.
- Una interfaz sólo puede tener métodos abstractos; no se permiten métodos concretos.
- Los métodos de las interfaces son por defecto public y abstract; la declaración explícita de estos modificadores es opcional.
- Las interfaces pueden tener constantes; estas son siempre implícitamente public, static y final.
- Las declaraciones de constantes como public, static y final son opcionales en cualquier combinación.
- Una clase no abstracta legal de implementación tiene las siguientes propiedades:
- Proporciona implementaciones concretas para los métodos de la interfaz.
- Debe seguir todas las reglas legales de sobreescritura en los métodos que implementa.
- No debe declarar nuevas excepciones verificadas en las implementaciones de métodos.
- No debe declarar excepciones verificadas que sean más amplias que las excepciones declaradas en el método de la interfaz.
- Puede declarar excepciones en tiempo de ejecución en la implementación de un método de interfaz independientemente de la declaración de la interfaz.
- Debe mantener la firma exacta y el tipo de retorno (permitiendo retornos covariantes) de los métodos que implementa, pero no tiene que declarar las excepciones de la interfaz.
- Respecto de las excepciones, sigue las reglas de la sobrescritura de métodos.
- Una clase que implementa una interfaz puede ser ella misma abstract.
- Una clase de implementación abstract no tiene porqué implementar los métodos de la interfaz, aunque la primera subclase concreta de esta sí debe hacerlo.
- Una clase puede extender/heredar de sólo una clase (no existe la herencia múltiple), pero puede implementar muchas interfaces.
- Las interfaces pueden extender/heredar de una o varias interfaces.
- Las interfaces no pueden extender/heredar de una clase ni implementar una clase o interfaz.
- Cuando realice el examen, verifique que las declaraciones de interfaz y de clase sean legales antes de verificar la lógica del resto del código.
- Los métodos y variables (no locales) de instancia son conocidos como "miembros".
- Los miembros pueden utilizar los cuatro niveles de acceso: public, protected, por defecto y private.
- El acceso a miembros se verifica cuando:
- El código de una clase puede acceder a un miembro de otra clase.
- Una subclase puede heredar un miembro de su superclase.
- Si una clase no puede ser accedida, sus miembros no pueden ser accedidos.
- Determine la visibilidad de la clase antes de determinar la visibilidad de sus miembros.
- Los miembros public se puede acceder desde todas las clases incluso desde otros paquetes.
- Si un miembro de una superclase es público, la subclase lo heredará, independientemente de su paquete.
- Los miembros accedidos sin el operador punto (.) deben pertenecer a la misma clase.
- this. siempre se refiere al objeto de ejecución actual.
- Invocar this.aMethod() es lo mismo que invocar aMethod().
- Los miembros private sólo pueden ser accedidos por el código de la misma clase.
- Los miembros private no son visibles para las subclases, así que no pueden heredarse.
- Los miembros con acceso por defecto y protected sólo se comportan diferente cuando están involucradas subclases:
- Los miembros por defecto solo pueden ser accedidos por las clases del mismo paquete.
- Los miembros protected pueden ser accedidos por clases del mismo paquete, además de las subclases (independientemente del paquete).
- protected = package más niños (entendiendo niños como las subclases).
- Para las subclases fuera del paquete, el miembro protected puede ser accedido solo mediante herencia. Una subclase fuera del paquete no puede acceder a un miembro protected utilizando una referencia a una instancia de su superclase. En otras palabras, la herencia es el único mecanismo por el que una subclase fuera del paquete puede acceder a un miembro protected de su superclase.
- Un miembro protected heredado por una subclase de otro paquete no es accesible por ninguna otra clase de ese paquete, a excepción de las subclases de dicha subclase.
- Las declaraciones de variables locales (de método, automáticas o de pila) no pueden tener modificadores de acceso.
- final es el único modificador disponible para variables locales.
- Las variables locales no toman valores por defecto, por lo que deben ser inicializadas antes de su uso (al contrario que las variables primitivas de instancia, sean static o no).
- Los métodos final no pueden ser sobrescritos por una subclase.
- Los métodos abstract se declaran mediante una firma, un tipo de retorno y una cláusula throws opcional, pero no se implementan.
- Los métodos abstract terminan con un punto y coma, sin llaves.
- Hay tres maneras de detectar un método no abstracto:
- El método no está marcado como abstract.
- El método tiene llaves.
- El método tiene el código entre las llaves.
- La primera clase no abstracta (concreta) que extiende/hereda de una clase abstract debe implementar la totalidad de los métodos abstract de la misma.
- El modificador synchronized sólo se aplica a los métodos y a los bloques de código.
- Los métodos synchronized pueden tener cualquier control de acceso y también se pueden marcar con final.
- Los métodos abstract deben ser implementados por una subclase, por lo que deben ser heredables. Por esa razón:
- Los métodos abstractos no pueden ser private.
- Los métodos abstractos no pueden ser final.
- El modificador native se aplica sólo a métodos.
- El modificador strictfp se aplica sólo a clases y métodos.
- Un método sin cuerpo (sin llaves, finalizado con punto y coma) debe siempre llevar el modificador abstract (no compila), ya que es abstracto.
- A partir de Java 5, los métodos pueden declarar un parámetro que acepte de cero a muchos argumentos; es el llamado método "arg-var".
- Un parámetro arg-var se declara con la sintaxis type... name, por ejemplo: doStuff (int... x) {}
- Un método arg-var sólo puede tener un parámetro arg-var.
- En métodos con parámetros normales y un parámetro arg-var, el parámetro arg- var debe ir en último lugar.
- Las variables de instancia pueden:
- No tener ningún modificador de acceso (tendrían nivel por defecto o package).
- Ser marcadas como final o transient.
- Las variables de instancia no pueden ser abstract, synchronized, native ni strictfp.
- Es legal declarar una variable local con el mismo nombre que una variable de instancia; a esto se le llama "sombreado".
- Las variables final tienen las siguientes propiedades:
- No pueden ser reinicializadas una vez se les ha asignado un valor.
- Las variables de referencia final no pueden hacer referencia a un objeto diferente una vez que el objeto ya ha sido asignado a la variable final.
- Las variables de referencia final deben ser inicializadas antes de que el constructor termine.
- No existe nada llamado objeto final. Una referencia de objeto marcada como final no significa que el objeto en sí mismo sea inmutable.
- El modificador transient se aplica únicamente a las variables de instancia.
- El modificador volatile sólo se aplica a variables de instancia.
- Las matrices pueden contener primitivas u objetos, pero la matriz en sí misma es siempre un objeto.
- Cuando se declara una matriz, los corchetes pueden estar a la izquierda o a la derecha del nombre de la variable.
- Nunca es legal incluir el tamaño de una matriz en la declaración.
- Una matriz de objetos puede contener cualquier objeto que pase la prueba ES- UN (o instanceof) para el tipo declarado de la matriz. Por ejemplo, si Horse extiende/hereda de Animal, entonces un objeto Horse puede ir en una matriz de Animal.
- No están vinculados a ninguna instancia de una clase.
- No es necesaria una instancia de una clase para utilizar los miembros static de la misma.
- Sólo hay una copia de una variable/clase estática y todas las instancias la comparten.
- Los métodos estáticos no tienen acceso directo a los miembros no estáticos.
Un enum especifica una lista de valores constantes asignados a un tipo.
Un enum no es un una cadena ni un entero; tiene un comportamiento prácticamente idéntico a una clase. Una constante de tipo enum es del tipo del enum (clase). Por ejemplo: SUMMER y FALL son del tipo enum SEASON.
Un enum puede ser declarado fuera o dentro de una clase, pero no dentro de un método.
Un enum declarado fuera de una clase NO debe ser marcado static, final, abstract, protected ni private.
Las enumeraciones pueden contener constructores, métodos, variables y cuerpos de clase constantes. Por ejemplo:
enum CoffeeSize { BIG(8), HUGE(10), // 8, 10 y 16 al constructor OVERWHELMING(16) { // cuerpo de clase constante public int getOunces() { // sobrescribe el método return 0; } }; // punto y coma OBLIGATORIO CoffeeSize(int ounces) { // constructor this.ounces = ounces; } private int ounces; // una variable de instancia public int getOunces() { // un método return ounces; } }Las constantes enum pueden enviar argumentos a los constructores enum utilizando la sintaxis BIG(8), donde el literal entero 8 se pasa al constructor enum.
Los constructores enum pueden tener argumentos y pueden ser sobrecargados.
Los constructores enum nunca pueden ser invocados directamente en el código, siempre son llamados automáticamente cuando se inicializa el enum.
El punto y coma al final de una declaración enum es opcional. Estas formas son igualmente legales:
enum Foo { ONE, TWO, THREE } enum Foo { ONE, TWO, THREE };MyEnum.values() devuelve una matriz de valores MyEnum.
Visibilidad desde public protected paquete private la misma clase Sí Sí Sí Sí el mismo paquete, cualquier clase Sí Sí Sí No el mismo paquete, una subclase Sí Sí Sí No distinto paquete, una subclase Sí
- Sí, si
- hereda
Sí No distinto paquete, cualquier clase Sí No No No
Modificador De acceso Vars. locales/argumentos Vars de instancia Métodos final Sí Sí Sí public Sí Sí Sí protected Sí Sí Sí private Sí Sí Sí static Sí Sí transient Sí volatile Sí abstract Sí synchronized Sí strictfp Sí native Sí
Tipo Bytes Mínimo Máximo byte 1 -2^7 2^7 - 1 short 2 -2^15 2^15 - 1 int 4 -2^31 2^31 - 1 long 8 -2^63 2^63 - 1 float 4 N/D N/D double 8 N/D N/D
- 1.2 Implementando interfaces (150):
- Desarrollar código que declare una interfaz. Desarrollar código que implemente o amplíe una o más interfaces. Desarrollar código que declare una clase abstracta. Desarrollar código que amplíe una clase abstracta.
- 1.3 Estáticas (175):
- Desarrollar código que declare, inicialice y use primitivas, arreglos, enums y objetos como variables estáticas, de instancia y locales. Asimismo, utilizar identificadores válidos para los nombres de variable.
- 1.5 Sobrescritura / Sobrecarga (133), tipos de retorno válidos (156):
- Con un ejemplo de código dado, determinar si un método está sobrescribiendo o sobrecargando correctamente otro método e identificar valores de retorno válidos (incluidos valores de retorno covariantes) para el método.
- 1.6 Constructores e instanciación (160):
- A partir de una serie de clases y superclases, desarrollar constructores para una o varias clases. Con una declaración de clase dada, determinar si se creará un constructor predeterminado y, en caso afirmativo, determinar su comportamiento. Con una lista de clases anidadas y no anidadas, escribir código para crear instancias de la clase.
- 5.1 Encapsulación (116), acoplamiento y cohesión (181):
- Desarrollar código que implemente encapsulación estricta, acoplamiento débil y alta cohesión en las clases, y describir las ventajas que ofrece.
- 5.2 Moldeado de variables de referencia (146):
- En una situación dada, desarrollar código que demuestre el uso del polimorfismo. También determinar cuándo se va a necesitar la conversión de tipos y distinguir los errores del compilador de los errores de tiempo de ejecución relacionados con la conversión de referencias de objeto.
- 5.2 Polimorfismo (128):
- En una situación dada, desarrollar código que demuestre el uso del polimorfismo. También determinar cuándo se va a necesitar la conversión de tipos y distinguir los errores del compilador de los errores de tiempo de ejecución relacionados con la conversión de referencias de objeto.
- 5.3 Constructores e instanciación (160):
- Explicar el efecto de los modificadores en la herencia en lo que se refiere a constructores, variables de instancia o estáticas y métodos de instancia o estáticos.
- 5.4 Sobrescritura / Sobrecarga (133), constructores e instanciación (160):
- En una situación dada, desarrollar código que declare y/o llame a métodos sobrescritos o sobrecargados y código que declare y/o llame a constructores de superclase, sobrescritos o sobrecargados.
- 5.5 Herencia, ES-UN, TIENE-UN (120):
- Desarrollar código que implemente relaciones "is-a" y/o "has-a".
- La encapsulación ayuda al ocultamiento de la implementación de una interfaz (o API)
- El código encapsulado tiene dos características:
- La variables de instancia se mantienen protegidas (normalmente con el modificador private)
- Los métodos Getter y Setter proporcionan el acceso a las variables de instancia.
- La relación ES-UN se refiere a la herencia o implementación.
- La relación ES-UN se expresa con la palabra clave extends (extender o ampliar)
- Las expresiones "hereda desde" y "es un subtipo de " son equivalentes en la relación ES-UN.
- TIENE-UN significa que una instancia de una clase "tiene una" referencia a una instancia de otra clase o a otra instancia de la misma clase.
- La herencia permite a una clase ser una subclase de una superclase, y por tanto heredar las variables y métodos públicos (public) y protegidos (protected) de la superclase.
- La herencia es el concepto principal que subyace en: ES-UN, polimorfismo, sobrescritura, sobrecarga y moldeado (casting).
- Todas las clases (excepto la clase Object), son subclases del tipo Object, y por tanto heredan los métodos de Object.
- Polimorfismo significa "muchas formas".
- Una variable de referencia es siempre de un tipo simple inmutable, pero se puede referir a un objeto del subtipo.
- Un solo objeto puede ser referenciado por variables de referencia de muchos tipos diferentes, siempre y cuando sean del mismo tipo o un supertipo del objeto.
- La variable del tipo de referencia (no el tipo del objeto), determina que métodos pueden ser llamados.
- El polimorfismo solo se aplica en la invocación de métodos sobrescritos, nunca sobre las variables de instancia (las variables de instancia nunca se sobrescriben.
Los métodos pueden ser sobrescritos o sobrecargados, los constructores solo pueden ser sobrecargados.
Los métodos abstractos deben ser sobrescritos por la primera clase concreta (no abstracta) que los herede.
Con respecto a las sobrescritura de métodos, los métodos sobrescritos:
- Deben tener la misma lista de parámetros.
- Deben tener el mismo tipo de retorno, excepto en Java 5 que el tipo devuelto puede ser una subclase, a esto se le conoce como devolución covariante (covariant return).
- No puede cambiarse el modificador de acceso a uno más restrictivo (de public a private).
- Puede cambiarse el modificador de acceso a uno menos restrictivo (de protected a public).
- No se pueden ampliar (cambiar por superclases) o añadir nuevas excepciones verificadas a la declaración (sí si son de tiempo de ejecución).
- Pueden controlarse menos excepciones o incluso ninguna pero nunca más (si no son subclases de las declaradas en la superclase).
Los métodos marcados como final no pueden ser sobrescritos.
Solo los métodos heredados pueden ser sobrescritos, y recuerde que los métodos privados no son heredados.
Una subclase usa super.nombreMetodoSobrescrito para llamar a la versión del método de la superclase que se sobrescribe.
Sobrecarga significa reutilización del nombre de un método, pero con diferentes listas de parámetros.
Los métodos sobrecargados:
- Deben tener una lista de parámetros distinta.
- Pueden tener retornos de tipo diferentes, si la lista de parámetros también es diferente.
- Pueden tener diferentes modificadores de acceso.
- Pueden lanzar o controlar diferentes excepciones.
Los métodos definidos en una superclase pueden ser sobrecargados en la subclase.
El polimorfismo se aplica solo a la sobrescritura, no a la sobrecarga.
El tipo de objeto (no la variable de referencia) determina qué método sobrescrito es usado en tiempo de ejecución.
El tipo de referencia determina qué método sobrecargado se usa en tiempo de compilación.
Hay dos tipos de moldeado de variables de referencia: downcasting y upcasting. Por ejemplo:
// Caballo.java:
class Animal {} // Tipo public class Caballo extends Animal { //Subtipo public void relinchar() { System.out.println("Heeee..."); } public static void main(String... args) { Animal a; Caballo c = new Caballo(); // Caballo ES-UN Animal // Upcasting a = (Animal)c; // Moldeado explícito no necesario a = c; // Compila bien: moldeado implícito // Downcasting if(a instanceof Caballo) { // DEBE protegerse el moldeado c = (Caballo)a; // Moldeado obligatorio //c = a; // Error de compilación c.relinchar(); // relinchar() es método sólo de Caballo } } }Upcasting: Podemos asignar una variable de referencia (c) a una variable de referencia de un supertipo (a) explícita o implícitamente. Está es una operación segura debido a que las capacidades de acceso se restringen en la nueva variable.
Downcasting: Si tenemos una variable de referencia (a) que se refiere a un tipo de objeto (Animal), podemos asignárselo a una variable de referencia (c) del subtipo (Caballo). Para ello, debemos hacer un "cast" explícito, y el resultado es que se puede acceder al subtipo (Caballo) con los miembros de esta nueva variable de referencia (c).
- Cuando implementamos una interfaz, cumplimos con su contrato.
- Implementar una interfaz supone sobrescribir (implementar) de una forma adecuada y concreta todos los métodos definidos en la interfaz.
- Una sola clase puede implementar muchas interfaces.
- Los métodos sobrecargados pueden cambiar el tipo de retorno, los métodos sobrescritos no (excepto en el caso de los retornos covariantes).
- Si el tipo de retorno es un tipo de objeto, se puede devolver null como valor.
- Una matriz (array) es un tipo de retorno válido, tanto para ser declarado como devuelto.
- Para métodos que devuelven tipos primitivos, cualquier valor que pueda ser implícitamente convertido al tipo devuelto es válido como retorno.
- Nada puede ser devuelto por un método marcado como void. Se permite simplemente decir return.
- Los métodos que pueden devolver una referencia a un objeto, pueden devolver un subtipo del objeto.
- Los métodos que pueden devolver una interfaz, pueden devolver cualquier objeto que la implemente.
- Cuando se crea un objeto nuevo siempre se invoca un constructor.
- Todas las superclases de un árbol de herencia encadenarán llamadas a sus constructores.
- Todas las clases, incluso las abstractas, tienen al menos un constructor.
- Los constructores deben tener el mismo nombre que la clase.
- Los constructores no tiene tipo de retorno. Si lo tuvieran, se trataría de un método con el mismo nombre que la clase y no de un constructor.
- La ejecución normal de un constructor es como sigue:
- El constructor de la clase llama al constructor de su superclase, la cual llama al constructor de su superclase y así hasta llegar al constructor de la clase Object.
- El constructor de la clase Object es ejecutado y devuelve el control al constructor que le llamó, y así hasta llegar al constructor de la clase que inicio la llamada, que al terminar crea una instancia de la clase.
- Los constructores pueden usar cualquier modificación de acceso, incluso private.
- El compilador crea un constructor por defecto si no se define uno en la clase.
- El constructor por defecto es un constructor sin parámetros con una llamada a super().
- La primera sentencia de un constructor debe ser una llamada a this() (o constructor sobrecargado) o super().
- El compilador añade una llamada a super() a menos que ya exista una llamada a this() o super().
- Los miembros de instancia estarán disponibles o accesibles solo después de ejecutarse el constructor del super.
- Las clases abstractas tienen constructores (nunca podrán sobrescribirse) que son llamados cuando una subclase concreta es instanciada.
- Las interfaces no tienen constructores.
- Si la superclase no tiene un constructor sin parámetros, debe crearse un constructor con una llamada al super con los parámetros necesarios.
- Los constructores nunca se heredan, no pueden ser sobrescritos.
- Un constructor solo puede ser invocado desde otro constructor (usando llamadas a super() o this()).
- Cuestiones con la llamada a this():
- Solo puede aparecer como la primera sentencia de un constructor.
- La lista de parámetros determina el constructor sobrecargado a llamar.
- Los constructores puede llamar a constructores que pueden llamar a otros constructores (de la misma clase), y así sucesivamente, hasta que tarde o temprano uno de ellos llama al super() o explota la pila.
- Las llamadas this() y super() no pueden estar en el mismo constructor. Puede utilizarse una de ellas, pero no las dos.
Usamos métodos estáticos para implementar comportamientos que no afecten al estado de las instancias.
Las variables definidas como estáticas mantienen el mismo valor para todas las instancias de la clase que la contiene.
Todos los miembros estáticos pertenecen a la clase y no a cualquiera de sus instancias.
Un método estático no puede acceder directamente a las variables de instancia de la clase.
Usamos el operador punto para acceder a los miembros estáticos. Recordemos que usar una variable de referencia con el operador punto es un truco de sintaxis, y el compilador sustituye la variable de referencia por el nombre de la clase: d.methodStatic() por ClassName.methodStatic(). Por ejemplo:
// Estatica.java:
class Una { static void metodoEstatico () { System.out.println("Una.metodoEstatico"); } void metodoNoEstatico(){ System.out.println("Una.metodoNoEstatico"); } } public class Estatica extends Una { static void metodoEstatico () { System.out.println("Estatica.metodoEstatico"); } void metodoNoEstatico(){ System.out.println("Estatica.metodoNoEstatico"); } public static void main (String... args) { Una una = new Estatica(); // El compilador lo sustituira por Una.metodoEstatico una.metodoEstatico(); // El compilador lo sustituira por Estatica.metodoEstatico ((Estatica)una).metodoEstatico(); // El compilador comprueba que metodoNoEstatico está en Una, // pero en ejecución, el polimormismo usará el de Estatica. una.metodoNoEstatico(); // Intentar forzar al compilador a usar Una.metodoNoEstatico // no tiene éxito, ya que el polimorfismo obliga a usar el // método sobrescrito metodoNoEstatico de Estatica ((Una)una).metodoNoEstatico(); } }Los métodos estáticos no pueden ser sobrescritos, pero pueden ser redefinidos.
- El acoplamiento se refiere al grado en que una clase conoce o usa los miembros de otra clase.
- Un acoplamiento débil es el estado deseado que tienen que tener las clases para una buena encapsulación, minimizando las referencias a otras y limitando la amplitud del uso de API.
- Un acoplamiento fuerte es el estado no deseable que tienen las clases que rompen las reglas del acoplamiento débil.
- La cohesión se refiere al grado en el cual las clases tienen una sola responsabilidad o papel bien definido.
- Una alta cohesión es el estado deseado de una clase cuyos miembros cumplen un única función o responsabilidad.
- Una baja cohesión es el estado no deseado de una clase cuyos miembros cumplen múltiples funciones o responsabilidades.
- 1.3 Literales, asignaciones y variables (215), declaración de matrices,
- construcción e inicialización: Desarrollar código que declare, inicialice y use primitivas, arreglos, enums y objetos como variables estáticas, de instancia y locales. Asimismo, utilizar identificadores válidos para los nombres de variable.
- 1.5 Sobrecarga (276):
- Con un ejemplo de código dado, determinar si un método está sobrescribiendo o sobrecargando correctamente otro método e identificar valores de retorno válidos (incluidos valores de retorno covariantes) para el método.
- 3.1 Usando clases envoltorio y encaje (266):
- Desarrollar código que utilice las clases wrapper primitivas (como booleano, carácter, doble, entero, etc.) y/o autoboxing y unboxing. Describir las diferencias entre las clases String, StringBuilder y StringBuffer.
- 5.4 Sobrecarga (276):
- En una situación dada, desarrollar código que declare y/o llame a métodos sobrescritos o sobrecargados y código que declare y/o llame a constructores de superclase, sobrescritos o sobrecargados.
- 7.3 Pasando variables a métodos (242):
- Determinar cómo afectan las referencias de objeto y valores primitivos cuando son pasados a métodos que realizan asignaciones u otras modificaciones en los parámetros.
- 7.4 Recolección de basura (283):
- Con un ejemplo de código reconocer el momento en el que un objeto se convierte en elegible del garbage collection, determinar que está y que no está garantizado por el sistema del garbage collection y reconocer los comportamientos del método Object.finalize().
- 7.6 Literales, asignaciones y variables (215):
- Escribir código que aplique correctamente los operadores adecuados para obtener el resultado deseado, incluidos los operadores de asignación limitados a: =, +=, -=), los operadores aritméticos (limitado a: +, -, *, /, %, ++, --), los operadores relacionales (limitado a: <, <=, >, >=, ==, !=), el operador instanceof, los operadores lógicos (limitado a: &, |, ^, !, &&, ||) y el operador condicional ( ? : ), para producir un resultado deseado. Escribir código que determine la igualdad de dos objetos o dos primitivas.
- Las variables locales (variables de método) viven en la pila.
- Los objetos y sus variables de instancia viven en el montículo.
- Los literales enteros pueden ser decimales, octales (precedidos por 0) y hexadecimales (precedidos por 0x).
- Los literales long finalizan en L o l
- Los literales float finalizan en F o f, los literales double finalizan en D o d.
- Los literales boolean son true o false.
- Los literales para chars son un solo carácter encerrado entre comillas simples: 'c'.
- El entorno o ámbito se refiere al tiempo de vida de una variable.
- Hay 4 tipos de entornos básicos:
- La vida de las variables estáticas es tan larga como la vida de su clase.
- La vida de las variables de instancia es tan larga como la vida de su objeto.
- La vida de las variables locales es tan larga como la vida de su método en la pila; sin embargo, si su método invoca a otro método, quedan temporalmente no disponibles.
- Las variables de bloque (por ejemplo: en un for o un if) viven hasta que se completa el bloque.
Los literales enteros son implícitamente int.
Las expresiones enteras siempre tienen como resultado un valor de tamaño entero, nunca más pequeño.
Los números en coma flotante son implícitamente doubles (64 bits).
Una reducción de un tipo primitivo trunca los bits menos significativos (high order bits).
La asignaciones compuestas (p.e: +=) ejecutan un moldeado (cast) automático.
Una variable de referencia mantiene los bits que son usados para referenciar a un objeto.
Las variables de referencia pueden referenciar a subclases de un tipo declarado pero no a superclases. P.e: Si Beagle ES-UN Dog y Dog ES-UN Animal:
Dog d = new Beagle(); // correcto, Beagle es una subclase de Dog Dog d = new Animal(); // incorrecto, Animal es una superclase de DogCuando creamos un objeto nuevo, p.e.: Button b = new Button();, suceden 3 cosas:
- Creamos una variable de referencia llamada b de tipo Button.
- Creamos un nuevo objeto Button.
- Asignamos el objeto Button a la variable de referencia b.
- Cuando una matriz de objetos es instanciada, los objetos dentro de la matriz no son instanciados automáticamente, pero todas las referencias obtienen el valor por defecto null.
- Cuando una matriz de tipos primitivos es instanciada, los elementos de la matriz son inicializados con sus valores por defecto.
- Las variables de instancia son siempre inicializadas con sus valores por defecto (las primitivas a 0, las de referencia a null, sean static o no).
- Las variables locales, automáticas o de método nunca tienen un valor por defecto. Si las usamos antes de su inicialización obtenemos un error del compilador.
- Los métodos puede tomar tipos primitivos y/o referencias a objetos como parámetros.
- Los parámetros de un método son siempre copias.
- Los parámetros de un método nunca son objetos, aunque pueden ser referencias (copias de referencias) a objetos.
- Un parámetro de tipo primitivo es una copia independiente del tipo primitivo original.
- Un parámetro de referencia es otra copia de la referencia del objeto original.
- El sombreado (shadowing) ocurre cuando dos variables de distintos entornos comparten el mismo nombre. Esto da lugar a errores difíciles de encontrar, y preguntas de examen difíciles de contestar.
- El modificador final de un argumento se usa en la declaración de métodos para evitar que al llamar al método se modifique el valor del argumento (contenido de la referencia o valor primitivo) en su interior.
Las matrices pueden mantener tipos primitivos u objetos, pero las matrices (en si mismas) son siempre un objeto.
Cuando declaramos una matriz, los corchetes pueden ir a la izquierda y/o a la derecha del nombre.
Nunca debe incluirse el tamaño de la matriz en la declaración, pero sí puede (y debe, si no se inicializa) llevarla la definición.
Debemos incluir el tamaño de la matriz cuando la construimos (usando new) a menos que la creemos con una matriz anónima. Por ejemplo:
int[] a = new int[3]; // No inicializada int[] b = new int[] {1,3,4}; // Inicializada, conoce tamañoLos elementos en una matriz no son automáticamente creados, aunque si los elementos de la matriz son de tipo primitivo tiene asignados valores por defecto.
Obtenemos la excepción NullPointerException si usamos un elemento de la matriz que no tiene una referencia a un objeto real.
Las matrices son indexadas comenzando por el cero.
La excepción ArrayIndexOutOfBoundsException sucede cuando usamos un valor de índice incorrecto.
Las matrices tienen la variable length, cuyo valor es el número de elementos en la matriz.
El último elemento de la matriz puede ser siempre accedido restándole uno a la variable length.
Las matrices multidimensionales son matrices de matrices.
Las dimensiones de una matriz multidimensional puede tener diferentes tamaños.
Una matriz de tipos primitivos puede aceptar cualquier valor que pueda ser promovido implícitamente al tipo de la matriz, p.e. una variable byte puede ser un elemento válido para una matriz de tipo int:
byte b = 0; // b se promueve a int, Integer se 'desencaja' en int int[] a = { b, 1, new Integer(3), Integer.parseInt("4") }; // OJO, NO VÁLIDO: b no puede ensancharse y encajarse //Integer[] a = { b, 1, new Integer(3), Integer.parseInt("4") }; // Así sí Integer[] a = { (int)b, 1, new Integer(3), Integer.parseInt("4") };Una matriz de objetos puede mantener cualquier objeto que cumpla la relación ES-UN (o instanceof) para el tipo declarado por la matriz. Por ejemplo, Si Caballo extiende Animal, entonces un objeto Caballo puede ir dentro de una matriz Animal.
Si asignamos una matriz a otra matriz previamente declarada, estas deben ser de las mismas dimensiones:
int[] i = new int[3]; // Matriz de dimensión 1 tamaño 3 int[] j = new int[5]; // Matriz de dimensión 1 tamaño 5 int[][] a = new int[1][1]; // Dimensión 2 tamaños 1 y 1 i = j; // Válido, ya que tienen misma dimensión i = a[0]; // Válido, a[0] es una matriz de dimensión 1 //a = i; // No válido, a tiene dimensión 2, i 1Podemos asignar una matriz de un tipo a otra matriz previamente declarada de uno de sus supertipos. Por ejemplo, una matriz Honda puede ser asignada a una matriz declarada del tipo Coche ya que Honda extiende Coche:
Honda[] h = new Honda[3]; // Honda ES-UN Coche Coche[] c = new Coche[1]; // Coche no ES-UN Honda c = h; // Válido, tienen mismas dimensiones y son compatibles //h = c; // No válido, Coche no ES-UN Honda
- Los bloques de inicialización estáticos se ejecutan una vez, cuando la clase se carga por primera vez (incluso antes de que se ejecute main).
- Los bloques de inicialización de instancia se ejecutan cada vez que una nueva instancia es creada. Son ejecutados después de la ejecución de todos los super-constructores y antes del constructor de la clase.
- Si existen varios bloques de inicio en una clase, son ejecutados en el orden en el que aparecen en el archivo fuente.
- Todas las clases envoltorio se correlacionan con tipos primitivos.
- Las clases envoltorio tienen dos funciones principales:
- Envolver los tipos primitivos para que puedan ser gestionados como objetos.
- Proporcionar métodos de utilidad para los tipos primitivos (normalmente con versiones).
- Las tres familias de métodos más importantes son:
- xxxValue(): no tienen parámetros, devuelve un tipo primitivo.
- parseXxx(): static, toma un String, devuelve el valor de la cadena en un tipo primitivo, excepción: NumberFormatException (NFE).
- valueOf(): static, toma un String, devuelve un objeto envoltorio, excepción: NFE
- Los constructores de las clases envoltorio puede tomar un String o un tipo primitivo, excepto para Character que solo puede tomar un char.
- Radix se refiere a la base, normalmente base 10. Si Radix=8 es octal y si es 16 hexadecimal.
- Las clases envoltorio son finales e inmutables. No se pueden subclasificar y, una vez construido el objeto del tipo, no podrá nunca cambiarse su valor.
Abreviaturas:
- s
static
- n
lanza NumberFormatException
- R
requiere base de numeración (10, 8 ó 16)
- p
devuelve un tipo primitivo
Método Boolean Byte Char Double Float Integer Long Short byteValue x x x x x x doubleValue x x x x x x floatValue x x x x x x intValue x x x x x x longValue x x x x x x shortValue x x x x x x . parseXxx s,n x x x x x x parseXxx s,n,R x x x x . valueOf s,n x x x x x x x valueOf s,n,R x x x x . toString s x x x x x x x x toString s,p x x x x x x x x toString s,p,R x x
- A partir de Java 5, el encaje (boxing) permite convertir de tipos primitivos a sus clases envoltorio y el desencaje (unboxing) permite convertir de clases envoltorio a sus tipos primitivos automáticamente.
- La utilización del == con objetos envoltorio creados mediante encaje (sin el operador new) es mañoso; aquellos que tengan pequeños valores (típicamente entre -128 y 127) y tipos Boolean, Byte, Character, Short, Integer y Long serán iguales (==), los valores mayores no serán iguales (!=).
- El desencaje (unboxing) solo es posible si la referencia a desencajar apunta a un objeto no nulo. Si la refencia contiene null, la conversión lanzaría NullPointerException.
- El encaje (boxing) también se realiza con literales. Es posible inicializar objeto envoltorio con literales
El ensanchamiento de tipos primitivos utiliza el método del argumento "más pequeño" posible.
Utilizados por separado, el encaje y los arg-var son compatibles con la sobrecarga.
No puede utilizarse ensanchamiento de un tipo envoltorio a otro (ES-UN falla).
No puede utilizarse ensanchado y encaje (un int no puede convertirse en un Long).
Es posible encajar o desencajar y luego ensanchar (un int puede convertirse en Object a través de Integer y un Integer puede desencajarse en int para después ensancharlo a long).
Pueden combinarse arg-var tanto con ensanchado como con encaje.
El ensanchamiento de tipos envoltorio utiliza el método del tipo más general (p.e. de Integer se ensancha en Number u Objeto).
Ejemplo:
// Sobrecarga:
public class Sobrecarga { static String metodo(Integer i, Integer j) { return "Integer Integer"; } static String metodo(Short s, int i) {return "Short int";} static String metodo(int... i) {return "int... ";} public static void main(String... args) { int i = 0; // Primero: encaja ambos argumentos a Integer System.out.println("Parámetros int ejecutamos metodo(" + metodo(i, i) + ")"); short s = 0, t = 0; // Segundo: encaja s a Short y ensancha t a int System.out.println("Parámetros short ejecutamos metodo(" + metodo(s, t) + ")"); byte b = 0; // Tercero: ensancha ambos, no puede ensanchar y encajar System.out.println("Parámetros byte ejecutamos metodo(" + metodo(b, b) + ")"); } }
- En java, la recolección de basura (GC) provee de gestión de memoria automática.
- El objetivo de la GC es eliminar objetos que no pueden alcanzarse.
- Solo la MVJ decide cuando ejecutar la GC, aunque puede sugerírselo.
- No es posible conocer el algoritmo de la GC con seguridad.
- Los objetos deben ser considerados elegibles antes de ser recolectados como basura.
- Un objeto es elegible cuando ningún hilo vivo puede alcanzarlo.
- Para alcanzar un objeto, debe haber una referencia viva y alcanzable al objeto.
- Las aplicaciones Java se pueden quedar sin memoria.
- Las islas de objetos pueden ser recolectadas como basura incluso si tienen referencias entre sí (enlazan objetos inalcanzables).
- La llamada para recolección de basura es System.gc(); (solo hasta el SCJP 6).
- La clase Object tiene un método finalize().
- Se garantiza que el método finalize() se ejecutará una y sólo una vez antes de que el recolector de basura elimine un objeto.
- El recolector de basura no da garantías de que finalize() no se ejecute nunca.
- Es posible hacer no elegible un objeto para la GC desde dentro de finalize().
- 7.6 Operadores Java (317):
- Escribir código que aplique correctamente los operadores adecuados para obtener el resultado deseado, incluidos los operadores de asignación limitados a: =, +=, -=), los operadores aritméticos (limitado a: +, -, *, /, %, ++, --), los operadores relacionales (limitado a: <, <=, >, >=, ==, !=), el operador instanceof, los operadores lógicos (limitado a: &, |, ^, !, &&, ||) y el operador condicional ( ? : ), para producir un resultado deseado. Escribir código que determine la igualdad de dos objetos o dos primitivas.
- Los operadores relacionales siempre producen un valor boolean (true o false).
- Hay seis operadores relacionales: >, >=, <, <=, == y !=. Los dos últimos (== y !=) son referidos a veces como operadores de igualdad.
- Cuando compara caracteres, Java utiliza el valor Unicode del carácter como valor numérico.
- Operadores de igualdad
- Hay dos operadores de igualdad: == y !=.
- Pueden compararse valores de cuatro tipos: números, caracteres, booleanos y variables de referencia.
- Cuando se comparan variables de referencia, == devuelve true solo si ambas variables son referencias al mismo objeto.
- El operador == sólo admite tipos compatibles: primitivas, desencajes (uno de los dos operandos es primitivo), o tipos idénticos.
- instanceof sólo se usa con variables de referencia y verifica si un objeto es de un tipo determinado.
- El operador instanceof puede usarse solo para probar objetos (o null) contra tipos de clases que estén en la misma jerarquía de clases.
- Para interfaces, un objeto pasa la prueba de instanceof si cualquiera de sus superclases implementa la interfaz en la parte derecha del operador instanceof.
- Hay cuatro operadores matemáticos principales: sumar, restar, multiplicar y dividir.
- El operador resto (%) devuelve el resto de una división.
- Las expresiones son evaluadas de izquierda a derecha, a no ser que se añadan paréntesis o que algunos operadores de la expresión tengan mayor precedencia que otros.
- Los operadores *, / y % tienen mayor precedencia que + y -.
- Si uno de los dos operadores es un String, el operador + concatena los operandos.
- Si ambos operandos son numéricos, el operador + suma los operandos.
- La concatenación de operadores + se evalúa de izquierda a derecha (por pares); si uno o más operandos son cadenas, el resultado terminará siendo una cadena.
- Los operadores prefijos (++ y --) se ejecutan antes del uso del valor en la expresión.
- Los operadores postfijos (++ y --) se ejecutan después del uso del valor en la expresión.
- En cualquier expresión, ambos operandos se evalúan completamente antes de aplicar el operador.
- Las variables marcadas final no pueden ser incrementadas o decrementadas.
- Devuelve uno de dos valores basándose en si una expresión boolean es true o false.
- Devuelve el valor detrás de ? si la expresión es true.
- Devuelve el valor detrás de : si la expresión es false.
- El examen cubre seis operadores "lógicos": &, |, ^, !, && y ||.
- Los operadores lógicos funcionan con dos expresiones (excepto !) que deben resolverse en valores boolean.
- Los operadores && y & devuelven true solo si ambos operandos son true.
- Los operadores || y | devuelven true si uno de los dos operandos es true.
- Los operadores && y || son conocidos como operadores cortocircuito.
- El operador && no evalúa el operando derecho si el operando izquierdo es false.
- El operador || no evalúa el operando derecho si el operando izquierdo es true.
- Los operadores & y | siempre evalúan ambos operandos.
- El operador ^ (llamado "XOR lógico") devuelve true si exactamente un operando es true.
- El operador ! (llamado operador "inversión") devuelve el valor opuesto del operando boolean al que precede.
- 2.1 Las sentencias if y switch (357):
- Desarrollar código que implemente una instrucción if o switch e identificar tipos de argumentos válidos para estas instrucciones.
- 2.2 Bucles e iteradores (Iterator) (372):
- Desarrollar código que implemente todas las formas de ciclos e iteradores, incluidos el uso de for, el ciclo mejorado (for-each), do, while, labels, break y continue. Indicar los valores que adoptan las variables de control del ciclo durante y después de la ejecución del ciclo.
- 2.3 Trabajando con el mecanismo de asertos (412):
- Escribir código que utilice afirmaciones y distinga entre el uso apropiado e inapropiado de las afirmaciones.
- 2.4 Manejando excepciones (385):
- Desarrollar código que utilice excepciones y cláusulas de manejo de excepciones (try, catch, finally), y declarar métodos y sobreescribir métodos que generen excepciones.
- 2.5 Manejando excepciones (385):
- Reconocer el efecto que produce una excepción que se genera en un punto dado de un fragmento de código. Puede ser una excepción runtime, una excepción comprobada (checked) o un error.
- 2.6 Excepciones y errores más comunes (407):
- Reconocer las situaciones en las que se generará alguna de las siguientes exceptions: ArrayIndexOutOfBoundsException,ClassCastException, IllegalArgumentException, IllegalStateException, NullPointerException, NumberFormatException, AssertionError, ExceptionInInitializerError, StackOverflowError o NoClassDefFoundError. Saber cuáles genera la máquina virtual y en qué situaciones deberían generarse programáticamente otras exceptions.
La única expresión legal en una sentencia if es una expresión boolean; en otras palabras, una expresión que se resuelve a una variable de tipo boolean o a una referencia a un objeto de tipo Boolean (en cuyo caso debe estar inicializada a un objeto no nulo).
Cuidado con las asignaciones (=) de boolean, pueden confundirse con la prueba boolean de igualdad (==).:
boolean x = false; if (x = true) { } // una asignación, ¡así que x siempre será true!Las llaves son opcionales en los bloques if que sólo tengan una sentencia condicional, pero cuidado con la indentación confusa.
Las sentencias switch pueden evaluarse sólo con tipos enum, byte, short, int y char. No puede usarse: long s = 30; switch(s) { }
La constante case debe ser un literal, una variable final o una expresión constante, incluyendo un enum. No puede haber un caso que incluya una variable no final o un rango de valores.
Si la condición de una sentencia switch se corresponde con una constante case, la ejecución seguirá a través de todo el código del switch que siga a la sentencia case correspondiente hasta una sentencia break o hasta que se encuentre el final de la sentencia switch. En otras palabras, el case que coincida será sólo el punto de entrada al bloque case pero, a no ser que haya una sentencia break, el case correspondiente no será el único código case que se ejecutará.
La palabra clave default deberá ser usada en una sentencia switch si quiere ejecutar algún código cuando ninguno de los valores case se corresponden con el valor condicional.
El bloque default puede localizarse en cualquier lugar del bloque switch; si no hay ningún case coincidente, se entrará en el bloque default y, si éste no contiene un break, entonces el código se seguirá ejecutando (cayendo) hasta el final del switch o hasta que se encuentre una sentencia break.
- Una sentencia for básica tiene tres partes: declaración y/o inicialización, evaluación booleana y la expresión de iteración.
- Si una variable es incrementada o evaluada dentro de un bucle for básico, debe ser declarada antes del bucle o dentro de la declaración del bucle for.
- Una variable declarada (pero no inicializada) dentro de la declaración del bucle for básico no puede accederse desde fuera del bucle for. En otras palabras, el código debajo del bucle for no podrá utilizar la variable.
- No se puede inicializar más de una variable del mismo tipo en la primera parte de la declaración del bucle for básico. Cada inicialización debe ir separada por una coma.
- La sentencia mejorada for (nueva en Java 6) tiene dos partes: la declaración y la expresión. Se utiliza sólo para iterar sobre matrices y colecciones.
- En un for mejorado, la expresión es una matriz o colección sobre la que queremos iterar.
- En un for mejorado, la declaración es el bloque con la variable cuyo tipo es compatible con los elementos de la matriz o colección y dicha variable contiene el valor del elemento en la cada iteración.
- No se puede usar un número (vieja construcción al estilo C) o ningún otro valor que no se evalúe en boolean como condición de una sentencia if o construcción de bucle. No se puede, por ejemplo usar "if(x)" a no ser que x sea una variable boolean.
- El bucle do entrará en el cuerpo del bucle al menos una vez, incluso si la condición de prueba no se verifica.
- Una sentencia break sin etiqueta causará que la iteración actual de la construcción de bucle más interna se detenga y continúe en la línea de código siguiente al bucle.
- Una sentencia continue sin etiqueta provocará que: la iteración actual del bucle más interno se detenga, que la condición de ese bucle se evalúe y que, si la condición se verifica, el bucle se ejecute de nuevo.
- Si las sentencias break o continue tienen etiqueta, se ejecutará una acción similar en el bucle etiquetado, no en el bucle más interno.
Las excepciones tienen dos tipos: verificadas y no verificadas.
Las excepciones verificadas incluyen todos los subtipos de Exception, excepto las clases que heredan de RuntimeException.
Las excepciones verificadas están sujetas a la regla de declarar o manejar: cualquier método que pueda lanzar una excepción manejada (incluidos los que invoquen métodos que puedan lanzar una excepción manejada) deben declarar la excepción usando throws y/o manejarla con el try/catch apropiado.
Los subtipos de Error y RuntimeException son excepciones no verificadas, así que el compilador no obliga a la regla declarar o manejar. Es opcional manejarla o declararla, pero al compilador no le importará ni la una ni la otra.
Si se usa el bloque opcional finally, siempre será invocado, independientemente de si se lanza una excepción en el bloque try correspondiente o no y de si una excepción lanzada se captura o no.
La única excepción a la regla de ejecución segura de finally es que finally no se invocará si la MVJ de detiene. Esto puede ocurrir si el código de un bloque try o catch llama a System.exit().
Solo porque finally sea invocado no significa que termine. El código del bloque finally también puede lanzar una excepción o llamar a System.exit().
Las excepciones no capturadas se propagan hacia abajo en la pila empezando desde el método en que se lanza la excepción y terminando en el primer método que tenga una captura correspondiente al tipo de excepción o con una parada de la MVJ, lo que puede ocurrir si la excepción llega a main() o main () relanza la excepción declarándola.
Es posible crear excepciones propias, normalmente heredando de Exception o de uno de sus subtipos. La excepción propia será considerada una excepción verificada y el compilador obligará a cumplir la regla de declarar o manejar para esa excepción.
Todos los bloques catch deben estar ordenados de más específico a más general. Si hay una cláusula catch tanto para IOException como para Exception, debe ponerse primero el bloque catch de IOException. Si no, la IOException sería capturada por el catch(Exception e), ya que el argumento de catch puede capturar la excepción especificada o cualquiera de sus subtipos. El compilador evitará que se definan cláusulas catch que no puedan ser alcanzadas.
Los programadores pueden crear algunas excepciones; otras son creadas por la MVJ.
Jerarquía de errores y excepciones:
Nombre
Throwable
Error
Exception
RuntimeException
NullPointerException
X
X
X
ArithmeticException
X
X
X
IllegalArgumentException
X
X
X
NumberFormatException**
X
X
X
IndexOutOfBoundsException
X
X
X
IllegalMonitorStateException
X
X
X
ClassNotFoundException
X
X
InterruptedException
X
X
IOException*
X
X
NotSerializableException*
X
X
AssertionError
X
X
StackOverflowError
X
X
OutOfMemoryError
X
X
- (*)
IOException y NotSerializableException (que hereda de IOException) son las únicas excepciones de java.io, el resto están todas en java.lang y no necesitan importación explícita.
- (**)
NumberFormatException, además hereda de IllegalArgumentException
Puede escribirse un bloque try/finally (sin parte catch). En este caso, las excepciones no serán capturadas, si no propagadas hacia arriba en la pila, aunque el bloque finally se ejecutará siempre y antes de propagar la excepción.
La sintaxis de assert es la siguiente:
assert(<expresión booleana>)[:<expresión que devuelva algo>];La segunda parte (incluyendo los dos puntos) es opcional y, si se incluye, el aserto falla (la primera expresión se evalúa a false) y se habilitaron asertos para la clase en que incluyó, se imprimirá como mensaje del error AssertionError seguido de resto del volcado de pila.
Los asertos proporcionan un modo de probar las asunciones durante el desarrollo y depuración.
Los asertos se habilitan normalmente durante las pruebas, pero se deshabilitan en el despliegue.
Es posible usar assert como palabra clave (desde la versión 1.4) o como identificador, pero no como ambos a la vez. Para compilar código antiguo que utiliza assert como identificador (por ejemplo, como nombre de método) use el indicador de línea de comandos -source 1.3 en javac.
Los asertos están deshabilitados en tiempo de ejecución por defecto. Para habilitarlos, use el indicador de línea de comandos -ea o -enableassertions.
Es posible habilitar asertos selectivamente usando los indicadores -da o - disableassertions.
Si habilita o deshabilita los asertos usando los indicadores sin argumentos, se hace de forma general. Es posible combinar los conmutadores de habilitar y deshabilitar para habilitar asertos en algunas clases/paquetes pero no en otros.
Es posible habilitar y deshabilitar asertos clase por clase utilizando la sintaxis: java -ea -da:MiClase ClasePrueba
Es posible habilitar y deshabilitar asertos paquete por paquete y cualquier paquete especificado también incluirá los subpaquetes (paquetes por debajo de la jerarquía de directorios).
No use asertos para validar los argumentos de métodos public.
No use expresiones assert que causen efectos laterales. No se garantiza que los asertos se ejecuten siempre: es indeseable que el comportamiento cambie dependiendo de si los asertos están habilitados o no.
Use asertos (incluso en métodos públicos) para validar un bloque de código que no debe ser ejecutado nunca. Se usa assert false; para código que nunca debe alcanzarse, de modo que se lance un error en el aserto inmediatamente si la sentencia del assert se ejecuta.
- 3.1 String, StringBuilder y StringBuffer (454):
- Desarrollar código que utilice las clases wrapper primitivas (como booleano, carácter, doble, entero, etc.) y/o autoboxing y unboxing. Describir las diferencias entre las clases String, StringBuilder y StringBuffer.
- 3.2 Navegación de ficheros y E/S (471):
- En una situación en la que se requiera desplazarse por los file systems, leer archivos o escribir en archivos, desarrollar la solución adecuada mediante el uso de las siguientes clases (o una combinación de ellas) del paquete java.io: BufferedReader, BufferedWriter, File, FileReader, FileWriter y PrintWriter.
- 3.3 Serialización (487):
- Desarrollar código que serialice y/o deserialice objetos mediante el uso de las siguientes API de java.io: DataInputStream, DataOutputStream, FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream y Serializable.
- 3.4 Fechas, números y moneda (501):
- Utilizar API de J2SE estándar del paquete java.text para asignar formato y analizar correctamente fechas, números y valores de moneda de una configuración regional específica. En una situación dada, determinar los métodos que se deben utilizar si se desea emplear la configuración regional predeterminada u otra específica. Describir el objetivo y la utilidad de la clase java.util.Locale.
- 3.5 Análizando, trozeando y formateando (515):
- Escribir código que utilice API de J2SE estándar de los paquetes java.util y java.util.regex para asignar formato o analizar cadenas o secuencias. Para cadenas, escribir código que utilice las clases Pattern y Matcher y el método String.split. Reconocer y utilizar patrones de expresión regulares para establecer la coincidencia (limitado a: . (punto), * (asterisco), + signo más), ?, d, s, w, [], ()). El uso de *, + y ? se limitará a cuantificadores greedy y el operador de paréntesis sólo se empleará como mecanismo de agrupación, en lugar de para capturar contenido durante la coincidencia. Para secuencias, escribir código utilizando las clases Formatter y Scanner y los métodos PrintWriter.format/printf. Reconocer y utilizar los parámetros de formato (limitado a: %b, %c, %d, %f, %s) en cadenas de formato.
- Los objetos String son inmutables, las variables de referencia de tipo String no.
- Si se crea un nuevo String sin asignarlo, se perderá para el programa.
- Si se redirige una referencia a String a un String nuevo, el antiguo String puede perderse.
- Los métodos de String usan índices basados en cero, excepto el segundo argumento de substring(a, b). Se cumple que la longitud de la subcadena será b - a.
- La clase String es final; sus métodos no pueden sobrescribirse.
- Cuando la MVJ encuentra un literal String, lo añade al área de literales String (String pool). Por esto dos literales iguales (repetidos) verifican la relación ==.
- Las cadenas tienen un método llamado length(), las matrices tienen un atributo llamado length.
- El API de StringBuffer es idéntico al nuevo API de StringBuilder, excepto que los métodos de StringBuilder no están sincronizados para uso seguro en hilos.
- Los métodos de StringBuilder se deberían ejecutar más rápido que los correspondientes de StringBuffer.
- Todos los puntos siguientes aplican tanto a StringBuffer como a StringBuilder:
- Son mutables: pueden cambiar sin crear un nuevo objeto.
- Los métodos actúan en el objeto invocado, así que pueden cambiar sin una asignación explícita en la sentencia.
- El método equals() no está sobrescrito: no compara valores.
- Recuerde que los métodos encadenados se evalúan de izquierda a derecha.
- Métodos a recordar de String: charAt(), concat(), equalsIgnoreCase(), length (), replace(), substring(), toLowerCase(), toString(), toUpperCase() y trim().
- Métodos de StringBuffer a recordar: append(), delete(), insert(), reverse() y toString().
- El método equals() devuelve true si los tipos primitivos y los valores de los objetos que compara son iguales.
- Las clases java.io que es necesario entender son: File, FileReader, BufferedReader, FileWriter, BufferedWriter, PrintWriter y Console.
- Un objeto File nuevo no significa que haya un nuevo fichero en el disco.
- Los objetos File pueden representar tanto un fichero como un directorio.
- La clase File permite gestionar (añadir, renombrar y eliminar) ficheros y directorios.
- Los métodos createNewFile() y mkdir() añaden entradas en el sistema de ficheros.
- FileWriter y FileReader son clases de E/S de bajo nivel. Pueden usarse para leer y escribir en ficheros, pero normalmente suelen envolverse.
- Las clases de java.io está diseñadas para ser "encadenadas" o "envueltas". Este es un uso común del patrón de diseño Decorador.
- Es muy común "envolver" un FileReader con un BufferedReader o un FileWriter en un BufferedWriter para obtener acceso a métodos de más alto nivel (más convenientes).
- Los objetos PrintWriter pueden usarse para envolver objetos Writer, pero en Java 5 pueden construirse directamente desde objetos File o String.
- Los objetos PrintWriter en Java 5 tienen los nuevos métodos append(), format() y printf().
- Los objetos Console pueden leer entrada no mostrada y son instanciados utilizando System.console().
- El método readPassword() de System.console() no devuelve un String, si no un char[]
- Las clases que es necesario entender están todas en el paquete java.io. Se incluyen: ObjectOutputStream y ObjectInputStream principalmente, y FileOutputStream y FileInputStream porque las usará para crear los flujos de datos de bajo nivel que usarán las clases ObjectXxxStream.
- Una clase (y todas las clases de sus variables de instancia) deben implementar Serializable para que sus objetos puedan ser serializados.
- El método ObjectOutputStream.writeObject() serializa objetos y el método ObjectInputStream.readObject() los deserializa.
- Si se marca una variable de instancia como transient, no será serializada incluso aunque el resto del estado del objeto lo sea.
- Es posible suplantar el proceso de serialización automática de una clase implementando los métodos writeObject() y readObject(). Si se hace esto, las llamadas embebidas a defaultWriteObject() y defaultReadObject(), respectivamente, gestionarán la parte de serialización que ocurre normalmente.
- Si una superclase implementa Serializable, entonces todas sus subclases lo harán automáticamente.
- Si una superclase no implementa Serializable, entonces cuando un objeto de su subclase sea deserializado, se llamará al constructor de la superclase además de su(s) superconstructor(es).
- DataInputStream y DataOutputStream no están en el examen, al margen de lo que digan los objetivos de Sun.
- Si se marca una variable de clase como static, no será serializada incluso aunque el resto del estado del objeto lo sea.
- Las clases serializables que contengan (TIENE-UN) uno o varios objetos de clases no serializables no serán serializadas (lanzarán la excepción verificada java.io.NotSerializableException).
- Las clases que tiene que entender son: java.util.Date, java.util.Calendar, java.text.DateFormat, java.text.NumberFormat y java.util.Locale.
- La mayoría de los métodos de la clase Date han sido despreciados.
- Un objeto Date se almacena como long, el número de milisegundos desde el 1 de enero de 1970.
- Los objetos Date son intermediarios entre las clases Calendar y Locale.
- La clase Calendar provee un poderoso conjunto de métodos para manipular fechas, realizar tareas como obtener los días de la semana o añadir algún número de meses (u otros incrementos) a un año de una fecha.
- Las instancias de Calendar se crean usando métodos de factoría estáticos (getInstance()).
- Los métodos de Calendar a aprender son add(), que permite añadir o restar varios componentes (minutos, días, años y demás) de fechas y roll(), que funciona como add() pero no incrementa los componentes mayores de una fecha. Por ejemplo: añadiendo 10 meses a una fecha de octubre, el mes de la fecha cambiará a agosto, pero no se incrementará el valor del año del objeto Calendar.
- Las instancias de DateFormat se crean usando métodos estáticos de factoría (getInstance() y getDateInstance()).
- Hay varios "estilos" de formato disponibles en la clase DateFormat.
- Los estilos de DateFormat pueden aplicarse contra varios objetos Locale para crear un amplio abanico de salidas para cualquier fecha dada.
- El método DateFormat.format() se utiliza para crear cadenas que contengan fechas adecuadamente formateadas.
- La clase Locale se utiliza en conjunción con DateFormat y NumberFormat (p.e. DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);.
- Tanto los objetos DateFormat como los NumberFormat pueden ser construidos con un objeto Locale específico pero inmutable.
- Para el examen, debería saber crear objetos Locale utilizando idiomas o una combinación de idioma y país (p.e. Locale l = new Locale("es", "MX");).
- NumberFormat.parse() requiere un bloque try/catch; además el número máximo de dígitos de precisión (setMaximumFractionDigits) afecta apliando redondeo sólo al método format y no al parse.
"regex" es una abreviatura de expresiones regulares; estos son patrones usados para buscar datos dentro de fuentes de datos grandes.
Las expresiones regulares (regex) son un sublenguaje que existe en Java y otros lenguajes (como Perl).
Las expresiones regulares permiten crear patrones de búsqueda usando caracteres literales o metacaracteres. Los metacaracteres permiten buscar datos ligeramente más abstractos, como "dígitos" o "espacios en blanco".
Estudie los metacaracteres d (dígito), s (espacio), w (carácter de palabra, incluyendo letras, dígitos y _) y . (cualquier carácter).
Las expresiones regulares proveen de "cuantificadores", que permiten especificar conceptos como "busca uno o más dígitos seguidos".
Recuerde que los metacaracteres y cadenas no se mezclan bien a no ser que se "escapen" adecuadamente. Por ejemplo String s = "\\d";
Las clases Pattern y Matcher tienen las capacidades de expresiones regulares más poderosas.
Debería aprender el método matcher() y compile() de Pattern, así como los métodos matches(), pattern(), find(), start(), end() y group() de Matcher (los tres últimos lanzan IllegalStateException). Por ejemplo:
// Regex.java:
import java.util.regex.*; import static java.lang.System.*; class Regex { public static void main(String [] args) { // Usar args[0] como patrón de expresión regular Pattern p = Pattern.compile(args[0]);// Compilar antes usar Matcher m = p.matcher(args[1]); // Aplicar patrón a args[1] // Comprueba si la coincidencia completa con el patrón if(m.matches()) { out.println("Cadena completa"); } m.reset(); // La comprobación anterior altera el objeto while(m.find()) { // Mientras haya ocurrencias del patrón out.print(m.start()+": "); // Dónde empieza la ocurrencia out.println(m.group()); // La subcadena que coincide } } }Estudie los cuantificadores voraces ? (uno solo), * (cero o más), y + (uno o más) y los austeros ??, *? y +?. Usando el ejemplo anterior, si usáramos el cuantificador voraz con java Regex ".*xx" "yyxxxyxx" el resultado sería:
Cadena completa 0: yyxxxyxxY, sin embargo, con el austero java Regex ".*?xx" "yyxxxyxx":
Cadena completa 0: yyxx 4: xyxxNo es necesario aprender los métodos orientados a reemplazamiento de Matcher.
Puede usarse java.util.Scanner para realizar búsquedas de expresiones regulares simples, pero está principalmente indicado para troceado.
El troceado es el proceso de separación de datos delimitados en pequeñas piezas.
En el troceado, los datos que se desea extraer se llaman trozos (token), y las cadenas (expresiones regulares) que separan los trozos son llamados delimitadores (delimiter).
El troceado se puede realizar con la clase Scanner o con String.split().
// ScanSplit.java:
import java.util.Scanner; class ScanSplit { public static void main(String [] args) { String str = "10 none false 0 "; // Cadena a interpretar String delim = " "; // Delimitador de las porciones // Variables para guardar las porciones encontradas int i = 0; boolean b = true; String s = ""; // Uso de String.split(): devuelve una matriz de cadenas for(String p: str.split(delim)) System.out.print(p + " ");// Imprime cadena igual a str System.out.println("\n" + str); // Imprime str // Uso de Scanner: puede detenerse la búsqueda Scanner sn = new Scanner(str); sn.useDelimiter(delim); // Usamos el mismo delimitador while(b && sn.hasNext()) { // Mientras haya porciones if(sn.hasNextInt()) { // Distingue los tipos primitivos i = sn.nextInt(); } else if (sn.hasNextBoolean()) { b = sn.nextBoolean(); // Puede acabarse la iteración } else { s = sn.next(); // La siguiente porción es cadena } } // Imprime también la misma cadena si añadimos 0 al final System.out.println(i + " " + s + " " + b + " 0 "); } }Los delimitadores son caracteres como comas o expresiones regulares complejas (un String que representa una regex en Scanner y split() o un Pattern en Scanner).
La clase Scanner permite trocear datos dentro de un bucle, lo que permite detener el troceado cuando se desee.
La clase Scanner permite trocear cadenas, flujos de datos o ficheros.
El método String.split() trocea una fuente de datos entera de una vez, así que el procesamiento de grandes cantidades de datos puede ser bastante lento.
En Java 5 se usan dos métodos nuevos para formatear datos de salida. Estos métodos son format() y printf(). Estos métodos están en la clase PrintWriter; dos instancias static de esta son los objetos out y err de System.
Los métodos format() y printf() tiene idéntica funcionalidad.
El formateo de datos con printf() (o format()) se realiza usando "cadenas de formato", que son asociadas con argumentos primitivos o de cadena.
El método format() permite mezclar literales con la cadena de formato.
Los valores que debe conocer para la cadena de formato son:
%[índice_arg$][indicador][anchura][.precisión]conversor
- arg_index
Un entero seguido del símbolo $ que indica qué número de argumento irá en esta posición.
- anchura
Mínimo número de caracteres a imprimir.
- precisión
Para números en coma flotante solamente. Indica el número de digitos a imprimir después del punto decimal.
- indicadores
- (justificar a la izquierda), + (incluir signo), 0 (rellenar con ceros), "," (usar separador de grupo específico del idioma), y "(" (encerrar los números negativos con paréntesis).
- conversor
b (boolean), c (char), d (integer), f (float) y s (String).
Si el carácter conversor no se corresponde con el tipo del argumento, se lanzará una excepción.
- 6.1 Colecciones (584):
- En una situación de diseño dada, determinar las clases o interfaces de colección que deberían utilizarse para implementar ese diseño de forma adecuada, incluido el uso de la interfaz Comparable.
- 6.2 Sobreescribiendo hashCode() y equals() (570):
- Distinguir entre los valores de reemplazo correctos e incorrectos de los métodos hashCode y equals correspondientes, y explicar la diferencia entre == y el método equals.
- 6.3 Usando el marco de trabajo de las colecciones(594), Tipos genéricos (623):
- Escribir código que utilice las versiones genéricas de las colecciones del API, en particular las interfaces Set, List y Map y las clases de implementación. Identificar las limitaciones de las colecciones API no genéricas y cómo refactorizar código para utilizar versiones genéricas. Escribir código que use las interfaces NavigableSet y NavigableMap.
- 6.4 Tipos genéricos (623):
- Desarrollar código que utilice correctamente los parámetros de tipo en las declaraciones de clase/interfaz, las variables de instancia, los argumentos de métodos y los tipos de retorno. Escribir métodos genéricos o métodos que utilicen comodines y comprender las similitudes y diferencias entre estos dos métodos.
- 6.5 Usando el marco de trabajo de las colecciones(594):
- Utilizar las funciones del paquete java.util para escribir código destinado a manipular una lista para ordenarla, realizando un búsqueda binaria o convirtiéndola en un arreglo. Utilizar las funciones del paquete java.util para escribir código destinado a manipular un arreglo ordenándolo, realizando un búsqueda binaria o convirtiéndolo en una lista. Utilizar las interfaces java.util.Comparator y java.lang.Comparable para afectar la clasificación de las listas y los arreglos. Además, conocer el efecto que produce la "ordenación natural" de las clases primitivas wrapper y java.lang.String al ordenar.
- equals(), hashCode() y toString() son miembros public de Object.
- Sobrescriba toString() para que System.out.println() y otros métodos puedan ver algo útil, como el estado del objeto.
- Use == para determinar si dos variables referencian el mismo objeto.
- Use equals() para determinar si dos objetos son significativamente equivalentes.
- Si no se sobrescribe equals() los objetos no serán claves de dispersión útiles.
- Si no se sobrescribe equals(), todos los objetos serán considerados siempre diferentes.
- Las cadenas y las clases envoltorio sobrescriben equals() y representan buenas claves de dispersión.
- Cuando sobrescriba equals(), use el operador instanceof para estar seguro de que está evaluando la clase apropiada.
- Cuando sobrescriba equals(), compare los atributos significativos del objeto.
- Las propiedades del contrato de equals() son:
- Reflexiva: x.equals(x) es true.
- Simétrica: si x.equals(y) entonces y.equals(x) debe ser true.
- Transitiva: si x.equals(y) es true y y.equals(z) es true, entonces z.equals(x) debe ser true.
- Consistente: múltiples llamadas a x.equals(y) devolverán el mismo resultado.
- Elemento nulo: si x no es null, entonces x.equals(null) será false.
- Si x.equals(y) es true, entonces x.hashCode() == y.hashCode() es true.
- Si sobrescribe equals(), sobrescriba hashCode().
- HashMap, HashSet, Hashtable, LinkedHashMap y LinkedHashSet usan tablas de dispersión.
- Una sobrescritura apropiada de hashCode() mantiene el contrato de hashCode().
- Una sobrescritura eficiente de hashCode() distribuye las claves uniformemente entre sus cubos.
- Un método equals() sobrescrito debe ser al menos tan preciso como su hashCode() correspondiente.
- Recordar: si dos objetos son iguales, sus códigos de dispersión son iguales.
- Es legal que un método hashCode() devuelva el mismo valor para todas las instancias, aunque en la práctica es muy ineficiente.
- Las propiedades del contrato hashCode() son:
- Consistencia: múltiples llamadas a x.hashCode() devuelven el mismo entero.
- Si x.equals(y) es true, x.hashCode() == y.hashCode() debe ser true.
- Si x.equals(y) es false, x.hashcode() == y.hashCode() puede ser tanto true como false, pero false tiende a crear mejor eficiencia.
- Las variables transient no son apropiadas ni para equals() ni para hashCode().
- En resumen: (x.equals(y) == true) si y solo si (x.hashCode() == y.hashCode())) y si (x.hasCode() != y.hashCode()) entonces x.equals(y) == false, lo demás es opcional.
- Al añadir un elemento, primero se usa el hashCode() para localizar la caja a utilizar y después equals(); si hay un elemento igual, no se añade.
- Si no se implementa hashCode(), todos los objetos tendrán un código de dispersión distinto.
Las actividades con las colecciones más comunes son: añadir objetos, eliminar objetos, verificar la inclusión de objetos, recuperar objetos y la iteración.
Hay tres significados de "colección":
- colección: representa la estructura de datos en la cual se almacenan objetos.
- Collection: interfaz java.util de la que heredan Set y List.
- Collections: Una clase que mantiene métodos de utilidad estáticos para colecciones.
Las colecciones son de cuatro tipos: listas, conjuntos, mapeos y colas:
- Listas de cosas: ordenadas, con duplicados e índice.
- Conjuntos de cosas: pueden estar o no ordenados y/o clasificados, sin duplicados.
- Mapeos de cosas con claves: pueden o no estar ordenadas y/o clasificadas; no se permiten claves duplicadas.
- Colas de cosas a procesar: ordenadas por FIFO o por prioridad.
Cuatro subtipos de colecciones: clasificada, desclasificada, ordenada y desordenada.
- Ordenada: iterar sobre una colección en un orden específico, no aleatorio.
- Clasificada: iterar sobre una colección con un orden de clasificación.
La clasificación puede ser alfabética, numérica o definida por el programador.
Tabla de interfaces y clases principales del marco de trabajo de colecciones:
Clases/Interfaces
Collection
Map
Set
List
Queue
Util
Vector**
X
X
Hashtable**
X
HashMap
X
HashSet
X
X
ArrayList
X
X
PriorityQueue
X
X
LinkedHashMap
X
LinkedHashSet
X
X
LinkedList
X
X
X
TreeMap*
X
TreeSet*
X
X
Collections
X
Arrays
X
- (*)
TreeMap implementa, además, NavigableMap y SortedMap; TreeSet implementa, además, NavigableSet y SortedSet.
- (**)
Vector y Hashtable son clases antiguas y las únicas sincronizadas.
- ArrayList: rápida iteración y acceso aleatorio rápido.
- Vector: un ArrayList más lento, pero tiene los métodos sincronizados.
- LinkedList: buena para añadir elementos en los extremos, p.e. pilas (LIFO) y colas (FIFO).
- HashSet: acceso rápido, asegura que no hay duplicados pero sin orden.
- LinkedHashSet: sin duplicados, iteración por orden de inserción.
- TreeSet: sin duplicados, iteración en orden de clasificación.
- HashMap: actualización más rápida (clave/valor), permite la clave null y múltiples valores null.
- Hashtable: un HashMap más lento, como un Vector, debido a sus métodos sincronizados; no permite valores ni claves null.
- LinkedHashMap: iteraciones más rápidas, en orden de inserción o de último acceso; permite una clave null y múltiples valores null.
- TreeMap: un Map clasificado.
- PriorityQueue: una lista de trabajos por hacer ordenada por prioridad.
Las colecciones mantienen sólo objetos, aunque las primitivas son auto- encajadas.
Itere con el for mejorado o con un Iterator gracias a hashNext() y next().
hasNext() determina si existen más elementos sin mover el Iterator.
next() devuelve el siguiente elemento y mueve el Iterator hacia adelante.
Para que funcione correctamente, las claves de un Map deben sobrescribir equals() y hashCode().
Las colas (PriorityQueue) usan offer() o add() para añadir un elemento, poll() para eliminar la cabeza de la cola y devolver el primer elemento, peek() para mirar en la cabeza de la cola y remove() para eliminar el elemento devolviendo si lo hizo con éxito. Si se construyen con el constructor vacío, usarán orden natural.
Desde Java 6, TreeSet y TreeMap tienen los nuevos métodos de navegación floor() y higher().
Puede crear o ampliar subcolecciones vinculadas (backed collections) de objetos TreeSet y TreeMap con los métodos headXxx, tailXxx y subXxx.
Ojo: TreeSet y TreeMap "ordenan" cuando se intenta iterar sobre ellos (los elementos que almacenen deben implementar Comparable. Para poder compararse entre sí o mediante orden natural).
Importantes métodos de navegación de TreeSet y TreeMap:
Prefijo
TreeSet
TreeMap
Devuelve...
TreeSet
TreeMap
ceiling
Key(key)
el/la más bajo/a
elemento >= e
clave >= key
higher
Key(key)
el/la más bajo/a
elemento > e
clave > key
floor
Key(key)
el/la más alto/a
elemento <= e
clave <= key
lower
Key(key)
el/la más alto/a
elemento < e
clave < key
pollFirst
()
Entry()
y borra primero/a
entrada
par valor-clave
pollLast
()
Entry()
y borra último/a
entrada
par valor-clave
descending
Set()
Map()
invertido un
NavigableSet*
NavigableMap*
- (*)
El método descending sólo está disponible en Java6.
Importantes métodos de subcolecciones vinculadas son:
Método
Devuelve un...
headSet(e,b*)
subconjunto terminado en/excluyendo el elemento e
headMap(k,b*)
submapa terminado en/excluyendo clave desde el inicio
tailSet(e,b*)
subconjunto comenzado en/incluyendo e hasta el final
tailMap(k,b*)
submapa comenzando en/incluyendo key hasta el final
subSet(s,b*,e,b*)
subconjunto comenzado con s, terminado antes de e
subMap(s,b*,e,b*)
submapa comenzado en clave s, terminado antes de e
- (*)
Los argumentos booleanos sirven para especificar si los puntos inicial y final serán incluidos (true) o no (false). En Java5, los argumentos booleanos no existen y siempre los puntos inicial y final no se incluyen. En Java6 existen versiones con y sin estos argumentos. En el primer caso (argumentos booleanos), los métodos devolverán NavigableSet y NavigableMap. En el segundo caso y siempre en Java5 (sin booleanos) los métodos devolverán SortedSet y SortedMap.
- La clasificación puede realizarse en orden natural o con un Comparable o varios Comparator.
- Implemente Comparable usando int compareTo(T o) para proveer un orden de clasificación único.
- Cree tantos Comparator como formas de clasificar tenga la clase implementando int compare(T o1, T o2).
- Para buscar y clasificar elementos de List, estos deben ser "comparables".
- Para buscar en objetos matriz y List, estos deben estar clasificados primero.
- Ambas clases de java.util proveen:
- Un método sort(), para clasificar usando un Comparator o en orden natural.
- Un método binarySearch(), para buscar en una matriz o List ya clasificados.
- Arrays.asList() crea un List de una matriz y enlaza ambos objetos.
- Collections.reverse() invierte el orden de los elementos de un List.
- Collections.reverseOrder() devuelve un Comparator() que clasifica al revés.
- List y Set tienen un método toArray() para crear matrices.
- Arrays.sort() ordena una matriz usando una interfaz Comparator opcional. Si no se especifica ésta último, ordenará en orden natural.
- Arrays.binarySearch() se invoca usando una matriz ordenada, un elemento y la misma interfaz que se usó para ordenar dicha matriz; devuelve la posición del elemento encontrado (basado en 0) o un valor menor que 0 si no encuentra el elemento o se le invoca con un Comparator diferente.
Los genéricos permiten forzar la seguridad de tipos en tiempo de compilación en colecciones (u otras clases y métodos declarados usando parámetros de tipo genérico).
Un ArrayList<Animal> puede aceptar referencias del tipo Dog, Cat o cualquier otro subtipo de Animal (subclase o, si Animal es una interfaz, implementación).
Cuando se usan colecciones genéricas, no es necesario moldear para sacar elementos del tipo declarado de la colección. Con colecciones no genéricas se necesitaría moldear:
List<String> gList = new ArrayList<String>(); List list = new ArrayList(); // más código String s = gList.get(); // no se requiere moldear String s = (String)list.get(0); // sí es necesario moldearPuede pasarse una colección genérica a un método que requiere una colección no genérica, pero los resultados pueden ser desastrosos. El compilador no puede evitar que el método inserte el tipo incorrecto en la anterior colección de tipo seguro.
Si el compilador puede reconocer que el código de tipo inseguro está poniendo en peligro potencial algo que ha sido originalmente declarado como de tipo seguro, emitirá un aviso. Por ejemplo, si pasa un List<String> en un método declarado como:
void foo(List aList) { aList.add(anInteger); }se emitirá un aviso (unchecked warning) porque add() es potencialmente "inseguro".
"Compila sin error" no es lo mismo que "compila sin avisos". Un "aviso" de compilación no es considerado un "error" o "fallo" de compilación.
La información de tipo genérico no existe en tiempo de ejecución, es sólo para la seguridad en tiempo de compilación. La mezcla de genéricos con código antiguo puede crear código compilado que puede lanzar una excepción en tiempo de ejecución (además, es emitido un aviso de no verificación si no se especifica -source 1.4).
Las asignaciones polimorfas aplican solo al tipo base, no al parámetro del tipo genérico. Se puede tener:
List<Animal> aList = new ArrayList<Animal>();pero no:
List<Animal> aList = new ArrayList<Dog>();La regla de asignación polimorfa aplica en todos los sitios en que se pueda hacer una asignación. No se permite lo siguiente:
void foo(List<Animal> aList) { } // no puede llevar un List<Dog> List<Animal> bar() { } // no puede devolver un List<Dog>La sintaxis de patrones permite a un método genérico aceptar subtipos (o supertipos) del tipo declarado en el argumento del método:
void addD(List<Dog> d) { } // admitiría solo <Dog> void addD(List<? extends Dog>) { } // admitiría <Dog> o <Beagle> void addD(List<? super Beagle>) { } // admitiría <Dog> o <Animal>La palabra del patrón extends se usa tanto con el significado "extends" como "implements". Así, en <? extends Dog>, Dog puede ser una clase o una interfaz.
Cuando se usa un patrón, List<?>, cualquier tipo genérico podría asignarse a la referencia, pero sólo para acceso, no para modificación.
List<Object> se refiere solo a List<Object>, mientas que List<?> o List<? extends Object> puede mantener cualquier tipo de objeto, pero solo para acceso.
La convención de declaración para genéricos usa T para tipo y E para elemento (el tipo del elemento de la colección):
public interface List<E> // declaración del API para List boolean add(E o) // declaración de List.add()Los identificadores de tipo genérico pueden usarse en declaraciones de clase, método y variables:
class Foo<T> { } // una clase T anInstance; // una variable de instancia Foo(T aRef) { } // un argumento del constructor void bar(T aRef) { } // un argumento de un método T baz() { } // un tipo de retornoEl compilador sustituirá el tipo real.
Puede usar más de un tipo parametrizado en una declaración: public class UseTwo<T, X> { }
Puede declarar un método genérico usando un tipo no definido en la clase:
public <Y> void makeList(Y y) { }Esto no es usar Y como tipo de retorno. Este método tiene el tipo de retorno void, pero para usar Y dentro de los argumentos del método debe declararlo con <Y>, lo que se hace antes del tipo de retorno (solo necesario si Y no era un genérico de la clase).
No es posible referirse a una variable de tipo paramétrico de una clase en un método estático o inicializador, declaración de variable estática o bloque de inicialización estático:
/* Clase completamente errónea */ class Generica<T> { static T a; // Error static void metodo(T a) { } // Error static { T b; // Error } public static final void main(String... args) { // Error de sintaxis Generica<String>.metodo(new String("Hola")); // No funcionaría, aunque no hay error en esta línea Generica.metodo(new String("Hola"); } }Provocaría un error de compilación, ya que T no se resuelve hasta que no se instancia la clase.
El compilador infiere los tipos genéricos a usar en un método genérico (método que incluye un tipo paramétrico exclusivo para dicho método) basándose en los argumentos reales, eligiendo el tipo del argumento más a la derecha en la llamada. Por ejemplo:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) { } Integer[] ia = new Integer[100]; Object[] oa = new Object[100]; Collection<Number> cn = new ArrayList<Number>(); Collection<Object> co = new ArrayList<Object>(); fromArrayToCollection(ia, cn); // T se infiere como Number fromArrayToCollection(ia, co); // T se infiere como Object //fromArrayToCollection(oa, cn); // Error, oa no ES-UN NumberTodas las instancias de una clase genérica tienen la misma clase en ejecución (new ArrayList<String>().equals(new ArrayList<Integer>()) == true). Como consecuencia, la verificación con instanceof y el moldeado de las variables de referencia pueden ser ilegales o provocar avisos de no verificación.
Las matrices de tipos paramétricos no están permitidas, aunque sí lo están las matrices de tipos con comodín enlazado (bounded wildcard):
List<String>[] l = new ArrayList<String>[10]; // No permitido List<?>[] l = new ArrayList<?>[10]; // Permitido y válido List<String>[] l = new ArrayList<?>[10]; // Aviso de no verificación
Una clase interna "regular" se declara dentro de las llaves de otra clase, pero fuera de cualquier método u otro bloque de código.
Una clase interna es un miembro "de pleno derecho" de la clase que la incluye, por lo que puede ser marcada con un modificador de acceso como abstract o final (recuerde que abstract debe ser subclasificado, mientras que final no puede ser subclasificado).
Una instancia de una clase interna comparte una relación especial con la instancia de la clase que la contiene. Esta relación da a la clase interna acceso a todos los miembros de la clase que la contiene, incluidos los marcados como private.
Además, por esta misma relación "especial" la clase que la contiene también tiene acceso a los miembros privados de la interna.
Para instanciar una clase interna, es necesario tener una referencia a una instancia de la clase que la contiene.
Desde el código de la clase contenedora, podemos instanciar a la clase interna con solo usar el nombre de la clase interna de la siguiente manera:
MyInner mi = new MyInner();Desde código fuera de la clase contenedora, podemos instanciar una clase interna sólo mediante el uso de los nombres de la clase interna y externa y una referencia a la clase externa de la siguiente manera:
MyOuter mo = new MyOuter(); MyOuter.MyInner mi = mo.new MyInner();o usando una instancia anónima de la clase contenedora:
MyOuter.MyInner mi = new MyOuter().new MyInner();Desde el código de la clase interna, la palabra reservada this se refiere a la instancia de la clase interna. Para referenciar al objeto this de la clase externa precederemos a la palabra reservada this con el nombre de la clase externa de la siguiente manera:
MyOuter.this;Una clase interna con el mismo nombre que una clase externa en el mismo paquete "sombrea" a la clase externa.
Una clase interna Método-Local se define dentro de un método de la clase que la contiene.
Para ser utilizada, la clase interna debe ser instanciada, y la instanciación debe suceder después de la definición de la clase.
Una clase interna Método-Local no puede usar las variables declaradas dentro del método (incluidos los parámetros) a menos que estas sean declaradas con el modificador final.
Los únicos modificadores que pueden aplicarse a las clases internas Método- Local son abstract y final (nunca ambos a la vez).
Una clase interna Método-Local puede acceder a todas las variables de instancia (incluso privadas) de su clase contenedora pero no al revés (la clase contenedora no puede mantener una referencia válida a dicha clase fuera del método de manera directa). Por ejemplo:
// Contenedora:
class Contenedora { Object o; private String variable = "Contenedora"; void acceder() { class MetodoLocal { String variable = "MetodoLocal"; void acceder() { // Es posible acceder a la contenedora System.out.println("Variable contenedora: " + Contenedora.this.variable); } } MetodoLocal ml = new MetodoLocal(); ml.acceder(); o = ml; // Asigno referencia a objeto MetodoLocal } public static final void main(String... args) { Contenedora c = new Contenedora(); c.acceder(); // Imposible moldear a una clase desconocida System.out.println("Variable MetodoLocal: " + ((MetodoLocal)c.o).variable); } }
- Las clases internas anónimas no tienen nombre, y su tipo debe ser una subclase del tipo nombrado o una implementación de una interfaz.
- Una clase interna anónima se crea siempre como parte de una sentencia; no se olvide de cerrar la declaración después de la definición de la clase con una llave. Esto es un caso raro en Java, una llave seguida de un punto y coma.
- Debido al polimorfismo, los únicos métodos que pueden llamarse sobre la clase interna anónima son los definidos en la clase (o interfaz) de la variable de referencia, a pesar de que la clase anónima sea una subclase o implementación del tipo de la variable de referencia. Métodos nuevos serán ignorados por el compilador y no podrán ser usados en ejecución.
- Una clase interna anónima siempre hereda de una única clase o bien implementa una única interfaz. Una clase interna anónima, a diferencia de una clase normal, no puede heredar de una clase e implementar una interfaz al mismo tiempo, y no puede implementar más de una interfaz.
- Una clase interna definida como un parámetro de una llamada a un método se instancia automáticamente como parte de la invocación. Lo importante es recordar que la clase se define dentro del argumento de un método, así que la sintaxis indica que la definición de la clase terminará con una llave cerrada, seguida por un paréntesis cerrado para terminar la llamada del método y, finalmente, un punto y coma para terminar la sentencia así: });
- Una clase anónima no puede sobrescribir ningún constructor de la clase de la que hereda porque los constructores nunca se heredan (no compila).
Las clases anidadas estáticas son clases internas marcadas con el modificador static.
Una clase anidada estática no es una clase interna, es una clase anidada de alto nivel.
Dado que las clases anidadas son estáticas, no comparten ninguna relación especial con la instancia de la clase que las contienen. De hecho, no necesitamos una instancia de la clase que la contiene para instanciar la clase anidada.
Las clases anidadas estáticas necesitan instanciarse (al contrario de lo que puede sugerir la palabra static). La instanciación de una clase anidada estática requiere usar tanto el nombre de la clase externa como el de la anidada (de modo similar a como se haría con una clase pública de otro paquete) como sigue:
BigOuter.Nested n = new BigOuter.Nested();Una clase anidada estática no puede acceder a los miembros no estáticos de la clase que la contiene, ya que no tiene una referencia implícita de la clase que la contiene. En otras palabras, la instancia de la clase anidada estática no tiene acceso al objeto this de la clase contenedora.
Importante: es muy útil y sencillo ver una clase anidada únicamente como una clase dentro del espacio de nombres de la clase externa. Sólo habrá que tener en cuenta que para acceder a dicha clase, los modificadores de acceso de ambas clases deberán permitirlo.
- 4.1 Definiendo, instanciando y arrancando hilos (730):
- Escribir código para definir, instanciar e iniciar nuevos threads utilizando java.lang.Thread y java.lang.Runnable.
- 4.2 Estados y transiciones de hilos (746):
- Reconocer los estados en los que puede existir un thread, e identificar condiciones en las que puede pasar de un estado a otro.
- 4.3 Sincronizando código (756):
- En una situación dada, escribir código que utilice correctamente el bloqueo de objetos para proteger las variables estáticas o de instancia de los problemas de acceso concurrente.
- 4.4 Interación de hilos (774):
- En una situación dada, escribir código que utilice correctamente wait, notify o notifyAll.
- Un hilo (clase ejecutable) puede crearse heredando de Thread y sobrescribiendo el método public void run().
- Los objetos Thread también pueden crearse llamando al constructor de Thread con argumento Runnable. Se llama objetivo del hilo a dicho objeto Runnable.
- Solo puede llamarse a start() en un Thread una sola vez. Si se llama a start() más de una vez en un Thread, lanzará una RuntimeException.
- Es legal crear varios objetos Thread usando el mismo objeto Runnable como objetivo.
- Cuando se crea un objeto Thread, no se convierte en un hilo de ejecución hasta que se invoca start(). Cuando un objeto Thread existe pero no ha sido iniciado, está en estado "nuevo" y no se considera "vivo".
- Una vez que se ha iniciado un hilo, siempre entrará en el estado "ejecutable".
- El planificador de hilos puede mover un hilo adelante y atrás entre los estados "ejecutable" y "en ejecución".
- En una máquina típica de un único procesador, solo un hilo puede estar ejecutándose a la vez, aunque varios hilos pueden estar en estado "ejecutable".
- No hay garantías de que el orden en el que los hilos hayan arrancado determine el orden en que correrán.
- No hay garantías de que los hilos seguirán turnos de forma justa; esto corresponde al planificador de hilos, tal como sea determinado por la implementación de cada máquina virtual particular. Si se desea garantizar que los hilos siguen turnos independientemente de la MVJ subyacente, puede usarse el método sleep(). Esto evitará que un hilo acapare la ejecución del proceso mientras que otros se estancan. En la mayoría de los casos, sin embargo, yield() funcionará lo bastante bien para animar a los hilos a jugar bien juntos.
- Un hilo en ejecución puede entrar en un estado "bloqueado"/"esperando" con una llamada wait(), sleep() o join().
- Un hilo puede entrar en un estado "bloqueado"/"esperando" si no puede establecer un bloqueo en un bloque de código sincronizado.
- Cuando deja de dormir o esperar, o el bloqueo sobre un objeto está disponible, un hilo solo puede entrar en estado "ejecutable". A efectos prácticos solamente, irá directamente de "esperando" a "en ejecución".
- Un hilo "muerto" no puede arrancarse de nuevo.
- sleep() se usará para retrasar la ejecución por un periodo de tiempo dado, aunque no se liberan los bloqueos cuando un hilo se va a dormir.
- Se garantiza que un hilo durmiente lo hará por lo menos el tiempo especificado en el argumento a la llamada a sleep() (a no ser que sea interrumpido), pero no hay ninguna garantía de que el hilo recién despertado vuelva a estar "en ejecución".
- sleep() es un método static que pone el estado del hilo en ejecución actual en "dormido". Un hilo no puede decir a otro hilo que duerma.
- El método setPriority() se usa en los objetos Thread para dar a los hilos una prioridad entre 1 (baja) y 10 (alta), aunque las prioridades no están garantizadas y no todas las MVJ reconocen 10 niveles de prioridad distintas; algunos niveles pueden tratarse en la práctica como idénticos.
- Si no se establece explícitamente, la prioridad de un hilo será la prioridad del hilo que lo creó.
- El método yield() es static, y puede causar que un hilo en ejecución se eché atrás si hay hilos ejecutables con la misma prioridad, pero no afectará a los bloqueos adquiridos antes de la cesión. No hay garantía de que esto ocurra y tampoco de que, si ocurre, el hilo elegido para ejecutar sea diferente. Un hilo puede ceder e inmediatamente pasar de nuevo al estado "en ejecución".
- Lo más plausible a garantizar es que, en un momento dado, cuando un hilo se está ejecutando, no tendrá una prioridad inferior a ningún hilo en estado ejecutable. Si un hilo de baja prioridad está corriendo cuando un hilo de alta prioridad entra en estado ejecutable, la MVJ normalmente reemplazará el hilo de baja prioridad por el hilo de alta prioridad.
- Cuando un hilo llama al método join() de otro hilo, el que esté actualmente en ejecución esperará hasta que el hilo al que se une haya terminado. Piense en el método join() (de un Thread) como si dijese: "Oye, hilo: quiero unirme a ti cuando termines. Hazme saber cuando hayas terminado para que pueda entrar en estado ejecutable".
- sleep() y join() requieren un bloque try/catch, ya que pueden lanzar la excepción InterruptedException.
- Los métodos synchronized evitan que más de un hilo acceda al código crítico de un objeto de forma simultánea.
- Puede usar la palabra clave synchronized como un modificador de método o para comenzar un bloque de código sincronizado.
- Para sincronizar un bloque de código (o, en otras palabras, código de un alcance menor que el del método completo) debe especificar un argumento que es el objeto sobre cuyo bloqueo quiere sincronizarse.
- Mientras que un único hilo puede estar accediendo a código sincronizado en una instancia particular, múltiples hilos pueden estar, sin embargo, accediendo al código no sincronizado del mismo objeto.
- Cuando un hilo se va a dormir, sus bloqueos no estarán disponibles a otros hilos.
- Los métodos static pueden ser synchronized, usando el bloqueo de una instancia de java.lang.Class que representa esa clase.
- El método wait() permite a un hilo decir: "no tengo nada que hacer ahora, así que ponme en tu lista de espera y notifícame cuando ocurra algo que me importe". Básicamente, una llamada a wait() significa "espérame en tu sitio" o "ponme en tu lista de espera".
- El método notify() se usa para enviar una señal a uno y sólo uno de los hilos que están esperando en ese mismo sitio de espera del objeto.
- El método notify() no puede especificar a qué hilo en espera quiere notificar.
- El método notifyAll() funciona igual que notify(), excepto que manda una señal a todos los hilos que esperan al objeto.
- Los tres métodos, wait(), notify() y notifyAll(), deben llamarse en un objeto particular, y el hilo debe poseer el bloqueo de ese objeto (el objeto aparecerá en el argumento de un bloque synchronized contenedor o será this o nada, cuando el método contenedor sea synchronized).
- wait() puede lanzar las excepciones InterruptedException e IllegalMonitorException, por lo que debe ir rodeado de un bloque try/catch.
- notify() envía una señal para que otro hilo salga del estado "bloqueado", pero no libera el bloqueo sobre el objeto en que se encuentra, esto ocurrirá cuando termine el bloque syncronized que lo contiene.
- El interbloqueo ocurre cuando la ejecución de hilos llega a un punto muerto porque el código está esperando a que se eliminen bloqueos de objetos.
- El interbloqueo puede ocurrir cuando un objeto bloqueado intenta acceder a otro objeto bloqueado y este está intentando acceder al bloqueo del primer objeto. En otras palabras, ambos hilos están esperando la liberación de los bloqueos de los respectivos hilos, así que los bloqueos nunca serán liberados.
- El interbloqueo es malo, no lo haga.
Método Requiere try/catch static Thread Object synchro sleep** Sí Sí Sí join** Sí Sí yield Sí Sí wait*** Sí Sí Sí notify* Sí Sí notifyAll* Sí Sí
- (*)
- Lanza IllegalMonitorStateExeption (RuntimeException)
- (**)
- Lanza InterruptedException
- (***)
- Lanza InterruptedException e IllegalMonitorStateException
- 7.1 Usando los comandos javac y java (817), Usando Static Import (833):
- Dado un ejemplo de código y una situación, escribir código que utilice los modificadores de acceso, las declaraciones package y las instrucciones import adecuadas para interactuar (a través de acceso o herencia) con el código del ejemplo.
- 7.2 Usando los comandos javac y java (817):
- Con un ejemplo de una clase y una línea de comandos, determinar el comportamiento previsto del tiempo de ejecución.
- 7.5 Usando los comandos javac y java (817), Ficheros JAR (829):
- Con el nombre completo de una clase que se implementa dentro y/o fuera de un archivo JAR, construir la estructura de directorios adecuada a dicha clase. Con un ejemplo de código y una ruta de clase dados, determinar si la ruta de clase permite que el código se compile correctamente.
Utilice -d para cambiar el destino de un fichero de clase cuando javac lo genera por primera vez.
La opción -d puede construir clases en destinos dependientes del paquete al vuelo si el paquete "raíz" ya existe. Por ejemplo:
package automake; // No es el paquete raíz public class AutoMakeDir { } // Crea con éxito el dir ./automake // y genera ./automake/AutoMakeDir.class % javac -d . AutoMakeDir.java // Falla, no existe el directorio automake % javac -d automake AutoMakeDir.java // Ojo, esto funcionaría, pero no se podría ejecutar: % javac AutoMakeDir.java % java AutoMakeDir Exception in thread "main" java.lang.NoClassDefFoundError: AutoMakeDir (wrong name: automake/AutoMakeDir) ...Utilice la opción -D en conjunción con el comando java cuando quiera establecer una propiedad del sistema.
Las propiedades del sistema consisten en pares nombre=valor que deben ser añadidas directamente detrás del -D, por ejemplo, java -Dmipropiedad=mivalor.
Los argumentos en línea de órdenes son siempre tratados como String.
El argumento de la línea de órdenes java número 1 se coloca en el elemento 0 de la matriz, el 2 en el elemento 1 y así sucesivamente.
- Tanto java como javac utilizan los mismos algoritmos para buscar clases.
- La búsqueda comienza en las ubicaciones que contienen las clases estándar que vienen con J2SE (solo con java, javac busca antes en el classpath).
- Los usuarios pueden definir ubicaciones secundarias usando rutas de clases ( classpaths).
- Las rutas de clases por defecto pueden definirse usando variables de entorno del sistema operativo.
- Una ruta de clases puede declararse en la línea de órdenes; en este caso sobrescribirá la ruta de clases por defecto.
- Una ruta de clases única puede definir múltiples ubicaciones de búsqueda.
- En las rutas de clases de Unix, la barra inclinada (/) se usa para separar los directorios que componen una ruta. En Windows se usa la barra invertida (\).
- En Unix, los dos puntos (:) se usan para separar las diferentes rutas dentro de una ruta de clases. En Windows se usa el punto y coma (;).
- En una ruta de clases, para especificar el directorio actual como ubicación de búsqueda, use un punto (.)
- En una ruta de clases, una vez que se localiza una clase, la búsqueda se detiene, así que el orden de las ubicaciones de búsqueda es importante.
- Cuando una clase se pone en un paquete, debe usarse su nombre totalmente cualificado.
- Una sentencia import provee de un sobrenombre de un nombre de clase totalmente cualificado (no existen rutas relativas en import).
- Para localizar una clase, su nombre totalmente cualificado debe tener una estrecha relación con la estructura de directorios en que reside.
- Una ruta de clases puede contener rutas absolutas y relativas.
- Una ruta absoluta empieza con un / o con un \.
- Sólo se buscará en el directorio final de una ruta dada.
- Si dos sentencias import proveen un mismo sobrenombre, el compilador mostrará un error de referencia ambigua.
- Puede archivarse una estructura de árbol entera en un único fichero JAR.
- Los ficheros JAR pueden ser usados en búsquedas por java y javac.
- Cuando se incluye un fichero JAR en una ruta de clases, debe incluirse no sólo el directorio en que está ubicado el fichero JAR, si no también el nombre del propio fichero JAR.
- Sólo para las pruebas, pueden ponerse ficheros JAR dentro de .../jre/lib/ext, que estará en algún lugar dentro del árbol de directorios de Java de la máquina.
Debe comenzar una importación estática así: import static
Debe usar importaciones estáticas para crear atajos para miembros estáticos (variables estáticas, constantes y métodos) de cualquier clase. Por ejemplo:
import static java.lang.System.out; public static final void main(String... args) { out.println("Hola mundo"); }
Version: 1.3, 3 November 2008 Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
The "publisher" means any person or entity that distributes copies of the Document to the public.
A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
- Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
- List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
- State on the Title page the name of the publisher of the Modified Version, as the publisher.
- Preserve all the copyright notices of the Document.
- Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
- Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
- Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
- Include an unaltered copy of this License.
- Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
- Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
- For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
- Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
- Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.
- Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
- Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements".
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
"Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site.
"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
"Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.