|
|||||||
|
|
|
|||||
|
|
|||||||
En Java se crea un objeto mediante la creación de un objeto de una clase, es decir, instanciando una clase. Ej:
Date hoy = new Date();
String nombre = new String("Juan");
Para declarar un objeto se procede como cualquier otra declaración de variable, las declaraciones de objetos pueden ser:
Date hoy;
Las declaraciones no crean nuevos objetos. Para ejemplarizar una clase, se utiliza el operador NEW.
Numeros n = new Numeros();
El operador new permite realizar una instancia de una clase, mediante la asignación de memoria para el objeto nuevo de ese tipo. new necesita un sólo argumento: una llamada al método del constructor.
Rectangle rect = new Rectangle(0,
0, 100, 200);
Una clase podría tener múltiples constructores para realizar diferentes tipos de inicialización en los nuevos objetos. Los constructores tienen el mismo nombre de la clase y no tienen tipo de retorno. Un constructor que no tiene ningún argumento, es conocido como construtor por defecto. Si una clase tiene varios constructores, éstos tendrán el mismo nombre pero diferentes parámetros.Ej:
Date hoy = new Date();
Date cumpleaños = new
Date(1951,04,04);
Recolector de basura.
Un objeto es elegible para la recolección de basura cuando no existen más referencas a ese objeto. Las referencias que se mantienen en una variable desaparecen de forma natural cuando la variable sale de su ámbito o cuando se borra explicitamente un objeto mediante el uso de null.
String nom=new String("Juan");
nom=null;
El recolector de basura funciona en un thread(hilo) de baja prioridad de forma síncrona o asíncrona. Escanea dinámicamente la memoria buscando objetos, marcando aquellos que han sido referenciados. Se puede invocar al recolector de basura aunque no se garantiza que los objetos sean recolectados con System.gc();
Antes de que un objeto sea recolectado,
el recolector de basura le permite limpiarse él mismo mediante la
llamada al método finalize() del propio objeto.
Clases.
La clase es un prototipo que se puede utilizar para crear objetos. La implementeación de una clase comprende dos componentes: la declaración y el cuerpo de la clase.
class Nombre de la Clase{
//cuerpo
de la clase
}
Dentro de la declaración de la clase se puede declarar cual es la superclase de la clase, listar las interfaces implementadas por la clase y declarar si la clase es pública, abstracta o final.
En Java, todas las clases tienen una superclase. Si no se especifica una superclase para una clase que es la clase Object(declarada en java.lang). Para especificar explícitamente una superclase de una clase, se debe poner la palabra clave "extends" más el nombre de la superclase.
class NombreClase extends NombreSuperclase
El cuerpo de la clase compone la implementación de la propia clase y contiene dos secciones diferentes: la declaración de variables y la de métodos. Primero se declaran las variables miembro de la clase y después la declaración e implementación de los métodos.
Como mínimo una declaración de variables miembro tiene dos coponentes: el tipo de dato y el nombre de la variable.Ej:
class Entero{
static final
int unEntero=10;
float unFlotante;
}
La declaración de variables miembro, aparece dentro de la implementación del cuerpo de la clase pero no dentro de un método. Este posicionamiento determina que una variable es variable miembro. La implementación de métodos consiste en dos partes: Declaración y el cuerpo del método. Los únicos elementos necesarios de una declaración de método son el nombre y el tipo de retorno de método. Ej:
public boolean action(Event
e,Object o){
if(e.target==factorial){
num1=Integer.parseInt(input1.getText());
repaint(); res=1;
}
return true;
}
Las variables son públicas
por omisión.
this.
La palabra this, se utiliza para llamara a una variable miembro de una clase, cuando alguno de sus métodos llama a una de sus variables con el mismo nombre.
class HSBColor{
int luminosidad,
saturacion, brillo;
HSBColor(int
luminosidad, int saturacion, int brillo){
this.luminosidad=luminosidad;
this.saturacion=saturacion;
this.brillo=brillo;
}
}
super.
Si el método oculta una de las variables miembro de la superclase se puede referir a la variable oculta utilizado super.
class MiClase{
boolean
unaVariable;
void unMetodo(){
unaVariable=true;
}
}
class OtraClase extends MiClase{
boolean
unaVariable;
void unMetodo(){
unaVariable=false;
super.unMetodo();
System.out.println(unaVariable);
System.out.println(super.unaVariable);
}
}
Acceso a los miembros de una
clase.
En Java se puede utilizar los especificadores de accceso para proteger tanto las variables como los métodos de la clase cuando se declaran. En Java se tienen cuatro niveles de acceso: provate, protected, public y acceso a paquetes.
Especificador
Clase SubClase
Paquete Mundo
private
X
protected
X
X*
X
public
X
X
X
X
package
X
X
Private.- Un miembro privado
es accesible sólo para la clase en la que está definido.
Proteceted.-Un miembro es accesible
para la clase, las subclases y todas las clases dentro del mismo paquete
que
accedan a los miembros.
Public.-Todas las clases tienen
acceso a lso miembros públicos.
Acceso de Paquete.-Se obtiene
si no se especifica ningún otro nivel de acceso a los miembros.
Este nivel permite
que las clases del mismo paquete que la clase tengan acceso a los miembros.Ej:
class Alfa{
private
int soyPrivado;
private
void metodoPrivado(){
System.out.println(“Metodo Privado”);
}
}
class Beta{
public static
void main(String arg[]){
Alfa a=new Alfa();
a.soyPrivado=10;declarados como privados}}
Constructores.
Los constructores tienen la tarea de crear e inicializar el objeto. Tienen el mismo nombre de la clase y no retornan un dato, por lo cual, en la declaración del constructor no se incluye un tipo de dato. Java soporta la sobrecarga de los nombres de métodos, en consecuencia una clase podrá tener más de un constructor. Al igual que cualquier método, los constructores se diferencían por el número y tipo de argumentos. Si el programador no especifica un constructor, Java proporciona un constructor por default, este constructor no tiene argumentos. Ej:
class Animation Thread extends
Thread{
int framesPerSecond;
int numImages;
Image[]images;
Animation
Thread(int fps,int num){
int i;
super(“Animation Thread”);
this.framesPerSecond=fps;
this.numImages=num;
this.images=new Image[numImages];
for(i=0;i<numImages;i++){
//Carga de imágenes
}
}
}
Cuando se declaren constructores
para las clases, se pueden utilizar los especificadores de acceso para
especificar si otros objetos pueden crear ejemplares de sus clase.
Métodos de la clase Applet.
Estos métodos están definidos por la Java API de modo tal que no hacen nada a menos que el programador provea una definición en la definición de la clase de su applet.
Método Descripción
public void init()
Este método es invocado una vez por el Appletviewer o navegador
cuando se
carga un applet para ejecutarse. Este método inicializa un applet
(inicialización de variables, componentes GUI, creación de
hilos).
public void paint(Graphics g)
Este método se invoca para dibujar el applet después que
el método init termina
de ejecutarse y se ha comenzado a ejecutar el método start; también
se ejecuta
cuando el applet necesita dibujarse.
public void start()
Este método se invoca después de que termina de ejecutarse
el método init y
cada vez que el usuario del navegador regresa a la página HTML en
la que
el applet reside. Este método realiza todas las tareas que deben
llevarse a
cabo cuando el applet se carga por primera vez y cada vez que se vuelva
a
visitar la página.
public void stop()
Este método se invoca cuando la applet debe terminar su ejecución,
regularmente cuando el usuario del navegador abandona la página.
public void destroy()
Este método se invoca cuando el applet se va a desalojar de la memmoria,
lo
que normalmente sucede cuando el usuario del navegador sale de la sesion
de
navegación.
Paneles.
Un panel es un contenedor. La clase Panel hereda de la
clase Container y la clase Applet hereda de Panel. Por
tanto, los Applet y los paneles son contenedores y se les
puede agregar componentes, incluidos otros paneles. El
constructor Panel no recibe aargumentos y no está
sobrecargado. Ej:
Panel panel1;//Declaración
Label label1;
panel1 = new Panel();//Crea un objeto en init()
label1 = new Label("Panel 1");
panel1 = setBackground(Color.blue);//en init
panel1.add(label);
.
.
.
add(panel1);
Casillas de verificación y botones de radio.
Estos son botones de estaado encendido/apagado o
verdadero/falso.
-Casillas de verificación:
Constructores. public Checkbox() Crea un objeto sin
título y sin marca.
public Checkbox(String s) Crea un
objeto con títulos y sin marca.
Ej:
Font fuente;
.
.
.
CheckBox checa1, checa2;
checa1 = new CheckBox("Negrita");
checa2 = new CheckBox();
checa2.setLabel("Cursiva");
t = new Font("TimesRoman", Font.PLAIN, 14);
t.setFont(t);
add(t);
add(checa1);
add(checa2);
//fin init
//en action
int b, i;
if(e.target instanceof Checkbox){
if(checa1.getState() == true)
b = Font.BOLD;
else
b = Font.PLAIN;
if(checa2.getState() == true)
i = Font.ITALIC;
else
i = font.PLAIN;
f = new Font("TimesRoman", b+i, 14);
t.setFont(f);
}
return true;
.
.
.
ARCHIVOS
Java considera los archivos como flujos secuenciales de
bytes. Cada archivo termina con un marcador de fin de
archivo.
Cuando se abre un archivo, se crea un objeto y se asocia un
flujo (stream) a dicho objeto.
Para procesar archivos se necesita importar el paquete
java.io que contiene entre otras cosas la definicion de las
clases FileInputStream y FileOutputStream (para flujos de
entrada y salida) Estas clases heredan de las clases
Inputsream y OutputStream (flujos de entrada / salida de
datos).
En java se pueden utilizar archivos de:
* acceso secuencial
* acceso aleatorio
ACCESO SECUENCIAL
El programador debe estructurar los archivos.
DataOutputStream output; //para escribir tipos de datos
output = new DataOutputStream(new FileOutputStream
("Dato.dat")) //encadenamiento de objetos
//de flujo
^ se abre archivo para esritura ^
DataInputStream input;
input = new DataInputStream(new FileInputStream("Dato.dat"));
^ se abre archivo para lectura ^
ejemplo de escritura:
output.write(Cadena);
ejemplo de lectura:
input.read();
debemos agregar las exepciones en caso de haber algun error:
try{
output = new DataOutput....
Output.write...
}catch(IOExeption e){
vista.append("error al crear archivo");
}
ejemplo para escribir diferentes tipos de datos:
output.writeUTF(cadena);
output.writeInt(entero);
output.writeBoolean( );
output.writeByte( );
output.writeBytes( );
output.writeChar( );
output.writeChars( );
output.writeDouble( );
output.writeFloat( );
output.writeLong( );
output.writeShort( );
Introducción a los Canales de I/O.
El paquete java.io contiene dos clases, InputStream y
OutputStream, de las que derivan la mayoría de las clases de
este paquete.
La clase InputStream es una superclase abstracta que
proporciona un interface de programación mínimo y una
implementación parcial del canal de entrada. La clase
InputStream define métodos para leer bytes o arrays de
bytes, marcar posiciones en el canal, saltar bytes de la
entrada, conocer el número de bytes disponibles para ser
leídos, y resetear la posición actual dentro del canal. Un
canal de entrada se abre automáticamente cuando se crea. Se
puede cerrar un canal explícitamente con el método close(),
o puede dejarse que se cierre implícitamente cuando se
recolecta la basura, lo que ocurre cuando el objeto deja de
referenciarse.
La clase Outputstream es una superclase abstracta que
proporciona un interface de programación mínimo y una
implementación parcial de los canales de salida. Un canal
de salida se abre automáticamente cuando se crea. Se puede
cerrar un canal explícitamente con el método close(), o se
puede dejar que se cierre implícitamente cuando se recolecta
la basura, lo que ocurre cuando el objeto deja de
referenciarse.
El paquete java.io contiene muchas subclases de InputStream
y OutputStream que implementan funciones específicas de
entrada y salida. Por ejemplo, FileInputStream y
FileOutputStream son canales de entrada y salida que operan
con ficheros en el sistema de ficheros nativo.
Canales simples de I/O.
Lo siguiente es una introducción a las clases no abstractas
que descienden directamente desde InputStream y OutputStream:
FileInputStream y FileOutputStream.
Leen o escriben datos en un fichero del sistema de ficheros
nativo.l
PipedInputStream y PipedOutputStream.
Implementan los componentes de entrada y salida de una
tubería. Las tuberías se utilizan para canalizar la salida
|n programa hacia la entrada de otro. Un PipedInputStream
debe ser conectado a un PipedOutputStream y un
PipedOutputStream debe ser conectado a un PipedInputStream.
ByteArrayInputStream y ByteArrayOutputStream.
Leen o escriben datos en un array de la memoria.
SequenceInputStream.
Concatena varios canales de entrada dentro de un solo canal
de entrada.
StringBufferInputStream.
Permite a los programas leer desde un StringBuffer como si
fuera un canal de entrada.
Introducción a los Canales de I/O.
El paquete java.io contiene dos clases, InputStream y
OutputStream, de las que derivan la mayoría de las clases de
este paquete.
La clase InputStream es una superclase abstracta que
proporciona un interface de programación mínimo y una
implementación parcial del canal de entrada. La clase
InputStream define métodos para leer bytes o arrays de
bytes, marcar posiciones en el canal, saltar bytes de la
entrada, conocer el número de bytes disponibles para ser
leídos, y resetear la posición actual dentro del canal. Un
canal de entrada se abre automáticamente cuando se crea. Se
puede cerrar un canal explícitamente con el método close(),
o puede dejarse que se cierre implícitamente cuando se
recolecta la basura, lo que ocurre cuando el objeto deja de
referenciarse.
La clase Outputstream es una superclase abstracta que
proporciona un interface de programación mínimo y una
implementación parcial de los canales de salida. Un canal
de salida se abre automáticamente cuando se crea. Se puede
cerrar un canal explícitamente con el método close(), o se
puede dejar que se cierre implícitamente cuando se recolecta
la basura, lo que ocurre cuando el objeto deja de
referenciarse.
El paquete java.io contiene muchas subclases de InputStream
y OutputStream que implementan funciones específicas de
entrada y salida. Por ejemplo, FileInputStream y
FileOutputStream son canales de entrada y salida que operan
con ficheros en el sistema de ficheros nativo.
Canales simples de I/O.
Lo siguiente es una introducción a las clases no abstractas
que descienden directamente desde InputStream y OutputStream:
FileInputStream y FileOutputStream.
Leen o escriben datos en un fichero del sistema de ficheros
nativo.l
PipedInputStream y PipedOutputStream.
Implementan los componentes de entrada y salida de una
tubería. Las tuberías se utilizan para canalizar la salida
|n programa hacia la entrada de otro. Un PipedInputStream
debe ser conectado a un PipedOutputStream y un
PipedOutputStream debe ser conectado a un PipedInputStream.
ByteArrayInputStream y ByteArrayOutputStream.
Leen o escriben datos en un array de la memoria.
SequenceInputStream.
Concatena varios canales de entrada dentro de un solo canal
de entrada.
StringBufferInputStream.
Permite a los programas leer desde un StringBuffer como si
fuera un canal de entrada.
Canales Filtrados.
FilterInputStream y FilterOutputStream son subclases de
InputStream y OutputStream respectivamente, y también son
clases abstractas. Estas clases definen el interface para
los canales filtrados que procesan los datos que están
siendo leídos o escritos. Por ejemplo, los canales
filtrados BufferedInputStream y BufferedOutputStream
almacenan datos mientras los leen o escriben para aumentar
su velocidad.
DataInputStream y DataOutputStream
Lee o escribe datos primitivos de Java en una máquina
independiente del formato.
BufferedInputStream y BufferedOutputStream
Almacena datos mientras los lee o escribe para reducir el
número de accesos requeridos a la fuente original. Los
canales con buffer son más eficientes que los canales
similares sin buffer.
LineNumberInputStream
Tiene en cuenta los números de línea mientras lee.
PushbackInputStream
Un canal de entrada con un buffer de un byte hacia atrás.
Algunas veces cuando se leen bytes desde un canal es útil
chequear el siguiente carácter para poder decir lo que hacer
luego. Si se chequea un carácter del canal, se necesitará
volver a ponerlo en su sitio para que pueda ser leído y
procesado normalmente.
PrintStream
Un canal de salida con los métodos de impresión convenientes.
Además de las clases streams, el paquete java.io contiene
estas otras clases:
File
Representa un fichero en el sistema de ficheros nativo. Se
puede crear un objeto File para un fichero en el sistema de
ficheros nativo y luego pedirle al objeto la información que
se necesite sobre el fichero(como su path completo).
FileDescriptor
Representa un manejador de fichero (o descriptor) para abrir
un fichero o una conexión.
RandomAccessFile
Representa un fichero de acceso aleatorio.
StreamTokenizer
Divide el contenido de un canal en Token(partes). Los
Tokens son la unidad más pequeña reconocida por el algoritmo
de análisis de texto(como son palabras, símbolos, etc...).
Un objeto StreamTokenize puede ser utilizado para analizar
cualquier fichero de texto. Por ejemplo, podrías utilizarlo
para dividir un fichero fuente de Java en nombres de
variables, etc... o un fichero HTML en etiquetas de HTML.
Y finalmente el paquete java.io define tres interfaces:
DataInput y DataOutput
Estos dos interfaces describen canales que pueden leer o
escribir datos de tipos primitivos de Java en máquinas
independientes del formato. DataInputStream,
DataOutputStream y RandomAccessFile implementan estos
interfaces.
FilenameFilter
El método list() de la clase File utiliza un objeto
FilenameFilter para determinar los ficheros a listar en un
directorio. Este interface acepta ficheros basándose en sus
nombres. Se podría utilizar FileNameFilter para
implementar una sencilla expresión de búsqueda al estilo de
los comodines como fichero.*, etc....
Utilizar ficheros de acceso aleatorio.
La clase RandomAccessFile implementa los interfaces
DataInput y DataOutput y por lo tanto puede utilizarse tanto
para leer como para escribir. RandomAccessFile es similar a
FileInputStream y FileOutputStream en que se especifica un
fichero del sistema de ficheros nativo para abrirlo cuando
se crea. Se puede hacer esto con un nombre de fichero o un
objeto File. Cuando se crea un RandomAccessFile se debe
indicar si solo se va a leer el fichero o también se va a
escribir en él. La siguiente línea de código java crea un
RandomAccessFile para leer el fichero llamado farrago.txt:
new RandomAccessFile("farrago.txt", "r");
Y esta otra abre el mismo fichero para leer y escribir:
new RandomAccessFile("farrago.txt", "rw");
Después de haber abierto el fichero, se pueden utilizar los
métodos comunes readXXX() o writeXXX() par arealizar la I/O
sobre el fichero.
RandomAccessFile soporta la noción de puntero de fichero.
El puntero de fichero indica la posición acutal dentro del
fichero. Cuando el fichero se crea por primera vez, el
puntero de fichero es cero, indicando el principio del
fichero. Las llamadas a los métodos readXXX() y writeXXX()
ajustan el puntero de fichero el número de bytes leidos o
escritos.
Además de los métodos normales de I/O que mueven
implícitamente el puntero de fichero cuanod ocurre una
operación, RandomAccessfile contiene tres métodos que
manipulan explícitamente el puntero de fichero.
skipBytes()
Mueve el puntero de fichero hacia delante el número de bytes
especificado.
seek()
Posiciona el puntero de fichero justo en el byte
especificado.
GetFilePointer()
Devuelve la posición actual del puntero de fichero.
Interface
Definición: Un interface es una colección de definiciones
de métodos (sin implementaciones) y de valores constantes.
Los interfaces se utilizan para definir un protocolo de
comportamiento que puede ser implementado por cualquier
clase del árbol de clases.
Los interfaces son útiles para:
* Capturar similitudes entre clases no relacionadas sin
forzar una relación entre ellas.
* Declarar métodos que una o varias clases necesitan
implementar.
* Revelar el interface de programación de un objeto sin
recelar sus clases (los objetos de este tipo son llamados
objetos anónimos y pueden ser útiles cuando compartas un
paquete de clases con otros desarrolladores).
En java, un interface es un tipo de dato de referencia, y
por tanto, puede utilizarse en muchos de los sitios donde se
pueda utilizar cualquier tipo (como en un argumento de
métodos y una declaración de variables).
Definir un Interface.
Para crear un Interface se debe escribir tanto la
declaración como el cuerpo del interface:
declaraciondeInterface{
cuerpodeInterface
}
La declaración de interface declara varios atributos del
interface, como su nombre o si se extiende desde otro
interface. El cuerpo de interface contiene las constantes y
las declaraciones de métodos del Interface.
La declaración de interface.
Como mínimo, una declaración de interface contiene la
palabra clave interface y el nombre del interface que se va
a crear:
interface Contable{
...
}
Nota: Por convención, los nombres de interfaces empiezan
con una letra mayúscula al igual que las clases.
Frecuentemente los nombres de interfaces terminan en "able"
o "ible".
Una declaración de interface puede tener otros dos
componenetes: el especificador de acceso public y una lista
de "superinterfaces". Un interface puede extender otros
interfaces como una clase puede extender o subclasificar
otra clase. Sin embargo, mientras que una clase sólo puede
extender una superclase, los interfaces pueden extender de
cualquier número de interfaces. Así, nua declaración
completa de interface se parecería a esto:
[public] interface Nombredeinterface [extends
listadeSuperInterfaces]{
...
}
El especificador de acceso public indica que el interface
puede ser utilizado por todas las clases en cualquier
paquete. Si el interface no se especifica como público,
sólo será accesible para las clases definidas en el mismo
paquete que el interface.
La claúsula extends es similar a la utilizada en la
declaración de una clase, sin embargo, un interface puede
extender varios interfaces(mientras una clase sólo puede
extender una), y un interface no puede extender clases.
Esta lista de superinterfaces es una lista delimintada por
comas de todos los interfaces extendidos por el nuevo
interface.
Un interface hereda todas las constantes y métodos de sus
superinterfaces a menos que el interface oculte una
constante con el mismo nombre o redeclare un método con una
nueva declaración.
El cuerpo de interface.
El cuerpo del interface contiene las declaraciones de
métodos para los métodos definidos en el interface, además
de las declaraciones de los métodos, una interface puede
contener declaraciones de constantes.
Nota: Las declaraciones de miembros en un interface no
permiten el uso de algunos modificadores y desaconsejan el
uso de otros. No se podrán utilizar transient, volatile, o
synchronized en una declaración de miembro en un interface.
Tampoco se podrá utilizar los especificadores private y
protected cuando se declaren miembros de un interface.
Todos los valores constantes definidos en un interface son
implícitamente públicos, estáticos y finales. El uso de
estos modificadores en una declaración de constante en un
interface está desaconsejado por falta de estilo.
Similarmente, todos los métodos declarados en un interface
son implícitamente públicos y abstractos.
Este código define un nuevo interface llamado colección que
contiene un valor constante y tres declaraciones de métodos:
interface colección{
int MAXIMO = 500;
void añadir(Object obj);
void borrar(Object obj);
Object buscar(Object obj);
Int contadorActual();
}
El interface anterior puede ser implementado por cualquier
clase que reperesente una colección de obejtos como pueden
ser pilas, vectores, enlaces, etc...
Observa que cada declaración de método está seguida por un
punto y coma (;) porque un interface no proporciona
implementación para los métodos declarados dentro de él.
Implementar un Interface.
Para utilizar un interface se debe escribir una clase que lo
mplemente. Una clase declara todos los interfaces que
implementa en su declaración de la clase. Para declarar que
una clase implementa uo o más interfaces, se utiliza la
palabra clave implementes seguida por una lista delimitada
por comas con los interfaces implementados por la clase.
Por ejemplo, consideremos el interface colección presentado
en la página anterior. Ahoraa supongamos qu queremos
escribir una clase que implemente una pila FIFO (primero en
entrar, primero en salir). Como una ppila FIFO contiene
otros objetos tiene sentido que implemente el interface
colección. La clase PilaFIFO declara que implementa el
interface colección de esta forma:
class PilaFIFO implements coleccion{
...
void añadir(Object obj){
...
}
void borrar(Object obj){
...
}
Object buscar(Object obj){
...
}
Int contadorActual(){
...
}
}
así se garantiza que proporciona implementación para los
métodos añadir(), borrar(), buscar() y contadorActual().
Por convención, la clausula implements sigue a la clausula
extends si es que ésta existe.
Observa que las firmas de los métodos del interface
colección implementados en la clase PilaFIFO debe
corresponder exactamente con las firmas de los métodos
declarados en la interface colección.
Utilizar un interface como un tipo.
Como se mencionó anteriormente, cuando se define un nuevo
interface, en esencia se está definiendo un tipo de
referencia. Se pueden utilizar los nombres de interface en
cualquier lugar donde se usaría un nombre de dato de tipos
primitivos o un nombre de datos del tipo de referencia.
Por ejemplo, supongamos que se ha escrito un programa de
hoja de cálculo que contiene un conjunto tabular de celdas y
cada una contiene un valor. Querríamos poder poner cadenas,
fechas, enteros, ecuaciones, en cada una de las celdas de la
hoja. Para hacer esto, las cadenas, las fechas, los enteros
y las ecuaciones tienen que implementar el mismo conjunto
de métodos. Una forma de conseguir esto es encontrar el
ancestro común de las clases e implementar ahi los métodos
necesarios. Sin embargo, esto no es una solución práctica
porque el ancestro común más frecuente es Object.
Una aproximación podría ser escribir una clase llamada
ValordeCelda que representara los valores que pudiera
contener una celda de la hoja de cálculo. Entonces se
podrían crear distintas subclases de ValordeCelda para las
cadenas, los enteros o las ecuaciones.