Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

POO Con Java PDF

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 71

UNIVERSIDAD JOSE CARLOS MARIÁTEGUI

FACULTAD DE INGENIERIA

INGENIERIA DE SISTEMAS E INFORMÁTICA

PROGRAMACIÓN ORIENTADA
A OBJETOS CON JAVA

MSc. Ing. Euler Tito Chura


TABLA DE CONTENIDO
1:Programación Orientada a Objetos.......................................................................................3
Introducción: .......................................................................................................................3
La Crisis del Software .........................................................................................................3
La metodología orientada a objetos ....................................................................................4
Clases y objetos...................................................................................................................4
Mensajes y métodos ............................................................................................................5
Encapsulamiento. ................................................................................................................5
Herencia ..............................................................................................................................5
Polimorfismo.......................................................................................................................6
Abstracción..........................................................................................................................7
2:La Tecnología Java...............................................................................................................8
La Plataforma Java. .............................................................................................................8
Tipos de programas en java...............................................................................................10
Compilación y Ejecución de Programas ...........................................................................10
Tipos de datos primitivos. .................................................................................................12
El recolector de basura ......................................................................................................13
3: Clases y objetos.................................................................................................................14
Atributos y métodos ..........................................................................................................16
Constructores, la palabra reservada this ............................................................................18
Variables y métodos de clase ............................................................................................25
Clases envolventes o wrappers..........................................................................................27
Arreglos.............................................................................................................................28
Arrays de dos dimensiones ...........................................................................................30
Java archivos (JAR) ..........................................................................................................30
Limpieza: Finalización y recolección de basura. ..............................................................31
La condición de Muerto ................................................................................................34
Comentarios y documentación ..........................................................................................35
Sintaxis..........................................................................................................................35
HTML empotrado .........................................................................................................36
4:La Clase String ...................................................................................................................38
Comparación de Strings ....................................................................................................39
5: Herencia ............................................................................................................................42
La palabra reservada super................................................................................................43
Sobrecarga y sobreescritura de métodos ...........................................................................45
Sobrescritura de Métodos..................................................................................................46
Conversión hacia arriba (upcasting)..................................................................................47
La palabra clave final ........................................................................................................48
Para Datos .....................................................................................................................48
Constantes Blancas. ......................................................................................................50
Métodos Constantes ......................................................................................................51
Clases Constantes..........................................................................................................51
6: Polimorfismo .....................................................................................................................53
Clases y métodos abstractos..............................................................................................57
Interfaces y clases internas................................................................................................59
Extender una interfaz con herencia. ..............................................................................61
Clases Internas: .................................................................................................................61
7:Paquetes..............................................................................................................................64
Apéndice A: Breve historia de Java ......................................................................................69

MSc. Ing. Euler Tito Chura 2


1:Programación Orientada a Objetos.

Introducción:

Los lenguajes de programación son técnicas que permiten expresar


instrucciones que deben ser ejecutadas por la computadora. Este lenguaje de
programación sirve de nexo entre la parte humana y la computadora.

Una de estas técnicas es la programación estructurada, en la cual se considera


a un dato como pasivo y existe para ser manipulado dentro del programa
durante el desarrollo del mismo. La variedad de sistemas hoy en día (y desde
hace 20 años) ha demostrado que esta idea de estructuras de datos simples no
es adecuada para soportar grandes cambios o cambios graduales.

Tales cambios surgieron cuando aumentaron las expectativas de lo que se


podía hacer con un sistema informático, ocurrió entonces lo que se conoce
como “crisis del software”, en la que no fue suficiente la mano de obra para
mantener los sistemas actuales.

La Crisis del Software

La crisis del software es el hecho de que el software que se construye no


solamente no satisface los requerimientos ni las necesidades pedidos por el
cliente, sino que además excede los presupuestos y los horarios de tiempos.
Como alternativas de esta crisis se plantearon varias propuestas:

La parametrización: Se trato de ubicar en datos externos al programa el


conjunto de alternativas posibles para que durante la ejecución del proceso se
determine que política utilizar para resolver un problema. Esta técnica no
alcanzó a cubrir siquiera las necesidades inmediatas.

La Modularización: Se comenzó por la década de los 60’s, con Pascal, al


definirse una nueva alternativa a la parametrización que estaba basada en
encapsular comportamiento en módulos. El advenimiento de lenguajes como
Modula II y Ada, en los 70’s, fueron muy promisorios para la construcción de
sistemas de software “grande”.

El gran esfuerzo en la escritura de código como consecuencia del poco análisis


y diseño del sistema originó una nueva técnica llamada Metodología Orientada
a Objetos.

En el paradigma de objetos, no es necesario el concepto de programa, pues


cada objeto tiene una razón de ser para el ambiente que lo contiene y su
comportamiento viene dado por su naturaleza.

MSc. Ing. Euler Tito Chura 3


La metodología orientada a objetos

A medida que se acercaban los años 80, la metodología orientada a objetos


comenzaba a madurar como un enfoque de desarrollo de software.
Empezamos a crear diseños de aplicaciones de todo tipo utilizando la forma de
pensar orientada a los objetos e implementamos (codificamos) programas
utilizando lenguajes y técnicas orientadas a los objetos.

La metodología orientada a objetos presenta características que lo hacen


idóneo para el análisis, diseño y programación de sistemas; sin embargo, el
análisis de requisitos, que es la relación entre la asignación de software al nivel
del sistema y el diseño del software, se quedó atrás por lo que empezaron a
surgir diferentes métodos de análisis y diseño orientado a objetos, entre los que
destacan los métodos Booch, OOSE (Object Oriented Software Engineering) y
OMT (Object Modeling Technique). Para poner fin a la "guerra de métodos" que
se presentó en ese momento, se creó el Lenguaje Unificado de Modelado
(UML).

La programación orientada a objetos, intenta simular el mundo real a traves del


significado de objetos que contiene caracteristicas y funciones. Los lenguajes
orientados a objetos se clasifican como lenguajes de quinta generacion.

Como su mismo nombre indica, la programación orientada a objetos se basa


en la idea de un objeto, que es una combinacion de variables locales y
procedimientos llamados metodos que juntos conforman una entidad de
programación.

Clases y objetos

En la metodología orientada a objetos la esencia es el objeto. Un objeto en el


mundo real viene a representar cualquier cosa: un plumón, una caja, una silla,
un automóvil, etc. Por esta razón y en base a nuestra experiencia de la vida
diaria podemos identificar grupos o clases de objetos, por ejemplo piense en 5
plumones como los que se muestran a continuación:

De estos 5 plumones podemos decir que pertenecen a la misma


clase de objetos pero cada uno de ellos tiene las características
necesarias que lo identifican como un objeto de la clase plumones
y no con otros objetos como podría ser los objetos de tipo
automóvil.

A partir de aquí podemos decir que un objeto tiene características propias que
llamaremos atributos y comportamientos o acciones propios de esa clase de
objetos que llamaremos métodos.

MSc. Ing. Euler Tito Chura 4


Mensajes y métodos

Como ya hemos dicho un método es una acción que puede realizar un objeto.
Cuando un objeto necesita interactuar con otro lo hace a través de un método.

Figura 1.1

Cuando un objeto A necesita que un objeto B ejecute alguno de sus métodos lo


hace a través de sus métodos.

Un método se implementa dentro la clase que defina al objeto. Un buen diseño


de clases hace que los atributos solo sean modificados mediante el acceso a
un método.

Encapsulamiento.
Un objeto lo hemos representado de la siguiente manera:

En donde se puede ver que loas datos (variables) y


las acciones (métodos) se reúnen de tal forma que
se oculte al mundo exterior parte de su información.
De esta manera si queremos acceder a un atributo
lo tenemos que hacer a través de alguno de sus
métodos, a su vez los métodos también pueden ser
restringidos de cierta forma.

Figura 1.2
El encapsulamiento provee una idea poderosa: la modularidad, es decir el
código fuente puede ser escrito y darle mantenimiento de forma independiente
al resto del programa y de los objetos que interactúan con él.

Herencia

La herencia es propiedad que permite a los objetos construirse a partir de otros


objetos. El concepto de herencia está presente en nuestras vidas diarias donde
las clases se dividen en subclases.

Hay diferentes tipos de herencia: los más importantes son simples y múltiples.
La Herencia simple consiste en que una clase sólo puede heredar de otra clase
llamada clase padre o superclase, en la herencia múltiple una clase puede
heredar de una o mas clases.

MSc. Ing. Euler Tito Chura 5


Figura 1.3

La figura 1.3 muestra un ejemplo de herencia simple, la clase B y la clase C


son subclases de la clase A, que a su vez es la superclase de B y C, en esta
figura la Clase C y la Clase B heredan de la Clase A.

Con la Herencia se obtienen múltiples beneficios, al heredar una clase de otra


la se obtienen todos sus atributos y métodos que compone la clase padre. Con
la herencia y con un buen diseño Orientado a Objetos podemos llevar a la
práctica la reutilización de código, ya que si una clase es muy parecida a una
anterior, podemos programar únicamente la diferencia entre estas y aplicar la
herencia. La figura 1.4 muestra un ejemplo del uso de la herencia.

Figura 1.4

Polimorfismo

El polimorfismo es otra característica esencial de los lenguajes de POO. Un


objeto solo tiene una forma, la que se le asigna cuando es creado, pero la

MSc. Ing. Euler Tito Chura 6


referencia a ese objeto es polimorfita ya que puede referirse a objetos de
diferentes clases. Para que esta referencia sea polimorfica debe haber
necesariamente una relación de herencia entre las clases.

Por ejemplo, en nuestro diagrama de clases anterior:

• Una referencia a objeto de la clase Empleado también puede ser una


referencia a objeto de la clase Trabajador.
• Una referencia a objeto de la clase Consultor también puede ser una
referencia a objeto de la clase Trabajador.

Abstracción

Como mencionamos anteriormente en la POO para poder utilizar o crear un


objeto es necesaria la clase del objeto, a esa clase de objeto la podemos definir
como aquello que se desea abstraer, de esta forma el diseño de clases lo
podemos considerar como una abstracción de datos, por ejemplo nuestro
diagrama de clases de la figura 1.4 presenta una abstracción de datos en la
parte superior y esta abstracción desminuye conforme se desciende del árbol,
es decir, hablar de un trabajador resulta mas abstracto que hablar de un
empleado o bien un consultor, conforme descendemos en el árbol las clases se
convierten en algo mas concreto.

Diseñar una clase de una manera muy general para varias clases que hereden
de ella nos proveerá de un mejor diseño como se verá mas adelante en este
curso en el apartado de clases abstractas.

MSc. Ing. Euler Tito Chura 7


2:La Tecnología Java.

El lenguaje de programación Java consiste en un lenguaje de programación y


una plataforma. La mayoría de los lenguajes se caracterizan por ser
interpretados (por ejemplo: Basic) o bien por ser compilados (por ejemplo C)
esto determina la manera en que serán ejecutados por la computadora.

Java tiene la característica de ser al mismo tiempo compilado e interpretado. El


compilador es el encargado de convertir el código fuente de un programa en un
código intermedio llamado bytecode que es independiente de la plataforma en
que se trabaje y que es ejecutado por el intérprete de Java que forma parte de
la Máquina Virtual de Java.

.
Figura 2.1

La Plataforma Java.

Una plataforma es el ambiente de hardware o software en el cual se ejecutan


los programas. En general, la mayoría de las plataformas pueden ser descritas
como una combinación de hardware y sistema operativo. Algunas de las
plataformas más populares son Windows, Solaris, Linux y MacOS.

La plataforma Java difiere de las anteriores en que ésta es una plataforma


basada únicamente en software que corre por encima de las plataformas
basadas en hardware.

La plataforma Java consta de dos componentes:

• La Máquina Virtual de Java (JVM)


• La Interfaz de Programación de Aplicaciones de Java (API Java)

A continuación se muestra una representación de los elementos que forman


parte de la plataforma Java.

MSc. Ing. Euler Tito Chura 8


Figura 2.2

La figura anterior muestra un aspecto importante:


1.- Como puede verse la máquina virtual esta por encima de la plataforma del
Hardware, esto quiere decir que la maquina virtual es la única que cambia de
una plataforma a otra y es la encargada de interpretar y ejecutar los archivos
Bytecode de nuestro programa.

La Interfaz de Programación de Aplicaciones (API) es el conjunto de paquetes


y herramientas que nos ayudan a realizar la implementación de nuestro
programa. Los programas de carácter general usan un API denominado J2SE
(Java 2 Estándar Edición) y será el API que se use a lo largo de este manual.

La elección del API a utilizar depende del tipo de programa que queremos
realizar, a continuación se muestran varios API (todos ellos bajo la tecnología
Java) y una breve descripción de cada uno.

• J2SE: Java Standard Edition. Se utiliza en la elaboración de programas


standalone comúnmente utilizados para ser ejecutados de manera local
en una PC.
• J2EE: Java Enterprise Edition. Son programas para ser ejecutados en
una arquitectura cliente – servidor.
• J2ME: Java Micro Edition. Este API provee de las clases necesarias
para la programación de dispositivos móviles tales como: Celulares,
PDA’s, PALM, etc.
• JavaCard: Con este API podemos incrustarnos en el mundo de la
programación de las llamadas smartCards (como las tarjetas de
telefono) a través del lenguaje java.
• JNDI: Java Naming and Directory Interface. Nos permite enlazar
programas Java con directorios de información como un directorio de
información LDAP.

Existen numerosos API’s, los cuales podemos mezclar en su mayoría para


lograr aplicaciones robustas y facilitar su implementación y mantenimiento.

Para obtener el J2SE que utilizaremos a lo largo del curso basta con entrar a la
pagina de java: http://java.sun.com y descargarlo. Para detalles de la
instalación revisar el apéndice C.

MSc. Ing. Euler Tito Chura 9


Tipos de programas en java.

Los programas en Java suelen estar en una de las siguientes categorías:

• Applets : Los applets son pequeños programas que se incorporan en


una página Web y que por lo tanto, necesitan de un Navegador Web
compatible con Java para poder ejecutarse. A menudo los applets se
descargan junto con una página HTML desde un Servidor Web y se
ejecutan en la máquina cliente.

• Aplicaciones: Las aplicaciones son programas standalone de propósito


general que normalmente se ejecutan desde la línea de comandos del
sistema operativo. Con Java se puede realizar cualquier programa que
normalmente se crearía con algún otro lenguaje de programación.

• Servlets: Los servlets al contrario de los applets son programas que


están pensados para trabajar en el lado del servidor y desarrollar
aplicaciones Web que interactúen con los clientes. Los servlets son una
alternativa de la programación CGI tradicional.

Compilación y Ejecución de Programas

La figura 2.3 muestra un esquema del proceso de construcción de una


aplicación, para entender su funcionamiento pasaremos a ejecutar un ejemplo
directamente.

Figura 2.3

Nuestro primer programa consiste en el tradicional hola mundo, escribirlo en un


editor de texto plano como puede ser el block de notas de windows o bien el
editor vi de unix.

MSc. Ing. Euler Tito Chura 10


public class HolaMundo
{
public static void main(String arg[])
{
System.out.println("Mi primer programa en java");
}
}

Para ejecutar nuestro programa tenemos que seguir algunas reglas:

El nombre del archivo debe tener el nombre de la clase publica, en este caso el
nombre del archivo corresponde a HolaMundo.java, Java es un lenguaje
sensitivo lo cual quiere decir que hace una distinción entre mayúsculas y
minúsculas, además la extensión siempre debe ser *.java.

Java sigue ciertas convenciones en la asignación de nombres a clases,


métodos y variables, dicha convención se muestra a continuación y será la que
adoptemos a lo largo de este manual:

• Para nombrar clases se usa la letra en mayúscula al inicio de cada


palabra, ejemplos:
o NombreDeClase
o HolaMundo
• Para nombrar variables o atributos se usa la primer palabra en
minúsculas y en mayúscula la primer letra de las siguientes palabras que
compongan el nombre, ejemplos:
o miVariable
o nombreDeVariable.
• Para nombrar métodos se usa la misma convención que para nombrar
variables, la diferencia es que los métodos van seguidos por paréntesis,
ejemplos:
o nombreDeMetodo()
o realizarSuma()

De esta forma, podemos identificar clases, variables y métodos en el programa


anterior:

HolaMundo: es clase
String: es clase
main(): método main de la clase.
System: clase
out: atributo de la clase System.
println(): método del atributo out.

Hasta este momento tenemos listo el código fuente de nuestro programa en un


archivo llamado HolaMundo.java este archivo esta listo para ser enviado al
compilador de java: javac (de Java Compiler)

Para invocar al compilador abrir una ventana de comandos (inicio, ejecutar y


escribir cmd en sistemas Windows 2000 y XP) e invocar al compilador de la
siguiente manera:

MSc. Ing. Euler Tito Chura 11


C:\> javac HolaMundo.java

Si la compilación tuvo éxito el compilador nos devolverá el prompt del sistema


operativo y nos generará un nuevo archivo en el directorio actual con el
nombre: HolaMundo.class, que será el archivo byteCode.

Como siguiente paso hay que invocar a la maquina virtual de java (JVM) para
que se encargue de interpretarlo, esto se hace mediante la siguiente
instrucción:
C:\> java HolaMundo

Nótese la ausencia de la extensión del archivo en este comando, esto es por


que Java busca la clase (el archivo ByteCode o .class) en las rutas
especificadas por la variable de entorno CLASSPATH, de no existir la clase o
no encontrarla java nos regresará un mensaje con el error encontrado.

La figura 2.4 muestra la ejecución del programa.

Figura 2.4

Tipos de datos primitivos.

En el lenguaje de programación Java, a pesar de ser un lenguaje orientado a


objetos, no todo es un objeto. Hay un grupo de tipos que tiene un tratamiento
especial: se trata de los tipos “primitivos”, que se usaran frecuentemente en los
programas. La razón para el tratamiento especial es que crear un objeto, para
variables pequeñas y simples no es eficiente, para estos tipos Java vuelve al
enfoque de C y C++. Es decir, en vez de crear un objeto, se crea una variable
“automática” que no es una referencia. La variable guarda el valor, y se coloca
en la pila para que sea más eficiente.

Java determina el tamaño de cada tipo primitivo. Estos tamaños no varían de


una plataforma a otra como ocurre en la mayoría de los lenguajes.

MSc. Ing. Euler Tito Chura 12


Tipo primitivo Tamaño Mínimo Máximo Envoltura
bolean - - - Boolean
char 16 bits Unicode 0 Unicote 216-1 Character
byte 8 bits -128 +127 Byte
short 16 bits -215 +215-1 Short
int 32 bits -231 +231-1 Integer
long 64 bits -263 +263-1 Long
float 32 bits IEEE754 IEEE754 Float
double 64 bits IEEE754 IEEE754 Double
void - - - Void

El estándar IEEE754 especifica básicamente lo siguiente:

Precisión sencilla: bit de signo + 8 bits de exponente + 23 bits de mantisa.


Precisión doble: bit de signo +11 bits de exponente + 52 bits de mantisa.

Todos los tipos primitivos tienen asociada una envoltura o wrapper que se
muestra en la última columna de la tabla anterior, esta envoltura será vista a
detalle en el capitulo 3: clases envolventes.

El recolector de basura

Los programadores conocen la importancia de la inicialización, pero a menudo


se les olvida la importancia de la limpieza. Java tiene un recolector de basura
para recuperar la memoria de los objetos que ya no se usan, es decir de los
cuales se ha perdido su referencia.

El recolector de basura se ejecuta en un proceso en segundo plano cada


determinado tiempo, verifica que objetos han dejado de usarse y libera esa
porción de memoria al sistema operativo para su nueva reasignación.

Sin embargo puede existir la necesidad de realizar alguna acción cuando un


objeto es destruido, por ejemplo hacer uso de un destructor similar al de C++,
Java soluciona este problema por medio del método finalize() que será visto en
el siguiente capitulo.

MSc. Ing. Euler Tito Chura 13


3: Clases y objetos
Como hemos mencionado Java asume que se desea llevar a cabo
exclusivamente programación orientada a objetos. Para poder crear un objeto
es necesario que exista previamente la clase de ese objeto.

La definición de una clase especifica cómo serán los objetos de dicha clase,
esto es, de que variables y de que métodos constarán.

La siguiente es la definición más simple de una clase:

class NombreClase /* Declaración de la clase */


{

/* Aquí va la definición de variables y métodos */

Veamos un ejemplo, crearemos una clase llamada Alumno de esa clase vamos
a crear un objeto. Ahora codificando esa clase, tenemos el siguiente código:

public class Alumno {

//Atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public static void main(String args[])


{
Alumno alumno1=new Alumno(); // creamos un nuevo objeto de tipo alumno.
alumno1.nombre="Juan";
alumno1.apellidoMaterno="Lopéz";
alumno1.apellidoPaterno="Hernandez";
alumno1.carrera="Computacion";
alumno1.edad=20;
alumno1.semestre=4;
alumno1.numeroDeCuenta="03021458";

System.out.println("Numero de cuenta: "+alumno1.numeroDeCuenta);


System.out.println("Nombre: "+alumno1.nombre+" "+alumno1.apellidoPaterno+"
"+alumno1.apellidoMaterno);
System.out.println("Edad: "+alumno1.edad);
System.out.println("Carrea: "+alumno1.carrera);
System.out.println("Semestre: "+alumno1.semestre);
}
}

MSc. Ing. Euler Tito Chura 14


Veremos que es lo que esta pasando en este programa. En el método main de
la clase creamos un nuevo objeto de tipo Alumno en la sentencia:

Alumno alumno1=new Alumno();

Esta sentencia crea un nuevo objeto, con la palabra reservada new, y lo asigna
a la referencia alumno1. Una vez creado el objeto, este contiene una copia de
todos los atributos declarados en la clase siempre y cuando no estén
declarados como static. Cuando ya esta creado el objeto podemos acceder a
un atributo mediante el operador punto (.). En el ejemplo también es
interesante resaltar el uso de operador + para concatenar cadenas.

Al compilar y ejecutar este programa se obtendrá la siguiente salida:


Numero de cuenta: 03021458
Nombre: Juan Hernandez Lopéz
Edad: 20
Carrea: Computacion
Semestre: 4

Ahora vamos a crear otro objeto de la clase Alumno, este nuevo alumno tendrá
como referencia: alumno2.

public class Alumno {


// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public static void main(String args[])


{
Alumno alumno1=new Alumno();// creamos un nuevo objeto de tipo alumno
Alumno alumno2= new Alumno();// creamos otro nuevo objeto
alumno1.nombre="Juan";//inicializamos sus atributos.
alumno1.apellidoMaterno="Lopéz";
alumno1.apellidoPaterno="Hernandez";
alumno1.carrera="Computacion";
alumno1.edad=20;
alumno1.semestre=4;
alumno1.numeroDeCuenta="03021458";

alumno2.nombre="Pedro";//inicializamos sus atributos.


alumno2.apellidoMaterno="Rodriguez";
alumno2.apellidoPaterno="Rodriguez";
alumno2.carrera="Ing. Electrica";
alumno2.edad=18;
alumno2.semestre=1;
alumno2.numeroDeCuenta="040012548";

System.out.println("Datos del alumno1:");


System.out.println("Numero de cuenta: "+alumno1.numeroDeCuenta);

MSc. Ing. Euler Tito Chura 15


System.out.println("Nombre: "+alumno1.nombre+" "+alumno1.apellidoPaterno+"
"+alumno1.apellidoMaterno);
System.out.println("Edad: "+alumno1.edad);
System.out.println("Carrea: "+alumno1.carrera);
System.out.println("Semestre: "+alumno1.semestre);
System.out.println("\nDatos del alumno2:");
System.out.println("Numero de cuenta: "+alumno2.numeroDeCuenta);
System.out.println("Nombre: "+alumno2.nombre+" "+alumno2.apellidoPaterno+"
"+alumno2.apellidoMaterno);
System.out.println("Edad: "+alumno2.edad);
System.out.println("Carrea: "+alumno2.carrera);
System.out.println("Semestre: "+alumno2.semestre);
}
}

En este ejemplo hemos creado el nuevo objeto el cual tiene la referencia


alumno2. de esta forma podemos darnos cuenta de que cada objeto, tanto
alumno1 como alumno2, contiene una copia de los atributos de la clase los
cuales almacenan valores de forma independiente.

La salida de este programa es la siguiente:

Datos del alumno1:


Numero de cuenta: 03021458
Nombre: Juan Hernandez Lopéz
Edad: 20
Carrea: Computacion
Semestre: 4

Datos del alumno2:


Numero de cuenta: 040012548
Nombre: Pedro Rodriguez Rodriguez
Edad: 18
Carrea: Ing. Electrica
Semestre: 1

Atributos y métodos

En la versión 2 de nuestra clase Alumno hemos creado 2 objetos de esta clase,


sin embargo el código propuesto hasta el momento resulta un tanto ineficiente
ya que si quisiéramos crear 40 alumnos de un salón de clase e imprimir sus
datos repetiríamos bastante el código que hasta ahorita tenemos y esto va en
contra de la POO en donde la reutilización de código es algo primordial.

Si observamos las líneas de código en donde se imprimen los datos de cada


alumno encontraremos que son prácticamente las mismas, entonces
¿Podemos unir esas líneas en una sola que permitan imprimir los datos de
cualquier objeto tipo Alumno creado?. La respuesta es sí y esto se hará a
través de un método.

Como ya se dijo en el capitulo 1, un método es una acción que puede ejecutar


un objeto, en este caso la acción ha realizar será imprimir el valor de sus

MSc. Ing. Euler Tito Chura 16


atributos. La implementación del método, para imprimir el valor de los atributos,
se muestra en la siguiente versión de la clase Alumno que renombraremos
como Alumno2 para notar de mejor manera la evolución de nuestra clase.

public class Alumno2 {


// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}

public static void main(String args[])


{
Alumno2 alumno1=new Alumno2();// creamos un nuevo objeto de tipo alumno
Alumno2 alumno2= new Alumno2();// creamos otro nuevo objeto
alumno1.nombre="Juan";//inicializamos sus atributos.
alumno1.apellidoMaterno="Lopéz";
alumno1.apellidoPaterno="Hernandez";
alumno1.carrera="Computacion";
alumno1.edad=20;
alumno1.semestre=4;
alumno1.numeroDeCuenta="03021458";

alumno2.nombre="Pedro";//inicializamos sus atributos.


alumno2.apellidoMaterno="Rodriguez";
alumno2.apellidoPaterno="Rodriguez";
alumno2.carrera="Ing. Electrica";
alumno2.edad=18;
alumno2.semestre=1;
alumno2.numeroDeCuenta="040012548";

alumno1.imprimirDatos();
alumno2.imprimirDatos();
}
}

Hemos agregado el método imprimirDatos, este método es llamado por los dos
objetos creados en las instrucciones:

alumno1.imprimirDatos();
alumno2.imprimirDatos();

Cada objeto ejecuta este método el cual, al ser ejecutado por alumno1, imprime
el valor de los atributos de este objeto, es decir de alumno1, cuando es llamado

MSc. Ing. Euler Tito Chura 17


por alumno2 el método imprimirDatos busca el valor de los atributos de ese
objeto, es decir del que lo mando llamar.

Constructores, la palabra reservada this

En nuestra clase Alumno2 revisemos las siguientes líneas:

Alumno2 alumno1=new Alumno2();// creamos un nuevo objeto de tipo alumno


Alumno2 alumno2= new Alumno2();// creamos otro nuevo objeto
alumno1.nombre="Juan";//inicializamos sus atributos.
alumno1.apellidoMaterno="Lopéz";
alumno1.apellidoPaterno="Hernandez";
alumno1.carrera="Computacion";
alumno1.edad=20;
alumno1.semestre=4;
alumno1.numeroDeCuenta="03021458";

alumno2.nombre="Pedro";//inicializamos sus atributos.


alumno2.apellidoMaterno="Rodriguez";
alumno2.apellidoPaterno="Rodriguez";
alumno2.carrera="Ing. Electrica";
alumno2.edad=18;
alumno2.semestre=1;
alumno2.numeroDeCuenta="040012548";

Podemos notar que la inicialización de los atributos de cada objeto vuelve a ser
prácticamente la misma, ¿Podemos unir estas líneas en un método como se
hizo con el método de imprimirDatos?. La respuesta de nueva cuenta es sí.

Cuando se crea un objeto se manda llamar un método que recibe el nombre de


constructor. Los constructores son métodos especiales que se ejecutan cuando
un objeto es creado, su principal función es inicializar los atributos de un objeto
y cuentan con las siguientes características:

• Son llamados una sola vez cuando es creado el objeto.


• Tiene el mismo nombre de la clase.
• No regresa ningún valor de retorno.

Hasta este momento no hemos definido ningún constructor para nuestra clase
Alumno, pero sin embargo hemos estado haciendo uso del constructor por
default. El constructor por default es agregado automáticamente por Java
siempre y cuando la clase no contenga ningún constructor. Otra característica
del constructor por default es que es un constructor que no tiene argumentos.
En la siguiente línea estamos utilizando el constructor por default.

Alumno2 alumno1=new Alumno2();


Alumno2 alumno2= new Alumno2();

La sentencia new Alumno2() constituye la llamada al constructor por default.


Ahora agregaremos un constructor a nuestra clase Alumno2 que ahora la
renombraremos por Alumno3.

MSc. Ing. Euler Tito Chura 18


public class Alumno3 {
// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public Alumno3()
{
System.out.println("Creando un nuevo Alumno...");
}

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}

public static void main(String args[])


{
Alumno3 alumno1=new Alumno3();// creamos un nuevo objeto de tipo alumno
Alumno3 alumno2= new Alumno3();// creamos otro nuevo objeto
alumno1.nombre="Juan";//inicializamos sus atributos.
alumno1.apellidoMaterno="Lopéz";
alumno1.apellidoPaterno="Hernandez";
alumno1.carrera="Computacion";
alumno1.edad=20;
alumno1.semestre=4;
alumno1.numeroDeCuenta="03021458";

alumno2.nombre="Pedro";//inicializamos sus atributos.


alumno2.apellidoMaterno="Rodriguez";
alumno2.apellidoPaterno="Rodriguez";
alumno2.carrera="Ing. Electrica";
alumno2.edad=18;
alumno2.semestre=1;
alumno2.numeroDeCuenta="040012548";

alumno1.imprimirDatos();
alumno2.imprimirDatos();
}
}

En este ejemplo hemos sobrescrito el constructor por default, esta nueva


implementación solo imprime un mensaje cuando el constructor es invocado, la
salida del programa quedará de la siguiente forma:

Creando un nuevo Alumno...


Creando un nuevo Alumno...
Numero de cuenta: 03021458

MSc. Ing. Euler Tito Chura 19


Nombre: Juan Hernandez Lopéz
Edad: 20
Carrea: Computacion
Semestre: 4
Numero de cuenta: 040012548
Nombre: Pedro Rodriguez Rodriguez
Edad: 18
Carrea: Ing. Electrica
Semestre: 1

Lo que demuestra que el constructor es invocado cada vez que se crea un


nuevo objeto de la clase. Ahora adecuaremos la firma del constructor para que
pueda recibir argumentos e inicialice los atributos del objeto, para esta
cambiaremos a firma del constructor de la siguiente manera:

public Alumno3(String nom, String apePat, String apeMat, int anios, String car, int sem, String
cuenta)
{

}

Observa que hemos cambiado intencionalmente el nombre de las variables


para que no concidan con el nombre de los atributos, es seguida explicaremos
la razón. Con esta modificación al constructor nuestro programa quedará de la
siguiente manera:
public class Alumno4 {
// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public Alumno4(String nom, String apePat, String apeMat, int anios, String car, int sem, String
cuenta)
{
System.out.println("Creando un nuevo Alumno...");
nombre=nom;
apellidoPaterno=apePat;
apellidoMaterno=apeMat;
edad=anios;
carrera=car;
semestre=sem;
numeroDeCuenta=cuenta;
}

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}

MSc. Ing. Euler Tito Chura 20


public static void main(String args[])
{
//creamos un nuevo objeto de tipo alumno
Alumno4 alumno1=new
Alumno4("Juan","Lopez","Hernadez",20,"computacion",4,"03021458");
//creamos otro nuevo objeto
Alumno4 alumno2= new Alumno4("Pedro","Rodriguez","Rodriguez",18,"Ing.
Electrica",1,"040012548");

alumno1.imprimirDatos();
alumno2.imprimirDatos();
}
}

Al correr este código veremos que se obtiene el mismo resultado. Ahora


revisemos de nueva cuenta el constructor, cambiemos en nombre de las
variables de los argumentos del constructor por el mismo nombre que tienen
los atributos, el resultado podría ser inesperado, el código se encuentra en el
archivo Alumno5.java en el cual se hizo el siguiente cambio en el constructor.

public Alumno4(String nombre, String apellidoPaterno, String apellidoMaterno, int edad, String
carrera, int semestre, String numeroDeCuenta)
{
System.out.println("Creando un nuevo Alumno...");
nombre=nombre;
apellidoPaterno=apellidoPaterno;
apellidoMaterno=apellidoMaterno;
edad=edad;
carrera=carrera;
semestre=semestre;
numeroDeCuenta=numeroDeCuenta;
}

El resultado de realizar estos cambios se muestra a continuación:


Creando un nuevo Alumno...
Creando un nuevo Alumno...
Numero de cuenta: null
Nombre: null null null
Edad: 0
Carrea: null
Semestre: 0
Numero de cuenta: null
Nombre: null null null
Edad: 0
Carrea: null
Semestre: 0

Como puede verse los atributos de cada objeto no fueron inicializados, esto
ocurre debido a que la asignación de variables en el constructor es únicamente
de forma local, es decir la sentencia:

nombre=nombre;

MSc. Ing. Euler Tito Chura 21


La variable nombre del lado derecho hace referencia a la variable nombre
declarada en los argumentos del constructor siendo la misma variable la del
lado derecho, es decir es una asignación entre la misma variable, nunca se
afecta al atributo del objeto. Para poder hacer una distinción de una variable
local y un atributo del objeto con el mismo nombre se usa la palabra reservada
this.

Con el uso de la palabra reservada this, podemos mejorar nuestro código de la


siguiente manera:

public class Alumno6 {


// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public Alumno6(String nombre, String apellidoPaterno, String apellidoMaterno, int edad, String
carrera, int semestre, String numeroDeCuenta)
{
System.out.println("Creando un nuevo Alumno...");
this.nombre=nombre;
this.apellidoPaterno=apellidoPaterno;
this.apellidoMaterno=apellidoMaterno;
this.edad=edad;
this.carrera=carrera;
this.semestre=semestre;
this.numeroDeCuenta=numeroDeCuenta;
}

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}

public static void main(String args[])


{
//creamos un nuevo objeto de tipo alumno
Alumno6 alumno1=new
Alumno6("Juan","Lopez","Hernadez",20,"computacion",4,"03021458");
//creamos otro nuevo objeto
Alumno6 alumno2= new Alumno6("Pedro","Rodriguez","Rodriguez",18,"Ing.
Electrica",1,"040012548");

alumno1.imprimirDatos();
alumno2.imprimirDatos();
}
}

MSc. Ing. Euler Tito Chura 22


En este ejemplo, que produce la misma salida de las versiones anteriores de
Alumno, podemos decir que la palabra reservada this hace referencia al objeto
que mando llamar el método, en esta caso el constructor.
Invocando a Constructores desde Constructores.

Cuando se escriben varios constructores para una clase, hay veces en las que
uno quisiera invocar a un constructor desde otro para evitar la duplicación de
código. Esto se puede lograr utilizando la palabra reservada this.

La palabra clave this toma un significado diferente cuando se le da una lista de


parámetros: hace una llamada explícita al constructor que coincida con la lista
de parámetros. Por consiguiente, hay una manera directa de llamar otros
constructores. Ejemplo:
public class Flor {
int numeroPetalos=0;
String texto=null;

public Flor(int petalos)


{
numeroPetalos=petalos;
System.out.println("Constructor: Parametro entero solo, petalos= "+petalos);
}
public Flor(String ss)
{
System.out.println("Constructor: Parametro cadena solo, texto= "+ss);
texto=ss;
}
public Flor(String ss, int petalos)
{
this(petalos);
//! this(ss); //No se pueden invocar dos
this.texto=ss;
System.out.println("Constructor: Parametro cadena y entero");
}
public Flor()
{
this("Hola",20);
System.out.println("Constructor por defecto (Sin parametros)");
}

public void print()


{
//this(11); // No se puede invocar this dentro de un no-constructor
System.out.println("Numero de petalos: "+numeroPetalos+" texto= "+texto);
}

public static void main(String args[])


{
Flor x= new Flor();
x.print();
Flor y= new Flor("Rosa",18);
y.print();
}

MSc. Ing. Euler Tito Chura 23


}
En el ejemplo anterior podemos observar el uso de varios constructores para
crear objetos. Además el uso de this con parámetros, es decir como llamada al
constructor, debe ser la primer cosa que se haga o se obtendrá un mensaje de
error del compilador. La salida del programa anterior es la siguiente:

Constructor: Parametro entero solo, petalos= 20


Constructor: Parametro cadena y entero
Constructor por defecto (Sin parametros)
Numero de petalos: 20 texto= Hola
Constructor: Parametro entero solo, petalos= 18
Constructor: Parametro cadena y entero
Numero de petalos: 18 texto= Rosa

Para terminar con este apartado mostraremos un ejemplo final de la clase


Alumno hasta ahora modificada pero esta vez en archivos distintos, es decir
por un lado en un archivo la clase Alumno que renombraremos por Alumno7 y
por el otro una clase llamada escuela en un archivo distinto. Estos dos archivos
deberán encontrarse en el mismo directorio por el momento.
//Alumno7.java
public class Alumno7 {
// atributos de la clase
String nombre;
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;

public Alumno7(String nombre, String apellidoPaterno, String apellidoMaterno, int edad, String
carrera, int semestre, String numeroDeCuenta)
{
System.out.println("Creando un nuevo Alumno...");
this.nombre=nombre;
this.apellidoPaterno=apellidoPaterno;
this.apellidoMaterno=apellidoMaterno;
this.edad=edad;
this.carrera=carrera;
this.semestre=semestre;
this.numeroDeCuenta=numeroDeCuenta;
}

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}

MSc. Ing. Euler Tito Chura 24


//Escuela.java
public class Escuela {

public static void main(String args[])


{
//creamos un nuevo objeto de tipo alumno
Alumno7 alumno1=new
Alumno7("Juan","Lopez","Hernadez",20,"computacion",4,"03021458");
//creamos otro nuevo objeto
Alumno7 alumno2= new Alumno7("Pedro","Rodriguez","Rodriguez",18,"Ing.
Electrica",1,"040012548");

alumno1.imprimirDatos();
alumno2.imprimirDatos();
}
}

Se comprobará que la salida no cambia en relación a programas anteriores.

Variables y métodos de clase

Generalmente, al crear una clase se está describiendo qué apariencia tienen


sus objetos y cómo se comportan. No se tiene nada hasta crear un objeto de
ese clase con new, momento en el que se crea el espacio de almacenamiento
y los métodos pasan a estar disponibles.

Pero hay dos situaciones en las que este enfoque no es suficiente. Una es
cuando se desea tener solamente un fragmento de espacio de almacenamiento
para una parte concreta de datos, independientemente de cuántos objetos se
creen, o incluso aunque no se cree ninguno. La otra es si se necesita un
método que no esté asociado con ningún objeto particular de esa clase. Es
decir, se necesita un método al que se puede invocar incluso si no se ha
creado ningún objeto. Ambos efectos se pueden lograr con la palabra clave
static. Al decir que algo es estático se está indicando que el dato o método no
está atado a ninguna instancia de objeto de esa clase. Con los datos y métodos
ordinarios no estáticos, es necesario crear un objeto para poder utilizarlos,
estos métodos y datos que necesitan un objeto para poder ser utilizados
reciben el nombre de variables y métodos de instancia.

Para declarar un dato o un método static, basta con colocar la palabra clave
static antes de la definición, por ejemplo:

public class PruebaEstatica


{
static int i=47;
}

Ahora, incluso si se construyen dos objetos de tipo PruebaEstatica, sólo habrá


un espacio de almacenamiento, es decir ambos objetos compartirán la misma i.
La sintaxis recomendada de llamar a una variable o método de clase es la
siguiente:

MSc. Ing. Euler Tito Chura 25


NombreDeClase.nombreDeAtributo;
NombreDeClase.nombreDeMétodo();

Modifiquemos nuestro ejemplo de la clase Alumno para ver un ejemplo:

//Alumno8.java
public class Alumno8 {
// atributos de la clase
String nombre; // variable de instancia, cada que creas un objeto se crea un copia para cada
objeto
String apellidoPaterno;
String apellidoMaterno;
int edad;
String carrera;
int semestre;
String numeroDeCuenta;
static int numeroDeAlumnos=0;// variable de clase, no se crean copias para cada objeto, es
fija.

public Alumno8(String nombre, String apellidoPaterno, String apellidoMaterno, int edad, String
carrera, int semestre, String numeroDeCuenta)
{
System.out.println("Creando un nuevo Alumno...");
this.nombre=nombre;
this.apellidoPaterno=apellidoPaterno;
this.apellidoMaterno=apellidoMaterno;
this.edad=edad;
this.carrera=carrera;
this.semestre=semestre;
this.numeroDeCuenta=numeroDeCuenta;
numeroDeAlumnos++;// modificamos una variable de clase
}

public static String metodoDeClase()


{
String mensaje="Metodo de clase";
//nombre="Paco"; //Un método de clase o puede modificar variables de instancia
return mensaje;
}

public void imprimirDatos()


{
System.out.println("Numero de cuenta: "+numeroDeCuenta);
System.out.println("Nombre: "+nombre+" "+apellidoPaterno+" "+apellidoMaterno);
System.out.println("Edad: "+edad);
System.out.println("Carrea: "+carrera);
System.out.println("Semestre: "+semestre);
}
}

Hemos agregado un método y una variable estática, ahora modifiquemos el


archivo Escuela para mandar llamar las variables estáticas.

//Escuela2.java
public class Escuela2 {

public static void main(String args[])

MSc. Ing. Euler Tito Chura 26


{
//Las variables y métodos de clase se pueden usar sin crear un objeto
System.out.println("Numero total de Alumnos: "+Alumno8.numeroDeAlumnos);
System.out.println("Mensaje del metodo de clase:
"+Alumno8.metodoDeClase());
//creamos un nuevo objeto de tipo alumno
Alumno8 alumno1=new
Alumno8("Juan","Lopez","Hernadez",20,"computacion",4,"03021458");
//creamos otro nuevo objeto
Alumno8 alumno2= new Alumno8("Pedro","Rodriguez","Rodriguez",18,"Ing.
Electrica",1,"040012548");
//Despues de crear dos objetos, la variable estatica se ha modificado
System.out.println("Numero total de Alumnos: "+Alumno8.numeroDeAlumnos);
//Los objetos tambien pueden accesar a las variables y metodos estaticos
System.out.println("Desde alumno1, Numero de Alumnos:
"+alumno1.numeroDeAlumnos);
//Los objetos tambien pueden modificar las variables estaticas directamente:
alumno2.numeroDeAlumnos++;
System.out.println("Numero total de Alumnos: "+Alumno8.numeroDeAlumnos);
}
}

La salida de este programa deberá ser la siguiente:


Numero total de Alumnos: 0
Mensaje del metodo de clase: Metodo de clase
Creando un nuevo Alumno...
Creando un nuevo Alumno...
Numero total de Alumnos: 2
Desde alumno1, Numero de Alumnos: 2
Numero total de Alumnos: 3

Clases envolventes o wrappers

Los tipos de datos primitivos tienen asociado una clase “envoltura”. Esto quiere
decir que si se desea hacer un objeto no primitivo para representar ese tipo
primitivo, se hace uso del envoltorio asociado. Por ejemplo:

char c= ‘x’;
Charácter C = new Character(c)

Veamos un ejemplo más práctico, queremos realizar un programa que reciba


desde la línea de comandos dos números y que los sume, mostrando el
resultado en pantalla. Para utilizar los parámetros de la línea de comandos
utilizamos el arreglo de String que viene en la firma del método main.

public static void main(String args[])

La referencia args es un arreglo de objetos tipo String, que veremos más


adelante en este capitulo, para acceder al primer parámetro utilizaremos el
índice 0 del arreglo y 1 para el segundo. Pero esto ocasionará un problema: los
datos estarán en un objeto String lo que dificultara la operación de suma que
queremos realizar, para solucionar esto utilizaremos la clase envolvente Integer

MSc. Ing. Euler Tito Chura 27


que nos provee de un método para realizar esta conversión de un String a un
int. El siguiente ejemplo ilustra lo anterior.

public class SumaDeNumeros {

public static void main(String args[])


{
int a= Integer.parseInt(args[0]);
int b= Integer.parseInt(args[1]);
int c= a+b;
System.out.println("El resultado de la suma es: "+c);
}
}

para ejecutar este programa hay que hacerlo de la siguiente manera:

C:\ javac SumaDeNumeros.java


C:\ java SumaDeNumeros 1 2

Arreglos.

Hasta ahora, hemos descrito datos (variables) individuales y aislados. Por


ejemplo:

int contador, suma;


String nombre;

Estos datos trabajan por su cuenta, desempeñando funciones útiles en los


programas, como contadores, sumas o lo que sea. Podemos pensar en estas
variables como posiciones en memoria que tienen asignados nombres
individuales.

En contraste, en la vida tratamos con datos que no están aislados, sino


agrupados en una colección de información. Para solucionar este problema
contamos con un tipo de almacenamiento que son los arrays. Existen muchas
otras formas de guardar objetos, pero como se verá a continuación el array
tiene dos aspectos especiales con respecto a otros tipos de contenedores: la
eficiencia y el tipo.

El array es la forma más eficiente que proporciona Java para almacenar y


acceder al azar a una secuencia de objetos (verdaderamente, referencias a
objetos). El array es una secuencia lineal simple, que hace rápidos los accesos
a elementos, pero se paga por esa velocidad: cuando se crea un objeto array
su tamaño es limitado y no puede variarse.

Para declara un array basta escribir:

int[] suma;

o bien:

MSc. Ing. Euler Tito Chura 28


int suma[]:

Son exactamente la misma sentencia, que declara que la referencia suma será
un array de objetos.

Un ejemplo de un primer array de cadenas es el siguiente:

public class PrimerArray{


public static void main(String arg[]){
String nombres[] ={
"Juan",
"Maria",
"Antonio",
"Victoria"
};
nombres[2]="Alejandro";
System.out.println("Numero de elementos en el array: "+nombres.length);
System.out.println(nombres[0]);
System.out.println(nombres[1]);
System.out.println(nombres[2]);
System.out.println(nombres[3]);
}
}

Java permite varias formas de inicializar los array, el acceso a cada elemento
de un array se realiza mediante el índice del elemento. He aquí la salida del
programa:

Numero de elementos en el array: 4


Juan
Maria
Alejandro
Victoria

También podemos realizar array de tipos primitivos, la diferencia es que el


objeto array no guarda referencias como array con objetos, si no que guarda
directamente el valor de cada elemento. Ejemplo:

public class ArrayDeEnteros {

public static void main(String[] args) {


int[] enteros; // declara un arreglo de enteros
enteros = new int[10]; // crea el objeto que alamcenara 10 enteros
// inicializa los elementos del arreglo y lo imprime
for (int i = 0; i < enteros.length; i++) {
enteros[i] = i;
System.out.print(enteros[i] + " ");
}
}
}

Este ejemplo muestra otra forma de inicializar el array, primero se declara el


tamaño y luego se inicializa el array cabe destacar que para especificar el

MSc. Ing. Euler Tito Chura 29


tamaño del array se usa new int[10], nótese el cambio de corchetes por los
tradicionales paréntesis, la salida del programa se muestra a continuación:

0123456789

Arrays de dos dimensiones

Java ofrece una extensión natural de los arreglos unidimensionales a dos


dimensiones, para crear un arreglo de dos dimensiones usamos dobles
corchetes, por ejemplo:

int[][] ventas = new ventas[4][7] ;

Esta instrucción declara una matriz de 4 x 7 elementos.

Java archivos (JAR)

El formato ZIP también se usa en el formato de archivos JAR (Java ARchive),


que es una forma de coleccionar un grupo de archivos en un único archivo
comprimido, exactamente igual que el ZIP. Sin embargo, como todo lo demás
en Java, los ficheros JAR son multiplataforma, por lo que no hay que
preocuparse por aspectos de plataforma. También se pueden incluir archivos
de audio e imagen, o archivos de clases.

Un archivo JAR consta de un único archivo que contiene una colección de


archivos ZIP junto con una declaración que los describe.

La utilidad jar que viene con el JDK de Sun comprime automáticamente los
archivos que se seleccionan. Se invoca en la línea de comandos:

jar [opciones] destino [manifiesto] archivo(s)Entrada

Las opciones son simplemente una colección de letras, los usuarios de linux
notarán una semejanza con las opciones tar. Las opciones son:

c Crea un archivo nuevo vacío.


t Lista la tabla de contenidos.
x Extrae todos los archivos.
x file Extraer el archivo nombrado.
f Nombre del archivo.
m Indica que el primer parámetro será el archivo de declaración.
v Genera una salida que describe que va haciendo jar.
O Simplemente almacena los archivos; no los comprime (usarlo para crear un
archivo JAR que se puede poner en el CLASSPATH)
M No crear automáticamente un archivo de declaración.

MSc. Ing. Euler Tito Chura 30


He aquí una forma habitual de invocar a Jar:

C:\jar cf miArchivoJar.jar *.class

Esto crea un fichero JAR llamado miFichero.jar que contiene todos los archivos
de clase del directorio actual, junto con un archive declaración creado
automáticamente.

El archivo de declaración que es creado automáticamente puede tener varias


utilidades como por ejemplo indicar la clase a partir de la cual se podrá ejecutar
el archivo completo JAR. Por ejemplo vamos a comprimir en un archivo JAR las
dos ultimas clases que trabajamos de la versión de nuestra clase Alumno que
son: Alumno8 y Escuela2. Primero vamos a crear nuestro archivo Manifiesto
que tenga la siguiente información, este archivo puede ser escrito en un editor
de texto plano como puede ser notepad de Windows o vi de Linux:

Manifest-Version: 1.0
Created-By: 1.5.0_02 (Sun Microsystems Inc.)
Main-Class: Escuela2

Nota que hemos especificado la clase que contiene el método main a ejecutar,
guarda este archivo en el mismo directorio de tus clases con el nombre:
MANIFEST.MF

Como siguiente paso vamos a comprimir los archivos, en la línea de comandos


escribe:

C:\ >jar cmf MANIFEST.MF Escuela.jar Alumno8.class Escuela2.class

Para ejecutar el archivo escribir:

C:\>java –jar Escuela.jar

Limpieza: Finalización y recolección de basura.

En el capitulo anterior hablamos del recolector de basura como un proceso que


se ejecuta en segundo plano y libera la memoria de aquellos objetos que han
perdido su referencia. Considere ahora un caso muy inusual. Supóngase que
los objetos asignan memoria “especial” sin utilizar new. El recolector de basura
sólo sabe liberar la memoria asignada por new, por lo que ahora no sabrá
como liberar esa memoria “especial” del objeto. Para hacer frente a este caso,
Java proporciona un método denominado finalize( ) que se puede definir en
cada clase. He aquí como se supone que funciona. Cuando el recolector de
basura está preparado para liberar el espacio de almacenamiento utilizado por
el objeto, primero invocara a finalize( ), y sólo recuperará la memoria del objeto
durante la pasada del recolector de basura. Por tanto, si se elige usar finalize(),
éste te proporciona la habilidad de llevar acabo alguna limpieza importante a la
vez que la recolección de basura.

MSc. Ing. Euler Tito Chura 31


Hay que señalar que no es lo mismo que un destructor para C++, que es una
función que siempre se invoca. Java no cuenta con algo parecido así que si se
necesita para un programa en específico tendrá que ser programado por su
cuenta. Por ejemplo, considere un objeto que dibuja una figura en pantalla, el
recolector de basura puede eliminar el objeto pero no la información que dibujo
en pantalla.

Pero la limpieza y recolección de basura esta ligada exclusivamente a la


liberación de memoria. Resulta que la necesidad de finalize( ) se limita a casos
especiales, en los que un objeto puede reservar espacio de almacenamiento de
forma distinta a la creación de un objeto.

Esto puede ocurrir principalmente a través de métodos nativos, que son la


forma de invocar a código no-Java desde Java.

Una de las cosas para las que puede ser útil finalize( ) es para observar el
proceso de recolección de basura. El ejemplo siguiente resume las
descripciones anteriores del recolector de basura:

//Silla.java
//Demostracion de recolector de Basura y
//finalizacion
public class Silla {

static boolean recolector=false;


static boolean f= false;
static int creadas = 0;
static int finalizadas =0;
int i;
public Silla()
{
i= ++creadas;
if(creadas==47)
System.out.println("Creadas 47");
}
public void finalize()
{
if(!recolector)
{//la primera vez que se invoca a finalize():
recolector=true;
System.out.println("Comenzando a finalizar tras haber creado "+
creadas +"sillas");
}
if(i==47)
{
System.out.println("Finalizando la silla #47, "+
"Poniendo el indicador que evita la creacion de mas
sillas");
f=true;
}
finalizadas++;
if(finalizadas>=creadas)
System.out.println("Las "+finalizadas+" han sido finalizadas");
}

MSc. Ing. Euler Tito Chura 32


}

//Basura.java
public class Basura {
public static void main(String args[])
{
//Mientras no se haya puesto la bandera,
//hacer sillas y cadenas de texto
while(!Silla.f)
{
new Silla();
new String("Ocupar Espacio");
}
System.out.println("Despues de haber creado todas las sillas: \n"+
"Creadas en total: "+Silla.creadas+", total finalizadas:
"+Silla.finalizadas);
}
}

El programa anterior crea muchos objetos Silla, y en cierto momento después


de que el recolector de basura comience a ejecutarse el programa deja de crear
objetos Silla. Dado que el recolector puede ejecutarse en cualquier momento,
uno no sabe exactamente cuando empezará, y hay un indicador denominado
recolector para indicar si el recolector a comenzado su ejecución o no. Un
segundo indicador f es la forma de que Silla le comunique al bucle main( ) que
deberá dejar de hacer objetos. Ambos indicadores se ponen dentro de finalize(
), que se invoca durante la recolección de basura.

La creación de un objeto String en cada iteración es simplemente la asignación


de almacenamiento extra para animar al recolector de basura a actuar, lo que
hará cuando se empiece a poner nervioso por la cantidad de memoria
disponible.

Una posible salida del programa anterior se muestra a continuación:


Creadas 47
Comenzando a finalizar tras haber creado 12207sillas
Finalizando la silla #47, Poniendo el indicador que evita la creacion de mas sillas
Las 33864 han sido finalizadas
Despues de haber creado todas las sillas:
Creadas en total: 33865, total finalizadas: 33864

Por consiguiente, no se invoca a todos los finalizadotes cuando acaba el


programa. Recuerde que ni el recolector de basura ni la finalización están
garantizadas. Si la Máquina Virtual Java (JVM) no está a punto de quedarse sin
memoria, entonces (sabiamente) no malgastará tiempo en recuperar memoria
mediante el recolector de basura.

Existe también una forma de invocar al recolector de basura explícitamente


cuando el programador lo desee y esto se hace mediante el método:
System.gc(). Si se llama a System.gc() se finalizan todos los objetos, por
consiguiente se destruirán todos los objetos que no estén en uso en ese
momento.

MSc. Ing. Euler Tito Chura 33


La condición de Muerto

En el momento que uno deja de estar interesado en un objeto –cuando está


listo para ser eliminado– el objeto debería estar en cierto estado en el que su
memoria puede ser liberada de manera segura. Por ejemplo, si el objeto
representa un fichero abierto, ese fichero debería ser cerrado por el
programador antes de que el objeto sea eliminado por el recolector de basura.
Si no se eliminan correctamente ciertas porciones de objeto, se tendrá un fallo
en el programa que podría ser difícil de encontrar. El valor de finalize( ) es que
puede usarse para descubrir esta condición, incluso si no se invoca siempre. Si
una de las finalizaciones acaba revelando el fallo, se descubre el problema,
que es lo que verdaderamente hay que cuidar.

He aquí un ejemplo simple de cómo debería usarse:

//Libro.java
//Utilizacion de finalize() para detectar un objeto
// que no ha sido correctamente eliminado
public class Libro {
boolean comprobado=false;
public Libro(boolean comprobar)
{
comprobado=comprobar;
}
void correcto()
{
comprobado=false;
}
public void finalize()
{
if(comprobado)
System.out.println("Error: comprobado");
}
}

//CondicionDeMuerto.java
public class CondicionDeMuerto {
public static void main(String[] args)
{
Libro novela = new Libro(true);
//Eliminacion Correcta
novela.correcto();
//Cargarse la referencia olvidando la limpieza
new Libro(true);
//forzar la recoleccion de basura y finalizacion
System.gc();

}
}

La condición de muerto consiste en que todos los objetos libros supuestamente


serán comprobados antes de ser recogidos por el recolector de basura, pero en
el método main( ) un error del programador no comprueba alguno de los libros.

MSc. Ing. Euler Tito Chura 34


Sin finalize( ) para verificar la condición de muerte, este error sería difícil de
encontrar.

Comentarios y documentación

Hay dos tipos de comentarios en Java. El primero es el estilo de comentarios


tradicional de C, que fue heredado por C++. Estos comentarios empiezan por /*
y pueden extenderse a lo largo de varias líneas hasta encontrar */.

Una de las partes más interesantes del lenguaje Java es que los diseñadores
no sólo tuvieron en cuenta que la escritura de código era la única actividad
importante, sino que también pensaron en la documentación del código. Esto
se hizo mediante comentarios especiales que se incrustan dentro del código
fuente, sin embargo, es necesaria una sintaxis especial y una herramienta para
extraer esos comentarios.

La herramienta para extraer comentarios se le denomina javadoc. Utiliza parte


de la tecnología del compilador Java para extraer etiquetas de comentarios
especiales. La salida de javadoc es un archivo HTML que puede visualizarse a
través del navegador web. Gracias a javadoc se tiene incluso un estándar para
la creación de documentación, tan sencillo que se puede incluso esperar o
solicitar documentación con todas las bibliotecas Java.

Sintaxis

Todos los comandos de javadoc se dan únicamente en comentarios /**. Estos


comentarios acaban con */. Hay dos formas principales de usar javadoc:
empotrar HTML, o utilizar “etiquetas doc”. Kas etiquetas doc son comandos que
comienzan por ‘@’ y se sitúan al principio de una línea de comentarios.

Hay tres “tipos” de documentación en forma de comentarios, que corresponden


con el elemento al que precede el comentario: una clase, una variable o un
método. Es decir, el comentario relativo a una clase aparece justo antes de la
definición de la misma; el comentario relativo a una variable precede siempre a
la definición de la variable, y un comentario de un método aparece
inmediatamente antes de la definición de un método. Un ejemplo simple:

/** Un comentario de clase */


public class PruebaDoc
{
/** Un comentario de una variable */
public int i;
/** Un comentario de un método */
public void f( ){}
}

MSc. Ing. Euler Tito Chura 35


HTML empotrado

Javadoc pasa comandos HTML al documento HTML generado. Esto permite un


uso total de HTML; sin embargo, el motivo principal es permitir dar formato al
código, como:

/**
* <pre>
* System.out.println(new Date());
* </pre>
*/

También puede usarse HTML como se haría en cualquier otro documento web
para dar formato al propio texto de las descripciones:

/**
* Uno puede <em>incluso</em> insertar una lista:
* <ol>
* <li> Elemento uno
* <li> Elemento dos
* <li> Elemento tres
* </ol>
*/

@see: Referencias a otras clases. Los tres tipos de comentarios de


documentación (de clase, variable y métodos) pueden contener etiquetas
@see, que permiten hacer referencia a la documentación de otras clases.
Javadoc generará HTML con las etiquetas @see en forma de vínculos a la otra
documentación. La forma es:

@see NombreDeClase

@version: Información de la versión de la clase. La forma es:

@version información-de-version.

@author: Suele ser el nombre del creador pero podría ser cualquier cosa como
la dirección de correo. La forma de uso es:

@author información-del-autor

@param: permite especificar una descripción de un parámetro. Forma de uso:

@param nombre-parámetro descripción

@return: especifica una descripción para un valor de retorno

@return descripción

@throws: Descripción para las excepciones, que serán vistas en el curso de


java Avanzado.

MSc. Ing. Euler Tito Chura 36


@throws nombre-de-clase descripción

Ejemplo de documentación.

import java.util.Vector;
/**
* Este es un ejemplo de código comentado<br>
* <h1>Se pueden usar etiquetas de HTML</h1>,
* para darle formato al texto.<br>
* En esta parte, se describe sobre las características, uso, y funcionamiento
* de la clase en general.
* @author PROTECO
*
*/
public class Comentada extends Vector implements Runnable{
/**
* Asi se comentan los atributos
*/
protected String atributo;
/**
* Este es una atributo de clase, y no modificable
*/
static final int VALOR=10;
/**
* Tambien los métodos constructores pueden ir comentados
*
*/
public Comentada(){

}
/**
* Asi se comentan lo métodos. Se da una descripción de lo que hacen
* y se pueden dar algunos ejemplos. Se utilizan
* @param arg1 Comentario del parámetro 1
* @param arg2 Comentario del parámetro 2
* @param num Comentario del parámetro n
* @return Comentario del valor de retorno
* @throws Exception Comentario sobre alguna excepción que regrese
*/
private int Metodo(String arg1,Vector arg2,int num) throws Exception{
return 0;
}
public void run(){

}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
Para ejecutar el comando javadoc en un ventana de comandos escribir:
javadoc Comantada.java

y la herramienta javadoc generará el archivo html en el directorio actual.

MSc. Ing. Euler Tito Chura 37


4:La Clase String
Dentro de un objeto de la clases String o StringBuffer, Java crea un array de
caracteres de una forma similar a como lo hace el lenguaje C++. A este array
se accede a través de métodos de la clase. Los String se pueden crear
explícitamente o implícitamente. Para crear un String implícitamente basta
poner una cadena de caracteres entre comillas dobles. Por ejemplo, cuando se
escribe:

System.out.println("El primer programa");

Java crea un objeto de la clase String automáticamente. Para crear un String


explícitamente escribimos:

String str=new String("El primer programa");

También se puede escribir, alternativamente

String str="El primer programa";

Para crear un String nulo se puede hacer de estas dos formas

String str="";
String str=new String();
Un string nulo es aquél que no contiene caracteres, pero es un objeto de la
clase String. Sin embargo,

String str;

Está declarando un objeto str de la clase String, pero aún no se ha creado


ningún objeto de esta clase.

Cómo se obtiene información acerca del String

Una vez creado un objeto de la clase String podemos obtener información


relevante acerca del objeto a través de las funciones miembro. Para obtener la
longitud, número de caracteres que guarda un String se llama al método length.

String str="El primer programa";


int longitud=str.length();

Podemos conocer si un string comienza con un determinado prefijo, llamando


al método startsWith, que devuelve true o false, según que el string comience o
no por dicho prefijo:

String str="El primer programa";


boolean resultado=str.startsWith("El");

En este ejemplo la variable resultado tomará el valor true.

MSc. Ing. Euler Tito Chura 38


Manual del Curso Java Básico Programa de Tecnología en Cómputo

De modo similar, podemos saber si un String finaliza con un conjunto dado de


caracteres, mediante el método endsWith:

String str="El primer programa";


boolean resultado=str.endsWith("programa");

Si se quiere obtener la posición de la primera ocurrencia de la letra p, se usa la


función indexOf:

String str="El primer programa";


int pos=str.indexOf('p');

Para obtener las sucesivas posiciones de la letra p, se llama a otra versión de


la misma función

pos=str.indexOf('p', pos+1);

El segundo argumento le dice a la función indexOf que empiece a buscar la


primera ocurrencia de la letra p a partir de la posición pos+1. Otra versión de
indexOf busca la primera ocurrencia de un substring dentro del String:

String str="El primer programa";


int pos=str.indexOf("pro");

Vemos que una clase puede definir varios métodos con el mismo nombre pero
que tienen distinto número de parámetros o de distinto tipo, esto se conoce
como sobrecarga de métodos y será visto a detalle en el siguiente capitulo.

Comparación de Strings

La comparación de strings nos da la oportunidad de distinguir entre el operador


lógico == y la función miembro equals de la clase String. En el siguiente código:

public class ClaseString {


public static void main(String[] args)
{
String str1="El lenguaje Java";
String str2=new String("El lenguaje Java");
if(str1==str2)
{
System.out.println("Los mismos objetos");
}
else
{
System.out.println("Distintos objetos");
}
if(str1.equals(str2))
{
System.out.println("El mismo contenido");
}
else
{
System.out.println("Distinto contenido");

MSc. Ing. Euler Tito Chura 39


}
}
}

Esta porción de código devolverá que str1 y str2 son distintos objetos pero con
el mismo contenido. str1 y str2 ocupan posiciones distintas en memoria pero
guardan los mismos datos.
Cambiemos la segunda sentencia y escribamos:

String str1="El lenguaje Java";


String str2=str1;
System.out.prinln("Son el mimso objeto "+(str1==str2);

Los objetos str1 y str2 guardan la misma referencia al objeto de la clase String
creado. La expresión (str1==str2) devolverá true. Así cuando deseamos
comparar el contenido de dos String se debe usar el método equals, ya que de
otra forma, con el operador = = compararemos si los Objetos apuntan a la
misma dirección de memoria.

El método comapareTo devuelve un entero menor que cero si el objeto String


es menor (en orden alfabético) que el String dado, cero si son iguales, y mayor
que cero si el objeto String es mayor que el String dado.

String str="Tomás";
int resultado=str.compareTo("Alberto");

La variable entera resultado tomará un valor mayor que cero, ya que Tomás
está después de Alberto en orden alfabético.

String str="Alberto";
int resultado=str.compareTo("Tomás");

La variable entera resultado tomará un valor menor que cero, ya que Alberto
está antes que
Tomás en orden alfabético.

Extraer un substring de un String

En muchas ocasiones es necesario extraer una porción o subcadena de un


String dado. Para este propósito hay un método de la clase String denominada
substring. Para extraer un substring desde una posición determinada hasta el
final del String escribimos:

String str="El lenguaje Java";


String subStr=str.substring(12);

Se obtendrá el substring "Java". Una segunda versión del método substring,


nos permite extraer un substring especificando la posición de comienzo y la el
final.

String str="El lenguaje Java";


String subStr=str.substring(3, 11);

MSc. Ing. Euler Tito Chura 40


Se obtendrá el substring "lenguaje". Recuérdese, que las posiciones se
empiezan a contar desde el indice cero.

Convertir un número a String


Para convertir un número en String se emplea el método estático valueOf:

int valor=10;
String str=String.valueOf(valor);

La clase String proporciona versiones de valueOf para convertir los datos


primitivos: int, long, float, double.

Cuando introducimos caracteres en un control de edición a veces es inevitable


que aparezcan espacios ya sea al comienzo o al final. Para eliminar estos
espacios tenemos el método trim:

String str=" 12 ";


String str1=str.trim();

MSc. Ing. Euler Tito Chura 41


5: Herencia
La herencia es una parte integral de Java. Resulta que siempre se esta
haciendo herencia cuando se crea una clase, pero a menos que se herede
explícitamente de otra clase, se hereda implícitamente de la clase raíz estándar
de Java Object.

Cuando se hereda, se dice: “Esta clase nueva es como esa clase vieja”. Se
dice esto en el código dando el nombre de la clase pero antes de abrir el
cuerpo de clase, se pone la palabra reservada extends seguida del nombre de
la clase base. Cuando se hace esto, automáticamente se tiene todos los
atributos y métodos de la clase base. He aquí un ejemplo.

//Animal.java
public class Animal {

String raza;
String nombre;
int edad;
String tamaño;
String tipoDePelaje;

public Animal(){
System.out.println("El animal es totalmente Rebelde");
}

public Animal(String nombre, String nombre){


this.nombre=nombre;
this.raza= nombre; }

public void comer() {


System.out.println("Alimentando al animal");
}

public void respirar() {


System.out.println("El animal respira");
}

public void reproduccion() {


System.out.println("El animal puede reproducirse");
}

public void dormir() {


System.out.println("El animal duerme");
}
}

//Gato.java
public class Gato extends Animal {
int numVidas=7;
String tipoDeComida;
public void maullar() {
System.out.println("El gato esta maullando");

MSc. Ing. Euler Tito Chura 42


}
public void rasgar() {
System.out.println("El gato esta rasgando");
}
public Gato(String nombre,String raza) {
this.nombre=nombre;
this.raza=raza;
System.out.println("\nGato creado");
}

public static void main(String args[])


{
Gato gato1=new Gato("Batman","Angora");
gato1.respirar();
gato1.maullar();
gato1.rasgar();
gato1.dormir();
}
}

En la clase Gato muestra el uso de la herencia en este ejemplo, como puede


verse la clase Gato no incorpora explícitamente los atributos nombre y raza,
estos son heredados directamente por la clase Animal. Como dijimos en el
capitulo uno, también los métodos son heredados, esto se puede ver en las
llamadas a los métodos respirar y dormir. He aquí la salida del programa:

El animal es totalmente Rebelde

Gato creado
El animal respira
El gato esta maullando
El gato esta rasgando
El animal duerme

Hace falta aun notar un punto importante en este programa, al observar la


salida del programa anterior nos encontramos en la primera linea: “El animal es
totalmente Rebelde”, Esta línea muestra que en la herencia se crean los
objetos correspondientes que se encuentran el la cima del árbol jerárquico, en
este caso antes de haber creado un Gato fue necesario crear primero un objeto
de tipo Animal, se invoca al constructor por default de la clase animal, debido a
que la clase gato no invoca de manera explicita ningún constructor. Invocar
explícitamente a un constructor es posible mediante el uso de la palabra
reservada super.

La palabra reservada super

Como ya dijimos, una vez creado un objeto de tipo Gato se creará, en primera
instancia, un objeto tipo Animal, el programa anterior crea este objeto por
medio del constructor por default, pero ¿Por qué no crear el objeto Animal
llamando otro constructor? Si usamos el segundo constructor de animal
podemos inicializar las variables nombre y raza de manera automática, para

MSc. Ing. Euler Tito Chura 43


invocar a un constructor en específico debemos hacer uso de la palabra super.
Modificando el programa anterior tenemos:

//Animal.java
public class Animal2 {

String raza;
String nombre;
int edad;
String tamaño;
String tipoDePelaje;

public Animal2(){
System.out.println("El animal es totalmente Rebelde");
}

public Animal2(String nombre, String raza){


this.nombre=nombre;
this.raza= nombre;
System.out.println("En el constructor llamado por super");
}

public void comer() {


System.out.println("Alimentando al animal");
}

public void respirar() {


System.out.println("El animal respira");
}

public void reproduccion() {


System.out.println("El animal puede reproducirse");
}

public void dormir() {


System.out.println("El animal duerme");
}
}

public class Gato2 extends Animal2 {


int numVidas=7;
String tipoDeComida;
public void maullar() {
System.out.println("El gato esta maullando");
}
public void rasgar() {
System.out.println("El gato esta rasgando");
}
public Gato2(String nombre,String raza) {
super(nombre, raza);
System.out.println("\nGato creado");
}

public static void main(String args[])


{

MSc. Ing. Euler Tito Chura 44


Gato2 gato1=new Gato2("Batman","Angora");
gato1.respirar();
gato1.maullar();
gato1.rasgar();
gato1.dormir();

}
}

Hemos agregado la llamada al constructor por medio de super en método


constructor de Gato, cabe señalar que super buscará un constructor que
contenga ese tipo de parámetros, de no existir, la compilación no tendrá éxito.
Cuando se usa super de esta manera debe ser la primera instrucción en
aparecen en el constructor. La salida del programa se muestra a
continuación:
En el constructor llamado por super

Gato creado
El animal respira
El gato esta maullando
El gato esta rasgando
El animal duerme

Sobrecarga y sobreescritura de métodos

La firma de un método es la combinación del tipo de dato que regresa, su


nombre y su lista de argumentos.

La sobrecarga de métodos es la creación de varios métodos con el mismo


nombre pero con diferentes firmas y definiciones. Java utiliza el número y tipo
de argumentos para seleccionar cuál definición de método ejecutar.

Java diferencia los métodos sobrecargados con base en el número y tipo de


argumentos que tiene el método y no por el tipo que devuelve.

También existe la sobrecarga de constructores: Cuando en una clase existen


constructores múltiples, se dice que hay sobrecarga de constructores. La
sobrecarga de constructores ya la hemos manejado en algunos ejemplos de
este manual, a continuación se muestra un ejemplo que ilustra la sobrecarga
de constructores.

//SobreCarga.java
public class SobreCarga{
public SobreCarga(){
System.out.println("Soy un objeto creado por el constructor sin argumentos");
}
public SobreCarga(int num){
System.out.println("Soy un objeto creado por el constructor con un argumento
int= "+num);
}
public SobreCarga(String cad){

MSc. Ing. Euler Tito Chura 45


System.out.println("Soy un objeto creado por el constructor con un argumento
String= "+cad);
}
public SobreCarga(char c,int num,String cad){
System.out.println("Soy un objeto creado por el constructor con tres
argumentos char= "+c+" ,int= "+num+" ,String= "+cad);
}
public static void main(String[] args){
new SobreCarga(2);
new SobreCarga("Hola enfermera");
new SobreCarga();
new SobreCarga('Z',7,"No hay papel");
new SobreCarga(9);
}
}

Sobrescritura de Métodos.
Una subclase hereda todos los métodos de su superclase que son accesibles a
dicha subclase a menos que la subclase sobrescriba los métodos.

Una subclase sobrescribe un método de su superclase cuando define un


método con las mismas características (nombre, número y tipo de argumentos)
que el método de la superclase.

Las subclases emplean la sobre-escritura de métodos la mayoría de las veces


para agregar o modificar la funcionalidad del método heredado de la clase
padre. Como ejemplo, regresemos al ejemplo de la clase Animal y Gato. Esta
vez la Clase Gato sobrescribirá el método dormir de la clase Animal cuyo
código no variara con respecto a la última versión, es decir Animal2.

//Gato3.java
public class Gato3 extends Animal2 {
int numVidas=7;
String tipoDeComida;
public void maullar() {
System.out.println("El gato esta maullando");
}
public void rasgar() {
System.out.println("El gato esta rasgando");
}
public Gato3(String nombre,String raza) {
super(nombre, raza);
System.out.println("\nGato creado");
}

public void dormir()


{
System.out.println("El gato esta durmiendo, no molestar");
}

public static void main(String args[])


{
Gato3 gato1=new Gato3("Batman","Angora");
gato1.respirar();

MSc. Ing. Euler Tito Chura 46


gato1.maullar();
gato1.rasgar();
gato1.dormir();

}
}

He aquí la Salida:
En el constructor llamado por super

Gato creado
El animal respira
El gato esta maullando
El gato esta rasgando
El gato esta durmiendo, no molestar

Observe que la última línea ha cambiado por la sobre-escritura del método


dormir. Ahora modifiquemos la clase Gato, esta vez agregaremos la siguiente
línea:

super.dormir();

Justo antes de la línea que imprime: “El gato esta durmiendo, no molestar”. Es
decir:

public void dormir()


{
super.dormir();
System.out.println("El gato esta durmiendo, no molestar");
}

Esta es otra forma de usar super, en la cual se ejecuta un método de la clase


Padre o superclase. Al usar super de esta manera, no hay ninguna restricción
del lugar donde se haga la llamada al método.

Conversión hacia arriba (upcasting)

Hasta ahora, podemos pensar que el aspecto más importante acerca de la


herencia, es que podemos heredar métodos a nuestra clase hija. Sin embargo,
la herencia es importante por la relación que se crea entre la clase padre y la
clase hija.

Veamos un ejemplo, consideremos como clase base Instrumento que


representa instrumentos musicales, y una clase derivada Viento. Como
sabemos, la herencia implica que todos los métodos de la clase padre estarán
disponibles en la clase hija; entonces; cualquier mensaje que le enviemos a la
clase padre podrá ser enviado a la clase hija.

//Instrumento.java
//Herencia y upcasting
public class Instrumento{

MSc. Ing. Euler Tito Chura 47


public void play(){}
public static void tune(Instrumento i){
//…
i.play();
}
}

//Viento.java
//Los instrumentos de Viento son instrumentos!
//porque tienen la misma interfaz
public class Viento extends Instrumento{
public static void main(String[] args){
Viento flauta=new Viento();
Instrumento.tune(flauta); //Upcasting
}
}

Vemos en el ejemplo lo siguiente: el método tune() tiene como argumento un


objeto Instrumento. Sin embargo, en el método Viento.main() el método
tune() es llamado con una referencia de tipo Viento. Como podemos
comprobar, los objetos de tipo Viento también son objetos de tipo
Instrumento.

Vemos que el upcasting tiene sentido ya que partimos de una clase más
específica a una más general, por lo que se cumple la regla. La clase hija podrá
tener más métodos que la clase padre, sin embargo, debe contener por lo
menos los métodos de la clase padre.

La palabra clave final

La palabra clave final de Java tiene significados ligeramente diferentes


dependiendo del contexto, pero en general dice: “Esto no puede cambiarse”.
Se podría querer evitar cambios por dos razones: diseño o eficiencia. Dado que
estas dos razones son bastantes diferentes, es posible utilizar erróneamente la
palabra clave final.

Para Datos

Una variable o atributo puede ser una constante que deseamos no cambia
nunca en nuestro programa, esto se puede realizar anteponiendo la palabra
final a la declaración de una variable. Utilizar constantes declaradas por final
puede eliminar parte de la sobrecarga en tiempo de ejecución de un programa.

Al usar final con referencias a objetos en vez que con datos primitivos, su
significado se vuelve algo confuso. Con un dato primitivo, final convierte el
valor en constante, pero con una referencia a un objeto, final hace de la
referencia una constante. Una vez que la referencia se inicializa a un objeto,
ésta nunca se puede cambiar para que apunte a otro objeto. Sin embargo se
puede modificar el objeto en sí; Java no proporciona ninguna manera de
convertir un objeto arbitrario en una constante.

MSc. Ing. Euler Tito Chura 48


He aquí un ejemplo que muestra el funcionamiento de los campos final:

//Valor.java
public class Valor {
int i = 1;
}

//DatosConstantes.java
public class DatosConstantes {
//Pueden ser constantes en tiempo de compilacion
final int variable1 = 9;
static final int VAL_DOS=99;
//Tipica constante publica
public static final int VAL_TRES=39;
//No pueden ser constantes en tiempo de compilacion
final int variable4= (int)(Math.random()*20);
static final int variable5=(int)(Math.random()*20);

Valor v1= new Valor();


final Valor v2 = new Valor();
static final Valor v3 = new Valor();
//Arrays:
final int[] a= {1,2,3,4,5,6};

public void escribir(String id)


{
System.out.println(id+" : variable4 ="+variable4+ ", variable5 ="+variable5);
}

public static void main(String[] args)


{
DatosConstantes fd1= new DatosConstantes();
//! fd1.variable1++; //Error: No se puede cambiar el valor
fd1.v2.i++; //El objeto no es constante
fd1.v1= new Valor(); //OK, el Objeto no es final
for(int i=0;i< fd1.a.length;i++)
fd1.a[i]++;
//! fd1.v2 = new Valor(); // No se puede
//! fd1.v3 = new valor3(); //Cambiar la referencia
//! fd1.a= new int[3];

fd1.escribir("fd1");
System.out.println("Creando un nuevo DatosConstantes");
DatosConstantes fd2= new DatosConstantes();
fd1.escribir("fd1");
fd2.escribir("fd2");

}
}

Nota que los datos primitivos static final, se escriben en mayúsculas por
convención. Una posible salida del programa se muestra a continuación:

fd1 : variable4 =12, variable5 =14


Creando un nuevo DatosConstantes
fd1 : variable4 =12, variable5 =14

MSc. Ing. Euler Tito Chura 49


fd2 : variable4 =19, variable5 =14

Fíjese que los valores de variable4 para fd1 y fd2 son únicos, pero el valor
variable5 no ha cambiado al crear el segundo objeto DatosConstantes. Esto
es porque es estático y se inicializa una vez en el momento de la carga y no
cada vez que se crea un nuevo objeto.

Las variables v2 y v3 demuestran el significado de una referencia final. Como


se puede ver en main( ), justo porque v2 sea final, no significa que no pueda
cambiar su valor. Sin embargo, no se puede reubicar v2 a un nuevo objeto,
precisamente por que es final. Esto es lo que final significa para un referencia.

Constantes Blancas.

Java permite la creación de constantes blancas, que son campos declarados


como final pero a los que no se da un valor de inicialización. En cualquier caso,
se debe inicializar una constante blanca antes de utilizarla, y esto lo asegura el
propio compilador. Sin embargo, las constantes blancas proporcionan mucha
mayor flexibilidad en el uso de la palabra clave final puesto que, por ejemplo,
un campo final incluido en una clase puede ahora ser diferente para cada
objeto, y sin embargo, sigue reteniendo su cualidad de inmutable. He aquí un
ejemplo:

//ConstanteBlanca.java
public class ConstanteBlanca {

final int i=0; //Constante inializada


final int j; // Constante blanca
final Elemento p; //Referencia a constante blanca

//Las constantes blancas DEBEN inicializarse en el constructor

public ConstanteBlanca(){
j=1; //Inicializa la constante blanca
p= new Elemento();
}
public ConstanteBlanca(int x){
j=x;//Inicializa la constante blanca
p=new Elemento();
}
public static void main(String args[])
{
ConstanteBlanca bf= new ConstanteBlanca();
}
}

MSc. Ing. Euler Tito Chura 50


Métodos Constantes

Hay dos razones que justifican los métodos constantes. La primera es poner un
“bloqueo” en el método para evitar que cualquier clase heredada varíe su
significado. Esto se hace por razones de diseño cuando uno se quiere asegurar
de que se mantenga el comportamiento del método durante la herencia,
evitando que sea sobrescrito.

La segunda razón para los métodos constantes es la eficiencia. Si se puede


hacer un método constante se ésta permitiendo al compilador convertir
cualquier llamada a ese método en llamadas rápidas.

Para que un método sea constante, basta con anteponer la palabra final en su
firma, ejemplo:

public final void nombreMetodo()


{
.
.
.
}

Clases Constantes

Cuando se dice que una clase entera es constante (precediendo su definición


de la palabra clave final), se establece que no se desea heredar de esta clase
o permitir a nadie más que lo haga. En otras palabras, por alguna razón el
diseño de la clase es tal que nunca hay necesidad de hacer cambios, o por
razones de seguridad no se desea la generación de subclases. De esta manera
alternativa, se pueden estar tratando aspectos de eficiencia, y hay que
asegurarse de que cualquier actividad involucrada con objetos de esta clase
sea lo más eficiente posible.

//Cerebro.java
public class CerebroPequenio {

//Dinosaorio.java
public final class Dinosaurio {
int i=7;
int j=1;
CerebroPequenio x= new CerebroPequenio();
public void f()
{}
}

//Jurasico.java
public class Jurasico {
public static void main(String args[])
{
Dinosaurio n= new Dinosaurio();

MSc. Ing. Euler Tito Chura 51


n.f();
n.i=40;
n.j++;
}
}

//public class SerEvolucionado extends Dinosaurio{


//} //Error: no se puede heredar de la clase constante.

MSc. Ing. Euler Tito Chura 52


6: Polimorfismo
El polimorfismo es la tercera característica esencial de un lenguaje orientado a
objetos. Es una herramienta que provee otra dimensión de interfaz, capaz de
separar el “qué” del “cómo”.

En el capítulo pasado aprendimos que con la herencia podemos tratar un


objeto como “tipo de” su clase padre. Esta habilidad es esencial porque permite
que objetos de varios tipos puedan ser tratados como objetos de un solo tipo,
todo en el mismo código para trabajar con todos los distintos tipos de manera
similar. El polimorfismo nos permite que distinguir entre los tipos de objetos que
son similares. Dicha diferencia se expresa a través del comportamiento de los
métodos que se heredan de la clase padre.

Veamos un ejemplo para recordar la conversión (Cast) hacia arriba:

//Nota.java
//Herencia y upcasting.
public class Nota{
private int valor;
private Nota(int val){ valor=val;}
public static final Nota DO_MAYOR=new Nota(0);
public static final Nota DO_SOSTENIDO=new Nota(1);
public static final Nota SI_BEMOL =new Nota(2);
}

//Instrumento2.java
public class Instrumento2{
public void play(Nota n){
System.out.println("Instrumento.play()");
}
}

//Viento2.java
//Los instrumentos de viento son también tipo Instrumento!
//porque tienen el mismo comportamiento.
public class Viento2 extends Instrumento2{
//Redefiniendo un método
public void play(Nota n){
System.out.println("Viento.play()");
}
}

//Musica2.java
public class Musica2{
public static void tonada(Instrumento2 i){
i.play(Nota.DO_SOSTENIDO);
}
public static void main(String[] args){
Viento2 flauta=new Viento2();
tonada(flauta); //Upcasting
}
}

MSc. Ing. Euler Tito Chura 53


El método Musica.tonada() acepta un objeto Instrumento como referencia,
pero también objetos derivado de éste. Por eso es que cualquier objeto Viento
es aceptable para dicho método, ya que Viento hereda de Instrumento. Este
programa parecería más directo sí el método tonada tuviera como argumento
un objeto de tipo Viento. Esto presenta un punto esencial: si se hiciera esto se
necesitará escribir un nuevo método tonada para cada tipo de Instrumento del
sistema. Supóngase que se sigue este razonamiento y se añaden los
instrumentos de Cuerda y Metal. Agregaremos las siguientes clases a nuestro
directorio, renombremos y modifiquemos la clase Musica2 por Musica3 como
se muestra a continuación:

//Metal.java
public class Metal extends Instrumento2{
//Redefiniendo un método
public void play(Nota n){
System.out.println("Metal.play()");
}
}

//Cuerda.java
public class Cuerda extends Instrumento2{
//Redefiniendo un método
public void play(Nota n){
System.out.println("Cuerda.play()");
}
}

//Musica3.java
public class Musica3{
public static void tonada(Viento2 v){
v.play(Nota.DO_SOSTENIDO);
}
public static void tonada(Cuerda c){
c.play(Nota.DO_SOSTENIDO);
}
public static void tonada(Metal m){
m.play(Nota.DO_SOSTENIDO);
}
public static void main(String[] args){
Viento2 f=new Viento2();
Cuerda c=new Cuerda();
Metal p=new Metal();
tonada(f);
tonada( c );
tonada( p );
}
}

Como podemos observar, en este ejemplo creamos un método para cada tipo
de objeto distinto. Nuestra primera impresión es que dicho código resulta
bastante largo debido a que repetimos una y otra vez la misma función.
Además resulta muy estático, dado que una vez que creemos un nuevo objeto
que herede de la clase Instrumento, tendremos que agregar una nueva

MSc. Ing. Euler Tito Chura 54


función. ¿ No sería más sencillo escribir un solo método que tome como
argumento a la clase base sin especificar el tipo de objeto en particular ?.

Regresemos al ejemplo de Musica.java. Es claro que la salida del programa es


Viento.play(), ya que el método tonada() recibe como argumento un objeto
Instrumento. Pero, ¿ cómo puede saber el compilador que el objeto que recibe
es Viento y no de otro tipo? La respuesta es la manera en que trabaja Java:
binding (ligadura). Expliquemos a grandes rasgos de en qué consiste este
concepto. Ligar la llamada de un método con el cuerpo de un método se llama
ligar (bind). Cuando el compilador realiza dicha acción antes de ejecutar un
código, se le conoce como early binding (ligadura temprana). Java utiliza una
alternativa llamada late binding (ligadura tardia), que significa que dicha
atadura ocurre en tiempo de compilación. A esta alternativa de binding se le
conoce también como dynamic binding (ligadura dinámica).

Todos los métodos en Java utilizan dicha técnica a menos que sean declarados
final. Dicho de otra forma, Java es capaz de reconocer el tipo de objeto que
será utilizado en un método gracias al dynamic binding.

Veamos un ejemplo clásico de la OOP. Consideremos la clase Figura y sus


clases hijas Círculo, Cuadrado y Triángulo. Este ejemplo es bastante
explícito ya que es bastante lógico decir: “un cuadrado es una figura”.

La frase anterior puede ser codificada correctamente de la siguiente manera:

Figura f = new Cuadrado();

En este ejemplo, un objeto Cuadrado es creado y el resultado es una


referencia asignada a Figura, lo cual parece incorrecto, sin embargo, y desde
la perspectiva anterior, “un Cuadrado es una figura”, por lo que en realidad la
sentencia es correcta. Ahora, supongamos que llamamos un método de la
clase padre:

f.Dibujar();

Podría suponerse que el método Dibujar() de Figura es llamado, sin embargo,


es el método de Cuadrado el que es llamado gracias al polimorfismo. Ahora
veamos el ejemplo en código Java:

//Figura.java
//Polimorfismo en Java
public class Figura{
void dibujar()
{
System.out.println("Dibujando una Figura");
}
void borrar()
{
System.out.println("Borrando una Figura");
}
}

MSc. Ing. Euler Tito Chura 55


//Circulo.java
public class Circulo extends Figura{
void dibujar(){
System.out.println("Circulo.dibujar()");
}
void borrar(){
System.out.println("Circulo.borrar()");
}
}

//Triangulo.java
public class Triangulo extends Figura{
void dibujar(){
System.out.println("Triangulo.dibujar()");
}
void borrar(){
System.out.println("Triangulo.borrar()");
}
}

//Cuadrado.java
public class Cuadrado extends Figura{
void dibujar(){
System.out.println("Cuadrado.dibujar()");
}
void borrar(){
System.out.println("Cuadrado.borrar()");
}
}

public class Figuras{


public static Figura figuraAleatoria(){
switch((int)(Math.random()*3)){
default:
case 0:
return new Circulo();
case 1:
return new Cuadrado();
case 2:
return new Triangulo();
}
}
public static void main(String[] args){
Figura[] s=new Figura[9];
//llenamos el arreglo de figures!
for(int i=0;i<s.length;i++)
s[i]=figuraAleatoria();
//Llamadas polimorficas
for(int i=0;i<s.length;i++)
s[i].dibujar();
}
}

La clase padre establece el comportamiento de las clases que la heredan. Es


decir, todas las subclases pueden borrar y dibujar. Cada subclase establece su
comportamiento particular para dichos métodos. En el ejemplo, se crean
objetos de manera aleatoria y se almacenan en un arreglo de objetos Figura.

MSc. Ing. Euler Tito Chura 56


Clases y métodos abstractos

En lo ejemplos de la clase Instrumento, los métodos declarados eran “falsos”,


su única intención era la de crear una interfaz común para todas las clases que
se deriven de Instrumento. Otra manera es llamar a la clase Instrumento, una
clase abstracta. Se crea una clase abstracta cuando se desea manipular un
conjunto de clases a través de una interfaz común.

Si se tiene una clase abstracta como instrumento, los objetos de esa clase casi
nunca tienen significado. Es decir, Instrumento simplemente tiene que
expresar la interfaz, y no una implementación particular, de forma que no tiene
sentido crear objetos de tipo Instrumento.

Java proporciona un mecanismo para hacer esto, denominado método


abstracto. Se trata de un método incompleto; tiene sólo declaración faltándole
los métodos. La sintaxis para una declaración de método abstracto es:

abstract void f ( );

Toda clase que contenga uno o más métodos abstractos, se califica de


abstracto. Con las clases abstractas tenemos las siguientes características:

• No se puede crear un objeto de una clase abstracta.


• Si una clase hereda de una clase abstracta, ésta debe implementar
todos los métodos abstractos o bien, seguir siendo abstracta.
• Una clase abstracta puede tener métodos no-abstractos y abstractos.
• Con un solo método abstracto, la clase debe ser declarada como
abstracta.

La clase instrumento puede convertirse fácilmente en una clase abstracta. Sólo


serán abstractos alguno de sus métodos.

//Instrumento4.java
//Clases abstractas y métodos.
abstract class Instrumento4{
int i;
public abstract void play();
public String quienSoy(){
return "Instrumento";
}
public abstract void adjust();
}

//Viento4.java
public class Viento4 extends Instrumento4{
public void play(){
System.out.println("Viento.play()");
}
public String quienSoy(){

MSc. Ing. Euler Tito Chura 57


return "Viento";
}
public void adjust(){}//Se implementa el body
}

//Cuerda.java
public class Cuerda4 extends Instrumento4{
public void play(){
System.out.println("Cuerda.play()");
}
public String quienSoy(){
return "Cuerda";
}
public void adjust(){}
}

//Percusion.java
public class Percusion4 extends Instrumento4{
public void play(){
System.out.println("Percusion.play()");
}
public String quienSoy(){
return "Percusion";
}
public void adjust(){}
}

//Flauta.java
public class Flauta4 extends Viento4{
public void play(){
System.out.println("Flauta.play()");
}
public String quienSoy(){
return "Flauta";
}
public void adjust(){ System.out.println("Flauta.adjust()");}
}

//Saxofon.java
public class Saxofon4 extends Viento4{
public void play(){
System.out.println("Saxofon.play()");
}
public String quienSoy(){
return "Saxofon";
}
}

//Musica4.java
public class Musica4{
static void tune(Instrumento4 i){
i.play();
}
static void tuneAll(Instrumento4[] e){
for(int i=0;i<e.length;i++)
tune(e[i]);
}
public static void main(String[] args){

MSc. Ing. Euler Tito Chura 58


Instrumento4[] orquesta=new Instrumento4[5];
orquesta[0]=new Viento4();
orquesta[1]=new Percusion4();
orquesta[2]=new Cuerda4();
orquesta[3]=new Flauta4();
orquesta[4]=new Saxofon4();
tuneAll(orquesta);
}
}

Interfaces y clases internas

Interfaces.

La palabra clave interfaz lleva el concepto de abstracción un paso más allá. Se


podría pensar que es una clase abstracta pura permite al creador establecer la
forma de una clase: nombres de métodos, listas de parámetros y tipos de
retorno, pero no cuerpos de método.

Una interfaz dice: “Ésta es la apariencia que tendrán todas las clases que
implementen esta interfaz”. Por consiguiente, cualquier código que use una
interfaz particular sabe qué métodos deberían ser invocados por esa interfaz, y
eso es todo.

Para crear una interfaz, se usa la palabra clave interface en vez de la palabra
clave class. Para hacer una clase que se ajuste a una interfaz particular (o a
un grupo de interfaces), se usa la palabra clave implements. Se esta diciendo
“La interfaz contiene la apariencia, pero ahora voy a decir cómo funciona”. Por
lo demás, es como la herencia. El ejemplo de los instrumentos utilizando
interfaces se muestra a continuación.

//Insterface.java
//Interfaces
interface Instrumento5{
int i=5;
//Los métodos no deben estar definidos.
void play();
String quienSoy();
void adjust();
}

//Viento5.java
public class Viento5 implements Instrumento5{
public void play(){
System.out.println("Viento.play()");
}
public String quienSoy()
{return "Viento";}
public void adjust(){}
}

public class Cuerda5 implements Instrumento5{


public void play(){

MSc. Ing. Euler Tito Chura 59


System.out.println("Viento.play()");
}
public String quienSoy(){return "Viento";}
public void adjust(){}
}

//Percusion5.java
public class Percusion5 implements Instrumento5{
public void play(){
System.out.println("Percusion.play()");
}
public String quienSoy(){return "Percusion";}
public void adjust(){}
}

//Flauta.java
public class Flauta5 extends Viento5{
public void play(){
System.out.println("Flauta.play()");
}
public String quienSoy(){
return "Flauta";
}
public void adjust(){ System.out.println("Flauta.adjust()");}
}

//Saxofon.java
public class Saxofon5 extends Viento5{
public void play(){
System.out.println("Saxofon.play()");
}
public String quienSoy(){
return "Saxofon";
}
}

//Musica5.java
public class Musica5{
static void tune(Instrumento5 i){
i.play();
}
static void tuneAll(Instrumento5[] e){
for(int i=0;i<e.length;i++)
tune(e[i]);
}
public static void main(String[] args){
Instrumento5[] orquesta=new Instrumento5[5];
int i=0;
orquesta[i++]=new Viento5();
orquesta[i++]=new Percusion5();
orquesta[i++]=new Cuerda5();
orquesta[i++]=new Flauta5();
orquesta[i++]=new Saxofon5();
tuneAll(orquesta);
}
}

MSc. Ing. Euler Tito Chura 60


Extender una interfaz con herencia.

Podemos fácilmente añadir un nuevo método a una interfaz usando herencia, y


también podemos combinar muchas interfaces con una nueva interfaz con
ayuda de la herencia:

//Monstruo.java
//Extendiendo una interfaz con herencia
public interface Monstruo{
void amenaza();
}

//MosntruoPeligroso.java
public interface MonstruoPeligroso extends Monstruo{
void destruye();
}

//Letal.java
public interface Letal{
void mata();
}

//Vampiro.java
interface Vampiro extends MonstruoPeligroso,Letal{
void ChupaSangre();
}

//Dragon.java
public class Dragon implements MonstruoPeligroso{
public void amenaza(){}
public void destruye(){}
}

//ShowDeHorror.java
public class ShowDeHorror {
static void u(Monstruo b){ b.amenaza();}
static void v(MonstruoPeligroso d){
d.amenaza();
d.destruye();
}
public static void main(String[] args){
Dragon barney=new Dragon();
u(barney);
v(barney);
}
}

Clases Internas:

Es posible colocar una definición de clase dentro de otra definición de clase. A


la primera se le denomina clase interna. Este tipo de clases son una

MSc. Ing. Euler Tito Chura 61


característica importante. Este tipo de clases son una característica valiosa,
pues permite agrupar clases que lógicamente están relacionadas una de otra.
Se crea una clase interna como uno esperaría, ubicando su definición dentro
del envolvente.

//Paquete1.java
//Creando clases internas
public class Paquete1{
class Contenidos{
private int i=11;
public int valor(){ return i;}
}
class Destino{
private String etiqueta;
Destino(String adonde){
etiqueta=adonde;
}
String leerEtiqueta(){ return etiqueta;}
}
public void enviar(String dest){
Contenidos c=new Contenidos();
Destino d=new Destino(dest);
System.out.println(d.leerEtiqueta());
}
public static void main(String[] args){
Paquete1 p=new Paquete1 ();
p.enviar("Tanzania");
}
}

Las clases internas, cuando se usan dentro de enviar tiene la misma apariencia
que muchas otras clases. Aquí, la única diferencia práctica es que los nombres
se anidan dentro de Paquete1. Generalmente, la clase externa tendrá un
método que devuelva una referencia a una clase interna, como esta:

//Paquete2.java
//Creando clases internas
public class Paquete2{
class Contenidos{
private int i=11;
public int valor(){ return i;}
}
class Destino{
private String etiqueta;
Destino(String aDonde){
etiqueta=aDonde;
}
String leerEtiqueta(){ return etiqueta;}
}
public Destino para(String s)
{
return new Destino(s);
}
public Contenidos cont()

MSc. Ing. Euler Tito Chura 62


{
return new Contenidos();
}
public void enviar(String dest){
Contenidos c= cont();
Destino d=para(dest);
System.out.println(d.leerEtiqueta());
}
public static void main(String[] args){
Paquete2 p=new Paquete2 ();
p.enviar("Tanzania");
Paquete2 q=new Paquete2();
//Definir referencias a clases internas
Paquete2.Contenidos c= q.cont();
Paquete2.Destino d= q.para("Borneo");
}
}

MSc. Ing. Euler Tito Chura 63


7:Paquetes.
Para hacer que una clase sea más fácil de localizar y utilizar así como evitar
conflictos de nombres y controlar el acceso a los miembros de una clase, las
clases se agrupan en paquetes.

• Paquete

Un paquete es un conjunto de clases e interfaces relacionadas.

La forma general de la declaración package es la siguiente:

package nombrePaquete;

Donde nombrePaquete puede constar de una sola palabra o de una lista de nombres de
paquetes separados por puntos.

Ejemplo

package miPaquete;

class MiClase
{
...
}

Ejemplo

package nombre1.nombre2.miPaquete;

class TuClase
{
...
}

Los nombres de los paquetes se corresponden con nombre de directorios en el sistema


de archivos.

De esta manera, cuando se requiera hacer uso de estas clases se tendrán que importar de
la siguiente manera.
Ejemplo

import miPaquete.MiClase;
import nombre1.nombre2.miPaquete.TuClase;

class OtraClase
{
/* Aqui se hace uso de la clase 'Miclase' y de la
clase 'TuClase' */
...
}

MSc. Ing. Euler Tito Chura 64


Para importar todas las clases que están en un paquete, se utiliza el asterisco ( * ).
Ejemplo

import miPaquete.*;

Si no se utiliza la sentencia package para indicar a que paquete pertenece una clase, ésta
terminará en el package por default, el cual es un paquete que no tiene nombre.
Ejemplo:

package paquete1;

public class ClaseEnPaquete {


int prueba;
public void algunMetodo()
{
System.out.println("Prueba de paquete");
}
public static void main(String args[])
{
ClaseEnPaquete a=new ClaseEnPaquete();
a.algunMetodo();
}
}
Para compilar este clase ejecutar la siguiente sentencia:
javac –d . ClaseEnPaquete.java

Donde el punto (.) a indica que se crearan los directorios a partir del directorio actual.

Para ejecutar esta clase podemos escribir:


java paquete1.ClaseEnPaquete

Modificadores de Acceso
Los modificadores más importantes desde el punto de vista del diseño de clases y
objetos, son los que permiten controlar la visibilidad y acceso a los métodos y variables
que están dentro de una clase.

Uno de los beneficios de las clases, es que pueden proteger a sus variables y métodos
(tanto de instancia como de clase) del acceso desde otras clases.

Java soporta cuatro niveles de acceso a variables y métodos. En orden, del más público
al menos público son: público (public), protegido (protected), sin modificador (también
conocido como package) y privado (private).

La siguiente tabla muestra el nivel de acceso permitido por cada modificador:

public protected (sin modificador) private

MSc. Ing. Euler Tito Chura 65


Clase SI SI SI SI

Subclase en
SI SI SI NO
el mismo paquete

No-Subclase en
SI SI SI NO
el mismo paquete

Subclase en
SI SI/NO (*) NO NO
diferente paquete

No-Subclase en
diferente paquete SI NO NO NO
(Universo)

(*) Los miembros (variables y metodos) de clase (static) si son visibles. Los miembros
de instancia no son visibles.
Como se observa de la tabla anterior, una clase se ve a ella misma todo tipo de variables
y métodos (desde los public hasta los private); las demas clases del mismo paquete (ya
sean subclases o no) tienen acceso a los miembros desde los public hasta los sin-
modificador. Las subclases de otros paquetes pueden ver los miembros public y a los
miembros protected, éstos últimos siempre que sean static ya de no ser así no serán
visibles en la subclase (Esto se explica en la siguiente página). El resto del universo de
clases (que no sean ni del mismo paquete ni subclases) pueden ver sólo los miembros
public.

Ejemplo:
//ClaseInicial.java
package paq01;
public class ClaseInicial
{
public int a = 1;
protected int b = 2;
int c = 3; //es amigable
private int d = 4;

public void metodoPublic()


{
System.out.println("En el metodo public");
}
protected void metodoProtected()
{
System.out.println("En el metodo protected");
}
void metodo()
{
System.out.println("En el metodo sin modificador");
}
private void metodoPrivate()
{
System.out.println("En el metodo private");
}

MSc. Ing. Euler Tito Chura 66


public static void main(String arg[])
{
ClaseInicial obj = new ClaseInicial();
System.out.println("a = " + obj.a);
obj.metodoPublic();
System.out.println("b = " + obj.b);
obj.metodoProtected();
System.out.println("c = " + obj.c);
obj.metodo();
System.out.println("d = " + obj.d);
obj.metodoPrivate();
}
}

// ClaseHijaEnDiferentePaquete.java
package paq02;
import paq01.*;
public class ClaseHijaEnDiferentePaquete extends ClaseInicial
{
public static void main(String arg[])
{
ClaseInicial obj = new ClaseInicial();
System.out.println("a = " + obj.a);
obj.metodoPublic();
/*
System.out.println("b = " + obj.b);
obj.metodoProtected();
System.out.println("c = " + obj.c);
obj.metodo();
System.out.println("d = " + obj.d);
obj.metodoPrivate();
*/
}
}
// ClaseHijaEnMismoPaquete.java
package paq01;

public class ClaseHijaEnMismoPaquete extends ClaseInicial


{
public static void main(String arg[])
{
ClaseInicial obj = new ClaseInicial();
System.out.println("a = " + obj.a);
obj.metodoPublic();
System.out.println("b = " + obj.b);
obj.metodoProtected();
System.out.println("c = " + obj.c);
obj.metodo();
//System.out.println("d = " + obj.d);
//obj.metodoPrivate();
}
}
// ClaseNoHijaEnDiferentePaquete.java
package paq02;
import paq01.ClaseInicial;
public class ClaseNoHijaEnDiferentePaquete
{
public static void main(String arg[])

MSc. Ing. Euler Tito Chura 67


{
ClaseInicial obj = new ClaseInicial();
System.out.println("a = " + obj.a);
obj.metodoPublic();
/*
System.out.println("b = " + obj.b);
obj.metodoProtected();
System.out.println("c = " + obj.c);
obj.metodo();
System.out.println("d = " + obj.d);
obj.metodoPrivate();
*/
}
}
// ClaseNoHijaEnMismoPaquete.java
package paq01;
public class ClaseNoHijaEnMismoPaquete
{
public static void main(String arg[])
{
ClaseInicial obj = new ClaseInicial();
System.out.println("a = " + obj.a);
obj.metodoPublic();
System.out.println("b = " + obj.b);
obj.metodoProtected();
System.out.println("c = " + obj.c);
obj.metodo();
//System.out.println("d = " + obj.d);
//obj.metodoPrivate();
}
}

Para ejecutar el ejemplo, compilar y ejecutar cada clase por separado.

MSc. Ing. Euler Tito Chura 68


Apéndice A: Breve historia de Java
Para apreciar el significado e importancia de Java, es muy importante conocer
su lugar de origen y cuales fueron sus propósitos: En Diciembre de 1990,
Patrick Naughton, un empleado de la empresa Sun, reclutó a sus colegas
James Gosling y Mike Sheridan para trabajar sobre un nuevo tema conocido
como "El proyecto verde". Este a su vez estaba auspiciado por la compañía
"Sun founder Hill Joy" y tenía como objetivo principal crear un lenguaje de
programación accesible, fácil de aprender y de usar, que fuera universal, y que
estuviera basado en un ambiente C++ ya que había mucha frustración por la
complejidad y las limitaciones de los lenguajes de programación existentes.

En abril de 1991, el equipo decidió introducir sistemas de software con


aplicaciones para consumidores smart como plataforma de lanzamiento para
su proyecto. James Gosling escribió el compilador original y lo denominó "Oak",
y con la ayuda de los otros miembros del equipo desarrollaron un decodificador
que mas tarde se convertiría en lenguaje Java. Para 1992, el equipo ya había
desarrollado un sistema prototipo conocido como "*7", que era una especie de
cruce entre un asistente digital personalizado y un mecanismo inteligente de
control remoto.

Por su parte el presidente de la compañía Sun, Scott McNealy, se dio cuenta


en forma muy oportuna y estableció el Proyecto Verde como una subsidiaria de
Sun. De 1993 a 1994, el equipo de Naughton se lanzó en busca de nuevas
oportunidades en el mercado, mismas que se fueron dando mediante el
sistema operativo base. La incipiente subsidiaria fracasó en sus intentos de
ganar una oferta con Time-Warner, sin embargo el equipo concluyó que el
mercado para consumidores electrónicos smart y las cajas Set-Up en
particular, no eran del todo eficaces. La subsidiaria Proyecto Verde fue
amortizada por la compañía Sun a mediados del 94’.

Afortunadamente, el cese del Proyecto Verde coincidió con el nacimiento del


fenómeno mundial Web. Al examinar las dinámicas de Internet, lo realizado por
el ex equipo verde se adecuaba a este nuevo ambiente ya que cumplía con los
mismos requerimientos de las settop box OS que estaban diseñadas con un
código de plataforma independiente pero sin dejar de ser pequeñas y
confiables. Patrick Naugthon procedió a la construcción del lenguaje de
programación Java que se accionaba con un browser prototipo, más tarde se le
fueron incorporando algunas mejoras y el browser Hot Java fue dado a conocer
al mundo en 1995. Con el paso del tiempo el Hot Java se convirtió en un
concepto práctico dentro del leguaje Java y demostró que podría proporcionar
una forma segura multiplataforma para que el código pueda ser bajado y
corrido del Host del World Wide Web y que de otra forma no son seguros.

Una de las características más atractivas del Hot Java fue su soporte para los
"applets", que son las partes del código Java que pueden ser cargadas
mediante una red de trabajo para después ejecutarlo localmente y así lograr o
alcanzar soluciones dinámicas en computación acordes al rápido crecimiento
del ambiente Web.

MSc. Ing. Euler Tito Chura 69


Para dedicarse al desarrollo de productos basados en la tecnología Java, Sun
formó la empresa Java Soft en enero de 1996, de esta forma de se dio
continuidad al fortalecimiento del programa del lenguaje Java y así trabajar con
terceras partes para crear aplicaciones, herramientas, sistemas de plataforma y
servicios para aumentar las capacidades del lenguaje.

Durante ese mismo mes, Java Soft dio a conocer el Java Developmet Kit (JDK)
1.0, una rudimentaria colección de componentes básicos para ayudar a los
usuarios de software a construir aplicaciones de Java. Dicha colección incluía
el compilador Java, un visualizador de applets, un debugger prototipo y una
máquina virtual Java(JVM), necesaria para correr programas basados en Java,
también incluía paquetería básica de gráficos, sonido, animación y trabajo en
red.

Asimismo el Netscape Comunications Inc, mostró las ventajas de Java y


rápidamente se asoció con Java Soft para explotar su nueva tecno logía. No
pasó mucho tiempo antes de que Netscape Communications decidiera apoyar
a los Java applets en Netscape Navigator 2.0. Este fue el factor clave que lanzó
a Java a ser reconocido y famoso, y que a su vez forzó a otros vendedores
para apoyar el soporte de applets en Java. Como parte de su estrategia de
crecimiento mundial y para favorecer la promoción de su nueva tecnología,
Java Soft otorgó permisos a otras compañías para que pudieran tener acceso
al código fuente de Java y al mismo tiempo mejorar sus navegadores, dicha
licencia también les permitía crear herramientas de desarrollo para
programación Java y los facultaba para acondicionar Máquinas Virtuales Java
(JVM), a varios sistemas operativos.

Muy pronto las licencias o permisos contemplaban a prestigiadas firmas como


IBM, Microsoft, Symantec, Silicon Graphics, Oracle, Toshiba y por supuesto
Novell. Desde su aparición, Java se ha ganado una impresionante cantidad de
apoyo. Virtualmente cada vendedor importante de software ha obtenido
autorización de Java y ahora ha sido incorporado en los principales sistemas
operativos base de PC’s de escritorio hasta estaciones de trabajo UNIX.

Un gran número de nuevas empresas ya están preparadas para recibir a la Ola


Java o para ingresar a los Mercados de software basados en Java, en algunos
casos como "Marimba´s
Castanet" se han concebido desde un principio con bases de tecnología Java
para Internet y han sido autorizados bajo licencia de Netscape para poner al
corriente "netcast", un producto informativo para PC’s de escritorio. Los nuevos
proyectos de Java son co-patrocinados por cientos de millones de dólares en
capital disponible de recursos tales como la Fundación Java, un fondo común
de capital formado el verano pasado por 11 compañías, incluyendo Cisco
Systems, IBM, Netscape y Oracle. Los Colegios y Universidades alrededor del
mundo están adoptando Java como un lenguaje universal y de enseñanza
indispensable, hoy en día existen más de 150 libros en Java que se están
imprimiendo en este momento.

MSc. Ing. Euler Tito Chura 70


En un reciente estudio se encontró que el 60% de los empresarios están
usando Java y el
40% expresaron que Java representa la solución estratégica que estaban
buscando para sus negocios..
Para darse una idea de la rápida aceptación que tiene Java en el mundo,
tenemos el ejemplo de las conferencias "Java Soft Java One" en San
Francisco, el primer Java One fue celebrado en abril de 1996 y atrajo a 5000
usuarios, un año después, en la segunda conferencia Java One albergó a
10,000 usuarios, asistentes. Java Soft estima que el número actual de usuarios
Java llega a 400 mil y sigue creciendo. Java también está ganando aceptación
en el área empresarial, se ha estimado que actualmente las compañías de hoy
que cuentan con más de 5000 empleados, una tercera parte están usando
Java.

MSc. Ing. Euler Tito Chura 71

También podría gustarte