Objetivos
Comprender el rol de la clase Object
Redefinir los métodos toString y equals
Comprender como el polimorfismo y el enlace dinámico mejoran la versatilidad del programa
Entender las restricciones de asignar un objeto de una clase a la variable de referencia de otra clase
Comprender cómo usar un arreglo de variables de referencia de un ancestro para implementar el polimorfismo
Verificar cómo una declaración abstract en la superclase elimina la necesidad de definir métodos tontos
Comprender cómo se crean y usan las interfaces
Entender el modificador de acceso protected
Contenidos
La clase Object
El método equals
El método toString
Polimorfismo y enlazamiento dinámico
Asignaciones entre objetos en una jerarquía de clases
Polimorfismo con arreglos
Métodos y clases Abstract
Interfaces
Modificador de acceso protected
1. La clase Object
La clase Object es una superclase para
todas las otras clases en Java
Cuando declaramos nuestras propias clases, no tenemos que especificar que heredarán de Object, lo hace automáticamente
Veremos 2 métodos de Object: equals y toString
2. El método equals
Para clases que no tienen su propio método equals
Si objetos de dichas clases son comparados con equals, ellos ya heredan y usarán el método equals de la clase Object
Dicho método retorna true si las 2 variables de
referencia que están siendo comparadas apuntan al mismo objeto (contienen la misma dirección)
2. El método equals
Asumiendo que la clase Car no tiene su método propio equals, ¿qué se imprimirá?
Car car1 = new Car("Honda", 2008, "red");
Car car2 = car1;
Car car3 = new Car("Honda", 2008, "red");
System.out.println(car2 == car1);
System.out.println(car2.equals(car1));
System.out.println(car3 == car1);
System.out.println(car3.equals(car1));
Trabaja exactamente igual que el operador ==
true
true
false
false
2. El método equals
Generalmente el método equals de la clase Object
no es tan útil
Casi siempre necesitamos comparar el contenido de 2 objetos en lugar de verificar que dos variables de referencia apuntan al mismo objeto
Para lograrlo deberíamos sobreescribir el método equals en nuestras clases, de tal forma que compare el contenido de los objetos
2. El método equals: definiendo el
nuestro
Ejemplo: usar lo siguiente
public class Car
{
private String marca;
private int anio;
private String color;
<equals method goes here>
}
public class CarDriver
{
public static void main(String[] args)
{
Car car1 = new Car();
Car car2 = new Car();
if (car1.equals(car2))
System.out.println("cars have identical features");
...
2. El método equals: definiendo el
nuestro
public class Car
{
private String marca;
private int anio;
private String color;
public Car(String make, int year, String color)
{ …
}
public boolean equals(Car otherCar)
{
return otherCar != null && marca.equals(otherCar.marca) &&
anio == otherCar.anio && color.equals(otherCar.color);
}
}
2. El método equals
El método equals está implementado en muchas
clases de la Java API
Por ejemplo en la clase String y en las clases
Wrapper
Esos métodos equals prueban si los contenidos de
los 2 objetos comparados son los mismos
¿Qué se imprimirá?
String s1 = "hello", s2 = "he";
s2 += "llo";
if (s1 == s2)
System.out.println(“mismo objeto”);
if (s1.equals(s2))
System.out.println(“mismo contenido");
2. El método equals
¿Qué se imprimirá?
String s1 = "hello", s2 = "hello";
if (s1 == s2)
System.out.println(“mismo objeto”);
if (s1.equals(s2))
System.out.println(“mismo contenido");
Sólo para Strings
3. El método toString
Retorna cadena que describe al objeto
El método toString de la clase Object retorna una cadena que es una concatenación del nombre completo de la clase del objeto (incluye nombre del paquete de la clase), el signo @ y una secuencia hexadecimal llamada hashcode
Considerar el código: Object obj = new Object();
System.out.println(obj.toString());
Car car = new Car();
System.out.println(car.toString());
Salida: java.lang.Object@601bb1
Car@1ba34f2
La clase Object está en el paquete java.lang
hashcode
3. El método toString
Lo anterior no es tan útil, por lo que llamar al método toString de la clase Object tampoco lo es
Debemos reescribir el método toString en nuestras clases
En general el método toString debería retornar un String que describe el contenido del objeto llamado
Se encuentran muchos métodos toString sobreescritos en las clases del Java API
La clase Date tiene un método toString que retorna los valores concatenados en un String del mes, día y año
Ya que recuperar los contenidos de un objeto es una tarea muy común, deberíamos tener el hábito de proveer un método toString para la mayoría o todas las clases propias
Típicamente el método toString debería simplemente concatenar los datos del objeto y devolver un String
Notar que el método toString no debería imprimir el String concatenado
3. El método toString
Escribir el método toString para la clase Car.
public class Car
{
private String marca;
private int anio;
private String color;
...
<toString method goes here>
}
public class CarDriver
{
public static void main(String[] args)
{
Car car1 = new Car("Honda", 1998, "silver");
System.out.println(car1);
...
3. El método toString: definiendo
el nuestro
public class Car
{
private String marca;
private int anio;
private String color;
public Car(String make, int year, String color)
{ …
}
public String toString()
{
return “marca= " + marca+ ", anio= " + anio + ", color = "
+ color;
}
3. El método toString
El método toString de un objeto es llamado
automáticamente cuando la variable de referencia del objeto es un argumento en un: System.out.println() o System.out.print()
Ejemplo:
System.out.println(car1);
También es llamado automáticamente cuando una variable de referencia es concatenada a un String (operador +)
String carInfo = "Car data: " + car1;
3. El método toString
Se puede seguir usando el método toString usando
la sintaxis de llamada a métodos estándar:
System.out.println(car1.toString());
String carInfo = "Car data: " +
car1.toString();
3. El método toString
EJERCICIO: Completar la clase Counter que corresponda al
siguiente código: public class Counter
{
private int count;
...
}
public class CounterDriver
{
public static void main(String[] args)
{
Counter co = new Counter(100);
String message = “Cuenta actual = " + co;
...
3. El método toString
public class Counter
{
private int count;
public Counter(int c)
{
count = c;
}
public String toString()
{
return Integer.toString(count);
}
}
4. Métodos toString de las clases
Wrapper
Todas las clases wrapper tienen métodos toString que
retornan un valor String del valor primitivo dado
String s1=Integer.toString(22); //convierte a string "22"
String s2=Double.toString(123.45);//convierte a string "123.45“
System.out.println(s1+" "+s2);
Tenemos la opción de usar el método valueOf de la clase String
String s3=String.valueOf(22);
String s4=String.valueOf(123.45);
String s5=String.valueOf('S');
char[] vocales = {'a','e', 'i', 'o', 'u'};
String s6=String.valueOf(vocales);
System.out.println(s3+" "+s4+" "+s5+" "+s6);
5. Polimorfismo
Es cuando diferentes tipos de objetos responden de forma diferente a la misma llamada a método
Para implementarlo: declarar un tipo general de variable de referencia que sea capaz de referirse a objetos de diferente tipo
Para hacerlo usamos una superclase
¿Cuál usaríamos sin necesidad de crear una clase propia?
La superclase Object
5. Polimorfismo
En el ejemplo obj se declara como un Object y la llamada a método obj.toString() es la que
exhibe un comportamiento polimórfico Si obj contiene un objeto Perro, toString retorna “Guau!
Guau!"
Si obj contiene un objeto Gato, toString retorna “Miau!
Miau!"
5. Polimorfismo
import java.util.Scanner;
public class Pets
{
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
Object obj;
System.out.print("Which type of pet do you prefer?\n" +
"Enter d for dogs or c for cats: ");
if (stdIn.next().equals("d"))
{
obj = new Dog();
}
else
{
obj = new Cat();
}
System.out.println(obj.toString());
System.out.println(obj);
} // end main
} // end Pets class
Se declara obj como un Object
Genérico
Llamada a método polimórfico.
6. Enlace Dinámico (Dynamic Binding)
El polimorfismo es un concepto, una forma de comportamiento
El enlace dinámico es el mecanismo que permite dicho comportamiento
Es lo que la JVM hace para corresponder una llamada a método polimórfico con un método en particular
Justo antes de ejecutar la llamada a método, la JVM mira el tipo de objeto que ha sido asignado a la variable de referencia
Si es de la clase X, la JVM enlaza el método correspondiente a X a la llamada al método original
Después que la JVM enlaza el método apropiado a la llamada al método, la JVM ejecuta el método enlazado
6. Enlace Dinámico (Dynamic Binding)
Si Perro implementa un método display que imprime “Soy un perro", ¿funcionará el siguiente código?
Object obj = new Perro();
obj.display();
6. Enlace Dinámico (Dynamic Binding)
Tener en cuenta:
1. Cuando un compilador ve la llamada a método
<variableReferencia>.<método>(), revisa si la
clase de la variable de referencia tiene la definición del método llamado, si no la encuentra, no compila
2. Normalmente, al asignar un objeto a una variable de referencia, la clase de ambos es la misma, pero en el ejemplo anterior vimos que un objeto de la clase Perro es asignado en una variable de referencia de tipo Object. Tal asignación sólo
funciona si la clase del lado derecho es una subclase de la clase del lado izquierdo
6. Enlace Dinámico (Dynamic Binding)
Object obj = new Object();
Object obj = new Perro();
Perro obj = new Object();
7. Operador instanceof
Operador que verifica si un objeto referenciado es instancia de una clase en particular
Devuelve true si el objeto se verifica con su clase
correspondiente o con cualquiera de sus superclases
Sintaxis:
<nombreObjeto> instanceof <nombreClase>
Ejemplo: Object obj=new Perro();
System.out.println(obj instanceof Perro);
System.out.println(obj instanceof Gato);
System.out.println(obj instanceof Object);
if(obj instanceof Perro)
System.out.println("Es un perrito");
8. Asignación entre objetos en una jerarquía de clases
Asignar un objeto de un tipo a una variable de referencia de otro tipo
En la jerarquía:
Persona p = new Estudiante();
Estudiante s = new Persona();
Persona
Estudiante
Error
8. Asignación entre objetos en una jerarquía de clases
Podemos hacer cast entre objetos
La condición es que el objeto del lado derecho del casting tenga todo lo del objeto del lado izquierdo
Dicho de otro modo, que el objeto al que le aplicamos cast sea del mismo tipo o de un tipo descendiente del de la variable de referencia de la izquierda
Object obj10=new Perro();
Perro obj11=(Perro) obj10;
System.out.println(obj10);
System.out.println(obj11);
Object obj10=new Object();
Perro obj11=(Perro) obj10;
System.out.println(obj10);
System.out.println(obj11);
9. Polimorfismo con Arreglos
La utilidad del polimorfismo viene cuando tenemos un arreglo de variables de referencia genérico y asignamos diferentes tipos de objetos a los diferentes elementos del arreglo
Nos permite recorrer el arreglo y llamar el método polimórfico para cada elemento del arreglo
En tiempo de ejecución, la JVM usa el enlazamiento dinámico para escoger el método en particular a aplicar a los diferentes tipos de objetos del arreglo
9. Polimorfismo con Arreglos
EJERCICIO
En la empresa tenemos 2 tipos de Empleado: el que tiene un salario fijo mensual y el que trabaja por horas (el salario fijo y el pago por hora varía de empleado a empleado)
Deseamos manejar la planilla y obtener el reporte de cuánto pagar a fin de mes para cada empleado
Crear las clases necesarias. Implementar el Diagrama UML y un main() que pruebe las clases creadas. Usar polimorfismo
9. Polimorfismo con Arreglos Employee
name : String
Employee(n : String)getPay() : doubleprintPay() : void
Salaried
salary : double
Salaried(n : String, s : double)getPay() : double
Hourly
hourlyRate : doublehours : double = 0
Hourly(n : String, rate : double)getPay() : doubleaddHours(h : double) : void
AplicacionPayroll
main()
9. Polimorfismo con Arreglos
TIPS:
Crear un arreglo de 100 Employees
Crear 3 empleados como elementos del arreglo: 2 empleados por horas y 1 empleado con salario
Darle una cantidad de horas trabajadas a los empleados por hora
Imprimir el reporte de cuanto se les debe pagar
Salida: Anna 4000.0
Donovan 3200.0
Simon 48000.0
9. Polimorfismo con Arreglos
EJERCICIO
El ejercicio anterior pero que añada 160 horas pero sólo a cada objeto de empleado que gana por horas (antes de la impresión de sus datos)
9. Polimorfismo con Arreglos
EJERCICIO
El ejercicio anterior pero aprovechando el toString
En main: System.out.println(employees[i]);
9. Polimorfismo con Arreglos
EJERCICIO
El ejercicio anterior pero crear un menú que pregunte el tipo de empleado que se va a insertar cada vez, e insertar los datos respectivos basado en el tipo
El ejercicio anterior con las siguientes restricciones: A los empleados por horas se les paga todos los viernes
A los empleados con salario se les paga cada quincena
El mes empieza un martes
Suponga que los empleados por horas SIEMPRE trabajan 8 horas diarias
Suponga que el mes tiene 30 días
Imprimir TODOS los pagos que debemos hacer al mes
4 Anna 800.0
4 Donovan 640.0
11 Anna 1000.0
11 Donovan 800.0
15 Simon 24000.0
18 Anna 1000.0
18 Donovan 800.0
25 Anna 1000.0
25 Donovan 800.0
30 Simon 24000.0
10. Métodos y clases abstract
Declarar un método como abstract si la clase del método es
una superclase y el método es un “método dummy” que será sobreescrito en las subclases
Java requiere que cuando definamos un método como abstract, debemos:
Usar una cabecera de método abstracto en lugar de una definición de método
Igual que una cabecera de método, excepto que incluye el modificador abstract y acaba con ;
public abstract double getPay();
Definir una versión sobreescrita de dicho método en cada una de las subclases de la superclase
Definir la superclase como abstract usando el modificador abstract
public abstract class Employee
{
}
10. Métodos y clases abstract
Definir una clase como abstract implica decirle al
compilador que no se permite crear instancias de dicha clase
Si un programa intenta instanciar una clase abstract, un error de compilación es generado
Un método abstract debería no ser ni private ni final
10. Métodos y clases abstract
public abstract class Employee
{
private String name;
public abstract double getPay();
public Employee(String n)
{
name = n;
}
public void printPay(int date)
{
System.out.println(date + " "+ name+" "+ getPay());
}
}
11. Interfaces
Una interface es como una clase abstracta pura
Sólo provee: Constantes de clase: public static final
Declaraciones de método: public abstract
Sintaxis: interface <nombreInterface>
{
<tipo> <nombreConstante> = <valor>;
...
<tipoRetorno> <nombreMétodo>(<listaParametros>);
...
}
11. Interfaces
Para implementar una interface: public class <nombreClase> implements <nombreInterface>
{
...
}
Para implementar varias interfaces: public class <nombreClase> implements
<nombreInterface1>, <nombreInterface2>, ...
{
...
}
Para herencia e implementación: public class <nombreClase> extends <nombreSuperClase>
implements nombreInterface1>, <nombreInterface2>, ...
{
...
}
11. Interfaces
Se usan las interfaces con diferentes fines:
1) Almacenar constantes universales
2) Implementar polimorfismo
3) Estandarizar la comunicación interclases
11. Interfaces
1) Almacenar constantes universales
Implementar una interface da a la clase que la implementa acceso libre a las constantes definidas en la interface
Brinda a dichas clases, un fácil acceso a constantes (evita la notación .dot)
Evita duplicar definiciones de esas constantes
Se podría utilizar una herencia, pero perderíamos la única posibilidad de usar el mecanismo de herencia, en cambio podemos implementar muchas interfaces
11. Interfaces
2) Implementar polimorfismo
Una de las principales razones de utilizar interfaces, es implementar múltiples polimorfismos
Sirven para implementar polimorfismos que no encajan con la jerarquía original
Imaginen que queremos un método que sea polimórfico, pero sólo para algunas clases de la jerarquía y que incluya clases que no están en la jerarquía de herencia dada
Ejemplo: mejoraremos el programa de la planilla
11. Interfaces
EJERCICIO
En la empresa tenemos 4 tipos de Empleado: el que tiene un salario fijo mensual, el que trabaja por horas (el pago por hora varía de empleado a empleado), el que trabaja por comisión % de sus ventas y el que tiene un salario fijo mensual, pero también comisión
Deseamos manejar la planilla y obtener el reporte de cuánto pagar a fin de mes para cada empleado
Implementar el Diagrama UML y un main() que pruebe las clases creadas. Usar polimorfismo e Interfaces
11. Interfaces
Salaried
salary : double
Salaried(name : String, s : double)getPay() : double
Hourly
hourlyRate : doublehours : double = 0
Hourly(n : String, rate : double)getPay() : doubleaddHours(h : double) : void
Commissioned
sales : double = 0.0
Commissioned(name : String)addSales(s : double) : voidgetPay() : double
SalariedAndCommissioned
sales : double
SalariedAndCommissioned(name : String, salary : double)
addSales(s : double) : void
getPay() : double
Employee
name : String
Employee(n : String)getPay() : doubleprintPay(date : double) : void
Commission
COMMISSION_RATE : double = 0.10
addSales(sales : double) : void
<<Interface>>
11. Interfaces
TIPS:
Crear un arreglo de 100 Employees
Crear 5 empleados como elementos del arreglo: 2 por horas, 1 con salario, 1 por comisión y 1 por salario y comisión
Darle una cantidad de horas trabajadas a los empleados por hora
Darle una cantidad de total de ventas a los empleados por comisión
Imprimir el reporte de cuanto se les debe pagar
Salida: Anna 4000.0
Simon 48000.0
Donovan 3200.0
Glen 1500.0
Carol 25500.0
11. Interfaces
3) Estandarizar la comunicación interclases
Especificar las cabeceras de un conjunto de métodos que otras clases deben implementar
Sirve de contrato entre el diseñador y los programadores
Muy útil en proyectos de software (especialmente los grandes)
11. Interfaces
EJEMPLO
Sistema de Contabilidad
Usa activos de la empresa como: cash, cuentas por cobrar, muebles, equipos, vehículos, edificios, etc.
A la vez podemos crear una subjerarquía con aquellos activos a largo plazo y que se deprecian: muebles, equipos, vehículos, edificios
El contador prepara anualmente los Estados Financieros de la empresa: Balance, Estado de ganancias y pérdidas
Para ello se requiere acceder a los datos de los objetos que se deprecian: costo original, fecha de adquisición y tasa de depreciación
11. Interfaces
Para facilitar el acceso a estos objetos, sería bueno tener referencias a ellos en un arreglo o arraylist
Luego el programa debería recorrer el arreglo y acceder a los métodos polimórficos get para obtener
el valor de los 3 atributos de cada objeto
Imaginar que se desarrolla el software en equipo y diferentes miembros trabajan en distintos estados financieros
La mejor forma para lograr coherencia entre ellos es requerir que todas las clases que accedan a un cierto conjunto de datos implementen la misma interface de Java: implements
11. Interfaces
La interface para los métodos get del ejemplo que accedan a los 3 atributos la llamaremos EnvejecimientoActivos
Contendrá declaraciones/cabeceras de los métodos, pero no definiciones
Recordar que si una clase en particular incluirá la definición de los métodos declarados en la interface, se deberá incluir la clausula implements en la cabecera de la clase
public class <nombreClase> implements <nombreInterface>
{
...
}
12. Modificador de acceso protected
El modificador de acceso protected está en medio de los modificadores public y private en términos de cuán
accesible es
Los miembros protected (variables de instancia, variables de
clase y métodos) sólo pueden ser accedidos por clases dentro del subárbol asociado con la clase del miembro
Object the root of the Java class tree
Employee
Manager Laborer Secretary
Executive MiddleManager
Employee
class's
subtreeManager
class's
subtree
12. Modificador de acceso protected
¿Cuándo usar modificador de acceso protected?
Cuando deseamos que un miembro sea accesible desde cualquier clase dentro de su subárbol de clases, pero no deseamos que sea accesible desde otro lugar más
Ejemplo: Suponga que la clase Employee contiene una variable de
instancia employeeId y todas sus clases descendientes
necesitan acceder a ella.
Para hacer más fácil el acceso para los descendientes declarar: employeeId como protected:
protected int employeeId;
Así, las clases descendientes pueden acceder a employeeId directamente en lugar de usar un accesosr getId()
12. Modificador de acceso protected
EJERCICIO (Usando protected)
La misma empresa vista, con la siguiente restricción:
Existen empleados a los que se les debe descontar cuando se les paga
Los empleados afectados son aquéllos que tienen como sueldo fijo 10000 ó más, la tasa de descuento es del 15%
Salida: Anna 4000.0
Simon 40800.0
Donovan 3200.0
Glen 1500.0
el salario original es: 24000.0 en ventas es: 15000.0
con descuento por impuestos: 3600.0
Carol 21900.0