>>
Lección 03


Paquetes, modificadores, subclases, clases abstractas e interfaces.


Cuanto más grandes son sus programas mayor necesidad tiene el programador de organizar su trabajo de manera cómoda y segura. Java ofrece varias herramientas de organización y protección del código que son el objetivo de la última parte de esta  lección.

Las herramientas de protección y organización forman un rico entramado de relaciones entre las clases, sus variables y sus métodos. Una clase puede extender a otra, puede implementar una interfaz, puede ser abstracta, puede ser o no ser pública y puede pertenecer a un paquete. Las variables y los métodos pueden ser públicos, privadosprotegidos o del paquete. Al final de la lección el alumno deberá comprender todos estos términos.

Provisionalmente se presentan algunas definiciones que servirán para dar una primera idea de estos conceptos.

Los paquetes son conjuntos organizados de clases que pueden compartir algunas variables y métodos sin compartirlos con las clases de otros paquetes. Ejemplos: java.lang.String y java.lang.System son dos clases del paquete java.lang.

Se llaman modificadores a los términos que especifican algunas características o propiedades de una clase, variable, método o interfaz. Ejemplos: public, static, abstract.

Una clase A que extiende a otra clase B se dice que es una subclase de B y también se dice que B es la superclase de A. Una subclase hereda todas las variables y métodos de su superclase y puede tener otros más.

Los métodos abstractos son encabezados de métodos sin implementación. Una clase que contiene métodos abstractos debe declararse como abstract y se dice que es una clase abstracta. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos de su superclase o declararse a su vez abstracta. Una clase totalmente abstracta y pública es lo que se llama una interfaz.

Las interfaces funcionan como contratos que una clase se compromete a cumplir cuando de ella se dice que implemente una interfaz. Las interfaces contienen únicamente los encabezados de los métodos que una clase se compromete a implementar si en su definición se dice que implementa dicha interfaz. Ejemplo: public class ejemplo implements Runnable obliga a la clase ejemplo a implementar el método public void run() porque la interfaz Runnable consta precisamente de tal encabezado.


Paquetes.


Los paquetes son conjuntos de clases. Para declarar que una clase pertenece al paquete ejem02.paquete1 es necesario que la primera línea del archivo .java de esa clase sea:

package ejem02.paquete1;

También es necesario que el archivo .class se coloque dentro del subdirectorio ./ejem02/paquete1. El nombre de un paquete puede tener puntos, y entonces eso indica que cada palabra separada por los puntos corresponde a un subdirectorio en la organización final de las clases.

El que dos paquetes compartan parte de su nombre, como sucede por ejemplo con los paquetes  java.awt y java.awt.Image, no tiene ninguna implicación respecto a los paquetes, excepto la relativa a la localización de las clases. El uso de estos nombres parcialmente compartidos es sólo una forma de organización mnemotécnica de los contenidos.

Como veremos en la siguiente sección sobre modificadores, las clases de un mismo paquete comparten cierta información que no comparten con las de otros paquetes. Esta es la principal aplicación de los paquetes.

Todas las clases pertenecen a algún paquete aunque en sus archivos .java no se escriba explícitamente. Cuando en un mismo directorio se desarrollan varias clases a las que no se les pone una declaración de pertenencia a algún paquete, el compilador de Java las considera a todas como miembros del paquete sin nombre de las clases que ocupan ese directorio. Dicho paquete se llama el paquete por defecto.

Una clase puede usar libremente las clases de su mismo paquete sin necesidad de importar nada. Sin embargo, si una clase usa clases de otro paquete, es necesario importar la clase o el paquete que la contiene. La única clase que nunca hay que importar es java.lang  pues se importa implícitamente de manera automática en todas las clases. Para importar una clase se debe escribir, antes de la definición de la clase que se está desarrollando, una línea con la palabra import seguida del nombre de la clase que se desea importar y de un punto y coma. Por ejemplo si deseamos importar la clase java.awt.Graphics debemos escribir:

import java.awt.Graphics;

Si uno desea utilizar varias clases de un paquete, lo más cómodo es importar todo el paquete y esto se hace escribiendo import seguido del nombre del paquete y luego ".*;" .  Por ejemplo, para importar todas las clases del paquete java.awt, hay que escribir:

import java.awt.*;

En ambos casos, para referirse a la clase Graphics, una vez hecha la importación, basta usar su nombre prescindiendo del nombre de la clase. Por ejemplo para declarar una variable de la clase Graphics basta escribir:

Graphics g;

Es posible utilizar la clase Graphics si haber hecho la importación al principio del archivo .java. Para ello hay que usar el nombre completo java.awt.Graphics. Por ejemplo, si se desea declarar una variable de este tipo siempre se puede hacer escribiendo:

java.awt.Graphics g;

aunque no se haya importado la clase o el paquete al principio del archivo .java.

Es frecuente que los programadores principiantes tengan dificultades con los nombres de las clases y los paquetes en Java porque el sistema empleado tiene algunas sutilezas. Pare evitar problemas, es importante saber que cuando una clase pertenece a un paquete, el nombre de la clase debe ir precedido por el del paquete de manera que, por ejemplo,  el nombre completo de Graphics es java.awt.Graphics. No siempre es necesario emplear el nombe completo de una clase, muchas veces, para hablar de ella se omite el prefijo del nombre del paquete y también se puede omitir al referise a ella cuando se ha importado previamente el paquete. Pero los nombres completos de las clases de Java tienen mucha importancia en la organización de las clases para la ejecución. Es común que los programadores encuentren dificultades para lograr ejecutar sus applets o sus aplicaciones porque el intérprete no encuentra la clase que ha de ejecutar. La mayor parte de las veces esto ocurre porque el programador olvida que el nombre completo de una clase incluye el nombre del paquete al que pertenece, o bien porque olvida localizar la clase dentro del directorio adecuado..

Para concretar esta explicación consideremos este ejemplo:

  Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Se trata de una clase Java ejecutable (es decir que tiene un método public static void main(String[] args), escrita en un archivo llamado Aplicacion1.java y que pertenece al paquete ejem02.paquete1. El archivo Aplicacion1.java se encuentra en el subdirectorio ejem02 y para compilarlo podemos hacer la llamada:

javac ejem02\Aplicacion1.java

y esto produce un archivo Aplicacion1.class que se encuentra en el directorio ejem02. Pues aunque parezca increibe, este archivo nunca se poodrá ejecutar si no se pone ne otro sitio. Si Ud. intenta ejecutarlo llamando a

java ejem02\Aplicacion1

obtendrá un error. Si intenta esto otro:

java ejem02.Aplicacion1

también obtendrá un error. Si intenta

java ejem02.paquete1.Aplicacion1

Y si se cambia al directorio ejem02 y hace intentos similares también obtendrá error. La única manera de ejecutar Aplicacion1 es crear un subdirectorio de ejem02 llamado paquete1, colocar allí Aplicacion1.class y desde el directorio principal hacer la llamada:

java ejem02.paquete1.Aplicacion1

El alumno debe hacer esta prueba para comprobar y comprender lo que se ha explicado.  

Las clases de un paquete tienen acceso a todas las clases del mismo paquete, sean públicas o no. Sólo las clases públicas de un paquete pueden ser utilizadas por clases de otros paquetes.Por tanto si una clase no se declara pública, queda restringido su acceso a las clases del mismo paquete. Las variables y métodos de una clase pueden tener diferentes niveles de accesibilidad dentro y fuera del paquete de la clase que los contiene. La siguiente sección se ocupa de los modificadores que determinan estos niveles de acceso.


Modificadores.


Las palabras public y static que el alumno habrá visto en las declaraciones de algunas clases, variables y métodos, se llaman modificadores. Su papel es especificar algunas propiedades para dichas clases, variables o métodos.

La siguiente tabla presenta todos los modificadores y una descripción de su función en el lenguaje cuando se aplica a clases, variables, métodos o interfaces. El significado y la importancia de los modificadores se irán aclarando a lo largo de esta lección y más adelante con las aplicaciones más avanzadas. Esta tabla debe servir como referencia.

modificador clases variables métodos interfaces
public visible en todas partes visible donde su clase lo sea visible donde su clase lo sea visible en todas partes
protected no se aplica a clases visible en el mismo paquete y en todas las subclases visible en el mismo paquete y en todas las subclases no se aplica a interfaces
ninguno (default) visible sólo en su paquete visible en el paquete de su clase visible en el paquete de su clase visible sólo en su paquete
private no se aplica visible sólo en su clase visible sólo en su clase no se aplica
abstract la clase tiene métodos no implementados no se aplica no hay implementación, sólo se da el encabezado y se termina con ; todas las interfaces son abstractas (aunque no se declaren así)
final no pueden crearse subclases su valor no se puede cambiar (es constante y el compilador puede pre-calcular el valor) no se puede sobreescribir no se aplica
native no se aplica no se aplica. está implementado en un lenguaje dependiente de plataforma, sólo se presenta el encabezado y se termina con ; no se aplica
static no se aplica es una variable de la clase, sólo hay una para todos los objetos de la clase y por tanto en todos los objetos tiene el mismo valor. Se puede invocar con el nombre de la clase. es un método de la clase, sólo puede usar las variables de clase. Se puede invocar con el nombre de la clase. no se aplica
synchronized no se aplica no se aplica. si es estático se bloquea al ejecutarse, y si no lo es, se bloquea su objeto. El bloqueo impide que se ejecuten otros hilos durante la ejecución del método. Este modificador se requiere cuando el método hace cambios no atómicos a la clase o al objeto no se aplica
transient no se aplica no es parte del estado del objeto (actualmente no se usa) no se aplica. no se aplica
volatile no se aplica se modifica asincrónicamente, puede ser un registro de hardware, siempre que se usa se verifica su valor por si ha cambiado. no se aplica no se aplica

El resto de esta sección la dedicaremos a un análisis del efecto de los modificadores en las variables de una clase sobre la accesibilidad de las variables desde las clases derivadas y desde otras clases.

Para fijar ideas consideremos los siguientes ejemplos. Se trata de cuatro clases llamadas claseA, claseB, claseC y claseD. Las dos primeras están en el paquete  ejem02.paquete1 y las otras en  ejem02.paquete2. claseB y claseC son extensiones de claseA. claseD declara y utiliza un objeto de claseA. La claseA tiene cuatro variables a,b,c y d con diferentes modificadores. La accesibilidad de estas variables desde las otras clases es el tema que vamos a explicar.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET. Aquí vería un applet si su navegador reconociese la etiqueta de APPLET. Aquí vería un applet si su navegador reconociese la etiqueta de APPLET. Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

El alumno puede ver que la variable pública d es accesible desde todas las clases. Las variables sin modificador y la protegida son accesibles desde claseB por ser ésta una subclase de claseA dentro del mismo paquete, sin embargo la variable sin modificador a no es accesible desde claseC a pesar de ser extensión de claseA y esto se debe a que está en otro paquete.   La variable privada c no es accesible más que desde la propia claseA donde fue definida.

Las clases claseA y claseB se definieron como públicas pues de otra manera no hubieran podido utilizarse desde el paquete ejem02.paquete2. En resumen, si se quiere que una variable o método sea accesible para otros paquetes, debe declararse como público y estar en una clase pública. El extremo opuesto a público es privado, que es accesible sólo desde la propia clase. Las variables y métodos declarados sin modificador de acceso, son accesibles para todas las clases del mismo paquete. Finalmente, las variables declaradas protegidas son accesibles para las clases en el mismo paquete y para todas las subclases estén o no en el mismo paquete.

Algunas variables y métodos juegan un papel importante en el funcionamiento interno de una clase, pero no deben ser modificados por los usuarios de la clase, que son los programadores que la utilizan. Tales variables deben declararse private. Algunas variables y métodos son importantes para varias clases de un paquete, pero no deben ser modifcados por los usuarios del paquete. Éstos deben declararse sin modificador de acceso. Finalmente, hay variables a las que debe poderse acceder desde cualquier subclase aunque no esté en el mismo paquete. Éstas deben declararse protected. Algo parecido ocurre con las propias clases. Hay clases que juegan un papel importante dentro de un paquete pero que no deben usarse fuera del paquete. Éstas deben declararse sin modificador de acceso. Las clases que están diseñadas para ser usadas fuera del paquete deben declarase public. Si se quiere que una clase no tenga subclases hay que declararla final.

¿Por qué hay tantas opciones de accesibilidad? ¿No sería más fácil que todo fuese público? Limitar el acceso a ciertas variables y métodos es importante para proteger el funcionamiento de los objetos de una clase. ¿De quién hay que protegerlo? De los programadores, de nosotros mismos. Todo programador sabe que a medida que un programa se complica es cada vez más difícil llevar control mental del papel que juega cada variable, cada método y cada clase y es muy fácil malinterpretar algo y usarlo erróneamente. Las partes afinadas de un pograma son muy valiosas y hay que protegerlas incluso del propio creador del programa y con mayor razón de un posible usuario del código que puede aprovechar el funcionamiento de una clase pero, por su propio bien, no debe modificar los detalles delicados.

Si el alumno no tiene mucha experiencia en otros lenguajes de programación es posible que tarde en reconocer la importancia de estas sutilezas. A la larga las agradecerá. De entrada lo mejor es no usar modificadores, con lo cual se adopta un punto intermedio que es lo más recomendable. Cuando se encuentre con que no tiene acceso a algo será porque está en otro paquete y el hecho de estar necesitando aquello es una señal de que debe declararse public. Y así, poco a poco, aprenderá a usar todos los modificadores correctamente.


Subclases.


La programación orientada a objetos y enparticular la programación en Java hace uso frecuente de la creación de subclases. En esta lección se explican algunos detalles de la relación que existe entre una subclase y la clase de la que es extensión, su superclase.

Una subclase es una clase que extiende a otra clase. La sintaxis para crear una subclase es esta:

class B extends A

En este caso se dice que B es una subclase de A o que B es una clase derivada de A y que A es la superclase de B. También se dice que A es una clase antecesora de B y se emplean todo tipo de términos que relacionan a B con la idea de hijo y a A con el de padre o madre.

Si B es una clase derivada de A entonces B tiene todas las variables y los métodos de A y puede tener además otras variables y otros métodos. Se utiliza la analogía genética del hijo heredando todos los rasgos genéticos del padre o la madre, pero teniendo algunas características propias. El símil puede ayudar a la comprensión del concepto, pero no conviene tomarlo muy en serio.

Una clase A puede tener muchas extensiones o clases derivadas (muchos hijos). Por otro lado, todas las clases, excepto java.lang.Object, son extensión de otra clase (todas descienden de otra clase). Si en la definición de una clase no se escribe explícitamente extends y el nombre de la clase que extiende, entonces extiende automáticamente a la clase Object. Una clase hereda las variables y métodos de su superclase, algunos de las y los cuales pueden ser heredados de otra clase. En este sentido una clase es extensión de una cadena de clases cada una de las cuales es extensión de otra, hasta llegar a Object que es el ancestro común de todas las clases. Pero a diferencia de los mamíferos que tienen dos ancestros directos (el padre y la madre), las clases de Java solo descienden de un solo ancestro inmediato, su superclase. Esto se pone de manifiesto en el hecho de que el compilador dará un error si al definir una clase se trata de decirle que extiende a más de una. En otras palabras, a la palabra extends en la definición de una clase sólo puede seguirle el nombre de una clase. Esto es diferente de lo que sucede con la palabra implements que se usa en relación con las interfaces, las cuales se estudian en la siguiente lección. Una clase puede implementar tantas interfaces como se desee.

Si la clase A tiene un solo constructor A() entonces la creación de un objeto de la subclase B llama automáticamente al constructor de A y el programador no tiene que ocuparse de ello. Sin embargo cuando una clase tiene varios constructores el programador puede decidir cual de ellos llamar al construir un objeto de la clase derivada B. Para ello puede utilizar la palabra super como si fuese el constructor de A y entre paréntesis pasarle los parámetros que le corresponden. Pero esto sólo puede hacerse en los constructores de B y sólo como primera instrucción dentro del constructor. Esto se debe a que cualquier cosa que se desee hacer con las variables de la clase derivada B, debe hacerse después de construida la parte correspondiente a la superclase A.


Sobrecarga y sobreescritura de métodos.


En Java varios métodos de una misma clase pueden tener el mismo nombre. Por ejemplo:

public static String valueOf(int i)

y

public static String valueOf(double d)

son dos métodos estáticos de la clase String que tienen el mismo nombre (e incluso los mismos modificadores: public y static; los modificadores se estudian en la lección 3), pero en cambio tienen diferentes parámetros. La posiblidad de definir varios métodos con el mismo nombre que sólo se distinguen por recibir diferentes parámetos, se llama sobrecarga. Se trata de algo muy sencillo, en realidad lo que ocurre es que el compilador de Java utiliza todo el encabezado como nombre de un método, así es que si dos métodos tienen diferente número de parámetros o alguno de ellos es de diferente tipo, eso basta para que sean diferentes para el compilador. Sin embargo al compilador no se le puede engañar tratando de definir dos métodos que sólo difieren en el nombre de sus parámetros...

La sobrecarga es muy útil en casos donde se necesitan varios métodos para realizar alguna función sobre objetos de diferente tipo como en el ejemplo indicado en donde se trata de una función que devuelve la cadena de dígitos (y punto decimal) que expresa la representación decimal de un número. Pero en un caso el número es de tipo int y en el otro de tipo double. Las implementaciones de ambos métodos son diferentes, el segundo debe hacer más trabajo pues debe distinguir dónde poner el punto decimal.

La sobrecarga se utiliza mucho y es muy cómoda para el programador pues le permite usar la misma nomenclatura para métodos análogos, con lo cual se ahorra tener que recordar nombres diferentes.

Ahora estudiaremos otra posibilidad que ofrece Java relacionada con los métodos que se llama la sobreescritura y que no debemos confundir con la sobrecarga.

Los métodos de una clase pueden sobreescribirse en sus clases derivadas. Consideremos los ejemplos siguientes:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.
Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

holaApplet es una extensión de helloApplet, y lo único que hace es sobreescribir el método public void start() de su superclase helloApplet. La sobreescritura consiste en crear un método con el mismo nombre de alguno de la superclase. En la ejecución de la subclase se ejecuta el método sobreescrito y no el de la superclase.

Si una clase B es extensión de otra clase A y sobreescribe un método de A, entonces tiene la posibilidad de utilizar ambos métodos. El suyo propio lo utiliza llamándolo por su nombre, el de la superclase lo utiliza anteponiendo super. al nombre del método. Por ejemplo, si en holaApplet se quisiera utilizar el método public void start() de helloApplet en lugar del suyo propio, tendría que llamarlo así:

super.start();

La sobreescritura es muy útil pues permite aprovechar todo el código que nos interese de una clase que ya existe y solamente sobreescribir las partes que nos interesa modificar. Esto se hace extendiendo la clase original para conservarla intacta y realizando sólo el trabajo necesario en la subclase, como se ilustra en el sencillo ejemplo anterior donde se aprovecha el trabajo hecho en los métodos public void init() y public void paint(Graphics g) de helloApplet en los que se definen los colores, la fuente y se centra el mensaje, y solamente se sobreescribe public void start() substituyendo el mensaje.


Clases abstractas.


Se dice que una clase es abstracta si tiene métodos no implementados. Los métodos no implementados constan sólo de un encabezado con los modificadores, el nombre y los parámetros y en lugar de la implementación entre llaves, se pone punto y coma. Por ejemplo

abstract public void miMétodo(int x,String s);

podría ser la declaración de un método no implementado de una clase abstracta. El modificador abstract es necesario, sin él el compilador marcaría un error al encontrar  ;  en lugar de la llave { .

Una clase que tiene métodos no implementados, debe declararse abstract. Por ejemplo:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

es una clase abstracta. A partir de esta clase hemos creado tres subclases llamadas triangulo, cuadrado y circunferencia, que implementan el método void dibujar(Graphics g) como corresponde al nombre de cada una. El applet que se muestra a continuación utiliza un objeto cd de la clase abstracta cosaDibujable para presentar la figuras. Al pulsarse uno de los botones se crea un objeto de la subclase correspondiente, se asigna a la variable cd y se dibuja. El método public void paint(Graphics g) simplemente llama al método void dibujar(Graphics g) de cd sin hacer distinción de la realización concreta de cd en ese momento. Esto es posible porque las clases triangulo, cuadrado y circunferencia son extensiones de la clase abstracta cosaDibujable   y esto garantiza que cada una implementa su propio método void dibujar(graphics g).

Este es el código del applet:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

y éstos los códigos de las tres clases derivadas :

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Podrían crearse muchas otras extensiones de cosaDibujable y el mismo applet dibujador podría encargarse de dibujarlas.

Las clases abstractas son muy útiles para crear familias de clases que comparten cierta funcionalidad pero la implementación concreta de algunos de sus métodos pueden ser diferentes. El siguiente ejemplo ilustra esta aplicación de las clases abstractas. Primero se define la clase abstract public insercionBinaria, que contiene la implementación del método de ordenación por inserción binaria, uno de los más rápidos y útiles. Se define como una clase abstracta porque todo depende del método:

abstract public boolean menor_o_igual(Object o1,Object o2) ;

que compara dos objetos arbitrarios. Si hubiésemos implementado este método habríamos limitando la aplicación de la clase a un solo método de comparación entre objetos de algún tipo. Dejando este método como abstracto abrimos la posibilidad de extender la clase a otras que ordenen objetos concretos. Este es el código de la clase abstacta insercionBinaria:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Como ejemplos de extensiones concretas de insercionBinaria   presentamos las clases ejecutables:

public class ordenaCadenas y public class ordenaNumeros.

La primera obtiene de los parámetros de ejecución una matriz de cadenas, la ordena y escribe el resultado. Aquí está su código:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

La segunda genera una matriz de veinte números enteros entre 0 y 1000, la escribe, la ordena y la vuelve a escribir:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

El alumno debe estudiar cuidadosamente las tres clases anteriores. En los ejercicios se le pedirá un análisis crítico detallado de ellas. En particular debe reflexionar sobre el ahorro de código que se logra con esta organización de los programas de ordenación y sobre la protección que se logra al haber declarado como privados ciertos métodos.. 


Interfaces.


Una interfaz es como una clase abstracta que no puede tener ninguna variable y ningún método implementado. Es decir, las interfaces constan exclusivamente de métodos abstractos y constantes (variables declaradas como static final). Si las interfaces son algo así como clases abstractas con restricciones, ¿para qué sirven?

La respuesta está en el hecho de que mientras una clase sólo puede extender a una clase, en cambio puede implementar tantas interfaces como quiera.

Las interfaces son contratos de implementación a los que una clase se compromete.

Como primer ejemplo de uso de una interfaz presentamos otra manera de organizar la ordenación binaria usando una sencilla interfaz y sin usar clases abstractas. Primero creamos una interfaz llamada ordenable con el siguiente código:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Luego creamos una clase insercionBinariaBis que realiza la ordenación utilizando un objeto ordenable:

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Finalmente creamos el programa para ordenar cadenas como una clase que implementa la interfaz ordenable y crea una instancia de insercionBinariaBis pasándole como parámetro el objeto ordenable en el que se ha implementado el método menor_o_igual.

Aquí vería un applet si su navegador reconociese la etiqueta de APPLET.

Conviene observar algunos detalles. Por ejemplo, el método menor_o_igual debe aparecer como public   porque todos los métodos de una interfaz son implícitamente abstractos y públicos. En segundo lugar, la clase final ordenaCadenasBis no es extensión de nada, por lo que la posibilidad de convertirla en extensión de cualquier otra clase queda libre gracias a que el ser ordenable se lo hemos dado diciendo que implementa una interfaz y no que extiende una clase abstracta. Por tal motivo, en este caso al menos parece más cómoda la organización de los programas de ordenamiento usando la interfaz ordenable que la clase abstracta de la sección anterior.

En muchos casos el programador puede elegir entre estas dos opciones pues muchas veces una clase abstracta se puede sustituir por una clase concreta que opera sobre un objeto de una clase que implementa una interfaz que contiene todos los métodos abstractos de la clase abstracta, como ha ocurrido en este caso. Queda a criterio del programador cual de las opciones le resulta más cómoda. La ventaja principal de usar interfaz en lugar de clase abstracta suele radicar en la posiblidad de múltiples implementaciones contra la unicidad de la extensión.


Índice

Ejercicios de la Lección 03.


José Luis Abreu y Marta Oliveró