sofia (77217)

Anuncio
HERENCIA
La herencia es uno de los mecanismos de los lenguajes de programación orientada a
objetos basados en clases, por medio del cual una clase se deriva de otra de manera que
extiende su funcionalidad. La clase de la que se hereda se suele denominar clase base,
clase padre, superclase, clase ancestro (el vocabulario que se utiliza suele depender en
gran medida del lenguaje de programación).
En los lenguajes que cuentan con un sistema de tipos fuerte y estrictamente restrictivo
con el tipo de datos de las variables, la herencia suele ser un requisito fundamental para
poder emplear el Polimorfismo, al igual que un mecanismo que permita decidir en
tiempo de ejecución qué método debe invocarse en respuesta a la recepción de un
mensaje, conocido como enlace tardío o enlace dinámico.
Ejemplo en Java
import javax.*;
import javax.swing.JOptionPane;
public class Mamifero{
private int patas;
private String nombre;
public void imprimirPatas(){
JOptionPane.showMessageDialog(null," Tiene " + patas + "
patas\n", "Mamifero", JOptionPane.INFORMATION_MESSAGE);
}
public Mamifero(String nombre, int patas){
this.nombre = nombre;
this.patas = patas;
}
}
public class Perro extends Mamifero {
public Perro(String nombre){
super(nombre, 4);
}
}
public class Gato extends Mamifero {
public Gato(String nombre){
super(nombre, 4);
}
}
public class CrearPerro {
public static void main(String[] args) {
Perro perrito = new Perro("Pantaleon");
perrito.imprimirPatas();
/*Está en la clase mamífero*/
}
}
Se declaran las clases mamíferos, gato y perro, haciendo que gato y perro sean unos
mamíferos (derivados de esta clase), y se ve como a través de ellos se nombra al animal
pero así también se accede a patas dándole el valor por defecto para esa especie.
Es importante destacar tres cosas. La primera, es que la herencia no es un mecanismo
esencial en el paradigma de programación orientada a objetos; en la mayoría de los
lenguajes orientados a objetos basados en prototipos las clases no existen, en
consecuencia tampoco existe la herencia y el polimorfismo se logra por otros medios.
La segunda, es que el medio preferido para lograr los objetivos de extensibilidad y
reutilización es la agregación o composición. La tercera, es que en lenguajes con un
sistema de tipos débiles, el polimorfismo se puede lograr sin utilizar la herencia.
Por otra parte y aunque la herencia no es un concepto indispensable en el paradigma de
programación orientada a objetos, es mucho más que un mecanismo de los lenguajes
basados en clases, porque implica una forma de razonar sobre cómo diseñar ciertas
partes de un programa. Es decir, no sólo es un mecanismo que permite implementar un
diseño, sino que establece un marco conceptual que permite razonar sobre cómo crear
ese diseño.
PROTECTED
Hasta ahora habíamos dicho que una subclase no tiene acceso a los campos de una
superclase de acuerdo con el principio de ocultación de la información. Sin embargo,
esto podría considerarse como demasiado restrictivo.
Decimos que podría considerarse demasiado restrictivo porque limita el acceso a una
subclase como si se tratara de una clase cualquiera, cuando en realidad la relación de
una superclase con una subclase es más estrecha que con una clase externa. Por ello en
diferentes lenguajes, Java entre ellos, se usa un nivel de acceso intermedio que no es ni
public ni private, sino algo intermedio que se denomina como “acceso protegido”,
expresado con la palabra clave protected, que significa que las subclases sí pueden
tener acceso al campo o método.
El modificador de acceso protected puede aplicarse a todos los miembros de una clase,
es decir, tanto a campos como a métodos o constructores. En el caso de métodos o
constructores protegidos, estos serán visibles/utilizables por las subclases y otras clases
del mismo package. El acceso protegido suele aplicarse a métodos o constructores, pero
preferiblemente no a campos, para evitar debilitar el encapsulamiento. En ocasiones
puntuales sí resulta de interés declarar campos con acceso protegido.
La sintaxis para emplear esta palabra clave es análoga a la que usamos con las palabras
public y private, con la salvedad de que protected suele usarse cuando se trabaja con
herencia. Desde un objeto de una subclase podremos acceder o invocar un campo o
método declarado como protected, pero no podemos acceder o invocar a campos o
métodos privados de una superclase. Declara un campo de una clase como protected y
en un test crea un objeto de la subclase y trata de acceder a ese campo con una
invocación directa del tipo interino43.IdProfesor = “54-DY-87”.
Java admite una variante más en cuanto a modificadores de acceso: la omisión del
mismo (no declarar ninguno de los modificadores public, private o protected). En la
siguiente tabla puedes comparar los efectos de usar uno u otro tipo de declaración en
cuanto a visibilidad de los campos o métodos:
MODIFICADOR
CLASE
PACKAGE
SUBCLASE
TODOS
public
Sí
Sí
Sí
Sí
protected
Sí
Sí
Sí
No
No especificado
Sí
Sí
No
No
private
Sí
No
No
No
EJEMPLOS
Considera que estás desarrollando un programa Java donde trabajas con la superclase
Profesor y la subclase Profesor Emerito. Crea el código para estas clases que cumpla los
requisitos que indicamos.
Como atributos de la superclase tendremos nombre (String), edad (int) y años
Consolidados (int) declarados como protected.
En la subclase se trabajará con el campo adicional años Emerito declarado como
private.
Un método de la subclase será double obtener Salario Base () que obtendrá el salario
base como (925 + años Consolidados * 33.25 + 47.80 * años Emerito).
Intenta acceder directamente al campo años Consolidados desde la subclase (como si
fuera un campo más de la subclase) para implementar este método. Es posible sin
utilizar una invocación a super ni un método get que ocurre si el atributo en la
superclase lo declaras prívate.
SUPER
En apartados anteriores del curso hemos trabajando con herencia, polimorfismo y sobre
escritura de métodos. Hemos usado como clases de ejemplo las clases Persona,
Profesor, Profesor Interino y Profesor Titular, donde Profesor hereda de Persona y los
profesores interino y titular de Profesor.
¿Cómo imprimir un listado con todos los profesores (titulares e interinos) y todos sus
datos? En los métodos de Profesor solo tenemos disponibles los campos de Profesor,
pero no los campos de Profesor Titular o de Profesor Interino. A su vez, Profesor Titular
(o Profesor Interino) no conoce los campos de Profesor porque son privados, y no
queremos hacerlos públicos para no romper el encapsulamiento (principio de
ocultación) de la clase.
Hemos visto cómo en los constructores de subclases usábamos la sintaxis súper () en la
primera línea para invocar al constructor de la superclase. Veremos ahora que esta otra
sintaxis: súper. Nombre Del Método (parámetros si los hay); tiene como efecto la
invocación de un método de la superclase. Consideremos el ejemplo anterior. En el
método mostrar Datos() de la clase Profesor Interino escribimos lo siguiente:
EJEMPLO:
public void mostrarDatos() {
super.mostrarDatos();
System.out.println("Comienzo
interinidad:
FechaComienzoInterinidad.getTime().toString() );
"
+
}
¿Qué hemos hecho? Dentro del método “hijo” hemos incluido una llamada al método
“padre” que había perdido visibilidad debido a que lo habíamos sobre escrito. Al
ejecutar el programa ahora obtenemos:
Se procede a mostrar los datos de los profesores existentes en el listín
Datos Profesor. Profesor de nombre: Juan Hernández García con Id de profesor: Prof
22-387-11
Datos Profesor. Profesor de nombre: José Luis Morales Pérez con Id de profesor:
Unknown
Comienzo interinidad: Fri Nov 22 12:40:38 CET 2019
Gracias a la instrucción súper. Mostrar Datos () hemos incluido dentro de un método
sobre escrito el método deseado de la superclase. La llamada a súper dentro de un
método puede ocurrir en cualquier lugar dentro del código. Equivale a la ejecución del
método de la superclase y es opcional: la hacemos sólo cuando nos resulta necesaria o
conveniente para poder acceder a un método sobre escrito.
Considera que estás desarrollando un programa Java donde trabajas con la superclase
Profesor y la subclase Profesor Emérito. Crea el código para estas clases que cumpla los
requisitos que indicamos.
Como atributos de la superclase tendremos nombre (String), edad (int) y años
Consolidados (int). Un método de la superclase será double obtener Salario Base () que
obtendrá el salario base como (725 + el número de años consolidados multiplicado por
33.25).
En la subclase se trabajará con el campo adicional años Emérito. Queremos hacer lo
siguiente: sobre escribir el método obtener Salario Base () en la subclase para calcular el
salario base del profesor emérito invocando mediante la palabra clave súper al cálculo
del salario base de Profesor y añadiéndole la cantidad de (47.80 * años Emérito).
FINAL
En los programas que generemos usualmente intervendrán constantes: valores
matemáticos como el número Pi, o valores propios de programa que nunca cambian. Si
nunca cambian, lo adecuado será declararlos como constantes en lugar de cómo
variables. Supongamos que queremos usar una constante como el número Pi y que
usamos esta declaración:
EJEMPLOS
// Ejemplo aprenderaprogramar.com
public class Calculadora {
private double PI = 3.1416;
public void mostrarConstantePi () { System.out.println (PI);
}
… constructor, métodos, … código de la clase … }
Si creas un objeto de tipo Calculadora, comprobarás que puedes invocar el método
mostrar Constante Pi para que te muestre el valor por pantalla. No obstante, una
declaración de este tipo presenta varios problemas. En primer lugar, lo declarado no
funciona realmente como constante, sino como variable con un valor inicial. Prueba a
establecer this.PI = 22; dentro del método y verás que es posible, porque lo declarado es
una variable, no una constante. En segundo lugar, cada vez que creamos un objeto de
tipo calculadora estamos usando un espacio de memoria para almacenar el valor 3.1416.
Así, si tuviéramos diez objetos calculadora, tendríamos diez espacios de memoria
ocupados con la misma información, lo cual resulta ineficiente. Para resolver estos
problemas, podemos declarar constantes en Java usando esta sintaxis:
CaracterPublico/Privado
valorDeLaConstante;
static
final
TipoDeLaConstante
=
En esta declaración intervienen dos palabras clave cuyo significado es importante:
a) static: los atributos miembros de una clase pueden ser atributos de clase o
atributos de instancia; se dice que son atributos de clase si se usa la palabra clave
static: en ese caso la variable es única para todas las instancias (objetos) de la
clase (ocupa un único lugar en memoria). A veces a las variables de clase se les
llama variables estáticas. Si no se usa static, el sistema crea un lugar nuevo para
esa variable con cada instancia (la variable es diferente para cada objeto). En el
caso de una constante no tiene sentido crear un nuevo lugar de memoria por cada
objeto de una clase que se cree. Por ello es adecuado el uso de la palabra clave
static. Cuando usamos “static final” se dice que creamos una constante de clase,
un atributo común a todos los objetos de esa clase.
b) final: en este contexto indica que una variable es de tipo constante: no
admitirá cambios después de su declaración y asignación de valor. final
determina que un atributo no puede ser sobre escrito o redefinido. O sea: no
funcionará como una variable “tradicional”, sino como una constante. Toda
constante declarada con final ha de ser inicializada en el mismo momento de
declararla. final también se usa como palabra clave en otro contexto: una clase
final (final) es aquella que no puede tener clases que la hereden. Lo veremos
más adelante cuando hablemos sobre herencia.
Cuando se declaran constantes es muy frecuente que los programadores usen letras
mayúsculas (como práctica habitual que permite una mayor claridad en el código),
aunque no es obligatorio.
Una declaración en cabecera de una clase como private final double PI = 3.1416;
podríamos interpretarla como una constante de objeto. Cada objeto tendrá su espacio de
memoria con un contenido invariable. Una declaración en cabecera de una clase como
private static final double Pi = 3.1416; la interpretamos como una constante de clase.
Existe un único espacio de memoria, compartido por todos los objetos de la clase, que
contiene un valor invariable. Veamos ejemplos de uso:
// Ejemplo aprenderaprogramar.com
// Sintaxis: CarácterPublico/Privado
valorDeLaConstante;
static
final
TipoDeLaConstante
private static final float PI = 3.1416f; //Recordar f indica que se trata de un float
private static double PI = 3.1416;
public static final String passwd = "jkl342lagg";
public static final int PRECIO_DEFAULT = 100;
Cuando usamos la palabra clave static la declaración de la constante ha de realizarse
obligatoriamente en cabecera de la clase, junto a los campos (debajo de la signatura
de clase). Es decir, un atributo de clase hemos de declararlo en cabecera de clase. Si
tratamos de incorporarlo en un método obtendremos un error. Por tanto dentro del
método main (que es un método de clase al llevar incorporado static en su declaración)
no podemos declarar constantes de clase. Por otro lado, final sí puede ser usado dentro
de métodos y también dentro de un método main. Por ejemplo una declaración como
final String psswd = “mt34rsm8” es válida dentro de un método. En resumen: en
cabecera de clase usaremos static final para definir aquellas variables comunes a todos
los objetos de una clase.
Modifica el código de la clase Calculadora que vimos anteriormente para declarar PI
como una constante de clase. Luego, intenta modificar el valor de PI usando una
invocación como this.PI =22;. Comprobarás que se produce un error al compilar ya que
los valores de las constantes no son modificables.
Define una clase Java denominada Circulo que tenga como atributo de clase (estático)
y constante numeroPi, siendo esta constante de tipo double y valor 3.1416. Además la
clase tendrá el atributo radio (tipo double) que representa el radio del círculo, y los
métodos para obtener y establecer los atributos. También debe disponer de un método
para calcular el área del círculo (método tipo funcion area Circulo que devuelve el área)
=
y la longitud del círculo (método tipo función que devuelve la longitud). Busca
información sobre las fórmulas necesarias para crear estos métodos en internet si no las
recuerdas. En una clase con el método main, declara el código que cree un objeto
círculo, le pida al usuario el radio y le devuelva el área y la longitud del círculo.
ABSTRACT
Una clase abstracta es aquella que posee al menos un método abstracto. Un método
abstracto es aquél que está declarado, pero que no posee implementación alguna (es
decir no tiene cuerpo). Está incompleto. Debido a esta carencia, es imposible declarar
objetos de una clase abstracta. ¿Para qué sirve entonces una clase abstracta? Una clase
abstracta sirve para establecer un marco de trabajo que deben cumplir todas las clases
que hereden de ella. Las clases que heredan de ella sí deben dotar de una
implementación a los métodos abstractos del padre. Si no lo hacen, automáticamente se
convierten también en abstractas. También es posible definir una clase abstracta sin que
posea métodos abstractos.
Las clases y métodos abstractos llevan la palabra clave abstract. Es importante que
tengas en cuenta que no pueden llevar el modificador abstract:



los constructores
los métodos estáticos
los métodos privados
Ejemplo 1.
La clase abstracta Mascota declara un método abstracto hablar que deberá ser redefinido
por las subclases Gato, Perro y Pato. Observa que la clase Mascota solo se está
utilizando para declarar el método hablar, de modo que las clases hijas la puedan usar.
/**
* Abstract class Mascota - Representa una mascota
*/
public abstract class Mascota
{
/**
* Método abstracto hablar para las mascotas
*/
abstract public void hablar();
}
//fin de la clase Mascota
/**
* La clase Gato que hereda de la clase Mascota.
*/
public class Gato extends Mascota
{
/**
* Implementación del método hablar
*/
public void hablar() {
System.out.println( "Meow" );
}
// fin del método hablar
}
// fin de la clase Gato
/**
* La clase Perro que hereda de la clase Mascota.
*/
public class Perro extends Mascota
{
/**
* Implementación del método hablar
*/
public void hablar() {
System.out.println( "Woof" );
}
// fin del método hablar
}
// fin de la clase Perro
/**
* La clase Pato que hereda de la clase Mascota.
*/
public class Pato extends Mascota
{
/**
* Implementación del método hablar
*/
public void hablar() {
System.out.println( "Quack" );
}
// fin del método hablar
}
// fin de la clase Pato
/**
* Clase controladora para los objetos Gato, Perro, Pato.
*
*/
public class Granja
{
/**
* Método principal de la aplicación
*/
public static void main( String[] args )
{
Mascota[] misMascotas = new Mascota[4];
misMascotas[0] = new Pato();
misMascotas[1] = new Perro();
misMascotas[2] = new Gato();
misMascotas[3] = new Pato();
for( int i = 0; i < misMascotas.length; i++ )
misMascotas[i].hablar();
}
}
//fin del método main
//fin de la clase Granja
Ejemplo 2.
La clase abstracta Producto incluye un método abstracto imprimirDatos. Observa el uso
de la palabra clave abstract antes del nombre de la clase a fin de informar al compilador
de Java que la clase incluye un método abstracto, o más. En virtud de que la clase
abstracta no define todos sus métodos no se pueden crear instancias de la clase
Producto.
/**
* Abstract class Producto - Representa el producto de una tienda
*
*/
public abstract class Producto
{
// variables de instancia
protected double precioVenta;
protected double costoFabrica;
protected String nombreProducto;
/**
* Constructor para Producto
*
* @param
nombre El nombre del producto
* @param
precioVenta El precio de venta del producto
* @param
costoFabrica El costo de fábrica del producto
*/
public Producto( String nombre, double precio, double costo )
{
nombreProducto = nombre;
precioVenta = precio;
costoFabrica = costo;
}
// fin del constructor Producto
/**
* Método abstracto para imprimirDatos
*/
public abstract String imprimirDatos();
}
// fin de la clase Producto
Observa que las clases Libro y DVD que extienden de la clase abstracta Producto e
implementan el método abstracto imprimirDatos.
/**
* Clase Libro que hereda de la clase Producto.
*/
public class Libro extends Producto
{
/**
* Constructor para los objetos de la clase Libro
* @param
titulo El título del libro
* @param
precio El precio de venta del libro
* @param
costo
El costo de fábrica del libro
*/
public Libro( String titulo, double precio, double costo )
{
super( titulo, precio, costo );
}
/**
* Imprime los datos asociados con el libro
*
* @return los datos del libro en un String
*/
public String imprimirDatos()
{
return "Libro: " + nombreProducto + "\tPrecio: $" +
precioVenta;
}
// fin del método imprimirDatos
}
// fin de la clase Libro
/**
* Clase Libro que hereda de la clase Producto.
*/
public class DVD extends Producto
{
/**
* Constructor para los objetos de la clase DVD
* @param
titulo El título del DVD
* @param
precio El precio de venta del DVD
* @param
costo
El costo de fábrica del DVD
*/
public DVD( String titulo, double precio, double costo )
{
super( titulo, precio, costo );
}
/**
* Imprime los datos asociados con el DVD
*
* @return los datos del DVD en un String
*/
public String imprimirDatos()
{
return "DVD: " + nombreProducto + "\tPrecio: $" + precioVenta;
}
//fin del método imprimirDatos
}
//fin de la clase DVD
/**
* Clase controladora para los objetos de DVD y Libros.
*/
public class PruebaProducto
{
/**
* Método principal de la aplicación
*/
public static void main( String[] args )
{
Libro miLibro = new Libro( "Biblioteca del programador",
54.95, 39.95 );
DVD miDVD = new DVD( "Curso multimedia de Java", 29.95, 19.95
);
}
}
System.out.println( "Los datos de mis productos." );
System.out.println( miLibro.imprimirDatos() );
System.out.println( miDVD.imprimirDatos() );
//fin del método main
//fin de la clase PruebaProducto
Descargar