resumen scjp pedro lopez salazar
TRANSCRIPT
Declaraciones y Control de Acceso
Identificadores
Los identificadores pueden empezar con una letra o los caracteres "_" o "$".
Después del primer caracter, los identificadores pueden incluir también dígitos.
Los identificadores pueden ser de cualquier tamaño.
Los métodos JavaBeans deben ser llamados usando "camelCase" y dependiendo del tipo
de método empezaran con get, set, is, add o remove.
Reglas de declaraciones
Un fichero con código puede tener solo una clase pública.
Si el fichero que contiene el código contiene una clase pública, el fichero debe llamarse
igual que la clase pública.
Un fichero solo puede tener una sentencia "package", pero puede tener múltiples
"import".
La sentencia package debe ser la primera línea del fichero.
Las sentencias import deben ir después de package y antes de la declaración de la clase.
Si no hay sentencia "package" las sentencias import deben ser las primeras líneas del
fichero.
Las sentencias package e import son aplicadas a todas las clases del fichero.
Un fichero puede contener más de una clase no pública.
Los ficheros que no tienen clase pública no tienen restricciones con el nombre del fichero.
Modificadores de acceso a clase
Hay tres modificadores de acceso: public, protected y private.
Hay cuatro niveles de acceso: public, protected, default y private.
Las clases solo pueden tener acceso public o default.
Una clase declarada como default puede ser vista solo por las clases de su mismo paquete.
Una clase declarada pública puede ser vista por todas las clases de todos los paquetes.
La visibilidad de una clase gira en torno a si el código de una clase puede ...
Crear una instancia de otra clase.
Extender (o subclase) de otra clase.
Acceso a variables y métodos de otras clases.
Modificadores de clase (no acceso)
Las clases pueden también ser declaradas con final, abstract y strictfp.
Una clase no puede ser abstract y final a la vez.
Una clase final no puede ser sobrescrita por una subclase.
Una clase abstract no puede ser instanciada.
Un solo método abstracto en una clase obliga a la clase a ser declarada abstracta.
Una clase abstracta puede tener ambos tipos de métodos abstractos y no abstractos.
La primera clase concreta que extienda una clase abstracta debe implementar todos sus
métodos abstractos.
Implementación de interfaz
Las interfaces son contratos que una clase puede hacer, pero no dicen nada de la manera
en la que la clase debe hacerlo.
Las interfaces pueden ser implementadas por cualquier clase, de cualquier árbol de
herencia.
Una interfaz es como una clase abstracta 100% y es declarada implícitamente abstract
aunque no lo declares así.
Una interfaz debe tener todos los métodos abstractos, no permite ningún método
concreto.
Los métodos de una interfaz son por defecto "public abstract", la declaración explícita de
estos modificadores es opcional.
Las interfaces pueden tener constantes, las cuales son implícitamente "public abstract
final".
La declaración de public, static y final es opcional en las constantes.
La implementación legal de una clase no abstracta tiene las siguiente propiedades:
Proporciona implementaciones concretas de todos los métodos de la interfaz.
Debe seguir todas las reglas de sobreescritura para los métodos implementados.
No debe declarar ninguna nueva excepción chequeada para la implementación de un
método.
No debes declarar ninguna excepción chequeada que sea más amplia que la declarada en
el método de la interfaz.
Puedes declarar excepciones en tiempo de ejecución en cualquier implementación de un
método de la interfaz independientemente de la declaración de la interfaz.
Debes mantener la nomenclatura y el tipo de devolución de los métodos implementados
(pero no tienes que declarar las excepciones de la interfaz).
Una clase que implemente una interfaz puede ser abstracta.
La clase abstracta que implemente una interfaz no tiene que implementar los métodos de
una interfaz (pero la primera subclase concreta si debe implementarlos).
Una clase puede extender de una sola clase (no hay herencia múltiple), pero puedes
implementar varias interfaces.
Las interfaces pueden extender de una o más interfaces.
Las interfaces no pueden extender de una clase o implementar una clase o interfaz.
Cuando estés en el examen, verifica que las declaraciones de interfaces y clases son
legales, antes de verificar cualquier otra lógica del código.
Modificadores de acceso Miembros
Los métodos y las variables de instancia (no variables locales) de una clase son conocidos
como miembros.
Los miembros pueden usar los cuatro niveles de acceso: public, protected, default y
private.
Hay dos maneras de acceder a los miembros:
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, tampoco se puede acceder a sus miembros.
Determina antes la visibilidad de la clase antes que la de los miembros.
Los miembros public pueden ser accedidos por cualquier clase, incluso de otro paquete.
Si un miembro de la superclase es public, la subclase lo heredara (independientemente del
paquete).
Para acceder a un miembro sin el operador (.) debemos estar en la misma clase.
this. Siempre se refiere al actual objeto en ejecución.
this.aMethod() es lo mismo que ejecutar aMethod().
Los miembros private pueden ser accedidos solo desde la misma clase.
Los miembros private no son accesibles a las subclases, así que los miembros private no se
heredan.
Los miembros default o protected solo difieren en el caso de las subclases:
Los miembros default pueden ser accedidos solo por clases de su mismo paquete.
Los miembros protected pueden ser accedidos por clases de su mismo paquete, mas las
subclases de diferente paquete.
protected = paquete + hijos(subclases).
Para las subclases fuera del paquete, el miembro protected puede ser accedido solo a
través de herencia; una subclase fuera del paquete de la clase del miembro no puede
acceder al miembro protected usando una referencia de la instancia de la superclase.
Un miembro protected de una superclase heredado por una subclase de un paquete
diferente al de la superclase no es accesible por otras clases del mismo paquete que la
subclase, excepto las propias subclases de la subclase.
Variables locales
Las declaraciones de una variable local no pueden tener modificadores de acceso.
final es el único permitido.
Las variables locales no obtienen valores por defecto, así que hay que inicializarlas antes
de ser usadas.
Otros Modificadores miembros
Los métodos final no pueden ser sobrescritos por una subclase.
Los métodos abstract son declarados con un nombre, un tipo de devolución y una clausula
throws opcional, pero no son implementados.
Los métodos abstractos terminan en ; y no llevan {}.
Hay tres maneras de reconocer que un método no es abstract:
El método no está marcado abstract.
El método tiene {}.
El método tiene código entre las llaves.
La primera clase concreta (no abstracta) que extienda de una clase abstracta debe
implementar todos los métodos abstract de la clase abstracta.
El modificador synchronized se usa solo en métodos y bloques de código.
Los métodos synchronized pueden tener cualquier control de acceso y también pueden
ser marcados final.
Los métodos abstractos deben ser implementados por la subclase, así que deben ser
heredables.
Un método abstracto no puede ser private.
Un método abstracto no puede ser final.
El modificador native se aplica solo a métodos.
El modificador strictfp es aplicable solo a clases y métodos.
Métodos con var-args
Después de Java 5, los métodos pueden aceptar un parámetro que acepta de cero a
muchos argumentos, así que son llamados métodos var-arg.
Un parámetro var-arg es declarado con la sintaxis "tipo... nombre".
Un método var-arg puede tener un solo parámetro var-arg.
Un método con parámetros normales y un var-arg, el var-arg se declarara al final.
Declaraciones de variables
Las variables instancia pueden:
Tener cualquier control de acceso.
Ser marcadas final o transient.
Las variables de instancia no pueden ser abstract, syncronized, native ni strictfp.
Es legal declarar una variable local con el mismo nombre que una variable de instancia,
esto se conoce como shadowing.
Las variables final tienen las siguientes propiedades:
Las variables final no pueden ser reinicializadas una vez tengan asignado un valor.
Las variables de referencia final no pueden referirse a un objeto diferente una vez el
objeto haya sido asignado a la variable final.
Las variables de referencia final deben ser inicializadas antes que el constructor acabe.
Un objeto referenciado marcado como final no significa que el objeto en si sea inmutable.
El modificador transient solo se aplica a variables de instancia.
El modificador volatile se aplica solo a variables de instancia.
Declaraciones de Array
Los arrays pueden almacenar primitivos o objetos, pero el array en si es siempre un
objeto.
Cuando declaras un array, los [] pueden estar a la izquierda o a la derecha del nombre de
la variable.
Nunca es legal incluir el tamaño del array en la declaración.
Un array de objetos puede almacenar a cualquier objeto que pase el test IS-A (o
instanceof) con el tipo declarado en el array.
Variables y métodos static
No esta atada a cualquier instancia particular de una clase.
No son necesarias instancias de una clase para usar sus miembro static.
Solo hay una copia de una variable static por clase y todas las instancias la comparten.
Los métodos static no tiene acceso directo a miembros no static.
Enums
Un enum especifica una lista de valores constantes que pueden ser asignados a un tipo
particular.
Un enum no es un String o un int; un tipo de enumerado constante es un tipo enum.
Un enum se puede declarar dentro o fuera de una clase, pero no en un método.
Un enum declarado fuera de una clase no debe ser marcado static, final, abstract,
protected o private.
Los enums pueden contener constructores, métodos, variables y constantes.
Las constantes enum pueden enviar argumentos al constructor enum, usando la sintaxis
BIG(8), donde el entero literal 8 es pasado al constructor enum.
Los constructores enum pueden tener argumentos y pueden ser sobrecargados.
Los constructores enum no pueden ser invocados directamente desde el código. Son
llamados automáticamente cuando el enum es inicializado.
El ; al final de una declaración enum es opcional.
Orientación a Objetos
Encapsulación IA-A, HAS-A
La encapsulación te ayuda a esconder la implementación detrás de una interfaz (o API).
Un código encapsulado tiene dos características:
Las variables instancia están protegidas (normalmente con el modificador private).
Los métodos Getter y Setter proporcionan acceso a las variables de instancia.
IS-A se refiere a herencia.
IS-A es expresado con las palabras clave extends.
IS-A, hereda de... y "es un subtipo de ..." son expresiones equivalentes.
HAS-A significa que una instancia de una clase tiene una referencia a una instancia de otra
clase o una instancia de la misma clase.
Herencia
La herencia permite a una clase ser subclase de una superclase y de este modo hereda
variables y métodos declarados protected o public en la superclase.
La herencia es un concepto clave que subyace de IS-A, polimorfismo, sobreescritura,
sobrecarga y casting.
Todas las clases (excepto la clase Object) son subclases de tipo Object y heredan los
métodos de Object.
Polimorfismo
Polimorfismo significa muchas formas.
Una variable de referencia es siempre se un solo tipo, pero puede referirse a objetos de un
subtipo.
Un solo objeto puede ser referenciado por varias variables de referencia de diferentes
tipos, que serian del mismo tipo o de un subtipo del objeto.
El tipo de variable de referencia (no el tipo del objeto) determina que método puede ser
llamado.
Las invocaciones de un método polimórfico se aplican solo a métodos de instancia
sobrescritos.
Sobrescritura y sobrecarga
Los métodos pueden ser sobrescritos o sobrecargados, los constructores pueden ser
sobrecargados pero no sobrescritos.
Los métodos abstractos deben ser sobrescritos por la primera subclase concreta (no
abstracta).
Con respecto a la sobreescritura de métodos:
Deben tener la misma lista de argumentos.
Deben devolver el mismo tipo, excepto después de Java 5 que el tipo devuelto puede ser
una subclase, esto es conocido como retorno covariante.
Puedes tener un modificador de acceso menos restrictivo.
No debes lanzar nuevas o ampliadas excepciones chequeadas.
Puedes lanzar cualquier excepción no chequeada.
Los métodos final no pueden ser sobrescritos.
Solo los métodos heredados pueden ser sobrescritos y recordar que los métodos private
no son heredados.
Una subclase usa super.overridenMethodName() para llamar a la versión de la superclase
de un método sobrescrito.
Sobrecarga significa reusar el nombre de un método, cambiándole la lista de argumentos.
Métodos sobrecargados:
Deben tener listas de argumentos diferentes.
Pueden tener diferentes tipos de devolución, si la lista de argumentos también es
diferente.
Puedes tener diferentes modificadores de acceso.
Puedes lanzar diferentes excepciones.
Los métodos de una superclase pueden ser sobrecargados en una subclase.
El polimorfismo se usa para sobrescribir no para sobrecargar.
Un tipo de Objeto (no el tipo de la variable de referencia) que método sobrescrito esta
usando en tiempo de ejecución.
El tipo de referencia determina que método sobrecargado será usado en tiempo de
compilación.
Variable de referencia Casting
Hay dos tipos de variable de referencia casting: downcasting o upcasting.
Downcasting: Si tienes una variable de referencia que se refiere a un objeto subtipo, se
puede asignar a una variable de referencia del subtipo. Se Debe hacer un casting para
hacer esto y el resultado es que puedes acceder a los miembros del subtipo son esta
nueva variable de referencia.
Upcasting: Puedes asignar una variable de referencia a una variable de referencia de un
supertipo explícitamente o implícitamente. Esto es una operación segura ya que la
asignación restringe el acceso a las capacidades de la nueva variable.
Implementando una interfaz
Cuando implementas una interfaz, tu estas cumpliendo su contrato.
Se implementa una interfaz sobrescribiendo todos los métodos definidos en la interfaz.
Una sola clase puede implementar muchas interfaces.
Tipos devueltos
Los métodos sobrecargados pueden cambiar el tipo de devolución, los métodos
sobrescritos no pueden excepto en el caso de retornos covariantes.
Un array es un legal tipo de devolución.
Para los métodos que devuelven tipos primitivos, cualquier valor que pueda ser
implícitamente convertido al tipo de devolución puede ser devuelto.
Nada puede ser devuelto de un void.
Los métodos que devuelven un tipo de objeto, pueden devolver un subtipo de el.
Los métodos que devuelven una interfaz, pueden devolver cualquier implementación.
Constructores e Instanciación
Un constructor es siempre es llamado cuando un nuevo objeto es creado.
Cada superclase en un árbol de herencia de objetos tendrá un constructor llamado.
Todas las clases, incluso las abstractas, tienen al menos un constructor.
Los constructores no devuelven nada. Si ves un método que devuelve algo con el mismo
nombre que la clase no es un constructor.
La ejecución típica de un constructor ocurre como veremos ahora:
El constructor llama al constructor de la superclase, el cual llama al constructor de su
superclase y así sucesivamente hasta llegar al constructor de Object.
El constructor de Object se ejecuta y entonces vuelve al constructor que lo llamo y así
sucesivamente hasta llegar al constructor de la actual instancia que se está creando.
Los constructores pueden usar cualquier modificador de acceso (incluso private).
El compilador creara un constructor por defecto si no creas ningún constructor en la clase.
El constructor por defecto es un constructor sin argumentos con una llamada al
constructor padre sin parámetros super().
La primera sentencia de un constructor debe ser this() o super().
El compilador añadirá una llamada a super() a menos que ya hayas puesto this() o super().
Los miembros de instancia son accesibles solo después de la ejecución del constructor
super.
Las clases abstractas tienen constructores que son llamados cuando se está instanciando
una subclase concreta.
Las interfaces no tienen constructores.
Si tu superclase no tiene un constructor sin argumentos, debes crear un constructor e
insertar una llamada super().
Los constructores nunca son heredados, entonces no pueden ser sobrescritos.
Un constructor puede ser invocado directamente solo por otro constructor (usando una
llamada a super() o this()).
this() solo puede aparecer en la primera sentencia en un constructor.
La lista de argumentos indica que constructor sobrecargado es llamado.
Tu puedes tener las llamadas this() o super() en un constructor, pero nunca ambas.
Statics
Usa métodos static para implementar características que no afecten al estado de la
instancia.
Usa variables estáticas para almacenar datos que son específicos de la clase pero no de las
instancias.
Todos los miembros static pertenecen a la clase no a la instancia.
Un método static no puede acceder directamente a una variable de instancia.
Usa el operador (.) para acceder a miembros static.
Los métodos static no pueden ser sobrescritos pero si redefinidos.
Acoplamiento y cohesión
Acoplamiento: se refiere al grado en el que una clase conoce o usa los miembros de otra
clase.
Bajo acoplamiento es el estado deseado, significa tener las clases bien encapsuladas.
Alto acoplamiento es el estado no deseado, significa no cumplir las reglas de bajo
acoplamiento.
Cohesión: se refiere al hecho de que una clase tenga un único y buen definido papel o
responsabilidad.
Alta cohesión es el estado deseable de una clase, cuyos miembros tiene un único y bien
definido su papel o responsabilidad.
La baja cohesión es el estado no deseable de una clase, cuyos miembros tienen múltiples
papeles o responsabilidades.
Usando clases de envoltura y Boxing
Hay una clase de envoltura para cada primitivo en Java.
Primitivo Clase de envoltura Argumentos Constructor
boolean Boolean boolean o String byte Byte byte o String char Character char double Double double o String float Float float, double o String int Integer int o String long Long long o String short Short short o String
Los constructores de envoltura
Todas las clases de envoltura excepto Character proporcionan dos constructores: uno que toma un valor
primitivo del tipo que está siendo construido y otro que toma un String en representación del tipo que está
siendo construido.
La clase Character proporciona solo un constructor que toma como argumento un char.
El constructor de la clase de envoltura Boolean toma un valor booleano "true" o "false" o un String case-
insensitive con el valor "true" o "false". Antes de Java 5, un objeto booleano no podía ser usado como
expresión en un test booleano.
A partir de Java 5, un objeto Boolean puede ser usado en un test booleano, ya que el compilador
automáticamente convierte el Boolean a boolean.
Usando utilidades de conversión en clases de envoltura
Como dijimos anteriormente, la gran función de una clase envoltura es convertir cosas. Los siguientes métodos son los más usados comúnmente y son los que probablemente más veas en el examen.
xxxValue()
Cuando necesitas convertir el valor numérico de una clase envoltura a un tipo primitivo use uno de los muchos métodos xxxValue(). Todos los métodos de esta familia no llevan argumentos. Hay 36 métodos xxxValue(). Cada una de las seis clases de envoltura tiene 6 métodos, así que cualquier numérico de una clase de envoltura puede ser convertido a cualquier tipo numérico primitivo.
parseXxx() y valueOf()
Los seis métodos parseXxx() están estrechamente relacionados con los métodos valueOf() que existen en todos los números de las clases de envoltura. Ambos métodos toman un String como argumento, lanzan un NumberFormatException si el argumento String no está bien formado, y puede convertir objetos String de
diferentes bases, cuando el subyacente tipo primitivo es cualquiera de los cuatro tipos de enteros. La diferencia entre los métodos es:
parseXxx devuelve el primitivo nombrado.
valueOf() devuelve un nuevo objeto de la clase de envoltura del tipo que invoca al método.
toString()
La clase Object tiene un método toString(). Dado que sabemos que todas las otras clases Java heredan de la clase Object, entonces todas las clases tienen un método toString(). La idea del método toString()te permite obtener una representación significativa de un objeto. En las clases de envoltura este método devuelve un String con el valor del objeto de la clase de envoltura.
Todas las clases de envolturas numéricas proporcionan un método sobrecargado toString() que toma un numérico primitivo del tipo apropiado.
Tabla de resumen:
~Método (s->static, n->NFE exception
~Boolean ~Byte Character 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 (base) s,n x x x x valueOf s,n s x x x x x x valueOf (base) s,n x x x x toString x x x x x x x toString(primitivo) s x x x x x x x toString(primitivo, base) s x x
Sobrecarga y sobreescritura de métodos
Si un método está sobrescrito pero usamos una referencia polimórfica (supertipo) para
hacer referencia al objeto subtipo con el método que sobrescribe, el compilador asume que
estamos llamado a la versión supertipo del método. Si la versión supertipo declara una
excepción checked, aunque no lo haga el método que la sobrescribe, el compilador sigue
creyendo que estamos llamando a un método que declara una excepción.
Ejemplo:
class Animal {
public void eat() throws Exception {
// throws an Exception
}
}
class Dog2 extends Animal {
public void eat() { // no Exceptions }
public static void main(String [] args) {
Animal a = new Dog2();
Dog2 d = new Dog2();
d.eat(); // ok
// compiler error -
a.eat();
// unreported exception
}
}
Este código no compilará por la Excepción declarada en el método eat() de Animal. Esto
ocurre siempre, aun cuando en tiempo de ejecución, el método eat() usado sea el de la
versión Dog, que no declara la excepción.
Buscar usos ilegales de extends e implements. A continuación se muestran ejemplos de
declaraciones legales e ilegales de clases e interfaces:
class Foo { } //OK
class Bar implements Foo { } //No! No se puede implementar una
clase
interface Baz { } //OK
interface Fi { } //OK
interface Fee implements Baz { } //No! Una interfaz no puede
implementar otra
interface Zee implements Foo { } //No! Una interfaz no puede
implementar una clase
interface Zoo extends Foo { } //No! Una interfaz no puede
extender una clase
interface Boo extends Fi { } //OK. Una interfaz puede extender
a otra
class Toon extends Foo, Button { } //No! Una clase no puede extender
múltiples clases
class Zoom implements Fi, Fee { } //OK. Una clase puede implementar
múltiples interfaces
interface Vroom extends Fi, Fee { } //OK. Una interfaz puede extender
a múltiples interefaces
class Yow extends Foo implements Fi { } //OK. Una clase puede hacer ambas
(extends debe ser 1º)
Resumen de las excepciones y errores
Categoría de excepciones y errores:
Excepciones JVM: Estas excepciones o errores que son exclusivas, son lanzadas por la JVM.
Excepciones programáticas: Estas excepciones son lanzadas explícitamente por la aplicación y/o la API de los programadores.
ArrayIndexOutOfBoundsException Es lanzada cuando se intenta acceder a una array con un índice invalido (negativo o mayor que el tamaño del array)
Por la JVM
ClassCastException Es lanzada cuando se intenta castear una variable de referencia a un tipo que falla el test IS-A
Por la JVM
IllegalArgumentException Es lanzada cuando un método recibe un argumento con un formato diferente al que espera el método.
Programáticamente
IllegalStateException Es lanzada cuando el estado del entorno no encuentra la operación que está intentando, e.g., usar un Scanner que ha sido cerrado.
Programáticamente
NullPointerException Es lanzada cuando intenta acceder a un objeto con una variable de referencia cuyo valor actual es null.
Por la JVM
NumberFormatException Es lanzada cuando un método que convierte un String a un número, no puede hacer la conversión con el String pasado.
Programáticamente
AssertionError Es lanzada cuando una sentencia booleana de prueba devuelve false.
Programáticamente
ExceptionInInitializerError Es lanzada cuando intenta inicializar una variable estática o un bloque de inicialización.
Por la JVM
StackOverflowError Normalmente lanzada cuando un método es recursivo infinitas veces.
Por la JVM
NoClassDefFoundError Es lanzada cuando la JVM no puede encontrar una clase que necesita, a causa de un error en la línea de comandos, classpath o un fichero .class perdido.
Por la JVM
Es ilegal usar una clausula try sin una clausula catch o finally. Una clausula try por si sola dará un error de compilación. Cualquier clausula catch debe seguir inmediatamente al bloque try. Cualquier finally debe seguir inmediatamente a la ultima clausula catch (o seguir al bloque try si no hay catch). Es legal omitir la clausula catch o la finally, pero no ambas a la vez. No puedes meter ningún código entre los bloques try, catch o finally.
Reglas de expresión Assertion
Los assertions pueden tener una o dos expresiones, dependiendo de si estas usando la simple o la realmente simple. La primera expresión debe dar siempre como resultado un valor booleano. Tiene las mismas reglas que para usar expresiones en pruebas if y while. El punto es hacer valer un Test, lo que significa que usted está afirmando que es cierto el Test. Si es cierto, no hay problema. Sin embargo si no es cierta, entonces tu suposición fue incorrecta y obtendrás un error AssertionError. La segunda expresión, usada solo en la versión simple de una sentencia assert, puede ser cualquier cosa que se traduzca en un valor. Recordar, la segunda expresión es usada para generar un String que se despliega en la pila de traza para darte una pequeña información mas para la depuración. Funciona de manera similar a System.out.println() al que le puedes pasar un valor primitivo o un objeto, y convertirlo en un String. Debe resolverse como un valor.
No usar assertions para validar argumentos de un método público
Usar assertions para validar argumentos de un método privado
No usar assertions para validar argumentos de la linea de comandos
Usar assertions, incluso en métodos públicos, para comprobar los casos que conoces que nunca supones que sucederán
No usar expresiones assert que puedan causar efectos secundarios
Genéricos y Colecciones
Recuerda que lo métodos equals(), hashCode() y toString() son públicos. Lo siguiente no sería una valida sobreescritura del método equals(), aunque puede parecer serlo si no te fijas lo suficiente durante el examen.
class Foo { boolean equals( Object o) { } }
Y cuidado también con las salidas y sus tipos de argumentos. El siguiente método esta sobrecargando y no sobrescribiendo el método equals():
class Boo { public boolean equals(Boo b) { } }
Collections es una clase, con métodos estáticos útiles, mientras que Collection es una interfaz con las declaraciones de los métodos mas comunes de las colecciones incluyendo add(), remove(), contains(), size() e iterator().
Cuando uses HashSet o LinkedHashSet, los objetos que le añadas debe sobrescribir hashCode(). Si no lo sobrescriben, el método por defecto Object.hashCode() permitirá que múltiples objetos, que tu debes considerar iguales, sean añadidos a tu conjunto donde "NO se permiten duplicados".
Es importante recordar que cuando sobrescribes equals() debes tomar un argumento de tipo Object, pero que cuando sobrescribes compareTo () debe tener un argumento del tipo de la clasificación.
La ultima regla que necesitas saber es que, cuando quiera ordenar un array o una colección, los elementos deben de ser mutuamente comparables. En otras palabras, si tiene s un Object[] y pones un Cat y objetos Dog, nos podrás ordenarlo. En general, los objetos de diferentes tipos deben considerarse no comparables entre sí, a menos que sea especificado.