CLASE Vector
Java proporciona un grupo de clases que almacenan secuencias de objetos de cualquier tipo, son las colecciones. Se diferencian en la forma de organizar los objetos y, en consecuencia, la manera de recuperarlos. La clase Vector (paquete java.util) es una de estas colecciones, tiene un
comportamiento similar a un array unidimensional.
Un Vector guarda objetos (referencias) de cualquier tipo y crece dinámicamente, sin necesidad de tener que programar operaciones adicionales. El array donde almacena los elementos es de tipo Object. Su declaración:
protected Object elementData[]
Los arrays en Java son suficientes para guardar tipos básicos de datos, y objetos de una determinada clase cuyo número conocemos de antemano. Algunas veces deseamos guardar objetos en un array pero no sabemos cuantos objetos vamos a guardar.
Una solución es la de crear un array cuya dimensión sea más grande que el número de elementos que necesitamos guardar.
La clase Vector nos proporciona una solución alternativa a este problema.
Un vector es similar a un array, la diferencia estriba en que un vector crece automáticamente cuando alcanza la dimensión inicial máxima.
Además, proporciona métodos adicionales para añadir, eliminar elementos, e insertar elementos entre otros dos existentes.
Crear un vector
Para usar la clase Vector hemos de poner al principo del archivo del código fuente la siguiente sentencia import
import java.util.*;
Cuando creamos un vector u objeto de la clase Vector, podemos especificar su dimensión inicial, y cuanto crecerá si rebasamos dicha dimensión.
Primer Constructor
Vector vector=new Vector(20, 5);
Tenemos un vector con una dimensión inicial de 20 elementos. Si rebasamos dicha dimensión y guardamos 21 elementos la dimensión del vector crece a 25.
Al segundo constructor, solamente se le pasa la dimensión inicial.
Vector vector=new Vector(20);
Si se rebasa la dimensión inicial guardando 21 elementos, la dimensión del vector se duplica. El programador ha de tener cuidado con este constructor, ya que si se pretende guardar un número grande de elementos se tiene que especificar el incremento de la capacidad del vector, si no se quiere desperdiciar inútilmente la memoria el ordenador.
Con el tercer constructor, se crea un vector cuya dimensión inicial es 10.
Vector vector=new Vector();
La dimensión del vector se duplica si se rebasa la dimensión inicial, por ejemplo, cuando se pretende guardar once elementos.
Añadir elementos al vector
Hay dos formas de añadir elementos a un vector. Podemos añadir un elemento a continuación del último elemento del vector, mediante la función miembro addElement.
v.addElement("uno");
Podemos también insertar un elemento en una determinada posición, mediante insertElementAt. El segundo parámetro o índice, indica el lugar que ocupará el nuevo objeto. Si tratamos de insertar un elemento en una posición que no existe todavía obtenemos una excepción del tipo ArrayIndexOutOfBounds. Por ejemplo, si tratamos de insertar un elemento en la posición 9 cuando el vector solamente tiene cinco elementos.
Para insertar el string "tres" en la tercera posición del vector v, escribimos
v.insertElementAt("tres", 2);
En la siguiente porción de código, se crea un vector con una capacidad inicial de 10 elementos, valor por defecto, y se le añaden o insertan objetos de la clase String.
Vector v=new Vector();
v.addElement("uno");
v.addElement("dos");
v.addElement("cuatro");
v.addElement("cinco");
v.addElement("seis");
v.addElement("siete");
v.addElement("ocho");
v.addElement("nueve");
v.addElement("diez");
v.addElement("once");
v.addElement("doce");
v.insertElementAt("tres", 2);
Para saber cuantos elementos guarda un vector, se llama a la función miembro size.
Para saber la dimensión actual de un vector se llama a la función miembro capacity.
Por ejemplo, en la porción de código hemos guardado 12 elementos en el vector v. La dimensión de v es 20, ya que se ha superado la dimensión inicial de 10 establecida en la llamada al tercer constructor cuando se ha creado el vector v.
System.out.println("nº de elementos "+v.size());
System.out.println("dimensión "+v.capacity());
Podemos eliminar todos los elementos de un vector, llamando a la función miembro removeAllElements. O bien, podemos eliminar un elemento concreto, por ejemplo el que guarda el string "tres".
v.removeElement("tres");
Podemos eliminar dicho elemento, si especificamos su índice.
v.removeElementAt(2);
Acceso a los elementos de un vector
El acceso a los elementos de un vector no es tan sencillo como el acceso a los elementos de un array. En vez de dar un índice, usamos la función miembro elementAt. Por ejemplo, v.elementAt(4) sería equivalente a v[4], si v fuese un array.
Para acceder a todos lo elementos del vector, escribimos un código semejante al empleado para acceder a todos los elementos de un array.
for(int i=0; i<v.size(); i++){
System.out.print(v.elementAt(i)+"\t");
}
Existe otra alternativa, que es la de usar las funciones del interface Enumeration.
Este interface declara dos funciones pero no implementa ninguna de ellas. Una
Enumeration nos permite acceder a los elementos de una estructura de datos de forma secuencial.
public interface Enumeration {
boolean hasMoreElements();
Object nextElement();
}
La función miembro elements de la clase Vector devuelve un objeto de la clase VectorEnumerator que implementa el interface Enumeration y tiene que definir las dos funciones hasMoreElements y nextElement.
final class VectorEnumerator implements Enumeration {
Vector vector;
int count;
VectorEnumerator(Vector v) {
vector = v;
count = 0;
}
public boolean hasMoreElements() {
//...
}
public Object nextElement() {
//...
}
}
El objeto enum devuelto por la función miembro elements es de la clase VectorEnumerator, sin embargo no podemos escribir
VectorEnumerator enum=v.elements();
porque VectorEnumerator no es una clase pública. Como podemos ver en su definición, no tiene la palabra reservada public delante de class. Sin embargo, podemos guardar un objeto de la clase VectorEnumerator en una variable enum del tipo Enumeration, por que la clase implementa dicho interface.
Enumeration enum=v.elements();
while(enum.hasMoreElements()){
System.out.print(enum.nextElement()+"\t");
}
Desde el objeto enum devuelto por la función miembro elements de la clase Vector llamamos a las funciones miembro hasMoreElements y nextElement de la clase VectorEnumerator. La función hasMoreElements devuelve true mientras haya todavía más elementos que se puedan acceder en el vector v. Cuando se ha llegado al último elemento del vector, devuelve false. La función nextElement devuelve una referencia al próximo elemento en la estructura de datos. Esta función devuelve una referencia a un objeto de la clase base Object, que el programador precisará en ciertos casos, como veremos más abajo, promocionar (casting) a la clase adecuada.
Para buscar objetos en un vector se puede usar una Enumeration y hacer una comparación elemento por elemento mediante equals, tal como vemos en la siguiente porción de código
Enumeration enum=v.elements();
while(enum.hasMoreElements()){
String elemento=(String)enum.nextElement();
if(elemento.equals("tres")){
System.out.println("Encontrado tres");
break;
}
}
Podemos usar alternativamente, la función miembro contains para este propósito.
if(v.contains("tres")){
System.out.println("Encontrado tres");
}
Crear un vector
Se utiliza el operando new de igual forma que para crear cualquier objeto. La clase Vector
dispone de diversos constructores:
public Vector() crea un vector vacío.
public Vector(int capacidad) crea un vector con una capacidad inicial.
public Vector(Collection org) crea un vector con los elementos de org.
Por ejemplo:
Vector v1 = new Vector();
Vector v2 = new Vector(100);
Vector v3 = new Vector(v2); // v3 contiene los mismo elementos que v2
Para usar la clase Vector hemos de poner al principo del archivo del código fuente la siguiente sentencia import
import java.util.*;
Cuando creamos un vector u objeto de la clase Vector, podemos especificar su dimensión inicial, y cuanto crecerá si rebasamos dicha dimensión.
Vector vector=new Vector(20, 5);
Tenemos un vector con una dimensión inicial de 20 elementos. Si rebasamos dicha dimensión y guardamos 21 elementos la dimensión del vector crece a 25.
Al segundo constructor, solamente se le pasa la dimensión inicial.
Vector vector=new Vector(20);
Si se rebasa la dimensión inicial guardando 21 elementos, la dimensión del vector se duplica. El programador ha de tener cuidado con este constructor, ya que si se pretende guardar un número grande de elementos se tiene que especificar el incremento de la capacidad del vector, si no se quiere desperdiciar inútilmente la memoria el ordenador.
Con el tercer constructor, se crea un vector cuya dimensión inicial es 10.
Vector vector=new Vector();
La dimensión del vector se duplica si se rebasa la dimensión inicial, por ejemplo, cuando se pretende guardar once elementos.
Insertar elementos
La clase dispone de diferentes métodos para insertar o añadir elementos al vector. Los elementos que se meten en el vector deben ser objetos, no pueden ser datos de tipos primitivos (int, char ...) .
boolean add (Object ob); añade el objeto a continuación del último elemento del vector.
void addElement(Object ob); añade el objeto a continuación del último elemento del vector.
void insertElement inserta el objeto en la posición p; los elementos
(Object ob, int p); posteriores a p se desplazan.
Acceso a un elemento
Se accede a un elemento del vector por la posición que ocupa. Los métodos de acceso devuelven
el elemento con el tipo Object, por esa razón es posible que sea necesario realizar una conversión
al tipo del objeto.
Object elementAt(int p); devuelve el elemento cuya posición es p.
Object getElement(int p); devuelve el elemento cuya posición es p.
Object get(int p); devuelve el elemento cuya posición es p.
int size(); devuelve el número de elementos.
Eliminar un elemento
Un vector es una estructura dinámica, crece o decrece según se añaden o se eliminan objetos. Se puede eliminar un elemento de distintas formas, por ejemplo, por la posición que ocupa (índice); a partir de esa posición, el resto de elementos del vector se mueven una posición a la izquierda y disminuye el número de elementos. Otra forma de eliminar es transmitiendo el objeto que se desea retirar del vector. También hay métodos de la clase para eliminar todos los elementos que son iguales a una colección; incluso se pueden eliminar todos los elementos.
void removeElementAt(int indice); elimina elemento índice y el resto se renumera.
boolean void removeElement (Object op); elimina la primera aparición de op;
devuelve true si realiza la eliminación.
void removeAll(Collection gr); elimina los elementos que están en gr.
void removeAllElements(); elimina todos los elementos
Búsqueda
Los diversos métodos de búsqueda de Vector devuelven la posición de la primera ocurrencia del
objeto buscado, o bien verdadero-falso según el éxito de la búsqueda.
boolean contains(Object op); devuelve true si encuentra op.
int indexOf(Object op); devuelve la primera posición de op, -1 si no está.
Ejercicio
Utilizar un vector para guardar indistintamente, números racionales y números complejos. Se supone que un número racional está representado por dos enteros, numerador y denominador respectivamente. Un número complejo también viene representado por dos enteros, parte real y parte imaginaria. Entonces, se declara la clase Numero con los atributos de tipo entero x, y; las clases Racional y Complejo derivan de Numero. Además, el método mostrar() se redefine en cada clase para escribir el tipo de número.
La clase principal crea un vector al que se añaden números racionales y complejos alternativamente. A continuación se recuperan los elementos y se escriben.
import java.util.*;
import java.io.*;
abstract class Numero
{
protected int x, y;
public Numero() {;}
public Numero(int _ x, int _ y)
{
x = _ x;
y = _ y;
}
abstract void mostrar();
}
class Racional extends Numero
{
public Racional() {;}
public Racional(int _ x, int _ y) { super( _ x, _ y); }
void mostrar()
{
System.out.println(x + "/" + y);
}
}
class Complejo extends Numero
{
public Complejo() {;}
public Complejo(int _ x, int _ y) { super( _ x, _ y); }
void mostrar()
{
System.out.println("(" + x + "," + y + ")");
}
}
public class VectorNumero
{
static final int N = 10;
public static void main (String [] a)
{
Vector num = new Vector();
for(int i = 1; i <= N; i++)
{
Numero q;
q = new Racional(3 * i, 3 * i % 7 + 1);
num.addElement(q);
q = new Complejo(3 * i % 7, 3 * i - 5);
num.addElement(q);
}
// recuperación de los elementos
int k;
k = num.size(); // número de elementos
for (int i = 1; i <= N; i++)
{
Numero q;
q = (Numero) num.elementAt(i);
q.mostrar();
}
}
}
RESUMEN
En este capítulo se analizan los tipos agregados de Java, arrays y diversos métodos para el manejo de cadenas incluidos en la clase String, StringBuffer. Después de leer este capítulo, debe tener un buen conocimiento de los conceptos fundamentales de los tipos
agregados.
Se describen y analizan los siguientes conceptos:
• Un array es un tipo de dato estructurado que se utiliza para localizar y almacenar elementos de un tipo de dato dado.
• Existen arrays de una dimensión, de dos dimensiones, y multidimensionales.
• En Java, los arrays se declaran especificando el tipo de dato del elemento, el nombre del array y tantos corchetes como dimensiones. El tamaño de cada dimensión del array se define con el operador new. Para acceder a los elementos del array se deben
utilizar sentencias de asignación directas, sentencias de lectura/escritura o bucles (mediante las sentencias for, while o do-while).
int total _ meses[] = new int[12];
• Los arrays en Java son considerados objetos. Por ello, todos tienen el atributo length
con la longitud del array.
Los arrays de caracteres en Java son secuencias de caracteres individuales. Java tiene
la clase String para el tratamiento de cadenas.
• Las cadenas en Java son objetos de la clase String, una vez creados no pueden ser modificados;
las cadenas del tipo StringBuffer si pueden cambiar dinámicamente.
• La clase String dispone de constructores para inicializar las cadenas y numerosos
métodos de manipulación; destacan los métodos que soportan concatenación, conversión,
inversión y búsqueda.
• Java considera las cadenas objetos; las variables String contienen la referencia al objeto
cadena. La asignación de una variable a otra supone asignar la referencia al objeto.
Además, en este capítulo se estudia la clase Vector, que se encuentra en el paquete java.
util. Los objetos Vector permiten guardar y recuperar objetos de cualquier tipo, se comportan
como arrays de tipo Object.
EJERCICIOS
Para los ejercicios del 1 a 6 suponga las declaraciones:
int i,j,k;
int Primero[] = new int[21];
int Segundo[] = new int[21];
int Tercero[][] = new int[7][8];
BufferedReader entrada = new BufferedReader(
(new InputStreamReader(System.in));
Determinar la salida de cada segmento de programa (en los casos que se necesite, se indica debajo el archivo de datos de entrada correspondiente; con ctrl r se indica que hay un fin de línea.).
1. for (i=1; i <= 6; i++)
Primero[i] = Integer.parseInt(entrada.readLine());
for (i=3; i>0; i--)
System.out.print(Primero[2*i] + " ");
.................
3 ctrl+ r 7 ctrl+ r 4 ctrl+ r -1 ctrl+ r 0 ctrl+ r 6
2. k = Integer.parseInt(entrada.readLine());
for (i=3; i<=k;)
Segundo[i++] = Integer.parseInt(entrada.readLine());
j= 4;
System.out.println( + Segundo[k] + " " + Segundo[j+1]);
.............
6 ctrl+ r 3 ctrl+ r 0 ctrl+ r 1 ctrl+ r 9
3. for (i= 0; i<10;i++)
Primero[i] = i + 3;
j = Integer.parseInt(entrada.readLine());
k = Integer.parseInt(entrada.readLine());
for (i= j; i<=k;)
System.out.println(Primero[i++]);
............
7 ctrl+ r 2 ctrl+ r 3 ctrl+ r 9
4. for (i=0, i<12; i++)
Primero[i] = Integer.parseInt(entrada.readLine());
for (j=0; j<6;j++)
Segundo[j]=Primero[2*j] + j;
for (k=3; k<=7; k++)
System.out.println(Primero[k+1] + " " + Segundo [k–1]);
...........
2 ctrl+ r 7 ctrl+ r 3 ctrl+ r 4 ctrl+ r 9 ctrl+ r -4 ctrl+ r
6 ctrl+ r -5 ctrl+ r 0 ctrl+ r 5 ctrl+ r -8 ctrl+ r 1
5. for (j=0; j<7; )
Primero[j++] = Integer.parseInt(entrada.readLine());
i = 0;
j = 1;
while ((j< 6) && (Primero[j–1]<Primero[j]))
{
i++; j++;
}
for (k=-1; k<j+2; )
System.out.println(Primero[++k]);
..........
20 ctrl+ r 60 ctrl+ r 70 ctrl+ r 10 ctrl+ r 0 ctrl+ r
40 ctrl+ r 30 ctrl+ r 90
6. for (i=0; i<3; i++)
for (j= 0; j<12; j++)
Tercero[i][j] = i+j+1;
for (i= 0; i< 3; i++)
{
j = 2;
while (j < 12)
{
System.out.println(i + " " + j " " + Tercero[i][j]);
j+=3;
}
}
7. Escribir un programa que lea el array:
4 7 1 3 5
2 0 6 9 7
3 1 2 6 4
y lo escriba como:
4 2 3
7 0 1
1 6 2
3 9 6
5 7 4
8. Dado el array:
4 7 -5 4 9
0 3 -2 6 -2
1 2 4 1 1
6 1 0 3 -4
escribir un programa que encuentre la suma de todos los elementos que no pertenecen
a la diagonal principal.
9. Escribir un método que intercambie la fila i-ésima por la j-ésima de un array de dos
dimensiones, mxn.
10. Considerando el siguiente segmento de código, indicar los errores y la forma de
corregirlos.
String b = "Descanso activo";
char p[] = "En la semana par.";
StringBuffer c = "Cadena dinámica";
b = cd;
StringBuffer fc = new Stringbuffer("Calor de verano");
b = fc;
11. Escribir un método que tenga como entrada una cadena y devuelva el número de
vocales, de consonantes y de dígitos de la cadena.
12. ¿Qué diferencias y analogías existen entre las variables c1, c2, c3? La declaración
es:
String c1;
String c2[];
StringBuffer c3;
13. Escribir un método que tenga como argumento una cadena con la fecha en formato:
dd/mm/aa y devuelva una cadena con la fecha en formato dd Mes(nominal) de
año. Por ejemplo:
21/4/01 debe transformarse a 21 Abril del 2001
14. Definir un array de cadenas para poder leer un texto compuesto por un máximo de 80
líneas. Escribir un método para leer el texto; el método debe de tener dos argumentos,
uno, el texto y el segundo, el número de líneas.
Para importar clases de un paquete se usa el comando import. Se puede importar una clase individual
import java.awt.Font;
o bien, se puede importar las clases declaradas públicas de un paquete completo, utilizando un arterisco (*) para reemplazar los nombres de clase individuales.
import java.awt.*;
Para crear un objeto fuente de la clase Font podemos seguir dos alternativas
import java.awt.Font; Font fuente=new Font("Monospaced", Font.BOLD, 36);
O bien, sin poner la sentencia import
java.awt.Font fuente=new java.awt.Font("Monospaced", Font.BOLD, 36);
Normalmente, usaremos la primera alternativa, ya que es la más económica en código, si tenemos que crear varias fuentes de texto.
Se pueden combinar ambas formas, por ejemplo, en la definición de la clase BarTexto
import java.awt.*; public class BarTexto extends Panel implements java.io.Serializable{ //... }
Panel es una clase que está en el paquete java.awt, y Serializable es un interface que está en el paquete java.io
Los paquetes estándar
Un interface es una colección de declaraciones de métodos (sin definirlos) y también puede incluir constantes.
Runnable es un ejemplo de interface en el cual se declara, pero no se implemementa, una función miembro run.
public interface Runnable { public abstract void run(); }
Las clases que implementen (implements) el interface Runnable han de definir obligatoriamente la función run.
class Animacion implements Runnable{ //.. public void run(){ //define la función run } }
El papel del interface es el de describir algunas de las características de una clase. Por ejemplo, el hecho de que una persona sea un futbolista no define su personalidad completa, pero hace que tenga ciertas características que las distinguen de otras.
Clases que no están relacionadas pueden implementar el interface Runnable, por ejemplo, una clase que describa una animación, y también puede implementar el interface Runnable una clase que realice un cálculo intensivo.
Un interface es simplemente una lista de métodos no implementados, además puede incluir la declaración de constantes. Una clase abstracta puede incluir métodos implementados y no implementados o abstractos, miembros dato constantes y otros no constantes.
Ahora bien, la diferencia es mucho más profunda. Imaginemos que Runnable fuese una clase abstracta. Un applet descrito por la clase MiApplet que moviese una figura por su área de trabajo, derivaría a la vez de la clase base Applet (que describe la funcionalidad mínima de un applet que se ejecuta en un navegador) y de la clase Runnable. Pero el lenguaje Java no tiene herencia múltiple.
En el lenguaje Java la clase MiApplet deriva de la clase base Applet e implementa el interface Runnable
class MiApplet extends Applet implements Runnable{ //... //define la función run del interface public void run(){ //... } //redefine paint de la clase base Applet public void paint(Graphics g){ //... } //define otras funciones miembro }
Una clase solamente puede derivar extends de una clase base, pero puede implementar varios interfaces. Los nombres de los interfaces se colocan separados por una coma después de la palabra reservadaimplements.
El lenguaje Java no fuerza por tanto, una relación jerárquica, simplemente permite que clases no relacionadas puedan tener algunas características de su comportamiento similares.
En el lenguaje C++, es posible la herencia múltiple, pero este tipo de herencia presenta dificultades. Por ejemplo, cuando dos clases B y C derivan de una clase base A, y a su vez una clase D deriva de B y C. Este problema es conocido con el nombre de diamante.
En el lenguaje Java solamente existe la herencia simple, pero las clases pueden implementar interfaces. Vamos a ver en este apartado que la importancia de los interfaces no estriba en resolver los problemas inherentes a la herencia múltiple sin forzar relaciones jerárquicas, sino es el de incrementar el polimorfismo del lenguaje más allá del que proporciona la herencia simple.
Para explicar este aspecto importante y novedoso del lenguaje Java adaptaremos los ejemplos que aparecen en el artículo del Bill Venners "Designing with interfaces" publicado en Java World (www.javaWorld.com) en Diciembre de 1998. Comparemos la herencia simple mediante un ejemplo similar al de la jerarquía de las figuras planas, con los interfaces.
polimorfismo: Animal.java, PoliApp.java
Creamos una clase abstracta denominada Animal de la cual deriva las clases Gato y Perro. Ambas clases redefinen la función habla declarada abstracta en la clase base Animal.
public abstract class Animal { public abstract void habla(); } class Perro extends Animal{ public void habla(){ System.out.println("¡Guau!"); } } class Gato extends Animal{ public void habla(){ System.out.println("¡Miau!"); } }
El polimorfismo nos permite pasar la referencia a un objeto de la clase Gato a una función hazleHablar que conoce al objeto por su clase base Animal
public class PoliApp { public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato); } static void hazleHablar(Animal sujeto){ sujeto.habla(); } }
El compilador no sabe exactamente que objeto se le pasará a la función hazleHablar en el momento de la ejecución del programa. Si se pasa un objeto de la clase Gato se imprimirá ¡Miau!, si se pasa un objeto de la clase Perro se imprimirá ¡Guau!. El compilador solamente sabe que se le pasará un objeto de alguna clase derivada de Animal. Por tanto, el compilador no sabe que función habla será llamada en el momento de la ejecución del programa.
El polimorfismo nos ayuda a hacer el programa más flexible, por que en el futuro podemos añadir nuevas clases derivadas de Animal, sin que cambie para nada el método hazleHablar. Como ejercicio, se sugiere al lector añadir la clase Pajaro a la jerarquía, y pasar un objeto de dicha clase a la función hazleHablar para que se imprima ¡pio, pio, pio ..!.
polimorfismo1: Parlanchin.java, Animal.java, Reloj.java, PoliApp.java
Vamos a crear un interface denominado Parlanchin que contenga la declaración de una función denominada habla.
public interface Parlanchin { public abstract void habla(); }
Hacemos que la jerraquía de clases que deriva de Animal implemente el interface Parlanchin
public abstract class Animal implements Parlanchin{ public abstract void habla(); } class Perro extends Animal{ public void habla(){ System.out.println("¡Guau!"); } } class Gato extends Animal{ public void habla(){ System.out.println("¡Miau!"); } }
Ahora veamos otra jerarquía de clases completamente distinta, la que deriva de la clase base Reloj. Una de las clases de dicha jerarquía Cucu implementa el interface Parlanchin y por tanto, debe de definir obligatoriamente la función habla declarada en dicho interface.
public abstract class Reloj { } class Cucu extends Reloj implements Parlanchin{ public void habla(){ System.out.println("¡Cucu, cucu, ..!"); } }
Definamos la función hazleHablar de modo que conozca al objeto que se le pasa no por una clase base, sino por el interface Parlanchin. A dicha función le podemos pasar cualquier objeto que implemente el interface Parlanchin, este o no en la misma jerarquía de clases.
public class PoliApp { public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato); Cucu cucu=new Cucu(); hazleHablar(cucu); } static void hazleHablar(Parlanchin sujeto){ sujeto.habla(); } }
Al ejecutar el programa, veremos que se imprime en la consola ¡Miau!, por que a la función hazleHablar se le pasa un objeto de la clase Gato, y después ¡Cucu, cucu, ..! por que a la función hazleHablar se le pasa un objeto de la clase Cucu.
Si solamente hubiese herencia simple, Cucu tendría que derivar de la clase Animal (lo que no es lógico) o bien no se podría pasar a la función hazleHablar. Con interfaces, cualquier clase en cualquier familia puede implementar el interface Parlanchin, y se podrá pasar un objeto de dicha clase a la función hazleHablar. Esta es la razón por la cual los interfaces proporcionan más polimorfismo que el que se puede obtener de una simple jerarquía de clases.
referencias:
http://www.sc.ehu.es/sbweb/fisica/cursoJava/fundamentos/colecciones/vector.htm