Tema06 HerenciaPolimorfismoTopicosAvanzados Verano (1)

64
EPIS – 2015 [email protected] [email protected] Fundamentos de Programación 2 Ing. Marco Aedo López

description

Ejemplos de herencia y polimorfimsmo

Transcript of Tema06 HerenciaPolimorfismoTopicosAvanzados Verano (1)

EPIS – 2015 [email protected] [email protected]

Fundamentos de Programación 2

Ing. Marco Aedo López

Herencia, Polimorfismo y Tópicos Avanzados

Capítulo 6

EPIS UNSA - 2008 [email protected]

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

1. La clase Object

Object

equals()toString()

Clase1 Clase2 ClaseN…

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

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

Este método nunca se ejecuta, se pone para satisfacer al compilador

Llamada a método polimórfico

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

12. Modificador de acceso protected