You are on page 1of 104

CUESTIONARIO UNIDAD 5

1. DEFINE EL CONCEPTO DE IMPLEMENTACIÓN


E ILUSTRE CINCO EJEMPLOS DE ELLO

Después de declarar una clase se deben implementar (escribir el código de) sus
funciones y procedimientos, así como su constructor y su destructor.

El código de las funciones y procedimientos de una clase se escribe igual que el


de las funciones y procedimientos habituales, teniendo únicamente en cuenta
que el nombre de la función o procedimiento que se debe indicar será:

Nombre_Clase.Nombre_Procedimiento_o_Funcion

Es decir, el nombre de la clase seguido de un punto y del nombre del


procedimiento o función.

Por su parte, el constructor y el destructor se implementan de la misma forma y


como si fueran procedimientos, pero utilizando las instrucciones constructor y
destructor respectivamente en vez de la instrucción procedimiento.

Todo esto se ve en los ejemplos que siguen.

Ejemplo: Creación de una clase TPregunta para encapsular las preguntas de


la prospección

El siguiente ejemplo es especialmente interesante, pues implementa al completo


una clase que permite trabajar con las preguntas de la prospección a partir de
unos objetos que las encapsulan y que hacen el código especialmente legible.

Se incluye un cuerpo principal que realiza tres preguntas correspondientes al


nombre, primer apellido y segundo apellido del interlocutor (se entiende que
son de tipo texto) y finalmente monta el nombre completo en otro campo de la
prospección (también de tipo texto), a partir de la concatenación de los tres
primeros

//=============
TYPE
//=============

TPregunta = clase

protegido
_CodPregunta: cadena;
_CodCampo: cadena;
funcion _LeeValor(): variante;
procedimiento _EscribeValor(_valor: variante);
publico

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

constructor Crear(p, c: cadena);


destructor Destruir();
procedimiento Pregunta();
propiedad valor: variante leer _LeeValor
escribir _EscribeValor;
fin;

//=============================
// IMPLEMENTACION DE TPregunta
//=============================

//------------------------------------------------------------------
constructor TPregunta.Crear(p, c: cadena);
//------------------------------------------------------------------
inicio
_CodPregunta := p;
_CodCampo := c;
fin;

//------------------------------------------------------------------
destructor TPregunta.Destruir();
//------------------------------------------------------------------
inicio
// Nada a hacer
fin;

//------------------------------------------------------------------
funcion TPregunta._LeeValor(): variante;
//------------------------------------------------------------------
inicio
resultado := ValorProspeccion(_CodCampo);
fin;

//------------------------------------------------------------------
procedimiento TPregunta._EscribeValor(_valor: variante);
//------------------------------------------------------------------
inicio
AsignarValorProspeccion(_CodCampo, _valor);
fin;

//------------------------------------------------------------------
procedimiento TPregunta.Pregunta();
//------------------------------------------------------------------
inicio
Preguntar(_CodPregunta);
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

fin;

//========================================================
=========
procedimiento DestruyePreguntas( pregs: tabla de TPregunta);
//========================================================
=========
//
// Destruye un array de TPregunta, una a una.
//
var
i: entero;
inicio

Para i:=low(pregs) hasta high(pregs) hacer


pregs[i].Destruir();
fin;

//====
VAR
//====
Nombre, Apellido1, Apellido2, NombreCompleto: TPregunta;
// Preguntas de la prospección

//=================
// CODIGO PRINCIPAL
//=================
INICIO

// Inicializamos las preguntas


Nombre := TPregunta.Crear( 'P1', 'C1');
Apellido1 := TPregunta.Crear( 'P2', 'C2');
Apellido2 := TPregunta.Crear( 'P3', 'C3');
NombreCompleto := TPregunta.Crear( '', 'C4');

// Se realizan las preguntas


Nombre.Pregunta();
Apellido1.Pregunta();
Apellido2.Pregunta();

// Montamos el nombre completo


NombreCompleto.Valor := cadena(Nombre.Valor) + ' ' +
cadena(Apellido1.Valor) + ' ' +
Apellido2.Valor;

Aviso('El nombre completo es: ' + NombreCompleto.Valor);

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

// Destruimos los objetos de las preguntas


DestruyePreguntas( [Nombre, Apellido1, Apellido2,
NombreCompleto]);

FinProspeccion(Cierto, '1');

FIN.

Otros ejemplos

En este primer ejemplo adicional, se declara e implementa una clase cuya


utilidad sería poder leer los registros de un cierto fichero de productos de un
determinado proyecto:

(...)

TIPO

TProducto = Clase
Privado
_RegId: entero;
_HaCambiado: booleano;
funcion _ValorCodigo(): cadena;
funcion _ValorDescripcion(): cadena;
funcion _ValorFamilia(): entero;
funcion _ValorPrecio(): real;
funcion _NoSeleccionar(): booleano;
funcion _ValorOID(): entero;
funcion _LeerHaCambiado(): booleano;
procedimiento _AsignarOID(_OID: entero);
Publico
constructor Crear();
destructor Destruir();

propiedad Codigo: cadena leer _ValorCodigo;


propiedad Descripcion: cadena leer _ValorDescripcion;
propiedad Familia: entero leer _ValorFamilia;
propiedad Precio: real leer _ValorPrecio;
propiedad NoSeleccionar: booleano leer _NoSeleccionar;
propiedad OID: entero leer _ValorOID escribir _AsignarOID;
propiedad HaCambiado: booleano leer _LeerHaCambiado;
fin;

//***************************************//
//** Implementación de clase TProducto **//
//***************************************//

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

constructor TProducto.Crear();
inicio
_RegId := 0;
fin;

destructor TProducto.Destruir();
inicio
Si _RegId <> 0 entonces
LiberarRegistro(_RegId);
fin;

funcion TProducto._ValorFamilia(): entero;


inicio
Si _RegId = 0 entonces
Resultado := 0
sino inicio
Resultado := ValorRegistro(_RegId, CodConsultaFamilias + 'C4');
fin;
fin;

funcion TProducto._ValorPrecio(): real;


inicio
Si _RegId = 0 entonces
Resultado := 0
sino
Resultado := ValorRegistro(_RegId, 'C3');
fin;

funcion TProducto._NoSeleccionar(): booleano;


inicio
Si _RegId = 0 entonces
Resultado := Falso
sino
Resultado := ValorRegistro(_RegId, 'C5');
fin;

funcion TProducto._ValorOID(): entero;


inicio
Si _RegId = 0 entonces
Resultado := 0
sino
Resultado := ValorRegistro(_RegId, 'OID');
fin;

procedimiento TProducto._AsignarOID(_OID: entero);


inicio
Si _RegId <> 0 entonces

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

LiberarRegistro(_RegId);

Si (NO LeerRegistro('PRODUCTOS', ['OID'], [_OID], _RegId)) entonces


inicio
_RegId := 0;
fin;

_HaCambiado := Cierto;
fin;

funcion TProducto._LeerHaCambiado(): booleano;


inicio
Resultado := _HaCambiado;
_HaCambiado := Falso;
fin;

(...)

En este segundo ejemplo, se declara e implementa una clase que permite


trabajar con parejas de enteros, que pueden opcionalmente mantenerse
ordenadas:

TIPO
TParejaEnteros = clase

Privado
procedimiento _Intercambia();

Protegido
_a, _b: entero;
_asignada: booleano;
_ordenar: booleano;

procedimiento _AsignaOrdenar(po: booleano);

Publico
constructor Crear();
destructor Destruir();

procedimiento InterCambia();
procedimiento Asigna(xx, yy: entero);
procedimiento Acerar();
funcion EsIgual( p: TParejaEnteros): booleano;
propiedad a: entero leer _a;
propiedad b: entero leer _b;
propiedad Ordenada: booleano leer _Ordenar
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

escribir _AsignaOrdenar;

fin;

constructor TParejaEnteros.Crear();
inicio
_a := 0;
_b := 0;
_ordenar := falso;
fin;

destructor TParejaEnteros.Destruir();
inicio
// Nada a hacer
fin;

procedimiento TParejaEnteros._AsignaOrdenar(po: booleano);


inicio
_ordenar := po ;
Si po Y (_b < _a) entonces _InterCambia();
fin;

procedimiento TParejaEnteros._Intercambia();
var
c: entero;
inicio
c := _b;
_b := _a;
_a := c;
fin;

procedimiento TParejaEnteros.InterCambia();
inicio
si NO _ordenar entonces _InterCambia();
fin;

procedimiento TParejaEnteros.Asigna(xx, yy: entero);


inicio
si _ordenar y (yy < xx) entonces
inicio
_a := yy;
_b := xx;
fin
sino
inicio
_a := xx;
_b := yy;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

fin;

fin;

procedimiento TParejaEnteros.Acerar();
inicio
_a := 0;
_b := 0;
fin;

funcion TParejaEnteros.EsIgual(p: TParejaEnteros): booleano;


inicio
Resultado := (_a = p.a) Y (_b = p.b);
fin;

INICIO
...
FIN.

Declarar Clases Java

Ahora que ya sabemos como crear, utilizar y destruir objetos, es hora de


aprender cómo escribir clases de las que crear esos objetos.

Una clase es un proyecto o prototipo que se puede utilizar para crear muchos
objetos. La implementación de una clase comprende dos componentes: la
declaración y el cuerpo de la clase.

DeclaraciónDeLaClase {

CuerpoDeLaClase

La Declaración de la Clase

Como mínimo, la declaración de una clase debe contener la palabra clave class
y el nombre de la clase que está definiendo. Así la declaración más sencilla de
una clase se parecería a esto.

class NombredeClase {

...

Por ejemplo, esta clase declara una nueva clase llamada NumeroImaginario.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

class NumeroImaginario {

...

Los nombres de las clases deben ser un identificador legal de Java y, por
convención, deben empezar por una letra mayúscula. Muchas veces, todo lo
que se necesitará será una declaración mínima. Sin embargo, la declaración de
una clase puede decir más cosas sobre la clase. Más especificamente, dentro de
la declaración de la clase se puede.

• declarar cual es la superclase de la clase.


• listar los interfaces implementados por la clase
• declarar si la clase es pública, abstracta o final

Declarar la Superclase de la Clase

En Java, todas las clases tienen una superclase. Si no se especifica una


superclase para una clase, se asume que es la clase Object (declarada en
java.lang). Entonces la superclase de NumeroImaginario es Object porque la
declaración no explicitó ninguna otra clase. Para obtener más información sobre
la clase Object, puede ver La clase Object.

Para especificar explícitamente la superclase de una clase, se debe poner la


palabra clave extends más el nombre de la superclase entre el nombre de la
clase que se ha creado y la llave abierta que abre el cuerpo de la clase, así.

class NombredeClase extends NombredeSuperClase {

...

Por ejemplo, supon que quieres que la superclase de NumeroImaginario sea la


clase Number en vez de la clase Object. Se podría escribir esto.

class NumeroImaginario extends Number {

...

Esto declara explícitamente que la clase Number es la superclase de


NumeroImaginario. (La clase Number es parte del paquete java.lang y es la
base para los enteros, los números en coma flotante y otros números).

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Declarar que Number es la superclase de NumeroImaginario declara


implícitamente que NumeroImaginario es una subclase de Number. Una
subclase hereda las variables y los métodos de su superclase.

Crear una subclase puede ser tan sencillo como incluir la clausula extends en su
declaración de clase. Sin embargo, se tendrán que hacer otras provisiones en su
código cuando se crea una subclase, como sobreescribir métodos. Para obtener
más información sobre la creación de subclases, puede ver Subclases,
Superclases, y Herencia.

Listar los Interfaces Implementados por la Clase

Cuando se declara una clase, se puede especificar que interface, si lo hay, está
implementado por la clase. Pero, ¿Qué es un interface? Un interface declara un
conjunto de métodos y constantes sin especificar su implementación para
ningún método. Cuando una clase exige la implementación de un interface,
debe proporcionar la implementación para todos los métodos declarados en el
interface.

Para declarar que una clase implementa uno o más interfaces, se debe utilizar la
palabra clave implements seguida por una lista de los interfaces
implementados por la clase delimitados por comas. Por ejemplo, imagina un
interface llamado Aritmetico que define los métodos llamados suma(), resta(),
etc... La clase NumeroImaginario puede declarar que implementa el interface
Aritmetico de esta forma.

class NumeroImaginario extends Number implements Aritmetico {

...

se debe garantizar que propociona la implementación para los métodos suma(),


resta() y demás métodos declarados en el interface Aritmetico. Si en
NumeroImaginario falta alguna implementación de los métodos definidos en
Aritmetico, el compilador mostrará un mensaje de error y no compilará el
programa.

nothing.java:5: class NumeroImaginario must be declared abstract. It does not


define

java.lang.Number add(java.lang.Number, java.lang.Number) from interface


Aritmetico.

class NumeroImaginario extends Number implements Aritmetico {

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Por convención, la clausula implements sigue a la clausula extends si ésta


existe.

Observa que las firmas de los métodos declarados en el interface Aritmetico


deben corresponder con las firmas de los métodos implementados en la clase
NumeroImaginario. Tienes más información sobre cómo crear y utilizar
interfaces en Crear y Utilizar Interfaces.

Clases Public, Abstract, y Final

Se puede utilizar uno de estos tres modificadores en una declaración de clase


para declarar que esa clase es pública, abstracta o final. Los modificadores van
delante de la palabra clave class y son opcionales.

El modificador public declara que la clase puede ser utilizada por objetos que
estén fuera del paquete actual. Por defecto, una clase sólo puede ser utilizada
por otras clases del mismo paquete en el que están declaradas.

public class NumeroImaginario extends Number implements Aritmetico {

...

Por convención, cuando se utiliza la palabra public en una declaración de clase


debemos asegurarnos de que es el primer item de la declaración.

El modificador abstract declara que la clase es una clase abstracta. Una clase
abstracta podría contener métodos abstractos (métodos sin implementación).
Una clase abstracta está diseñada para ser una superclase y no puede
ejemplarizarse. Para una discusión sobre las clases abstractas y cómo escribirlas
puedes ver Escribir Clases y Métodos Abstractos.

Utilizando el modificador final se puede declarar que una clase es final, que no
puede tener subclases. Existen (al menos) dos razones por las que se podría
querer hacer esto: razones de seguridad y razones de diseño. Para una mejor
explicación sobre las clases finales puedes ver Escribir Clases y Métodos
Finales.

Observa que no tiene sentido para una clase ser abstracta y final. En otras
palabras, una clase que contenga métodos no implementados no puede ser
final. Intentar declarar una clase como final y abstracta resultará en un error en
tiempo de compilación.

Sumario de la Daclaración de una Clase

En suma, una declaración de clase se parecería a esto.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

[ modificadores ] class NombredeClase [ extends NombredeSuperclase ]

[ implements NombredeInterface ] {

...

Los puntos entre [ y ] son opcionales. Una declaración de clase define los
siguientes aspectos de una clase.

• modificadores declaran si la clase es abstracta, pública o final.


• NombredeClase selecciona el nombre de la clase que está declarando
• NombredeSuperClase es el nombre de la superclase de NombredeClase
• NombredeInterface es una lista delimitada por comas de los interfaces
implementados por NombredeClase

De todos estos items, sólo la palabra clave class y el nombre de la clase son
necesarios. Los otros son opcionales. Si no se realiza ninguna declaración
explícita para los items opcionales, el compilador Java asume ciertos valores por
defecto (una subclase de Object no final, no pública, no obstracta y que no
implementa interfaces).

2. DEFINA Y EXPLIQUE AMPLIAMENTE QUE ES UN


MODIFICADOR DE ACCESO Y QUE TIPOS EXISTEN
Modificadores
Los modificadores son palabras clave que le entregan al compilador
información acerca de la naturaleza del código, datos o clases. Existen dos
grandes grupos de modificadores, los mas comunes son los modificadores de
acceso public, protected y private dejando en un segundo gran grupo otros
como como final, abstract, static, native, transient, synchronized, volatile..
public - Modificador de acceso que hace que un método o variable sea
accesible para cualquier otra clase.
Protected - Modificador de acceso que hace que un método o variable sea
accesible solo por las clases que se encuentran en el mismo paquete o por las
clases hijas de la clase que lo contiene.
private -Modificador de acceso que hace que un método o variable sea accesible
solo para la clase que lo contiene.

final - Hace que sea imposible de extender, sobrecargar un método o modificar


el valor de una variable.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

abstract - Palabra clave utilizada para declarar que una clase no puede ser
instanciada o para declarar que un método debe ser implementado en una clase
hija no abstracta.

static - Hace un método o variable relativo a la clase y no a la instancia.


native - Indica que un método esta escrito en un lenguaje dependiente de la
plataforma.

transient - Previene que un campo sea serializado.

synchronized - Indica que un método solo puede ser accedido por un hilo a la
vez.

volatile - Indica que una variable debe ser leída siempre directamente de la
memoria principal. De esta forma se evita que se realicen copias locales al hilo
que puedan diferir entre si.

class - Palabra clave utilizada para definir una clase.

int - Tipo de dato de 32 bits entero con signo que puede tomar valores de -231 a
231-1.

System - Esta clase, que no puede ser instanciada, contiene muchas campos y
métodos útiles entre los cuales se encuentran los flujos de entrada y salida
estándar, la salida de error, el acceso a propiedades definidas externamente,
medios para cargar ficheros y librerías y un método para rápidamente copiar
una parte de un arreglo.

cadena de caracteres - "Tengo "

void - Se utiliza en la declaración de un método para especificar que no hay


valor de retorno.

String - Esta clase representa cadenas de caracteres. Todos las cadenas de


caracteres literales en los programas Java, como "el conejo que salta", son
implementadas como instancias de esta clase.

this - Variable que hace referencia a la instancia actual de un objeto.

Serializable - La serialización de una clase es habilitada implementando esta


interfase. Todos las subclases de una clase serializable son serializables. La
interfase no tiene métodos o campos y se utiliza solo para identificar la
semántica de ser serializable.

Externalizable - Solo la identidad de la clase de una instancia Externalizable es


escrita el el flujo de una serialización y es responsabilidad de la clase guardar y

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

restaurar el contenido de su instancia. Los métodos writeExternal y


readExternal de la interfase son implementados por la clase para darle el
control completo sobre el formato y contenido del flujo de para el objeto y sus
clases padres. Estos métodos deben estar explícitamente coordinados con su
tipo padre para salvar su estado. La serialización de objetos utilizan las
interfases Serializable y Externalizable y los mecanismos de persistencia pueden
utilizarlos también. Con cada objeto almacenado se intenta con la interfase
Externalizable, si el objeto la soporta se llama al método writeExternal, si no lo
soporta e implementa Serializable es almacenado utilizando
ObjectOutputStream.

ObjectOutputStream - Escribe tipos de datos primitivos y gráficos de objetos


en un OutputStream. Los objetos pueden ser leídos (reconstruidos) utilizando
un objeto ObjectInputStream. El almacenamiento persistente de objetos puede
lograrse utilizando un fichero para el flujo. Si el flujo es un socket de red, los
objetos pueden ser reconstruidos en otro host o en otro proceso.

FileOutputStream - Un flujo de salida para escritura de datos en un File o en


un FileDescriptor. Que este o no el fichero disponible o si es creado depende de
capas mas bajas de la plataforma. Algunas plataformas, en particular, permiten
que el fichero sea abierto para escritura solo por un FileOutputStream (u otro
objeto de escritura de ficheros) a la vez. El algunas situaciones los constructores
en esta clase suelen fallar si el fichero involucrado ya está abierto.

OutputStream - No puedo especificar a que paquete pertenece este objeto por


falta de información para resolver la ambiguedad.Los candidatos son:
java.io de CORE v1.3.1
org.omg.CORBA.portable de CORE v1.3.1
org.omg.CORBA_2_3.portable de CORE v1.3.1

ObjectInputStream - Deserializa datos primitivos y objetos previamente


escritos utilizando un ObjectOutputStream. ObjectOutputStream y
ObjectInputStream pueden proporcionar a una aplicación almacenado
persistente cuando se utilizan con FileOutputStream y FileInputStream
respectivamente. ObjectInputStream es utilizado para recuperar esos objetos
previamente serializados. Otros usos incluyen intercambio de objetos entre
hosts utilizando sockets o para ordenar u desordenar argumentos y parámetros
en un sistema de comunicaciones.

default - En una sentencia switch ejecuta el bloque de código si no se cumple


ninguna de las condiciones.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
Los modificadores de acceso
Los modificadores de acceso controlan quienes pueden utilizar cada una de las
características de la clase que estamos definiendo. Las características de una
clase son: la misma clase, sus variables miembro, sus métodos y sus
constructores.
Con raras excepciones, las únicas variables que pueden ser controladas por los
modificadores de acceso son las variables a nivel de clase. Aquellas que están
declaradas y se utilizan dentro de un método pueden no tener modificadores
de acceso. Esto tiene sentido ya que una variable de método solo puede ser
utilizada dentro del propio método.
Los modificadores de acceso son: public, protected y private.
El único modificador de acceso permitido en una clase que no es interna es
public. Una característica puede tener solo un modificador de acceso. Si una
característica no tiene modificador se dice que el acceso por defecto, que
desafortunadamente no tiene un nombre estándar. El acceso por defecto es
llamado de tres formas: por defecto, de paquete o amigable. A partir de ahora
para referirnos a una característica que no tiene modificador lo haremos
utilizar el término por defecto.
public
Es el acceso mas permisivo. Una clase, variable o método público puede ser
utilizado por cualquier programa Java sin restricción. Un applet esta declarado
como público, de esta forma puede ser instanciado por un navegador. Una
aplicación declara su método main() público para que pueda ser invocado por
el intérprete.
private
El acceso mas restrictivo es private. Las clases del nivel mas alto no pueden ser
declaradas privadas ya que haría imposible el acceso a ningún método o
variable de esta. Un método o variable privada solo puede ser instanciado en la
clase que lo declara. Las variables y métodos privados solo pueden ser
accedidos por una instancia de la clase que las declara ya que los modificadores
de acceso indican que clases, no que instancias pueden acceder a sus
características. Las subclases tampoco pueden acceder a variables y métodos
privados.
Acceso por defecto
Acceso por defecto es el nombre que le vamos a dar al método de acceso
utilizado por clases, variables y métodos que no tienen especificado un
modificador de acceso.
Las clases, métodos y variables con acceso defecto solo pueden ser accedidos
por clases que se encuentran dentro del mismo paquete.
Aun cuando no se estén programando clases dentro de un paquete, el
compilador de Java considera el directorio donde se encuentran las clases como

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

un paquete por defecto, de esta forma todas las clases que se encuentren en este
directorio pueden acceder a las clases, métodos y variables que tienen acceso
por defecto.
protected
Aunque pueda ser mal interpretado, las variables, métodos y clases declaradas
como protegidas son mas accesibles que aquellas que tienen un acceso por
defecto. Tienen acceso a las variables, métodos y clases protegidas todas
aquellas clases que estén dentro del mismo paquete o sean subclases de la
clase.
Subclases y la privacidad de métodos
Java especifica que los métodos no pueden ser sobrescritos para ser mas
privados, esto quiere decir que cuando heredamos y realizamos una sobrecarga
o una sobrescritura, el acceso nunca puede ser mas restrictivo. Cualquier
métodos que sea sobrescrito con un acceso mas restrictivo producirá un error
de compilación.
Un método puede ser sobreescrito por un método con un acceso diferente
siguiendo algunas reglas:

• Un método privado puede ser sobrescrito por un método privado, por


defecto, protegido o público.
• Un método por defecto puede ser sobreescrito por un método por
defecto, protegido o público.
• Un método protegido puede ser sobrescrito por un método protegido o
público.
• Un método público solo puede ser sobreescrito por un método público.
Otros modificadores
Java no tiene en cuenta el orden de aparición de los modificadores. Declarar
una clase public final no es diferente de declararla final public.
No todos los modificadores pueden aplicarse a todo tipo de característica.
Veremos un detalle de esto.
final
El modificador final se aplica a clases, métodos y variables. El significado de
final varia de contexto a contexto, pero la idea en si es la misma, la
característica no puede ser cambiada. Esto quiere decir que de una clase final
no se puede derivar otra clase, una variable final no puede ser modificada una
vez que se le ha asignado el valor y un método final no puede ser sobreescrito.
Aunque una variable final no puede ser cambiada, su contenido puede ser
modificado. Si esta variable apunta a un objeto, es perfectamente válido
modificar las propiedades del objeto.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
abstract
El modificador abstract puede ser aplicado a clases y métodos. Una clase que es
abstracta no puede ser instanciada (esto es, no se puede llamar a su
constructor). Las clases abstractas se pueden utilizar como mecanismo para
trasladar la implementación de los métodos a la subclase. De esta forma, para
poder utilizar una clase abstracta se tiene que derivar y se tienen que
implementar los métodos abstractos definidos en ellas. El compilador obligará
a implementar todos los métodos abstractos de la clase o declarar la clase
derivada abstracta. Si una clase tiene uno o mas métodos abstractos el
compilador insiste en que se debe declarar abstracta. También debe ser
abstracta la clase si hereda uno o mas métodos abstractos para el cual no
provee implementación o si la clase declara una interfase pero no proporciona
implementaciones para cada uno de sus métodos.
static
Este modificador puede ser aplicado a variables, métodos e inclusive a cierto
código que rompe un poco las reglas del lenguaje y que no es parte de un
método. Se puede pensar que una característica estática esta asociada a la clase
en lugar de a la instancia individual de la clase.
Esto quiere decir que para una variable animales existe solo una variable
animales para todas las instancias de la clase. Se puede hacer referencia a una
variable estática mediante una instancia de la clase o mediante el nombre de la
clase.
Los métodos al igual que los datos, pueden ser declarados estáticos. Los
métodos estáticos solo pueden utilizar características estáticas y llamar a
métodos estáticos. Estos pueden ser invocados incluso antes de que alguna
instancia de la clase sea construida.
No es posible acceder a una variable de instancia o a un método de instancia
dentro de un método estático. Al igual que las variables estáticas, los métodos
estáticos no están asociados a una instancia individual de su clase.
Si un método estático necesita acceder a una variable no estática o llamar a un
método no estático, debe especificar que instancia de su clase es dueña de la
variable o ejecutar el método.
Un método estático no puede ser sobreescrito de tal forma de que deje de ser
estático.
Resumiendo, un método estático solo puede acceder a datos estáticos de su
clase y no puede acceder a métodos no estáticos. Un método solo puede llamar
los métodos estáticos de su clase y no puede llamar a métodos no estáticos. Un
método estático no tiene la variable this y no puede ser sobreescrito con un
método no estático.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
Inicializadores estáticos
Es legal para una clase contener código estático fuera del método de un cuerpo.
Una clase puede tener un bloque de código de inicialización simplemente
rodeado de llaves con la palabra estatic
public class Gallina {
   static int patas=2;
   static {
      System.out.prinln("Tengo " + patas + " patas.");
   }
   public static void main(String args[]) {
      System.out.println("Programa.");
   }
}
Este código es ejecutado exactamente una sola vez cuando la clase es cargada
en el orden en que esta escrito sin importar cuantos bloques haya. Hay que
prestar mucha atención con este tipo de construcciones y debe ser utilizado con
precaución ya que el abuso puede resultar en código confuso y poco claro.

native
Este modificador solo puede referirse a métodos, indica que el cuerpo de un
método se encuentra fuera de la máquina virtual de Java, en una librería. El
código nativo esta escrito en otro lenguaje de programación, típicamente C o
C++ y compilado para una sola plataforma por lo que la independencia de
plataforma de Java es violada cuando utilizamos este tipo de métodos.
transient
El modificador transient es solo aplicado a variables. Una variable transient no
es almacenada como parte del estado persistente de su objeto.
Muchos objetos que son declarados con interfases Serializable o Externalizable
pueden tener su estado serializado y escribir a destinos fuera de la máquina
virtual. Esto se logra pasando el objeto a el método writeObject() de la clase
ObjectOutputStream. Si el objeto es pasado a un FileOutputStream, entonces el
estado del objeto es escrito en un fichero. Si el objeto es pasado a un socket
OutputStream, entonces el estado del objeto será escrito en una red. En ambos
casos el objeto puede ser reconstruido leyendo de un ObjectInputStream.
Cuando hay cierta información que no se desea enviar como parte del objeto,
como puede ser cierta información delicada que quizás por razones de
seguridad no deben ser enviadas a través de un canal inseguro (una
contraseña), se declara transient y esta no es escrita durante la serialización.
synchronized
Este modificador es utilizado para controlar el acceso a código crítico en
programas de hilado múltiple. En artículos siguientes hablaremos en mas
detalle de este modificador ya que es casi imprescindible su uso cuando

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

utilizamos hilado múltiple y debemos acceder a propiedades o recursos desde


varios hilos a la vez.
volatile
Este modificador solo lo mencionaremos para completar la lista. Solo las
variables pueden ser declaradas volatile. Esto quiere decir que pueden ser
modificadas de forma asincrónica para que el compilador tome las
precauciones necesarias. Este tipo de variables tiene especial interés para los
ambientes con varios procesadores ya que cuando un hilo modifica una
variable de un objeto, este puede tener una copia local de la variable y
modificar esta. El problema surge cuando otro hilo lee la variable y el valor
recibido es el de la variable local al hilo. Esta puede diferir de la variable local
del otro hilo e inclusive de la variable almacenada en una suerte de "memoria
principal". Al especificar la variable como volatile se le indica a el compilador
que la variable debe ser leída y escrita directamente de la "memoria principal"
cada vez que se necesita evitando tener copias locales distintas.
Modificadores y características
No todos los modificadores pueden ser aplicados a todas las características. Las
clases de nivel superior no pueden ser protegidas y los métodos no pueden ser
transient. En cambio la palabra clave static es tan general que se puede aplicar
hasta en bloques de código flotantes.
La siguiente tabla muestra las posibles combinaciones entre características y
modificadores:

Modificador Clase Variable Método Constructor Bloque flotante

public yes yes yes yes no

protected no yes yes yes no

default yes yes yes yes yes

private no yes yes yes no

final yes yes yes no no

abstract yes no yes no no

static no yes yes no yes

native no no yes no no

transient no yes no no no

volatile no yes no no no

synchronized no no yes no yes


GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Programa Java

Un programa Java se compone de un conjunto de clases que contienen


variables de diversos tipos utilizadas para almacenar datos, y métodos que
implementan código capaz de manipular dichas variables y crear objetos o
instancias de clase, que permitan la interacción con otros métodos y variables
de esas clases.

El punto de inicio de todo programa Java es el código asociado al método main


(principal en inglés), es como la puerta de entrada del programa, lo primero que
se ejecuta.

A la clase que contiene al método main se la llama clase principal.

Las clases y métodos van entre llaves {} y al final de una instrucción o


declaración de variable debe escribirse un punto y coma (;). Se utilizan
tabuladores para sangrar las líneas de código con el fin de facilitar su
legibilidad, aunque si se omiten no pasa nada.

Ejemplo:

Este programa consta de una clase de nombre PrimerSaludo, no declara


ninguna variable y cuenta con dos métodos de nombres main y
mostrarMensaje. En programas más complejos, se tendrán varias clases, en cada
clase habrá muchos métodos y declaraciones de variables, dentro de los
métodos se declararán también variables, etc. Por el momento, con esta sencilla
clase nos conformaremos. Se va a explicar ahora cada una de sus líneas.

La primera línea es la definición de una clase, la segunda es el método main o


punto de entrada del programa (siempre se define de esta forma), la tercera es
una instrucción o sentencia que muestra por la consola del DOS el mensaje
entrecomillado, la cuarta sirve para crear un objeto de la clase llamado ps
mediante el que se llama o invoca a otros métodos de la clase, la quinta es la
llamada mediante el objeto ps al método mostrarMensaje(), la sexta muestra por
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

consola el mensaje entrecomillado. Luego aparece la definición del método


mostrarMensaje() cuyo código hace que se muestre por consola el mensaje
entrecomillado. Después de compilar y ejecutar este programa va a mostrarse
por consola lo siguiente

Por consola:

Hola Jesus

Primera clase del curso de Java

FIN DEL PROGRAMA

A continuación se van a explicar qué son los métodos:

Es una de las herramientas fundamentales de cualquier lenguaje orientado a


objetos. Contienen código que persigue una serie de objetivos. En el ejemplo
anterior, la clase contenía dos métodos y sus objetivos eran:

• Objetivos del método main: mostrar un mensaje por consola, crear un


objeto de la clase PrimerSaludo, invocar al método mostrarMensaje
mediante el objeto anterior y mostrar otro mensaje por consola. Aparte
de estos objetivos, el fundamental y más importante es servir como
punto de inicio de la ejecución del programa.

• Objetivos del método mostrarMensaje: mostrar un mensaje por


consola.

El programador, aparte de crear sus propios métodos como en el código


anterior, puede utilizar los que forman parte de la API (Application
Programming Interface) estándar de Java. La API se estudiará en siguiente
sección.

DECLARACIÓN GENÉRICA DE UN MÉTODO: tiene la siguiente estructura

<modificadores de acceso> <tipo de dato de retorno> <nombre del


método>(tipo1 arg1,tipo2 arg2,...){

Cuerpo del método;

Explicación de cada uno de los componentes de un método:

• Nombre del método: el que desee el programador.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
• Número y tipo de argumentos asociados al método (tipo1 arg1,tipo2
arg2,...): constituye su firma. Los argumentos pueden ser tanto
variables primitivas como variables referenciadas. Más adelante se
estudiarán estos dos tipos de variables. Por el momento, basta saber
que las variables primitivas se emplean para almacenar números,
caracteres o valores lógicos, mientras que las referenciadas están
asociadas a objetos de clases.

• Tipo de dato de retorno o tipo de dato que devuelve el método:

• Dato asociado a una variable primitiva.

• Dato asociado a una variable referenciada.

• void. Es lo que debe ponerse cuando el método no devuelve


nada y, por ejemplo, simplemente muestra por consola un
mensaje. Es el caso del método "void mostrarMensaje()" del
código anterior.

• Modificadores de acceso: public, private, protected y sin modificador.


Sirven para fijar el grado de accesibilidad de un método. Además de
los de acceso, se tienen otros como static, synchronized, final, abstract,
etc. que afectan de un determinado modo al método. Todos se irán
estudiando a lo largo del curso.

• Cuerpo del método: código asociado al método.

NOTA 1: los argumentos asociados a un método se consideran variables


locales, es decir, accesibles sólo desde el cuerpo del método.

NOTA 2: la palabra clave o reservada return se emplea para truncar la


ejecución de un método cuando el tipo de dato que devuelve es void o para
obtener lo que devuelve en el caso de que no sea void. Suele aparecer al final
del método. En Java, las palabras clave tienen un significado especial para el
compilador y no pueden utilizarse como nombres de clases, métodos o
variables. Se irán viendo durante el curso. Hay unas 50. A título de ejemplo,
todos los nombres de variables primitivas como byte, short, int, long, etc. son
palabras clave. También los modificadores de acceso, la palabra class, etc.

Fundamentos de las clases (C# y Java)

En las secciones siguientes se comparan los modificadores de C# y Java.

Modificadores de acceso

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Los modificadores de C# son bastante similares a los de Java, con varias


diferencias pequeñas. Cada miembro de una clase, o la propia clase, se puede
declarar con un modificador de acceso para definir el ámbito de acceso
permitido. Las clases no declaradas dentro de otras clases sólo pueden
especificar los modificadores públicos o internos. Las clases anidadas, como
otros miembros de clase, pueden especificar cualquiera de los cinco
modificadores de acceso siguientes:

• public

Visible para todos.

• protected

Visible sólo desde clases derivadas.

• private

Visible sólo dentro de la clase dada.

• internal

Visible sólo dentro del mismo ensamblado.

• protected internal

Visible sólo para el ensamblado actual o los tipos derivados de la


clase contenedora.

Modificadores public, protected y private


Un modificador public permite que el miembro esté disponible en cualquier
parte, tanto dentro como fuera de la clase. Un modificador protected indica que
el acceso está limitado al interior de la clase contenedora o las clases derivadas
de ésta. Un modificador private implica que el acceso sólo es posible desde
dentro del tipo contenedor. En C#, el modificador de acceso predeterminado es
privado, mientras que en Java el acceso se establece como predeterminado en
cualquier parte desde dentro del paquete contenedor.

Modificador internal
A un elemento internal sólo se puede tener acceso desde dentro del
ensamblado actual. Un ensamblado de .NET Framework es casi equivalente a

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

un archivo JAR de Java; representa las unidades de creación a partir de las


cuales se pueden crear otros programas.

Modificador protected internal


Un elemento protected internal está visible sólo para el ensamblado actual o los
tipos derivados de la clase contenedora.

Modificador sealed
Una clase con el modificador sealed en la declaración de clase es lo opuesto a
una clase abstracta: no se puede heredar. Puede marcar una clase como sealed
para evitar que otras clases reemplacen su funcionalidad. Naturalmente, una
clase con el modificador sealed no puede ser abstracta. Observe también que a
una estructura se le aplica implícitamente el modificador sealed; por
consiguiente, no se puede heredar. El modificador sealed es equivalente a
marcar una clase con la palabra clave final en Java.

Modificador readonly

Para definir una constante en C#, utilice el modificador const o readonly en


lugar de la palabra clave final de Java. El factor distintivo entre los dos
modificadores de C# es que los elementos const se tratan en tiempo de
compilación, mientras que valores de los campos readonly se especifican en
tiempo de ejecución. Esto significa que la asignación a los campos readonly se
puede producir tanto en el constructor de clase como en la declaración. Por
ejemplo, la clase siguiente declara una variable readonly denominada
IntegerVariable que se inicializa en el constructor de clase:

C#
public class SampleClass
{
private readonly int intConstant;
public SampleClass () //constructor
{
// You are allowed to set the value of the readonly variable
// inside the constructor
intConstant = 5;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

}
public int IntegerConstant
{
Set
{
// You are not allowed to set the value of the readonly variable
// anywhere else but inside the constructor
// intConstant = value; // compile-time error
}
get
{
return intConstant;
}
}
}
class TestSampleClass
{
static void Main()
{
SampleClass obj= new SampleClass();
// You cannot perform this operation on a readonly field.
obj.IntegerConstant = 100;
System.Console.WriteLine("intConstant is {0}", obj.IntegerConstant); // 5
}

public (Referencia de C#)

La palabra clave public es un modificador de acceso para tipos y miembros de


tipos. El acceso de tipo public corresponde al nivel de acceso menos restrictivo.
No existen restricciones para obtener acceso a los miembros públicos, como en
este ejemplo:

class SampleClass
{
public int x; // No access restrictions.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

}
.

En el siguiente ejemplo, se declaran dos clases, Point y MainClass. El acceso a


los miembros públicos x e y de Point se realiza directamente desde MainClass.

// protected_public.cs
// Public access
using System;
class Point
{
public int x;
public int y;
}

class MainClass
{
static void Main()
{
Point p = new Point();
// Direct access to public members:
p.x = 10;
p.y = 15;
Console.WriteLine("x = {0}, y = {1}", p.x, p.y);
}
}
Resultado
x = 10, y = 15
Si se cambia el nivel de acceso de public a private o protected, se aparecerá el
siguiente mensaje de error:

'Point.y' is inaccessible due to its protection level.

protected (Referencia de C#)

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

La palabra clave protected es un modificador de acceso a miembros. Un


miembro protegido es accesible dentro de su clase y por clases derivadas.
Encontrará una comparación de protected con los otros modificadores de
acceso en Niveles de accesibilidad.

Un miembro protegido de una clase base es accesible en una clase derivada sólo
si el acceso se realiza a través del tipo de la clase derivada. Por ejemplo,
considere el siguiente segmento de código:

// protected_keyword.cs
using System;
class A
{
protected int x = 123;
}

class B : A
{
static void Main()
{
A a = new A();
B b = new B();

// Error CS1540, because x can only be accessed by


// classes derived from A.
// a.x = 10;

// OK, because this class derives from A.


b.x = 10;
}
}

La instrucción a.x =10 genera un error, ya que A no se deriva de B.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Los miembros de una estructura no se pueden proteger, ya que la estructura no


se puede heredar.

Ejemplo

En este ejemplo, la clase DerivedPoint se deriva de Point; por lo tanto, puede


obtener acceso a los miembros protegidos de la clase base directamente desde la
clase derivada.

// protected_keyword_2.cs
using System;
class Point
{
protected int x;
protected int y;
}

class DerivedPoint: Point


{
static void Main()
{
DerivedPoint dp = new DerivedPoint();

// Direct access to protected members:


dp.x = 10;
dp.y = 15;
Console.WriteLine("x = {0}, y = {1}", dp.x, dp.y);
}
}
Resultados
x = 10, y = 15
Comentarios

Si se cambian los niveles de acceso de x e y a private, el compilador producirá


los siguientes mensajes de error:
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

'Point.y' is inaccessible due to its protection level.

'Point.x' is inaccessible due to its protection level.

private (Referencia de C#)

La palabra clave private es un modificador de acceso de miembros. El acceso de


tipo private corresponde al nivel de acceso más restrictivo. Los miembros
privados sólo son accesibles dentro del cuerpo de la clase o estructura en la que
se declaran, como en el siguiente ejemplo.

class Employee
{
private int i;
double d; // private access by default
}
Los tipos anidados del mismo cuerpo también pueden tener acceso a esos
miembros privados.

Hacer referencia a un miembro privado fuera de la clase o estructura en la que


se declara produce un error de compilación.

En este ejemplo, la clase Employee contiene dos miembros de datos privados,


name y salary. Como miembros privados, sólo pueden tener acceso a ellos los
métodos miembro; por tanto, hay que agregar los métodos públicos
denominados GetName y Salary para permitir el acceso controlado a los
miembros privados. Se tiene acceso al miembro name a través del método
público y se tiene acceso al miembro salary a través de una propiedad pública
de sólo lectura.

// private_keyword.cs
using System;
class Employee
{
private string name = "FirstName, LastName";
private double salary = 100.0;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

public string GetName()


{
return name;
}

public double Salary


{
get { return salary; }
}
}

class MainClass
{
static void Main()
{
Employee e = new Employee();

// The data members are inaccessible (private), so


// then can't be accessed like this:
// string n = e.name;
// double s = e.salary;

// 'name' is indirectly accessed via method:


string n = e.GetName();

// 'salary' is indirectly accessed via property


double s = e.Salary
}
}

3. DE LOS DIFERENTES TIPOS DE MODIFICADORES


DE ACCESO ILUSTRE 5 EJEMPLOS DE CADA UNO

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
Modificadores de acceso

Los modificadores de acceso sirven para restringir el acceso a los campos o a los
métodos de una clase.

Los principales modificadores de acceso son:

• private
• protected
• public

El modificador private permite que el campo o método sólo pueda ser accedido
dentro de la clase donde fue declarado.

El modificador protected permite que el campo o método sólo pueda ser


accedido dentro de la clase donde fue declarado y en todas las clases derivadas
de ella.

El modificador public permite que el campo o método pueda ser accedido


desde cualquier clase.

4. EXPLIQUE AMPLIAMENTE EN QUE CONSISTE EL


CONCEPTO DE ENCAPSULAMIENTO DE LA CLASE
Definición previa: un paquete es una colección de clases que se encuentran en el
mismo directorio.

Las clases permiten implementar tipos de datos abstractos. El problema que se


presenta es que desde cualquier clase se puede accesar los campos de un objeto
perteneciente a otra clase. Esto es una violación al principio de abstracción que
dice que un tipo de datos abstracto sólo puede ser manipulado a través de las
operaciones que se definen para éste.

Visibilidad de Campos y Métodos

En java al definir una clase se puede controlar la visibilidad que tendrán sus
campos y métodos al exterior de la clase. Este control se efectúa de la siguiente
forma:

class A
{
private int privx;
protected int protb;
public int pubc;
int paqd;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

private void MetPriv() { ... }


protected void MetProt() { ... }
public void MetPub(A a)
{
// Un campo siempre es visible
// en la clase en donde se define
... privx ... a.privx ...
... protb ... a.protb ...
... pubc ... a.pubc ...
// Un método siempre es visible
// en la clase en donde se define
MetPriv(); a.MetPriv();
}
void MetPaq() { ... }
}
Las palabras private, protected y public son atributos de un campo o un
método y su significado es el siguiente:

• private: El campo o método sólo es visible dentro de la clase donde se


define.
• protected: El campo o método es visible en la clase en donde se define y
en cualquiera de sus subclases.
• public: El campo o método es visible en cualquier clase.
• Ninguna de las anteriores: El campo o método es visible en cualquiera de
las clases pertenecientes al paquete en donde se define.

Ejemplo:
class B
{
public void MetB()
{
A a= new A();
a.pubc= 1; // Ok
a.priva= 2; // error, privado
a.protb= 3; // error, B no es
// subclase de A

a.MetPub(); // Ok
a.MetPriv(); // error, privado
}
}

Visibilidad de Clases

Al declarar una clase se puede especificar que es pública usando el atributo


public. De este modo la clase podrá ser usada por cualquier otra clase. Si la

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

clase no es pública entonces la clase sólo puede ser usada dentro del paquete
que la contiene.

public class Box extends GraphObj


{ ... }
Podemos hacer un resumen de los atributos que pueden tener campos, métodos
o clases:

• Campo: {private | public | protected} {final} {static}


• Método: {private | public | protected} {final | abstract} {static}
• Clase: {public} {final | abstract}

Sólo se puede especificar uno de los atributos puestos en la misma llave.

El nombre de archivo
Un archivo puede contener a lo más una clase pública, en cuyo caso el nombre
del archivo debe ser el mismo de la clase pública, más la extensión .java. El resto
de las clases del archivo sólo serán visibles dentro del paquete. Es usual que los
archivos contengan una sola clase, pero también a veces se agregan otras clases
al archivo cuando éstas son usadas sólo dentro de ese mismo archivo.

En programación modular, y más específicamente en programación orientada a


objetos, se denomina encapsulamiento al ocultamiento del estado, es decir, de
los datos miembro, de un objeto de manera que sólo se puede cambiar mediante
las operaciones definidas para ese objeto.

Cada objeto está aislado del exterior, es un módulo natural, y la aplicación


entera se reduce a un agregado o rompecabezas de objetos. El aislamiento
protege a los datos asociados a un objeto contra su modificación por quien no
tenga derecho a acceder a ellos, eliminando efectos secundarios e interacciones.

De esta forma el usuario de la clase puede obviar la implementación de los


métodos y propiedades para concentrarse sólo en cómo usarlos. Por otro lado se
evita que el usuario pueda cambiar su estado de maneras imprevistas e
incontroladas.

Encapsulamiento

Como se puede observar de los diagramas, las variables del objeto se localizan
en el centro o núcleo del objeto. Los métodos rodean y esconden el núcleo del
objeto de otros objetos en el programa. Al empaquetamiento de las variables de
un objeto con la protección de sus métodos se le llama encapsulamiento.
Típicamente, el encapsulamiento es utilizado para esconder detalles de la
puesta en práctica no importantes de otros objetos. Entonces, los detalles de la

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

puesta en práctica pueden cambiar en cualquier tiempo sin afectar otras partes
del programa.

El encapsulamiento de variables y métodos en un componente de software


ordenado es, todavía, una simple idea poderosa que provee dos principales
beneficios a los desarrolladores de software: El encapsulamiento consiste en
unir en la Clase las características y comportamientos, esto es, las variables y
métodos. Es tener todo esto en una sola entidad. En los lenguajes estructurados
esto era imposible. Es evidente que el encapsulamiento se logra gracias a la
abstracción y el ocultamiento que veremos a continuación. La utilidad del
encapsulamiento va por la facilidad para manejar la complejidad, ya que
tendremos a las Clases como cajas negras donde sólo se conoce el
comportamiento pero no los detalles internos, y esto es conveniente porque lo
que nos interesará será conocer qué hace la Clase pero no será necesario saber
cómo lo hace.

Formas de encapsular

1. Estándar (Predeterminado)
2. Abierto : Hace que el miembro de la clase pueda ser accedido desde el
exterior de la Clase y cualquier parte del programa.
3. Protegido : Solo es accesible desde la Clase y las clases que heredan (a
cualquier nivel).
4. Cerrado : Solo es accesible desde la Clases.

En el encapsulamiento hay analizadores que pueden ser semánticos y


sintácticos

Ocultación de información en C++

Todos hemos oido hablar de la encapsulación de información en los lenguajes


orientados a objetos y en C++. Vamos a ver aquí en qué consiste y algunos
"trucos" que podemos hacer en el caso concreto de C++ y que no suelen venir
en los libros de este lenguaje (aunque sí en libros sobre patrones de diseño).

Los puntos que veremos son:

• Encapsulamiento de los atributos de una clase


• Importancia de la encapsulación al compilar en C++
• Encapsulamiento a través de interfaces

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

5. ILUSTRE 5 EJEMPLOS DIFERENTES DONDE UTILIZE


EL ENCAPSULAMIENTO DE LA CLASE Y CUALES SON
LOS ELEMENTOS QUE SE ESTAN ENCAPSULANDO

Encapsulamiento de los atributos de una clase

Antes de nada, debe quedar claro que el encapsulamiento, igual que cualquier
buen hábito de programación (como no poner goto, comentar, etc) es útil para
código que más adelante se puede querer reutilizar o modificar, por otras
personas o por uno mismo. Si yo hago un programa de marcianos y nunca
jamas pienso volver a tocarlo, da igual que lo haga con gotos y sin comentar
mientras me entere yo mismo mientras lo estoy haciendo y funcione. Pagaré
este "pecado" si dentro de dos meses se me ocurre mejorarlo o quiero
reaprovechar algo de su código para otro programa.

Comento esto porque el encapsulamiento, llevado a su extremo, como es el


caso del punto final de interfaces, hace la programación un poco más
complicada (hay que hacer más clases). Este esfuerzo sólo se ve recompensado
si el código es muy grande (evitando recompilados innecesarios) o se va a
reutilizar en un futuro (podremos extraer clases con menos dependencias de
otras clases). Dicho esto, vamos al tema.

Cualquier curso de orientación a objetos nos dice que es mejor poner los
atributos de una clase protegidos o privados (nunca públicos) y acceder a ellos
a través de métodos públicos que pongamos en la clase. Veamos el motivo.
Supongamos, por ejemplo, que nos piden un programa que permita llevar una
lista de gente con sus fechas de nacimiento. Entre otras cosas, decidimos
hacernos nuestra clase Fecha con varios métodos maravillosos de la siguiente
manera.

class Fecha
{
public:
int anho; // El anho con cuatro cifras, ej. 2004
int mes; // El mes, de 1 a 12
int dia; // El dia, de 1 a 31
void metodoMaravilloso1();
void metodoMaravilloso2();
};

Ya hemos hecho la clase. Ahora hacemos el resto del código y en unos varios
miles de líneas de código usamos directamente cosas como esta

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Fecha unaFecha;
unaFecha.anho = 2004;
unaFecha.mes = 1;
unaFecha.dia = 25;

Finalmente acabamos nuestro programa y todo funciona de maravilla. Unos


días después nos dicen que el programa va a guardar tropecientas mil personas
y que ocupan mucho los ficheros, que a ver si podemos hacer algo para
remediarlo. ¡Vaya!, almacenamos una fecha con tres enteros. Si usamos el
formato de la mayoría de los ordenadores, en el que la fecha es el número de
segundos transcurridos desde el 1 de Enero de 1970 (lo que nos devuelve la
función time()), basta con un entero.

Total, que manos a la obra, cambiamos nuestra clase para que tenga lo
siguiente:

class Fecha
{
public:
/* Comentado por ineficiente
int anho;
int mes;
int dia; */

long numeroSegundos;

void metodoMaravilloso1();
void metodoMaravilloso2();
};

Ya está hecho lo fácil. Ahora sólo hay que ir por las tropecientas mil líneas de
código cambiando nuestras asignaciones y lecturas a los tres enteros anteriores
por el nuevo long.

Hubiera sido mucho mejor si hubieramos hecho estos tres enteros protegidos y
unos métodos para acceder a ellos. Algo como esto

class Fecha
{
public:
void tomaFecha (int anho, int mes, int dia);

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

int dameAnho ();


int dameMes ();
int dameDia ();
void metodoMaravilloso1();
void metodoMaravilloso2();
protected:
int anho; // El anho con cuatro cifras, ej. 2004
int mes; // El mes, de 1 a 12
int dia; // El dia, de 1 a 31
};

Si ahora tenemos que hacer el mismo cambio, basta con cambiar los atributos
protegidos. Los métodos tomaXXX() y dameXXX() se mantienen en cuanto a
parámetros y valor devuelto, pero se modifica su código interno para que
conviertan el año,mes y dia en un long de segundos y al revés. El resto del
código no hay que tocarlo en absoluto.

Es incluso mejor hacer los atributos privados que protegidos. Haciéndolos


protegidos, las clases hijas (las que heredan de Fecha) pueden acceder
directamente a estos atributos. Cuando hagamos el cambio por un long,
debemos cambiar también el código de las clases hijas. Si los atributos son
privados y obligamos a las clases hijas a acceder a ellos a través de métodos,
tampoco tendremos que cambiar el código de estas clases hijas.

El acceso a través de métodos es menos eficiente que hacerlo directamente, así


que aunque siguiendo el principio de ocultación es mejor hacer atributos
privados, por eficiencia en algunos casos quizás sea mejor hacerlos protegidos
(o incluso públicos) a riesgo de tener que cambiar más líneas de código en caso
de cambio

Importancia de la encapsulación en C++

Con lo contado hasta ahora evitamos tener que cambiar código en caso de
cambiar parámetros.

En el caso concreto de C++ hay un pequeño problema adicional. Es bastante


normal hacer que las clases se definan por medio de dos ficheros. En el caso de
la clase Fecha tendríamos un Fecha.h con la definición de la clase y un Fecha.cc (o
.cpp) con el código de los métodos de la clase. Cuando queremos usar la clase
Fecha, solemos hacer nuestro #include <Fecha.h>.

Cualquier proceso de compilado eficiente (como la utilidad make de linux y


supongo que el Visual C++) es lo suficientemente listo como para recompilar
sólo aquellos ficheros que es necesario recompilar. Es decir, si ya tenemos
nuestro proyecto compilado y tocamos un fichero, el compilador sólo compilará
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

ese fichero y todos los que dependen de él. Esta características es muy
importante en proyectos grandes (con muchos ficheros y muchas líneas de
código), para ahorrar tiempo de compilado cada vez que hacemos una
modificación (He trabajado en proyectos que tardaban en compilar desde cero
alrededor de 4 horas).

¿Cual es el problema?. El problema es que si decidimos, por ejemplo, cambiar


nuevamente el atributo privado de la clase Fecha por otra cosa, necesitamos
tocar el fichero Fecha.h. Esto hará que se recompilen todos los ficheros que
hagan #include <Fecha.h> y todos los ficheros que hagan #include de algun
fichero que a su vez haga #include de Fecha.h y así sucesivamente.

La solución es evidente, colocar lo menos posible en el fichero Fecha.h, en


concreto los #define y variables globales que no sea necesario ver desde otras
clases.

Por ejemplo, nuestra clase Fecha podía tener unos #define para indicar cual es el
número mínimo y máximo de mes. Es mejor colocar estos #define en Fecha.cc en
vez de en Fecha.h, salvo que alguien tenga que verlos.

// Esto mejor en el .cc que en el .h


#define MES_MINIMO 1
#define MES_MAXIMO 12

Encapsulamiento a través de interfaces

Nos queda una cosa. ¿Por qué tenemos que recompilar muchas cosas si
cambiamos un atributo privado de la clase?. Lo ideal sería poder cambiar las
cosas internas de la clase sin que haya que recompilar nada más, a fin de
cuentas, el atributo es privado y nadie lo utiliza directamente.

Es bastante habitual en programación orientada a objetos el uso de interfaces


para hacer que las clases no dependan entre sí. En el caso de C++ el uso de
interfaces es útil además para evitar recompilados innecesarios.

Una interface no es más que una clase en la que se definen los métodos públicos
necesarios, pero no se implementan. Luego la clase concreta que queramos
hacer hereda de esa interface e implementa sus métodos.

En nuestro caso, podemos hacer una clase InterfaceFecha, con los métodos
públicos virtuales puros (sin código). Luego la clase Fecha hereda de
InterfaceFecha e implementa esos métodos.

En el fichero InterfaceFecha.h tendríamos

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
class InterfaceFecha
{
public:
virtual void tomaFecha (int anho, int mes, int dia) = 0;
virtual int dameAnho () = 0;
virtual int dameMes () = 0;
virtual int dameDia () = 0;
virtual void metodoMaravilloso1() = 0;
virtual void metodoMaravilloso2() = 0;
};

De momento, ni siquiera existiría un InterfaceFecha.cc

La clase Fecha sigue igual, pero hereda de InterfaceFecha

#include <InterfaceFecha.h>

class Fecha : public InterfaceFecha


{
public:
void tomaFecha (int anho, int mes, int dia);
int dameAnho ();
int dameMes ();
int dameDia ();
void metodoMaravilloso1();
void metodoMaravilloso2();
protected:
int anho; // El anho con cuatro cifras, ej. 2004
int mes; // El mes, de 1 a 12
int dia; // El dia, de 1 a 31
};

Ahora, todo el que necesite una Fecha, tiene que tener un puntero a
InterfaceFecha en vez de a Fecha. Alguien instanciará Fecha y lo guardará en ese
puntero. Es decir, podríamos hacer algo como esto

#include <Fecha.h>
#include <InterfaceFecha.>
...
InterfaceFecha *unaFecha = NULL;
...
unaFecha = new Fecha();
unaFecha->tomaFecha (2004, 1, 27);
...
delete unaFecha;
unaFecha = NULL;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Si nos fijamos un poco, todavía no hemos arreglado nada, salvo complicar el


asunto. El que haga este código necesita hacer ahora #include tanto de
InterfaceFecha.h como de Fecha.h. Si tocamos algo en Fecha.h, este código se
recompilará.

Este código necesita #include <Fecha.h> para poder hacer el new de Fecha. Hay
que buscar la forma de evitar ese new. Suele ser también bastante habitual hacer
una clase (o utilizar la misma Interface si el lenguaje lo permite, como es el caso
de C++) para poner un método estático que haga el new y nos lo devuelva.

En el caso de Java, al poner este método, ya no tendríamos una interface, sino


una clase. Hacer que Fecha herede de InterfaceFecha nos limita a no heredar de
otra cosa (Java no admite herencia múltiple). Si esto es admisible, podemos
hacerlo así. Si necesitamos que Fecha herede de otra clase, en vez de poner el
método estático en la interface, debemos hacer una tercera clase aparte
GeneradorFecha con este método estático.

En nuestro ejemplo de C++, la clase InterfaceFecha quedaría.

class InterfaceFecha
{
public:

static InterfaceFecha *dameNuevaFecha();

virtual void tomaFecha (int anho, int mes, int dia) = 0;


virtual int dameAnho () = 0;
virtual int dameMes () = 0;
virtual int dameDia () = 0;
virtual void metodoMaravilloso1() = 0;
virtual void metodoMaravilloso2() = 0;
};

Ahora sí necesitamos un InterfaceFecha.cc. Dentro de él tendriamos

#include <InterfaceFecha.h>
#include <Fecha.h>

InterfaceFecha *InterfaceFecha::dameNuevaFecha()
{
return new Fecha();
}

El código que antes utilizaba el puntero a InterfaceFecha quedaría ahora

#include <InterfaceFecha.>
...

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
InterfaceFecha *unaFecha = NULL;
...
unaFecha = InterfaceFecha::dameNuevaFecha();
unaFecha->tomaFecha (2004, 1, 27);
...
delete unaFecha;
unaFecha = NULL;

Como vemos, sólo es necesario el #include de InterfaceFecha.h y este no incluye a


Fecha.h (lo hace InterfaceFecha.cc, no el .h). Hemos hecho que este código no vea
en absoluto a Fecha.h. Ahora podemos tocar sin ningún miramiento el fichero
Fecha.h, que este código no necesita ser recompilado.

Una ventaja adicional es que se puede cambiar la clase Fecha por otra clase
Fecha2 en tiempo de ejecución. Bastaría con poner un atributo estático en
InterfaceFecha para indicar qué clase Fecha queremos y hacer que el método
dameNuevaFecha() instancie y devuelve una u otra en función de ese atributo.

Este mecanismo de obtener una instancia de una clase a través de un método


estático y de una interface, para no depender de la clase concreta, creo que
dentro del mundo de los patrones de diseño es el patrón Factoria

6. EXPLIQUE AMPLIAMENTE COMO SE COMUNICAN


LOS ELEMENTOS QUE FORMAN PARTA UN
PROGRAMA ORIENTADO A OBJETOS

7- DEFINE Y EXPLIQUE EL CONCEPTO DE METODO Y


EXPLICA AMPLIAMENTE PARA QUE SIRVE Y COMO SE
UTILIZA

Los métodos son funciones que pueden ser llamadas dentro de la clase o por
otras clases. La implementación de un método consta de dos partes, una
declaración y un cuerpo. La declaración en Java de un método se puede expresar
esquemáticamente como:

tipoRetorno nombreMetodo( [lista_de_argumentos] ) {


cuerpoMetodo
}

En C++, el método puede declararse dentro de la definición de la clase, aunque


también puede colocarse la definición completa del método fuera de la clase,
convirtiéndose en una función inline. En Java, la definición completa del
método debe estar dentro de la definición de la clase y no se permite la

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

posibilidad de métodos inline, por lo tanto, Java no proporciona al programador


distinciones entre métodos normales y métodos inline.

Los métodos pueden tener numerosos atributos a la hora de declararlos,


incluyendo el control de acceso, si es estático o no estático, etc. La sintaxis
utilizada para hacer que un método sea estático y su interpretación, es
semejante en Java y en C++. Sin embargo, la sintaxis utilizada para establecer el
control de acceso y su interpretación, es muy diferente en Java y en C++.

La lista de argumentos es opcional, tanto en Java como en C++, y en los dos casos
puede limitarse a su mínima expresión consistente en dos paréntesis, sin
parámetro alguno en su interior. Opcionalmente, C++ permite utilizar la
palabra void para indicar que la lista de argumentos está vacía, en Java no se
usa. Los parámetros, o argumentos, se utilizan para pasar información al
cuerpo del método.

La sintaxis de la declaración completa de un método es la que se muestra a


continuación con los items opcionales en itálica y los items requeridos en
negrilla:

especificadorAcceso static abstract


final native synchronized tipoRetorno nombreMetodo( lista_de_argumentos )
throws listaEscepciones

especificadorAcceso, determina si otros objetos pueden acceder al método y


cómo pueden hacerlo. Está soportado en Java y en C++, pero la sintaxis e
interpretación es considerablemente diferente.

static, indica que los métodos pueden ser accedidos sin necesidad de instanciar
un objeto del tipo que determina la clase. C++ y Java son similares en el soporte
de esta característica.

abstract, indica que el método no está definido en la clase, sino que se encuentra
declarado ahí para ser definido en una subclase (sobreescrito). C++ también
soporta esta capacidad con una sintaxis diferente a Java, pero con similar
interpretación.

final, evita que un método pueda ser sobreescrito.

native, son métodos escritos es otro lenguaje. Java soporta actualmente C y C++.

synchronized, se usa en el soporte de multithreading, que se verá también en este


Tutorial.

lista_de_argumentos, es la lista opcional de parámentros que se pueden pasar al


método

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

throws listaExcepciones, indica las excepciones que puede generar y manipular el


método. También se verán en este Tutorial a fondo las excepciones en Java.

8.-TOMANDO COMO EJEMPLOS DE PROGRAMACION


CINCO COMANDOS DIFERENTES ILUSTRE COMO
FUNCIONAN LOS METODOS QUE SE UTILIZAN EN
CADA PROGRAMA

En Java es imprescindible que a la hora de la declaración de un método, se


indique el tipo de dato que ha de devolver. Si no devuelve ningún valor, se
indicará el tipo void como retorno.

Los métodos y funciones en C++ pueden devolver una variable u objeto, bien
sea por valor (se devuelve una copia), por puntero o por referencia. Java no
soporta punteros, así que no puede devolver nada por puntero. Todos los tipos
primitivos en Java se devuelven por valor y todos los objetos se devuelven por
referencia. El retorno de la referencia a un objeto en Java es similar a devolver
un puntero a un objeto situado en memoria dinámica en C++, excepto que la
sintaxis es mucho más simple en Java, en donde el item que se devuelve es la
dirección de la posición en memoria dinámica donde se encuentra almacenado
el objeto.

Para devolver un valor se utiliza la palabra clave return. La palabra clave return
va seguida de una expresión que será evaluada para saber el valor de retorno.
Esta expresión puede ser compleja o puede ser simplemente el nombre de un
objeto, una variable de tipo primitivo o una constante.

El ejemplo retorno por valor y por referencia.

// Un objeto de esta clase sera devuelto por referencia


class miClase {
int varInstancia = 10;
}

Si un programa Java devuelve una referencia a un objeto y esa referencia no es


asignada a ninguna variable, o utilizada en una expresión, el objeto se marca
inmediatamente para que el reciclador de memoria en su siguiente ejecución
devuelve la memoria ocupada por el objeto al sistema, asumiendo que la
dirección no se encuentra ya almacenada en ninguna otra variable. En C++, si
un programa devuelve un puntero a un objeto situado en memoria dinámica y
el valor de ese puntero no se asigna a una variable, la posibilidad de devolver la
memoria al sistema se pierde y se producirá un memory leak, asumiendo que la
dirección no está ya disponible para almacenar ninguna otra variable.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Tanto en Java como en C++ el tipo del valor de retorno debe coincidir con el
tipo de retorno que se ha indicado en la declaración del método; aunque en
Java, el tipo actual de retorno puede ser una subclase del tipo que se ha
indicado en la declaración del método, lo cual no se permite en C++. En Java
esto es posible porque todas las clases heredan desde un objeto raíz común a
todos ellos: Object.

En general, se permite almacenar una referencia a un objeto en una variable de


referencia que sea una superclase de ese objeto. También se puede utilizar un
interfaz como tipo de retorno, en cuyo caso, el objeto retornado debe
implementar dicho interfaz.

Nombre del Método

El nombre del método puede ser cualquier identificador legal en Java. Java
soporta el concepto de sobrecarga de métodos, es decir, permite que dos métodos
compartan el mismo nombre pero con diferente lista de argumentos, de forma
que el compilador pueda diferenciar claramente cuando se invoca a uno o a
otro, en función de los parámetros que se utilicen en la llamada al método.

El siguiente fragmento de código muestra una clase Java con cuatro métodos
sobrecargados, el último no es legal porque tiene el mismo nombre y lista de
argumentos que otro previamente declarado:

class MiClase {
...
void miMetodo( int x,int y ) { . . . }
void miMetodo( int x ) { . . . }
void miMetodo( int x,float y ) { . . . }
// void miMetodo( int a,float b ) { . . . } // no válido
}

Todo lenguaje de programación orientado a objetos debe soportar las


características de encapsulación, herencia y polimorfismo. La sobrecarga de
métodos es considerada por algunos autores como polimorfismo en tiempo de
compilación.

En C++, dos versiones sobrecargadas de una misma función pueden devolver


tipos diferentes. En Java, los métodos sobrecargados siempre deben devolver el
mismo tipo.

Métodos de Instancia

Cuando se incluye un método en una definición de una clase Java sin utilizar la
palabra clave static, estamos generando un método de instancia. Aunque cada
objeto de la clase no contiene su propia copia de un método de instancia (no

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

existen múltiples copias del método en memoria), el resultado final es como si


fuese así, como si cada objeto dispusiese de su propia copia del método.

Cuando se invoca un método de instancia a través de un objeto determinado, si


este método referencia a variables de instancia de la clase, en realidad se están
referenciando variables de instancia específicas del objeto específico que se está
invocando.

La llamada a los métodos de instancia en Java se realiza utilizando el nombre


del objeto, el operador punto y el nombre del método.

miObjeto.miMetodoDeInstancia();

En C++, se puede acceder de este mismo modo o utilizando una variable


puntero que apunte al objeto

miPunteroAlObjeto->miMetodoDeInstancia();

Los métodos de instancia tienen acceso tanto a las variables de instancia como a
las variables de clase, tanto en Java como en C++.

Métodos Estáticos

Cuando una función es incluida en una definición de clase C++, o un método e


incluso en una definición de una clase Java, y se utiliza la palabra static, se
obtiene un método estático o método de clase.

Lo más significativo de los métodos de clase es que pueden ser invocados sin
necesidad de que haya que instanciar ningún objeto de la clase. En Java se
puede invocar un método de clase utilizando el nombre de la clase, el operador
punto y el nombre del método.

MiClase.miMetodoDeClase();

En C++, hay que utilizar el operador de resolución de ámbito para poder


invocar a un método de clase:

MiClase::miMetodoDeClase();

En Java, los métodos de clase operan solamente como variables de clase; no


tienen acceso a variables de instancia de la clase, a no ser que se cree un nuevo
objeto y se acceda a las variables de instancia a través de ese objeto.

Si se observa el siguiente trozo de código de ejemplo:

class Documento extends Pagina {


static int version = 10;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

int numero_de_capitulos;
static void annade_un_capitulo() {
numero_de_capitulos++; // esto no funciona
}
static void modifica_version( int i ) {
version++; // esto si funciona
}
}

la modificación de la variable numero_de_capitulos no funciona porque se está


violando una de las reglas de acceso al intentar acceder desde un método
estático a una variable no estática.

Todas las clases que se derivan, cuando se declaran estáticas, comparten la


misma página de variables; es decir, todos los objetos que se generen comparten
la misma zona de memoria. Los métodos estáticos se usan para acceder
solamente a variables estáticas.

class UnaClase {
int var;
UnaClase() {
var = 5;
}
unMetodo() {
var += 5;
}
}

En el código anterior, si se llama al método unMetodo() a través de un puntero a


función, no se podría acceder a var, porque al utilizar un puntero a función no
se pasa implícitamente el puntero al propio objeto (this). Sin embargo, sí se
podría acceder a var si fuese estática, porque siempre estaría en la misma
posición de memoria para todos los objetos que se creasen de la clase UnaClase.

Paso de parámetros

En C++, se puede declarar un método en una clase y definirlo luego dentro de


la clase (bajo ciertas condiciones) o definirlo fuera de la clase. A la hora de
declararlo, es necesario indicar el tipo de argumentos que necesita, pero no se
requiere indicar sus nombres (aunque pueda hacerse). A la hora de definir el
método sí tiene que indicarse el nombre de los argumentos que necesita el
método.

En Java, todos los métodos deben estar declarados y definidos dentro de la


clase, y hay que indicar el tipo y nombre de los argumentos o parámetros que
acepta. Los argumentos son como variables locales declaradas en el cuerpo del

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

método que están inicializadas al valor que se pasa como parámetro en la


invocación del método.

En Java, todos los argumentos de tipos primitivos deben pasarse por valor,
mientras que los objetos deben pasarse por referencia. Cuando se pasa un
objeto por referencia, se está pasando la dirección de memoria en la que se
encuentra almacenado el objeto.

Si se modifica una variable que haya sido pasada por valor, no se modificará la
variable original que se haya utilizado para invocar al método, mientras que si
se modifica una variable pasada por referencia, la variable original del método
de llamada se verá afectada de los cambios que se produzcan en el método al
que se le ha pasado como argumento.

El ejemplo se ilustra el paso de parámetros de tipo primitivo y también el paso


de objetos, por valor y por referencia, respectivamente.

// Esta clase se usa para instanciar un objeto referencia


class MiClase {
int varInstancia = 100;
}

// Clase principal
class java515 {

// Función para ilustrar el paso de parámetros


void pasoVariables( int varPrim,MiClase varRef ) {
System.out.println( "--> Entrada en la funcion pasoVariables" );
System.out.println( "Valor de la variable primitiva: "+varPrim );
System.out.println( "Valor contenido en el objeto: "+
varRef.varInstancia );

System.out.println( "-> Modificamos los valores" );


varRef.varInstancia = 101;
varPrim = 201;

System.out.println( "--> Todavia en la funcion pasoVariables" );


System.out.println( "Valor de la variable primitiva: "+varPrim );
System.out.println( "Valor contenido en el objeto: "+
varRef.varInstancia );
}

public static void main( String args[] ) {


// Instanciamos un objeto para acceder a sus métodos
java515 aObj = new java515();

// Instanciamos un objeto normal


GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

MiClase obj = new MiClase();


// Instanciamos una variable de tipo primitivo
int varPrim = 200;
System.out.println( "> Estamos en main()" );
System.out.println( "Valor de la variable primitiva: "+varPrim );
System.out.println( "Valor contenido en el objeto: "+
obj.varInstancia );
// Llamamos al método del objeto
aObj.pasoVariables( varPrim,obj );

System.out.println( "> Volvemos a main()" );


System.out.println( "Valor de la variable primitiva, todavia : "+
varPrim );
System.out.println( "Valor contenido ahora en el objeto: "+
obj.varInstancia );
}
}

En C++, se puede pasar como parámetro un puntero que apunte a una función
dentro de otra función, y utilizar este puntero en la segunda función para
llamar a la primera. Esta capacidad no está directamente soportada en Java. Sin
embargo, en algunos casos, se puede conseguir casi lo mismo encapsulando la
primero función como un método de instancia de un objeto y luego pasar el
objeto a otro método, donde el primer método se puede ejecutar a través del
objeto.

Tanto en Java como en C++, los métodos tienen acceso directo a las variables
miembro de la clase. El nombre de un argumento puede tener el mismo nombre
que una variable miembro de la clase. En este caso, la variable local que resulta
del argumento del método, oculta a la variable miembro de la clase.

Cuando se instancia un método se pasa siempre una referencia al propio objeto


que ha llamado al método, es la referencia this.

Definición de métodos de una clase

Para definir los métodos se emplea la siguiente sintaxis:

[modifVisibilidad] [modifFunción] tipo nombreFunción (listaParámetros)


[throws listaExcepciones]

Para modifVisibilidad se aplica las mismas normas que para atributos:

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

public: indica que es un método accesible a través de una instancia del objeto.

private: indica que a través de una instancia no es accesible el método. Al


heredar el método se convierte en inaccesible.

protected: indica que a través de una instancia no es accesible el método. Al


heredar si se puede usar desde la clase derivada.

Sin especificar: indica visibilidad de paquete, se puede acceder a través de una


instancia, pero sólo de clases que se encuentren en el mismo paquete.

nombreFunc debe de ser un identificador válido en el lenguaje.

tipo es el tipo del valor devuelto por la función, pudiendo ser:

Un tipo básico.

Un objeto de una clase o interfaz. En este tipo de objetos se incluyen las


matrices o vectores.

void, en el caso de no devolver ningún valor.

Métodos

El comcepto de método consiste es una forma de encapsular un conjunto de


instrucciones dentro de una declaración específica (llamada generalmente
SUBPROGRAMA), permitiendo la descomposición funcional y la
diferenciación de tareas.

La declaración de un método está formada por una cabecera y un cuerpo.

Estructuración en Java

La codificación de un método consiste en una cabecera para su identificación y


de un cuerpo que contiene las sentencias que éste ejecuta. La cabecera se
compone de un nombre (identificador del método), el tipo del resultado(tipos
primitivos o clases) y una lista de parámetros, que puede contener cero o más
variables.

La lista de parámetros consiste en cero o más parámetros formales (variables),


cada uno de ellos con un tipo.
En caso que el método tenga más de un parámetro, estos deben ir separados
con una coma.

Llamada a un método

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Los métodos pueden ser invocados o llamados de cualquier método de la clase,


incluido él mismo.
Además, cuando se invoca, hay que pasar un valor a cada paramétro, a través
de una variable o un valor constante. En Java, la acción de pasar valores a
parámetros de tipo primitivo (int, double, boolean, char..) se denomina paso de
parámetros por valor
En éste caso, los argumentos que se pasan, no pueden ser modificados por la
función.

En caso que el parámetro sea de tipo Clase o arreglo, lo que se está haciendo es
un paso de parámetros por referencia, y en este caso, los parámetros si pueden
ser modificados por el método

Cuerpo

El código que realmente implementa el método,llamado cuerpo del método ,es


formalmente un bloque de instrucciones.

Ejemplo

/* 1) */ int sumar(int a , int b)


/* 2) */ {
/* 3) */ return a + b;
/* 4) */ }

1) cabecera del método : int sumar(int a,int b)

tipo del resultado : int


nombre del método : sumar
lista de parámetros : int a,int b

2) comienzo del bloque o cuerpo del método

3) Instrucción : se retorna la suma de a y b

4) fin del bloque

Si se coloca las palabras public static antes del método se logra un


comportamiento de tipo global.

import java.io.*;
class suma
{
public static void main(String arg[ ]) throws IOException
{
int x,y;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

BufferedReader in = new BufferedReader(new


InputStreamReader(System.in));

System.out.print("Ingrese un numero : ");


x = Integer.parseInt(in.readLine( ));

System.out.print("Ingrese un numero : ");


y = Integer.parseInt(in.readLine( ));

int s = suma(x,y);

System.out.println("La suma es : " + s);


}

public static int suma(int a,int b)


{
return a + b;
}

Salida a pantalla

Ejemplo de llamada a un método que determina si un número es par o impar

class metodo1
{
public static void main(String arg[ ])
{
int a = 5;

if ( par(a) == true)
{
System.out.println(a + " es par ");
}
else
{
System.out.println(a + " es impar");
}
}

public static boolean par(int num)

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

{
boolean p = false;
if (num % 2 == 0)
{
p = true;
}

return p;
}
}

Ejemplo

Tomando los algoritmos para invertir un numero especificados en la sección de


Manipulación numérica implementar un programa en java que determine los
100 primeros números palíndromes a partir de un número ingresado por
teclado en adelante, llamando al método : invertir_num.

Código fuente

import java.io.*;
class palindromes
{
public static void main(String Arg[ ]) throws IOException
{
int numero = 0;
int contador = 0;

BufferedReader in = new BufferedReader(new


InputStreamReader(System.in));

System.out.print("Ingrese numero : ");


numero = Integer.parseInt(in.readLine( ));

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

System.out.println("\nLos 100 primeros palindromes a contar del " +


numero);
System.out.println("\n");

while (contador < 100)


{
if ( invertir_num(numero) == numero)
{
System.out.print(numero + "\t");
contador++;
}

numero++;
}
}

public static int invertir_num ( int num )


{
int div_entera,resto,num_inv;

num_inv = 0;
div_entera = num;
resto = 0;

while (div_entera != 0)
{
resto = div_entera % 10;
div_entera = div_entera / 10;
num_inv = num_inv * 10 + resto;
}

return num_inv;
}
}

1) Traducir a Java los siguientes algoritmos

a) Se quiere determinar cuantos y cuales números perfectos y pares, existen


entre a y b.

**nota : un numero perfecto es aquel que la suma de sus divisores sea igual
al numero
ej --> 6 : 1 + 2 + 3
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Para ello el usuario, debe ingresar por teclado dos números enteros (a y b) e
implementar dos funciones :

par(num) : boolean
perfecto(num) : boolean

ALGORITMO
---------

FUNCION par(num : entero) : boolean


INICIO
SI (MOD(num/2) == 0) ENTONCES
RETORNAR true
SINO
RETORNAR false
FIN SI
FIN

FUNCION perfecto(num : entero) : boolean


INICIO
sum <-- 0
PARA i <-- 1 HASTA num - 1 HACER
SI(RESTO(num/i) == 0) ENTONCES
sum <-- sum + i
FIN SI
FIN PARA

SI (sum == num) ENTONCES


RETORNAR true
SINO
RETORNAR false
FIN SI

FIN

INICIO
cont <-- 0
leer a , b

PARA i <-- a HASTA b HACER


SI (par(i) == true y perfecto(i) == true) ENTONCES
escribir i

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

cont <-- cont + 1


FIN SI
FIN PARA

Escribir "Existen " + cont + " numeros que cumplen la condicion"

FIN

b) Se desea saber el valor de la siguiente sumatoria

s = SUMATORIA x^2 - y : desde a hasta b

siendo x : numero primo e y = numero multiplo de 5 o 7

Para ello se implemetaran tres funciones o métodos

sumatoria(a : entero, b : entero) : entero


primo(num : entero) : boolean
multiploEspecial(num : entero) : boolean

ALGORITMO
---------

FUNCION primo(num : entero) : boolean


INICIO
cont <-- 0
PARA i <-- 1 HASTA num - 1 HACER
SI (MOD(num/i) == 0) ENTONCES
cont <-- cont + 1
FIN SI
FIN PARA

SI (cont < 2) ENTONCES


RETORNAR true
SINO
RETORNAR false
FIN SI
FIN

FUNCION multiploEspecial(num : entero) : boolean


INICIO

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

aux <- false


SI (MOD(num/5) == 0 OR MOD(num/7) == 0 ) ENTONCES
aux <-- NOT aux
FIN SI
RETORNAR aux
FIN

FUNCION sumatoria(a : entero, b : entero) : entero


INICIO
sum <- 0
PARA i <- a HASTA b HACER
SI (primo(i) == true) ENTONCES
sum <-- sum + i * i
FIN SI

SI (multiploEspecial(i) == true) ENTONCES


sum <-- sum - i
FIN SI
FIN PARA

RETORNAR sum
FIN

INICIO
leer a , b
s <-- sumatoria(a,b)
escribir "El valor de la sumatoria de " + a + " hasta " + b + " es : " + s
FIN

9. EXPLIQUE AMPLIAMENTE, PARA ESCRIBIR


CORRECTAMENTE LAS EXPRESIONES QUE SE
UTLIZAN PARA COMUNICARSE A TRAVES DE LOS
METODOS
El cuerpo de los métodos

Otra vez recordaremos nuestra vieja clase Contador:

// Implementación de un contador sencillo


public class Contador {
………………..
public int incCuenta() {
cnt++;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

return cnt;
}
…………………
}

Dentro de los métodos pueden incluirse:

• Declaración de variables locales


• Asignaciones a variables
• Operaciones matemáticas
• Llamados a otros métodos:
o dentro de la clase
o de instancia, de otras clases
o de clase, de cualquier clase
• Estructuras de control
• Excepciones (try, catch, que veremos más adelante)

Declaración de variables locales

Las variables locales se declaran igual que los atributos de la clase:

Tipo NombreVariable [= Valor];

Ej: int suma;

float precio;

Contador laCuenta;

Sólo que aquí no se declaran private, public, etc., sino que las variables
definidas dentro del método sólo son accesibles por él.

Las variables pueden inicializarse al crearse:

Ej: int suma = 0;

float precio = 12.3;

Contador laCuenta = new Contador ( );

Asignaciones a variables

Se asigna un valor a una variable mediante el signo =:

Variable = Constante | Expresión ;

Ej: suma = suma + 1;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

precio = 1.05 * precio;

laCuenta.cnt = 0;

El último caso es válido si cnt es una variable pública de la clase Contador.


Personalmente no creo conveniente acceder directamente a variables de otro
objeto, ya que futuras modificaciones del objeto llamado o del que llama puede
propender la difusión de errores… Es mejor usar métodos como getCuenta o un
hipotético inicializarContador para ello. De hecho, algunos sugieren que todas las
variables de una clase se declaren como private.

En el primer caso, o sea en general:

Variable = Variable Operador Expresión;

se puede escribir en forma más sencilla:

Variable Operador= Expresión;

Por ejemplo, suma = suma + 9 - cantidad;

puede escribirse: suma += 9-cantidad;

y precio = precio * 0.97;

como: precio *= 0.97;

Operaciones matemáticas

Hay varios tipos de operadores:

Unarios: + - ++ -- ~ ! (tipo) …..etc.

Se colocan antes (o en algunos casos después) de la constante o expresión.

Por ejemplo: -cnt; // cambia de signo; por ejemplo si cnt es 12 el resultado es


-12; cnt no cambia.

++cnt; // equivale a cnt += 1;

cnt++; // equivale a cnt +=1; veremos la diferencia al hablar de estructuras de


control

--cnt; // equivale a cnt -= 1;

cnt--; // equivale a cnt -= 1;

Binarios: + - * / % …..etc.
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Van entre dos constantes o expresiones o combinación de ambas.

Por ejemplo: cnt + 2; // debuelve la suma de ambos.

promedio + ( valor / 2); // como se ve, se pueden usar paréntesis.

horas / hombres; // división.

acumulado % 3; // resto de la división entera entre ambos.

Nota: + sirve también para concatenar cadenas de caracteres; hablaremos de


String y StringBuffer pronto. Cuando se mezclan Strings y valores numéricos,
éstos se convierten automáticamente a cadenas:

"La frase tiene " + cant + " letras"

se convierte en: "La frase tiene 17 letras" // suponiendo que cant = 17

Precedencia de operadores en Java

La siguiente es la precedencia de los operadores en expresiones compuestas. De


todos modos, como en todos los lenguajes, se recomienda usar paréntesis en
caso de duda.

Posfijos [] . (params) expr++ expr--

Operadores unarios ++expr --expr +expr -expr ~ !

Creación y "cast" new (type)

Multiplicativos * / %

Aditivos + -

Desplazamiento << >> >>>

Relacionales < > <= >= instanceof

Igualdad == !=

AND bit a bit &

OR exclusivo bit a bit ^

OR inclusivo bit a bit |

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

AND lógico &&

OR lógico ||

Condicional ? :

Asignación = += -= *= /= %= ^= &= |= <<= >>= >>>=

Algunos ejemplos:

[] define arreglos: int lista[];

(params) es la lista de parámetros cuando se llama a un método:


convertir(valor, base);

new permite crear una instancia de un objeto: new Contador();

(type) cambia el tipo de una expresión a otro: (float)(total % 10);

>> desplaza bit a bit un valor binario: base >> 3;

<= devuelve "true" si un valor es menor o igual que otro: total <= maximo;

instanceof devuelve "true" si el objeto es una instancia de la clase: papa


instanceof Comida;

|| devuelve "true" si cualquiera de las expresiones es verdad: (a<5) || (a>20)

Llamadas a métodos

Se llama a un método de la misma clase simplemente con el nombre del método


y los parámetros entre paréntesis, como se ve, entre otros, en el ejemplo en
negrita:

// Archivo: Complejo.java
// Compilar con: javac Complejo.java
public final class Complejo extends Number {
// atributos:
private float x;
private float y;
// constructor:
public Complejo(float rx, float iy) {
x = rx;
y = iy;
}
// métodos:
public float Norma() {

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

return (float)Math.sqrt(x*x+y*y);
}
// obligatorios (son abstractos en Number):
public double doubleValue() {
return (double)Norma( );
}
public float floatValue() {
return Norma();
}
public int intValue() {
return (int)Norma();
}
public long longValue() {
return (long)Norma();
}
public String toString() {
return "("+x+")+i("+y+")";
}
}

Pueden probar la clase (mínima) con el siguiente ejemplo de aplicación; la línea


en negrita es un ejemplo de un llamado a un método de un objeto de otra clase.
Notar que es este caso, es necesario llamar al método sobre un objeto (instancia)
existente, por lo que se indica:

Nombre_del_Objeto<punto>Nombre_del_Método(parámetros)

// Archivo: Ejemplo4.java
// Compilar con: javac Ejemplo4.java
// Ejecutar con: java Ejemplo4
import java.io.*;

public class Ejemplo4 {


public static void main(String args[]) {
Complejo numComp = new Complejo(4,-3);
System.out.println(numComp.toString());
System.out.println(numComp.Norma());
}
}

En la clase Complejo tenemos también un ejemplo de un llamado a un método


de clase, o sea static:

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

return (float)Math.sqrt(x*x+y*y);

Como el método es de clase, no hace falta llamarlo para un objeto en particular.


En ese caso, en lugar del nombre de un objeto existente se puede utilizar
directamente el nombre de la clase:

Nombre_de_la_Clase<punto>Nombre_del_Método(parámetros)

Práctica

Continuamos con la clase Persona:

Vamos a crear 4 métodos que permitan acceder a los atributos privados de la


clase persona. Los agregamos dentro de la clase:

public int getEdad()

return edad;

public void setEdad(int laEdad)

edad = laEdad;

public String getNombre()

return nombre;

public void setNombre(String elNombre)

nombre = elNombre;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

listaParámetros es la lista de los parámetros que tomará la función separados


por comas y definidos cada uno de ellos como:

tipo nombreParámetro

modifFunción puede tener los siguientes valores:

static: el método pertenece a la clase, no a los objetos creados a partir de la clase.

final: el método no puede ser sobrescrito en una clase derivada.

abstract: En esta clase no se proporciona el código para la función, se debe de


proporcionar en alguna clase derivada. En el caso de poseer un método
abstracto la clase debe de llevar a su vez el modificador abstract. En caso de ser
abstracto un método, se debe de sustituir las llaves que contienen el código por
un punto y coma.

native: Es un método no escrito en java, sino en código nativo, que será usado
en java como un método propio de java.

synchronized: Es un método que sólo puede ser ejecutado por un hilo, y hasta
que ese hilo no acabe la llamada al método, no puede comenzar la llamada al
método otro hilo. Lo emplearemos al trabajar con hilos.

La cláusula opcional throws es empleada para indicar que dentro del método se
pueden generar errores en su ejecución, y que debemos estar preparados para
tratarlos.

listaExcepciones es el nombre de todos esos posibles errores, su utilización la


veremos en el punto dedicado a la gestión de errores mediante try y catch.

El método posee un par de llaves, dentro de las cuales estará el código que se
ejecutará al ser llamada la función. Dicho código estará formado por
instrucciones válidas en el lenguaje, finalizadas generalmente por punto y
coma.

10. TOMANDO EN CUENTA EL CONCEPTO DE


PARAMETRO EXPLIQUE AMPLIAMENTE COMO SE
UTILIZA
Un parametro es una variable que puede pasar su valor a un procedimiento
desde el principal o desde otro procedimiento. Existen ocasiones en que es
necesario mandar al procedimiento ciertos valores para que los use en algún
proceso. Estos valores que se pasan del cuerpo principal del programa al
procedimiento se llaman parametros. Entonces una declaracion completa es:

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Static void Nom Proc?(lista de parametros) { cuerpo de instrucciones; }; import


java.lang.*; import java.io.*; class prog13 { public static void main(String[] args)
{

// llamando procedimiento1 y pasando algunos parametros double


beta=3.1416; proc1(8+4 , beta, “Jesus” ); }; // cierra main public static void
proc1(int a, double b, String nom ) { double c = a + b; System.out.println(nom+
“ la suma fue =“ + c); }; // cierra proc } // cierra clase

REGLAS PARA EL USO DE PARAMETROS

1.- Cuando se usan variables como parametros, la variable que se manda debe
ser declarada dentro del principal o del procedimiento de donde se esta
enviando. 2.- La variable que se manda tiene un nombre, la que se recibe puede
tener otro nombre. 3.- La cantidad de variables que se envian deben ser igual en
cantidad, orden y tipo a las variables que reciben. 4.- La variable que recibe
tiene un ambito local dentro del procedimiento, es decir solo la puede usar ese
procedimiento. Y se pueden mandar datos, valores (excepto decimales),
expresiones algebraicas, pero siempre se recibe en variables.
Los parametros de una función son los valores que esta recibe por parte del
código que la llama. Pueden ser tipos simples u objetos.

En la declaración de la función se escriben después del nombre entre parentesis


indicandose el tipo de cada uno y su nombre. Veamos esto a modo de ejempo:

int dividir(int dividendo, int divisor) {

Está función recibe dos parámetros, ambos de tipo entero, uno el divisor y otro
el dividendo.

A la hora de llamar a la función, los parametros se escriben también a


continuación del nombre entre parentesis; pero en este caso no se indica el tipo
de estos. Veamoslo en un ejemplo:

int resultado = dividir(8,4);

En esta linea, se asigna a la variable entera resultado el retorno de la función


dividir pasandole como parametros 8 y 4.

Es importante recordar que en java, los parametros de los tipos primitivos (int,
long, etc.) SIEMPRE se pasan por valor. Los objetos se pasan por referencia.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

En el paso de parámetros a funciones hay dos aproximaciones clásicas: el paso


por valor y paso por referencia.

En el paso por valor se realiza una copia de los valores que se pasan, trabajando
dentro de la función con la copia. Es por ello que cualquier cambio que sufran
dentro, no repercute fuera de la función.

En el paso por referencia no se realiza dicha copia, por lo que las modificaciones
de dentro de las funciones afectan a los parámetros y esos cambios permanecen
al final de la función.

En Java el paso por parámetro es por valor, aunque los efectos son de paso por
referencia cuando los argumentos son objetos. ¿cómo sucede eso? Pues es muy
fácil, si una función tiene como argumento un tipo primitivo (int, float, etc...), en
Java se realiza una copia para la función y cualquier cambio a dicho argumento
no afecta a la variable original. Este paso de parámetros en Java está orientado a
utilizar el valor de la variable para otros cálculos.

En el caso de los objetos es distinto. En realidad lo que sucede es que en Java


siempre tenemos referencias a los objetos. Por eso al pasar a una función como
argumento un objeto, pasamos la referencia al mismo, es decir, aunque se hace
una copia para el paso por valor, como lo que se copia es una referencia, los
cambios al objeto referenciado sí son visibles y afectan fuera de la función.

La única excepción es la clase String , cuyos objetos no son mutables. Cualquier


modificación de un objeto String lleva aparejada la creación de una nueva
instancia del objeto. Si deseamos el mismo comportamiento para el paso de
parámetros del resto de objetos, tenemos que recurrir al objeto StringBuffer.

Un parametro es una variable que puede pasar su valor a un procedimiento


desde el principal o desde otro procedimiento.

Existen ocasiones en que es necesario mandar al procedimiento ciertos valores


para que los use en algún proceso.

Estos valores que se pasan del cuerpo principal del programa al procedimiento
se llaman parametros.

Entonces una declaracion completa es:

void NomProc(lista de parametros)

{ cuerpo de instrucciones; };

prog13.java

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class prog13 extends HttpServlet

PrintWriter pagina;

public void doGet (HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException

pagina =response.getWriter();

response.setContentType("text/html");

pagina.println("<HTML>");

// llamando procedimiento1 y pasando algunos parametros

double beta=3.1416;

proc1(8+4 , beta, "juan" );

pagina.println("</HTML>");

pagina.close();

};

public void proc1(int a, double b, String nom )

double c = a + b;

pagina.println(nom+ " la suma fue =" + c);

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

};

public void destroy(){super.destroy();};

REGLAS PARA EL USO DE PARAMETROS

1.- Cuando se usan variables como parametros, la variable que se manda debe
ser declarada dentro del principal o del procedimiento de donde se esta
enviando.

2.- La variable que se manda tiene un nombre, la que se recibe puede tener otro
nombre.

3.- La cantidad de variables que se envian deben ser igual en cantidad, orden y
tipo a las variables que reciben.

4.- La variable que recibe tiene un ambito local dentro del procedimiento, es
decir solo la puede usar ese procedimiento.

Y se pueden mandar datos, valores(excepto decimales), expresiones algebraicas,


pero siempre se recibe en variables.

TAREAS PROGRAMACION JAVA SERVLET

Capturar el nombre y las 3 calificaciones en un procedimiento, calcular


promedio en un segundo, imprimir nombre y promedio en principal

Construir una tabla de multiplicar que el usuario indique captura y control de


ciclo en el principal, calculo en un procedimiento.

Construir un procedimiento que reciba un numero entero y que mande llamar a


un segundo procedimiento pasando el letrero “PAR O IMPAR”.

11.- TOMANDO EN CUENTA EL CONCEPTO DE


PARAMETRO ILUSTRE 5 EJEMPLOS DE SU
UTILIZACION

Existe comúnmente la creencia errónea de que en Java es posible pasar


parámetros por referencia, y no es así. Java siempre pasa los parámetros por
valor. Esta confusión se da debido a que todas las variables de objeto son
referencias a objetos [1]. En el libro “The Java Programming Language” de Ken
Arnold y James Gosling (autores de Java), sección 2.6.1., tenemos la siguiente
cita: “There is exactly one parameter passing mode in Java - pass by value - and that

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

helps keep things simple.” [2] (Existe un solo modo de paso de parámetros en Java
– paso por valor – y eso ayuda a mantener las cosas simples.).

Antes de continuar, vamos a recordar cuáles son las definiciones de paso por
valor y paso por referencia: [3]:

Paso por valor significa que cuando un argumento se pasa a una función, la
función recibe una copia del valor original. Por lo tanto, si la función modifica
el parámetro, sólo la copia cambia y el valor original permanece intacto.

Paso por referencia significa que cuando un argumento se pasa a una función,
la función recibe la dirección de memoria del valor original, no la copia del
valor. Por lo tanto, si la función modifica el parámetro, el valor original en el
código que llamó a la función cambia.

Vamos a valernos de ejemplos para explicar el mecanismo con el que Java pasa
parámetros a los métodos.

Tenemos el siguiente programa Java:

1 public class ValorOReferencia {


2
3 private String param1 = new String();
4
5 /** Creates a new instance of PassValueOrReference */
6 public ValorOReferencia(String param1) {
7 this.setParam1(param1);
8 }
9
10 public static void cambiarObjeto(ValorOReferencia objeto) {
11 objeto = new ValorOReferencia(”Este es un nuevo objeto.”);
12 System.out.println(”Luego de \”reasignar\” pass: ” + objeto);
13 }
14
15 public static void cambiarParam1(ValorOReferencia objeto) {
16 objeto.setParam1(”Este es un nuevo valor para param1.”);
17 }
18
19 public static void main(String[] args) {
20 ValorOReferencia pass =
21 new ValorOReferencia(”Objeto inicial.”);
22 System.out.println(”Entender que Java pasa parámetros por valor: “);
23 System.out.println(”Antes de modificar pass es: ” + pass);
24 ValorOReferencia.cambiarObjeto(pass);
25 System.out.println(”De vuelta en main pass es: ” + pass);
26 System.out.println(”Ahora vamos a cambiar sólo param1:”);
28 ValorOReferencia.cambiarParam1(pass);

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

29 System.out.println(”De seguro param 1 ha cambiado: ” + pass);


30 System.out.println(”Parece difícil, pero no lo es.”);
31 }
32
33 public String getParam1() {
34 return param1;
35 }
36
37 public void setParam1(String param1) {
38 this.param1 = param1;
39 }
40
41 public String toString() {
42 return “[param1 = " + this.getParam1() + "]“;
43 }
44
45 }

Remitámonos a línea 20. Declaramos una variable pass, de tipo ValorOReferencia,


con su único atributo param1 inicializado con el valor “Objeto inicial.”. En la
línea 23, presentamos el objeto en pantalla, y se muestra el valor con el que fue
declarado.

Salida del programa:

Entender que Java pasa parámetros por valor:


Antes de modificar pass es: [param1 = Objeto inicial.]

Ahora, en la línea 24 pasamos nuestra variable pass al método cambiarObjeto,


método que tiene un parámetro formal de tipo ValorOReferencia. En dicho
método, en la línea 11, se realiza una asignación

objeto = new ValorOReferencia("Este es un nuevo objeto.");

, se presenta el objeto “modificado” y el control regresa al método main.

Salida del programa:

Luego de "reasignar" pass: [param1 = Este es un nuevo objeto.]

Suponiendo que el paso de parámetros en Java fuera por referencia, la


referencia pass apuntaría ahora a un nuevo objeto con el valor “Este es un nuevo
objeto.”. Pero, al regresar al método main, en la línea 25, presentamos de nuevo
pass, y vemos que el valor con el que fue originalmente declarado se mantiene.

Salida del programa

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

De vuelta en main() pass es: [param1 = Objeto inicial.]

Ahora, vamos a pasar pass y vamos a modificar solamente su único atributo. En


la línea 28, pasamos pass al método cambiarParam1, en donde tenemos la
sentencia

objeto.setParam1("Este es un nuevo valor para param1.");

en la línea 16. Así, se ha modificado el valor del atributo param1, y al volver al


método main, presentamos pass otra vez:

Salida del programa:

Ahora vamos a cambiar sólo param1:


De seguro param 1 ha cambiado: [param1 = Este es un nuevo valor para
param1.]
Parece difícil, pero no lo es.

Al ver esta última operación, quizá alguien pueda decir que Java sí pasa
parámetros por referencia, ya que se modificó el atributo del objeto, pero estaría
equivocado: ¿Por qué en cambiarObjeto la variable pass no sufre ninguna
modificación, y en el método cambiarParam1 su atributo se ve efectivamente
modificado? Porque Java no pasa objetos como parámetros [4], sino copias de
las referencias a esos objetos. Exacto. Java pasa parámetros por valor. Pasa
referencias a objetos por valor.

Vamos a explicar lo que hacen nuestros métodos cambiarObjeto(ValorOReferencia


objeto) y cambiarParam1(ValorOReferencia objeto).

cambiarObjeto(ValorOReferencia objeto)

En main, declaramos una variable

ValorOReferencia pass = new ValorOReferencia("Objeto inicial.");

Se ha creado un objeto ValorOReferencia en cierta posición de memoria y la


forma de acceder a él es usar la referencia pass.

Omito los métodos setters, getters y toString() en el diagrama porque no


intervienen en la explicación de este método. Este método tiene un parámetro
formal ValorOReferencia objeto. Como Java pasa parámetros por valor tenemos
que objeto, el parámetro formal de cambiarObjeto, es una copia de la referencia

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

pass, es un alias, mas no es la referencia pass. Siguiente a la llamada al método lo


que tenemos es lo siguiente:

objeto es una copia de la referencia pass, es otra referencia que apunta al mismo
lugar. Al ejecutar la sentencia

objeto = new ValorOReferencia("Este es un nuevo objeto.");

lo que hacemos de hecho es esto:

objeto, que originalmente era una copia de la referencia pass, apunta ahora a un
nuevo objeto creado en otra posición de memoria. Es por eso que de vuelta al
main, el objeto apuntado por pass no ha cambiado.

cambiarParam1(ValorOReferencia objeto)

Desde el método main pasamos a cambiarParam1 la referencia pass:

Incluyo el método setter setParam1(String param1) porque interviene en esta


explicación. cambiarParam1 tiene un parámetro formal ValorOReferencia objeto,
que es un alias de pass.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Al ejecutar la sentencia

objeto.setParam1("Este es un nuevo valor para param1.");

, lo que estamos haciendo es invocar al método setParam1 del objeto apuntado


por la referencia objeto. Es por eso que el atributo param1 del objeto referenciado
por pass es efectivamente modificado.

Cuando declaramos variables, por ejemplo,

ValorOReferencia valoRef = new ValorOReferencia();

, no declaramos un objeto ValorOReferencia, sino una referencia a un objeto


ValorOReferencia. Java tiene punteros (referencias a objetos), pero no es posible
manejarlos con la aritmética con que se manejan en C++ [5]. No obstante, la
implementación de estos punteros es similar en ambos lenguajes:

• Una sentencia Java ValorOReferencia valORef; es exactamente igual a


una sentencia C++ ValorOReferencia *valORef;.
• Una sentencia Java valORef.cambiarParam1(“Otro valor.”); es
exactamente igual a una sentencia C++ valORef -> cambiarParam1(“Otro
valor.”);. [6]

Hay que tener claro entonces, que cuando se escribe una sentencia del estilo

cualquierFuncion(CualquierTipo argumento);

en Java, lo que se pasa no es un objeto, sino una copia de la referencia al objeto.


Es importante no confundirnos. Java pasa objetos por referencia (pasa las referencias
a los objetos), pero nunca pasa un objeto como parámetro [7], ni parámetros por
referencia.

12. DEFINA EL CONCEPTO CONSTRUCTOR Y


EXPLIQUE AMPLIAMENTE PARA QUE SIRVE DENTRO
DE UN PROGRAMA
CONSTRUCTORES (EN JAVA)

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Un constructor es un método especial dentro de una clase, que se llama


automáticamente cada vez que se crea un objeto de esa clase.

Posee el mismo nombre de la clase a la cual pertenece y no puede regresar


ningún valor (ni siquiera se puede especificar la palabra reservada void). Por
ejemplo si añadiéramos a la clase SSuma un constructor, tendríamos que
llamarlo también SSuma. Cuando en una clase no se escribe propiamente un
constructor, Java asume uno por default.

Un constructor por default es un constructor sin parámetros que no hace nada.


Sin embargo será invocado cada vez que se construya un objeto sin especificar
ningún argumento, en cuyo caso el objeto será iniciado con los valores
predeterminados por el sistema (los atributos numéricos a ceros, los
alfanuméricos a nulos, y las referencias a objetos a null).

Un constructor por default, para la clase SSuma quedaría así:

public SSuma() {}

Como se observa el constructor no posee ningún parámetro, ya que como no ha


sido definido propiamente por el programador, Java lo hace por default. Si se
define un constructor con parámetros,(definido explícitamente) el constructor
por default se reemplaza por éste. Ahora podemos crear un constructor
explicito para una clase simple, utilizaré el nombre Arychan para mi clase.
Arychan es una clase que se refiere a una persona de cierta edad, que posee un
nombre y ciertos atributos, puede ser divertida, y hermosa, estos atributos serán
del tipo cadena de caracteres (String) por lo que agregaré un atributo mas
llamado salario y será de tipo numérico. Primero declaro la clase con sus
atributos:

class Arychan
{
//ATRIBUTOS
private String nombre;
private String descripción;
private String formaDeSer;
private double salario;

//METODOS

public Arychan() {} //CONSTRUCTOR SIN PARÁMETROS


public Arychan(String nom, String des, String forma, double sal)
{

asignarNombre(nom); // nombre = nom;


asignarDescripcion(des); // descripción = des;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

describir(forma); //formaDeSer = forma;


ingreso(sal); //salario = sal;
}

//...

El constructor sin parámetros es reemplazado por el constructor explicito. Es


este ejemplo se puede observar que los constructores preferentemente se
declaran públicos para que puedan ser invocados desde cualquier parte.

una línea como esta invocará al constructor sin parámetros:

Arychan ary01 = new Arychan();// invoca al constructor Arychan

El operador new crea un nuevo objeto, en este caso de la clase Arychan, y a


continuación se invoca al constructor de la clase para realizar las operaciones de
iniciación que estén programadas. Ahora invocaremos al constructor con
parámetros, recordemos que la clase Arychan es una persona con características
como divertida, hermosa, mismas que pasaremos como argumentos.

Arychan ary02 = new Arychan("Ary", "hermosa", "divertida", 25000);

13. MEDIANTE 5 EJEMPLOS DE PROGRAMACION


SEÑALE Y EXPLIQUE EL O LOS CONSTRUCTOR
UTILIZADOS
Código Fuente Arboles.java.

public class Arboles {

public Arboles() {
System.out.println("Un árbol genérico");
}

public Arboles(String tipo) {


System.out.println("Un árbol tipo " + tipo);
}

public Arboles(int altura) {


System.out.println("Un árbol de " + altura + " metros");

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

public Arboles(int altura,String tipo) {


System.out.println("Un " + tipo + " de " + altura + " metros");
}

public static void main(String args[]) {


Arboles arbol1 = new Arboles(4);
Arboles arbol2 = new Arboles("Roble");
Arboles arbol3 = new Arboles();
Arboles arbol4 = new Arboles(5,"Pino");

Clase Arboles
• Como en todo programa Java , primeramente se define la Clase a través
del vocablo class.

• Posteriormente son definidos 4 Constructores; nótese que cada uno recibe


el mismo nombre de la Clase y posee distintos argumentos de entrada.

• Dentro del método principal (main) son generadas cuatro instancias de


la Clase, como se puede observar, al ser generada la instancia a través
del vocablo new se pasa un parámetro, y es dependiendo de este
parámetro que es llamado el Constructor correspondiente, el cual a su
vez invoca la Clase System.out.println que imprime a pantalla.

Constructor Obligatorio...
En los ejemplos anteriores del curso se pudo notar que no se hizo uso de
Constructor alguno, y la razón es que el compilador lleva acabo esta definición
de Constructor vacío detrás de los escenarios, sin embargo, existe una
situación en la que es necesario definir un Constructor vacío y esta es cuando
se hace uso de otros constructores.

Lo anterior significa que si el compilador observa un método con el mismo


nombre de la clase con argumentos (Constructor), deberá existir un método
vacío por el mismo nombre, esto de cierta manera salvaguarda a un
programador al momento de definir métodos que no vayan a ser definidos
erróneamente como Constructores

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Tanto Java como C++ soportan la sobrecarga de métodos, es decir, que dos o
más métodos puedan tener el mismo nombre, pero distinta lista de argumentos
en su invocación. Si se sobrecarga un método, el compilador determinará ya en
tiempo de compilación, en base a lista de argumentos con que se llame al
método, cual es la versión del método que debe utilizar.

Tanto Java como C++ soportan la noción de constructor. El constructor es un


tipo específico de método que siempre tiene el mismo nombre que la clase y se
utiliza para construir objetos de esa clase. No tiene tipo de dato específico de
retorno, ni siquiera void. Esto se debe a que el tipo específico que debe devolver
un constructor de clase es el propio tipo de la clase.

En este caso, pues, no se puede especificar un tipo de retorno, ni se puede


colocar ninguna sentencia que devuelva un valor. Los constructores pueden
sobrecargarse, y aunque puedan contener código, su función primordial es
inicializar el nuevo objeto que se instancia de la clase. En C++, el constructor se
invoca automáticamente a la hora de crear un objeto. En Java, ha de hacerse una
llamada explícita al constructor para instanciar un nuevo objeto.

Cuando se declara una clase en Java, se pueden declarar uno o más


constructores opcionales que realizan la inicialización cuando se instancia (se
crea una ocurrencia) un objeto de dicha clase.

Utilizando el código de la sección anterior, cuando se crea una nueva instancia


de MiClase, se crean (instancias) todos los métodos y variables, y se llama al
constructor de la clase:

MiClase mc;
mc = new MiClase();

La palabra clave new se usa para crear una instancia de la clase. Antes de ser
instanciada con new no consume memoria, simplemente es una declaración de
tipo. Después de ser instanciado un nuevo objeto mc, el valor de i en el objeto
mc será igual a 10. Se puede referenciar la variable (de instancia) i con el
nombre del objeto:

mc.i++; // incrementa la instancia de i de mc

Al tener mc todas las variables y métodos de MiClase, se puede usar la primera


sintaxis para llamar al método Suma_a_i() utilizando el nuevo nombre de clase
mc:

mc.Suma_a_i( 10 );

y ahora la variable mc.i vale 21.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Luego, en Java, cuando se instancia un objeto, siempre se hace una llamada


directa al constructor como argumento del operador new. Este operador se
encarga de que el sistema proporcione memoria para contener al objeto que se
va a crear.

En C++, los objetos pueden instanciarse de diferentes formas, pero en Java


solamente se pueden instanciar en la pila de memoria, es decir, solamente se
pueden instanciar utilizando el operador new para poder solicitar memoria al
sistema en tiempo de ejecución y utilizar el constructor para instanciar el objeto
en esa zona de memoria. Si al intentar instanciar un objeto, la Máquina Virtual
Java (JVM) no puede localizar la memoria que necesita ese objeto, bien
inmediatamente o haciendo ejecutarse al reciclador de memoria, el sistema
lanzará un OutOfMemoryError.

Tanto en Java como en C++, si no se proporciona explícitamente un constructor,


el sistema proporciona uno por defecto que inicializará automáticamente todas
las variables miembro a cero o su equivalente, en Java. En C++, el constructor
de defecto no realiza ningún tipo de inicialización.

Se puede pensar en el constructor de defecto en Java como un método que tiene


el mismo nombre que la clase y una lista de argumentos vacía. Y en C++, el
constructor de defecto sería como la llamada cuando se instancia un objeto sin
parámetros

MiClase objeto;

En ambos lenguajes, si se proporciona uno o más constructores, el constructor


de defecto no se proporciona automáticamente y si fuese necesaria su
utilización, tendría que proporcionarlo explícitamente el programa.

Las dos sentencias siguientes muestran cómo se utiliza el constructor en Java


para declarar, instanciar y, opcionalmente, inicializar un objeto:

MiClase miObjeto = new MiClase();


MiClase miObjeto = new MiClase( 1,2,3 );

Las dos sentencias devuelven una referencia al nuevo objeto que es almacenada
en la variable miObjeto. También se puede invocar al constructor sin asignar la
referencia a una variable. Esto es útil cuando un método requiere un objeto de
un tipo determinado como argumento, ya que se puede incluir una llamada al
constructor de este objeto en la llamada al método:

miMetodo( new MiConstructor( 1,2,3 ) );

Aquí se instancia e inicializa un objeto y se pasa a la función. Para que el


programa compile adecuadamente, debe existir una versión de la función que
espere recibir un objeto de ese tipo como parámetro.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Tanto en Java como en C++, cuando un método o una función comienza su


ejecución, todos los parámetros se crean como variables locales automáticas. En
este caso, el objeto es instanciado en conjunción con la llamada a la función que
será utilizada para inicializar esas variables locales cuando comience la
ejecución y luego serán guardadas. Como son automáticas, cuando el método
concluye su ejecución, se destruirá (en C++) o será marcado para su destrucción
(en Java).

En el siguiente ejemplo, se ilustran algunos de los conceptos sobre constructores


que se han planteado en esta sección.

class MiClase {
int varInstancia;

// Este es el constructor parametrizado


MiClase( int dato ) {
// rellenamos la variable de instancia con los datos
// que se pasan al constructor
varInstancia = dato;
}

void verVarInstancia() {
System.out.println( "El Objeto contiene " + varInstancia );
}
}

class java507 {
public static void main( String args[] ) {
System.out.println( "Lanzando la aplicacion" );
// Instanciamos un objeto de este tipo llamando al
// constructor de defecto
java507 obj = new java507();
// Llamamos a la funcion pasandole un constructor
// parametrizado como parametro
obj.miFuncion( new MiClase( 100 ) );
}

// Esta funcion recibe un objeto y llama a uno de sus metodos


// para presentar en pantalla el dato que contiene el objeto
void miFuncion( MiClase objeto){
objeto.verVarInstancia();
}
}

Herencia

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

En casos en que se vea involucrada la herencia, los constructores toman un


significado especial porque lo normal es que la subclase necesite que se ejecute
el constructor de la superclase antes que su propio constructor, para que se
inicialicen correctamente aquellas variables que deriven de la superclase. En
C++ y Java, la sintaxis para conseguir esto es sencilla y consiste en incluir en el
cuerpo del constructor de la subclase como primera línea de código la siguiente
sentencia:

super( parametros_opcionales );

Esto hará que se ejecute el constructor de la superclase, utilizando los


parámetros que se pasen para la inicialización. En el código del ejemplo
siguiente, se ilustra el uso de esta palabra clase para llamar al constructor de la
superclase desde una subclase.

class SuperClase {
int varInstancia;

// Es necesario proporcionar el constructor por defecto,que


// es aquel que no tiene parametros de llamada
SuperClase(){}

// Este es el constructor parametrizado de la superclase


SuperClase( int pDato ) {
System.out.println(
"Dentro del constructor de la SuperClase" );
varInstancia = pDato;
}

void verVarInstancia() {
System.out.println( "El Objeto contiene " + varInstancia );
}
}

class SubClase extends SuperClase {


// Este es el constructor parametrizado de la subclase
SubClase( int bDato ) {
// La siguiente sentencia println no compila, la llamada
// a super() debe estar al principio de un metodo en caso de
// que aparezca
// System.out.println( "En el constructor de la SubClase" );

// Llamamos al constructor de la superclase


super( bDato );
System.out.println(
"Dentro del constructor de la SubClase" );
}
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

class java508 {
public static void main( String args[] ) {
System.out.println( "Lanzando la aplicacion" );

// Instanciamos un objeto de este tipo llamando al


// constructor de defecto
java508 obj = new java508();
// Llamamos a la funcion pasandole un constructor de la
// subclase parametrizado como parametro
obj.miFuncion( new SubClase( 100 ) );
}

// Esta funcion recibe un objeto y llama a uno de sus metodos


// para presentar en pantalla el dato que contiene el objeto,
// en este caso el metodo es heredado de la SuperClase
void miFuncion( SubClase objeto ) {
objeto.verVarInstancia();
}
}

Si super no aparece como primera sentencia del cuerpo de un constructor, el


compilador Java inserta una llamada implícita, super(), al constructor de la
superclase inmediata. Es decir, el constructor por defecto de la superclase es
invocado automáticamente cuando se ejecuta el constructor para una nueva
subclase, si no se especifica un constructor parametrizado para llamar al
constructor de la superclase.

Control de Acceso

El control de acceso también tiene un significado especial cuando se trata de


constructores. Aunque en otra sección se trata a fondo el tela del control de
acceso en Java, con referencia a los constructores se puede decir que el control
de acceso que se indique determina la forma en que otros objetos van a pode
instanciar objetos de la clase. En la siguiente descripción, se indica cómo se trata
el control de acceso cuando se tienen entre manos a los constructores:

private

Ninguna otra clase puede instanciar objetos de la clase. La clase puede contener
métodos públicos, y estos métodos pueden construir un objeto y devolverlo,
pero nadie más puede hacerlo.

protected

Solamente las subclases de la clase pueden crear instancias de ella.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
public

Cualquier otra clase puede crear instancias de la clase.

package

Nadie desde fuera del paquete puede construir una instancia de la clase. Esto es
útil si se quiere tener acceso a las clases del paquete para crear instancias de la
clase, pero que nadie más pueda hacerlo, con lo cual se restringe quien puede
crear instancias de la clase.

En Java y en C++, una instancia de una clase, un objeto, contiene todas las
variables y métodos de instancia de la clase y de todas sus superclases. Sin
embargo, los dos lenguajes soportan la posibilidad de sobreescribir un método
declarado en una superclase, indicando el mismo nombre y misma lista de
argumentos; aunque los procedimientos para llevar a cabo esto son totalmente
diferentes en Java y en C++.

Como aclaración a terminología que se empleo en este documento, quiero


indicar que cuando digo sobrecargar métodos, quiero decir que Java requiere que
los dos métodos tengan el mismo nombre, devuelvan el mismo tipo, pero tienen
una diferente lista de argumentos. Y cuando digo sobreescribir métodos, quiero
decir que Java requiere que los dos métodos tengan el mismo nombre, mismo
tipo de retorno y misma lista de argumentos de llamada.

En Java, si una clase define un método con el mismo nombre, mismo tipo de
retorno y misma lista de argumentos que un método de una superclase, el
nuevo método sobreescribirá al método de la superclase, utilizándose en todos
los objetos que se creen en donde se vea involucrado el tipo de la subclase que
sobreescribe el método.

Finalizadores

Java no utiliza destructores (al contrario que C++) ya que tiene una forma de
recoger automáticamente todos los objetos que se salen del alcance. No obstante
proporciona un método que, cuando se especifique en el código de la clase, el
reciclador de memoria (garbage collector) llamará:

// Cierra el canal cuando este objeto es reciclado


protected void finalize() {
close();
}

Cada objeto tiene el método finalize(), que es heredado de la clase Object. Si se


necesitase realizar alguna limpieza asociada con la memoria, se puede
sobreescribir el método finalize() y colocar en él el código que sea necesario.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Los programadores C++ deben tener en cuenta que el método finalize() no es un


destructor. En C++, si existe un destructor, éste será invocado siempre que el
objeto se salga de ámbito o vaya a ser destruido. En Java, aunque el método
finalize() siempre se invocará antes de que el reciclador de memoria libere la
zona de memoria ocupada por el objeto, no hay garantía alguna de que el
reciclador de memoria reclame la memoria de un determinado objeto, es decir,
no hay garantía de que el método finalize() sea invocado.

La regla de oro a seguir es que no se debe poner ningún código que deba ser
ejecutado en el método finalize(). Por ejemplo, si se necesita concluir la
comunicación con un servidor cuando ya no se va a usar un objeto, no debe
ponerse el código de desconexión en el método finalize(), porque puede que
nunca se llamado. Luego, en Java, es responsabilidad del programador escribir
métodos para realizar limpieza que no involucre a la memoria ocupada por el
objeto y ejecutarlos en el instante preciso. El método finalize() y el reciclador de
memoria son útiles para liberar la memoria de la pila y debería restringirse su
uso solamente a eso, y no depender de ellos para realizar ningún otro tipo de
limpieza.

No obstante, Java dispone de dos métodos para asegurar que los finalizadores
se ejecuten. Los dos métodos habilitan la finalización a la salida de la aplicación,
haciendo que los finalizadores de todos los objetos que tengan finalizador y que
todavía no hayan sido invocados automáticamente, se ejecuten antes de que la
Máquina Virtual Java concluya la ejecución de la aplicación. Estos dos métodos
son:

runFinalizersOnExit( boolean ), método estático de java.lang.Runtime, y

runFinalizersOnExit( boolean ), método estático de java.lang.System

Una clase también hereda de sus superclase el método finalize(), y en caso


necesario, debe llamarse una vez que el método finalize() de la clase haya
realizado las tareas que se le hayan encomendado, de la forma:

super.finalize();

En la construcción de un objeto, se desplaza uno por el árbol de jerarquía, de


herencia, desde la raíz del árbol hacia las ramas, y en la finalización, es al revés,
los desplazamientos por la herencia debe ser desde las ramas hacia las
superclases hasta llegar a la clase raíz.

Noción de constructor

Cuando se crea un objeto (se instancia una clase) es posible definir un proceso
de inicialización que prepare el objeto para ser usado. Esta inicialización se
lleva a cabo invocando un método especial denominado constructor. Esta

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

invocación es implícita y se realiza automáticamente cuando se utiliza el


operador new. Los constructores tienen algunas características especiales:

• El nombre del constructor tiene que se igual al de la clase.


• Puede recibir cualquier número de argumentos de cualquier tipo, como
cualquier otro método.
• No devuelve ningún valor (en su declaración no se declara ni siquiera
void).

El constructor no es un miembro más de una clase. Sólo es invocado cuando se


crea el objeto (con el operador new). No puede invocarse explicitamente en
ningún otro momento.

Continuando con los ejemplos del capítulo anterior se podría escribir un


constructor para la clase Punto, de la siguiente forma:

class Punto {
int x , y ;
Punto ( int a , int b ) {
x=a;y=b;
}
}

Con este constructor se crearía un objeto de la clase Punto de la siguiente forma:

Punto p = new Punto ( 1 , 2 );

Constructor no-args.

Si una clase no declara ningún constructor, Java incorpora un constructor por


defecto (denominado constructor no-args) que no recibe ningún argumento y
no hace nada.

Si se declara algún constructor, entonces ya no se puede usar el constructor no-


args. Es necesario usar el constructor declarado en la clase.

En el ejemplo el constructor no-args sería:

class Punto {
int x , y ;
Punto ( ) { }
}

Sobrecarga de constructores.

Una clase puede definir varios constructores (un objeto puede inicializarse de
varias formas). Para cada instanciación se usa el que coincide en número y tipo

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

de argumentos. Si no hay ninguno coincidente se produce un error en tiempo


de compilación.

Por ejemplo:

class Punto {
int x , y ;
Punto ( int a , int b ) {
x=a;y=b;
}
Punto () {
x = 0 ; y = 0;
}
}

En el ejemplo se definen dos constructores. El citado en el ejemplo anterior y un


segundo que no recibe argumentos e inicializa las variables miembro a 0. (Nota:
veremos más adelante que este tipo de inicialización es innecesario, pero para
nuestro ejemplo sirve).

Desde un constructor puede invocarse explicitamente a otro constructor


utilizando la palabra reservada this . this es una referencia al propio objeto.
Cuando this es seguido por parénteses se entiende que se está invocando al
constructor del objeto en cuestión. Puedes ver el uso más habitual de this aquí.
El ejemplo anterior puede reescribirse de la siguiente forma:

class Punto {
int x , y ;
Punto ( int a , int b ) {
x = a ; y = b ;
}
Punto () {
this (0,0);
}
}

Cuando se declaran varios constructores para una misma clase estos deben
distinguirse en la lista de argumentos, bien en el número, bien en el tipo.

Constructores

• Definicion: El constructor de una clase es un método estándar para inicializar


los objetos de esa clase

Se invoca automáticamente cuando new crea un objeto de esa clase.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

• Los constructores se declaran en el momento de definir la clase.


• class A {
• int x, y;
• A() { x=0; y=0; } // el constructor
• ...
• }

• A a= new A();
• a.Print(); // 0 0
• El constructor puede tener parámetros. En este caso, se deben colocar los
argumentos respectivos al crear el objeto:
• class A {
• int x, y;
• A(int ix, int iy)
• { x=ix; y=iy; } // el constructor
• ...
• }

• A a= new A(1,2);
• a.Print(); // 1 2

• a= new A(); // error, hay que colocar
• // los argumentos
• a.A(1,2); // error, no se puede
• // invocar el constructor
• Se pueden colocar varios constructores. Durante la creación de un objeto,
se invoca aquel que calza con los argumentos dados:
• class A {
• int x, y;
• A() { x=0; y= 0; }
• A(int ix, int iy)
• { x=ix; y=iy; }
• A(A from)
• { x= from.x; y= from.y; }
• ...
• }

• A a1= new A();
• a1.Print(); // 0 0
• A a2= new A(1,2);
• a2.Print(); // 1 2
• A a3= new A(a2);
• a3.Print(); // 1 2
• Un destructor es un método que se invoca automáticamente cuando el
objeto se destruye. Java no posee destructores, porque tiene recolección
de basuras. C++ posee destructores.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

14. DEFINA EL CONCEPTO DESTRUCTOR Y EXPLIQUE


AMPLIAMENTE PARA QUE SIRVE DENTRO DE UN
PROGRAMA

En esta sección abordaremos los conceptos básicos - iniciales, de la


Programación Orientada a Objetos, (POO). Se verán algunos conceptos como
clases, polimorfismo, herencia, etc., directamente con ejemplos, sin utilizar
muchas definiciones "académicas", tan sólo ejemplos.

Clases:

En lenguaje C tradicional existen las estructuras de datos, las cuales se definen


con la palabra clave struct, ejemplo:

struct Coordenadas
{
int x;
int y;
int z;
}

Con una estructura uno crea un tipo de dato nuevo, en este caso, se puede
declarar una variable de tipo Coordenadas, la cual puede almacenar 3 valores
enteros:

struct Coordenadas coo; //Declaración de la variable coo de tipo


Coordenadas
coo.x=7; //Valores iniciales para los datos miembros.
coo.y=15;
coo.z=55;

x, y, z son los "datos miembros" de la estructura. Para manipular estos datos,


(asignarles un valor inicial, cargarlos, mostrarlos, etc.), uno puede escribir
funciones globales en su programa. Ejemplo:

void Carga(void)
void Muestra(void)

Bueno, se podría decir que una estructura es el "antepasado" más directo de una
clase.
¿Por qué?.
Que tal si las funciones con las cuales uno manipula los datos de la estructura
formaran parte de ella, o sea, una estructura tal que además de definir sus datos
miembros también definiera las funciones para manipularlos. Este tipo de

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

estructuras existe en C++ y se definen igual que las estructuras de C pero


además uno puede declarar las funciones.
Mire el siguiente ejemplo: (para estos ejemplos puede usar Visual C++ o
Borland C++ 3.1, con cualquiera de ellos funcionan).

//Estructura con funciones miembros.


//Autor: Demian C. Panello.
#include <iostream.h>

struct Coordenadas
{
int x,y,z;

void Cargar(void) //Función miembro que carga los


datos.
{
x=8;
y=9;
z=10;
}
void Mostrar(void) //Función miembro que muestra el contenido de los
datos.
{
cout << x <<endl;
cout << y <<endl;
cout << z <<endl;
}
};

void main(void)
{
struct Coordenadas coo; //Se define una variable, (coo), de tipo
Coordenadas.

coo.Cargar(); //Llamadas a las funciones de coo.


coo.Mostrar();
}

Ahora examine el siguiente programa y encuentre las diferencias con el


anterior:

//Lo mismo pero con una clase.


//Autor: Demian C. Panello.
#include <iostream.h>

class Coordenadas
{

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

int x,y,z;

public:
void Cargar(void)
{
x=8;
y=9;
z=10;
}
void Mostrar(void)
{
cout << x <<endl;
cout << y <<endl;
cout << z <<endl;
}

};

void main(void)
{
Coordenadas coo;

coo.Cargar();
coo.Mostrar();

¿Encontró las diferencias?.


La verdad, no son muchas. En lugar de struct se pone class, luego se agrega la
etiqueta public, antes de definir las funciones miembros, ya que para una
estructura los datos miembros y funciones miembros son por defecto públicos,
pero en una clase por defecto los datos miembros son privados, (esto forma
parte, entre otras cosas, de lo que se llama "encapsular"), y sólo las funciones
públicas pueden tener acceso a los datos privados.
Y la otra diferencia es en el momento de definir(*) la variable coo, no hace falta
especificar la palabra class así como se hizo con struct.

(*) En la POO, utilizando clases, ya no se habla de "definir" una variable de una


clase en particular, sino que se crea una "instancia" o un objeto de dicha clase.

¿Por qué usar clases y no estructuras?.

A veces la diferencia, aparte de la sintaxis, no es del todo "pesada" como para


justificar una clase. En este ejemplo no hacía falta definir una clase, la versión
de la estructura es más que suficiente.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Pero cuando el concepto del objeto a crear es un tanto más complejo, y


preocupa, por ejemplo, la protección de los contenidos de los datos miembros, o
se tiene una gran cantidad de funciones miembros, o simplemente se pretende
en serio programar según POO, es cuando una clase se hace presente.
Pues como supongo astutamente dedujo, la Programación Orientada a Objetos,
consta de objetos, y una clase, define o es como la "plantilla" sobre la cual se
construyen los tan mentados.

Constructores:

En una clase existe una función miembro muy particular llamada Constructor.
Un constructor es una función que debe tener el mismo nombre que la clase y
no debe retornar ningún valor, (ni siquiera void), y se encarga de asignarle
valores iniciales, (o simplemente inicializar), a los datos miembros.
En el ejemplo descubrirá que allí no hay ningún constructor definido, cuando
ocurre esto el compilador de C++ crea en ejecución el constructor.
No obstante hubiera sido correcto haber definido un constructor que se
encargara de, por ejemplo, inicializar con 0 los datos miembros.
Un constructor es invocado automáticamente cuando se crea la instancia, o sea
que no hay llamarlo explícitamente desde el programa principal.
Existen 3 tipos de constructores:

- Constructor por defecto.


- Constructor común.
- Constructor de copia.

El constructor por defecto es, en caso que no lo haya definido, el que C++ en
tiempo de ejecución le asigne, o bien:

class Coordenadas
{
int x,y,z;

public:
Coordenadas(); //Constructor por defecto

};

También le podríamos haber agregado a este constructor, encerrados entre


llaves, los valores iniciales para los datos:
{x=0;y=0;z=0;}.
Cuando se crea el objeto se escribe:

void main(void)
{
Coordenadas coo;

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

....
}

El constructor común es aquel que recibe parámetros para asignarles como


valores iniciales a los datos miembros, o sea que al crear la instancia, se pasó
unos parámetros para inicializar.

class Coordenadas
{
int x,y,z;

public:
Coordenadas(int p, int q, int t) {x=p; y=q; z=t;} //Constructor común.

};

Cuando se crea el objeto se escribe:

void main(void)
{
Coordenadas coo(6,7,22); //Se le pasa los valores para inicializar.
.....
}

El constructor de copia se utilizan para inicializar un objeto con otro objeto de la


misma clase.

class Coordenadas
{
int x,y,z;

public:
Coordenadas ( int p, int q, int t) {x=p; y=q; z=t;} //Constructor común.
Coordenadas(const Coordenadas c) //Constructor de copia.
{
x=c.x;
y=c.y;
z=c.z;
}

};

Cuando se crea el objeto se escribe:

void main(void)
{

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Coordenadas k(1,2,3); //Creación de un objeto con lo valores


iniciales 1, 2 y 3.
Coordenadas coo=k; //Se llama al constructor de copia para que le
asigne a coo los valores de k.
....
}

Sobrecarga de funciones, (polimorfismo):

Habrá advertido en el último ejemplo de la clase, donde se ve el constructor de


copia, que también se define un constructor común. Bueno, eso es posible, una
clase puede tener varios constructores, que se irán usando de acuerdo a como
uno cree el objeto, (pasándole o no parámetros).
Pero, observe nuevamente, esta vez más detalladamente, la clase..., ¿no
encuentra otra cosa extraña?.
...(suspenso). : )

Los constructores son funciones, ¿¿¿cómo permite el compilador dos funciones


con el mismo nombre???.
Ahh, buena pregunta.

El compilador de C++ permitiría 100 funciones con el mismo nombre, el único


requisito es que cada una de ellas tenga diferente número y/o tipo de
parámetros.
Esta cualidad, que no se aplica solamente a los constructores y funciones
miembros de una clase, sino que a cualquier función de un programa de C++,
se llama Sobrecarga de funciones o Polimorfismo.
Cuando se llama a la función, C++ selecciona de todas las funciones
sobrecargadas aquella que se ajusta de acuerdo con los parámetros pasados, en
cantidad y tipo.

Funciones InLine:

También se puede estar preguntando, si las funciones miembros de una clase


pueden estar definidas fuera de la clase.
La respuesta es sí, por lo general las funciones miembros están definidas fuera
de la clase, dentro de esta última sólo se declararían los prototipos.
En el caso que la función esté definida dentro de la clase, ésta se llama función
inline, como las funciones Cargar() y Mostrar() de nuestra clase Coordenadas.
Se podría incluso agregar la cláusula inline, pero no hace falta.
¿Qué diferencia hay entre una función inline y otra, (definida dentro o fuera de
la clase)?
Se define una función inline cuando es muy corta y simple, como los
constructores y esas funciones del ejemplo. Declarar una función en línea
significa que el compilador puede, si así lo decide, reemplazar cada invocación
por la función, con la frecuencia que sea, por el código encerrado entre llaves.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Hay que tener en cuenta que funciones inline extensas consumen más memoria,
a pesar que elimina el tiempo que lleva hacer la invocación.
Cuando se escribe una función fuera de la clase se especifica el acceso de la
siguiente forma:

NombreClase::Función() //Note que se accede con ::

Así quedaría nuestro programa, con la clase con un constructor por defecto y
con las funciones miembro fuera de la clase.

#include <iostream.h>

class Coordenadas
{
int x,y,z;
public:
Coordenadas(){x=0;y=0;z=0;} //Constructor por defecto.
void Cargar(void); //Prototipo de las funciones.
void Mostrar(void);
};

void Coordenadas::Cargar(void) //Definición de las funciones fuera de la


clase
{
x=8;
y=9;
z=10;
}

void Coordenadas::Mostrar (void)


{
cout << x <<endl;
cout << y <<endl;
cout << z <<endl;
}

void main(void)
{
Coordenadas coo;

coo.Cargar();
coo.Mostrar();
}

Destructores:

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Existe una función especial más para las clases, y se trata de los destructores.
Un destructor es una función miembro que se llama cuando se destruye la clase.
Todas las clases tiene un destructor implícito, incluso aunque no esté declarado.
El destructor implícito no hace nada en particular, pero si uno quiere, puede
declarar un destructor de forma explícita. Su sintaxis sería:

class NombreClase
{
...
public:
~NombreClase();
...
}

El destructor debe comenzar con el caracter "ñuflo", (~), seguido por el nombre
de la clase, (igual que el constructor). Además el destructor no puede recibir
parámetros ni retornar nada, (ni siquiera void).
No puede haber más de un destructor para una clase y si no se define uno
explícitamente, el compilador crea uno automáticamente.
El destructor se llama automáticamente siempre que una variable de ese tipo de
clase, (una instancia u objeto), sale fuera de su ámbito, (por ejemplo cuando
termina el programa).

Especificadores de acceso:

Ya había dicho que por defecto los datos miembros de una clase son privados.
¿Qué significa esto?.
Que sólo las funciones miembros públicas de la misma clase tienen acceso a ellos. Si lo
desea puede escribir la cláusula private al momento de declarar los datos.
En cambio la cláusula public es obligatoria cuando se desea declarar un dato
público y este dato estará disponible para cualquier función del programa.
Existe una cláusula más, protected. Los datos definidos a continuación de esta
cláusula están restringidos para cualquier función externa a la clase, pero son
públicos para la propia clase y los miembros de clases derivadas.

Creación y Destrucción de Objetos

Ya se ha dicho que una clase es únicamente una especificación. Para poder


utilizar la funcionalidad contenida en la misma, se deben instanciar las clases.

1. Creación por Declaración.

Un objeto se puede instanciar de una forma simple, declarando una


variable del tipo de la clase.

En Ppal.h:

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

#include "ObjGraf.h"

En Ppal.cpp:

Pulsando dos veces en OnCreate de la pestaña Events del editor de objetos


de PpalFrm:

//--------------------------------------------------

void __fastcall TPpalFrm::FormCreate(TObject *Sender)


{
TObjGraf ObjGraf1();
TObjGraf ObjGraf2;
}

//--------------------------------------------------
Aunque esta forma es posible, y bastante utilizada en la programación de C++
clásica, en C++ Builder se utiliza en muy contadas ocasiones. Esto es así por
dos razones, fundamentalmente:

1. La duración de los objetos suele ir más allá de una simple función o


bloque. Debido al enfoque de la programación dirigida por eventos, suele
ser habitual que un objeto se cree en un gestor de eventos y se destruya en
otro.
2. No se puede usar esta modalidad de creación con la VCL.

Por lo tanto, nosotros no la utilizaremos.

Creación Dinámica

Es la forma habitual de crear objetos en C++ Builder, y se realiza mediante


el operador new .

Cuando usamos new para instanciar un objeto, se usa una variable que
referencie o apunte al nuevo objeto creado (de otra manera éste quedaría
totalmente inaccesible). En definitiva, se requiere la declaración previa de
un puntero a objetos del tipo del que se va a crear.

En Ppal.cpp:

TObjGraf * ObjGraf; // Variable Global.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

// ObjGraf es un puntero a objetos de tipo TObjGraf

//--------------------------------------------------

void __fastcall TPpalFrm::FormCreate(TObject *Sender)


{
ObjGraf = new TObjGraf;
}

//--------------------------------------------------

La forma de establecer el estado inicial o destruir las componentes de un


objeto se estudiarán en el apartado dedicado a Constructores y
Destructores (sección 5.4).

¡Cuidado! Cuando se utiliza esta forma de instanciación de clases es


responsabilidad únicamente del programador la correcta destrucción de los
mismos.

Destrucción de objetos

Cuando un objeto deja de ser útil hay que eliminarlo. De esta manera la
aplicación recupera los recursos (memoria) que ese objeto había acaparado
cuando se creó.

La destrucción de objetos creados en tiempo de ejecución con new se realiza


mediante el operador delete.

En Ppal.cpp:

Pulsando dos veces en OnDestroy de la pestaña Events del editor de objetos


de PpalFrm:

//--------------------------------------------------

void __fastcall TPpalFrm::FormDestroy(TObject *Sender)


{
delete ObjGraf;
}

Destructores en clases derivadas. Cuando remueve de la memoria un objeto de


una clase derivada, el recolector de basura invoca al destructor del objeto. Esto
inicia una cadena de invocaciones a destructores, en donde el destructor de la
clase derivada y los destructores de las clases bases directas e indirectas se
ejecutan en orden inverso al que se ejecutaron los constructores, esto es,

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

primero se ejecuta el destructor de la clase derivada y al final se ejecuta el


destructor de la clase base ubicada en el nivel superior de la jerarquía. La
ejecución de los destructores debe liberar todos los recursos que el objeto
adquirió, antes de que el recolector de basura reclame la memoria de ese objeto.
Cuando el recolector de basura invoca al destructor de un objeto de una clase
derivada, ese destructor realiza su tarea y después invoca al destructor de la
clase base. El proceso se repite hasta que se invoca al destructor de la clase
Object.

Ejemplo: // Destruct Derivadas?.cs : Destructores en clases derivadas. using C


= System.Console; class Animal { ~ Animal( ) { C.Write Line?(“Muere mi parte
Animal …”); } } class Mamífero : Animal { ~ Mamífero( ) { C.Write Line(“Muere
mi parte Mamífero …”); } } class Perro : Mamífero { ~ Perro( ) { C.Write
Line(“Muere mi parte Perro …”); } } public class Principal { static void Main( )
{ Perro Fido = new Perro ( ); } }

Salida: Muere mi parte Perro … Muere mi parte Mamífero … Muere mi parte


Animal …

El destructor es muy similar al constructor, excepto que es llamado


automáticamente cuando cada objeto sale de su ámbito de validez. Recordemos
que las variables automáticas tienen un tiempo de vida limitado, ya que dejan
de existir cuando se sale del bloque en que han sido declaradas. Cuando un
objeto es liberado automáticamente, su destructor, si existe, es llamado
automáticamente.
Un destructor tiene el mismo nombre que la clase a la que pertenece, pero
precedido con una tilde (~). Un destructor no tiene tipo devuelto.
En el ejemplo anterior, podemos definir un destructor que asigne cero a las
variables antes de que sean liberadas, con lo que en realidad no estamos
haciendo nada:

# include <iostream.h>

class Caja {
double longitud, anchura, altura;
public:
Caja (double dim1, double dim2, double dim3);
~Caja (void);
double volumen (void);
};

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Caja :: Caja (double dim1, double dim2, double dim3)


{
longitud = dim1;
anchura = dim2;
altura = dim3;
};

Caja::~Caja (void) { longitud = 0; anchura = 0; altura = 0; } double Caja::


volumen (void) {
return longitud * anchura * altura;
};

main ()
{
Caja pequeña(5, 4, 10), mediana (10, 6, 20), grande(20, 10, 30);

cout << "El volumen de la caja grande es " << grande.volumen() << '\n';
}

Si algún bloque de memoria fuera reservada dinámicamente en un objeto, se


puede utilizar el destructor para liberarla antes de que se pierdan los punteros a
esas variables.

#include <iostream.h>

class Taco {
public:
Taco (int hard) {
hardness = new int;
*hardness = hard;
}
~Taco() {
cout << "Destroying taco with hardness " ;
cout << *hardness <<;\n';
delete hardness;
}
private:
int *hardness; };

main ()
{
Taco hard(10);
Taco *soft = new Taco (0);

delete soft;
};

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

En este ejemplo, vemos que el constructor tiene el mismo nombre que la clase,
con un ~ delante. Cuando se crean punteros a clases, como soft en el ejemplo, se
llama al destructor cuando se libera la memoria del puntero. Si esto no se hace,
nunca se llamará al destructor.
Con clases declaradas estáticamente, como Taco hard, el destructor se llama al
final de la función donde se declara el objeto (en el ejemplo, al final de la
función main.
Incluse cuando se interrumpe un programa usando una llamada a exit(), se
llama a los destructores de los objetos que existen en ese momento.

15. MEDIANTE 5 EJEMPLOS DE PROGRAMACION


SEÑALE Y EXPLIQUE EL O LOS DESTRUCTOR
UTILIZADOS
Destructores
void __destruct ( void )

PHP 5 introduce un concepto de destructor similar a aquellos de otros lenguajes


de programación orientada a objetos, tal como C++. El método destructor será
llamado tan pronto como todas las referencias a un objeto en particular sean
removidas o cuando el objeto sea explícitamente destruido.

Ejemplo de Destructor

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();


?>

Como los constructores, los destructores de la clase padre no serán llamados


explícitamente por el compilador. Para ejecutar un destructor padre, se debe
tener una llamada explícita a parent::__destruct() en el cuerpo del destructor.

Nota: El destructor es llamado durante la finalización del script, de tal manera


que los headers ya han sido enviados.

Nota: Intentar arrojar una excepción desde un destructor produce un error fatal.

Ejemplo

En el siguiente ejemplo se crean tres clases que forman una cadena de herencia.
La clase First es la clase base, Second se deriva de First y Third se deriva de
Second. Las tres tienen destructores. En Main(), se crea una instancia de la clase
más derivada. Cuando ejecute el programa, observe que se llama a los
destructores de las tres clases automáticamente y en orden, desde la más
derivada hasta la menos derivada.
class First

~First()

System.Console.WriteLine("First's destructor is called");

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

class Second: First

~Second()

System.Console.WriteLine("Second's destructor is called");

class Third: Second

~Third()

System.Console.WriteLine("Third's destructor is called");

class TestDestructors

static void Main()

Third t = new Third();

Resultados

Third's destructor is called

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Second's destructor is called

First's destructor is called


class First
{
~First()
{
System.Console.WriteLine("First's destructor is called");
}
}

class Second: First


{
~Second()
{
System.Console.WriteLine("Second's destructor is called");
}
}

class Third: Second


{
~Third()
{
System.Console.WriteLine("Third's destructor is called");
}
}

class TestDestructors
{
static void Main()
{
Third t = new Third();
}
}

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Resultados
Third's destructor is called

Second's destructor is called

First's destructor is called

La destrucción del objeto’ a.) La destrucción de los objetos

Cuando un objeto no va a ser utilizado, el espacio de memoria de dinámica que


utiliza ha de ser liberado, así como los recursos que poseía, permitiendo al
programa disponer de todos los recursos posibles. A esta acción se la da el
nombre de destrucción del objeto.

En Java la destrucción se puede realizar de forma automática o de forma


personalizada, en función de las características del objeto.

b.) La destrucción por defecto: Recogida de basura

El intérprete de Java posee un sistema de recogida de basura, que por lo general


permite que no nos preocupemos de liberar la memoria asignada
explícitamente.

El recolector de basura será el encargado de liberar una zona de memoria


dinámica que había sido reservada mediante el operador new, cuando el objeto
ya no va a ser utilizado más durante el programa (por ejemplo, sale del ámbito
de utilización, o no es referenciado nuevamente).

El sistema de recogida de basura se ejecuta periódicamente, buscando objetos


que ya no estén referenciados.

c.) La destrucción personalizada: finalize

A veces una clase mantiene un recurso que no es de Java como un descriptor de


archivo o un tipo de letra del sistema de ventanas. En este caso sería acertado el
utilizar la finalización explícita, para asegurar que dicho recurso se libera. Esto
se hace mediante la destrucción personalizada, un sistema similar a los
destructores de C++.

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Para especificar una destrucción personalizada se añade un método a la clase


con el nombre finalize:

class Clase Finalizada?{


Clase Finalizada() { // Constructor
// Reserva del recurso no Java o recurso compartido
}
protected void finalize() {
// Liberación del recurso no Java o recurso compartido
}
}

El intérprete de Java llama al método finalize(), si existe cuando vaya a reclamar


el espacio de ese objeto, mediante la recogida de basura.

Debe observarse que el método finalize () es de tipo protected void y por lo


tanto deberá de sobreescribirse con este mismo tipo.

Un destructor es un método que pertenece a una clase y el mismo (en C++)


debe tener el mismo nombre de la clase a la que pertenece. A diferencia de los
otros métodos de la clase, un destructor deberá ser del tipo void, es decir, el
mismo no regresará valor alguno. Para diferenciar a un método destructor de
un método constructor, al nombre del destructor se le debe anteponer el
caracter ~ (Alt + 126).

El objetivo principal del destructor es el de retirar de la memoria al objeto, o


sea, el destructor hace todo lo contrario que el constructor.

Los destructores suelen usarse para liberar memoria que haya sido solicitada
por el objeto a travez de las ordenes malloc(), new, etc. En tales casos se deberá
incluir dentro del método destructor la orden free, delete, etc., según sea el
caso.

// clase Pareja con constructor y destructor


class Pareja
{
// atributos
double a, b;

public:
// constructor de base ( nulo )
Pareja() {}

// constructror parametrizado

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5

Pareja(double x, double y) : a(x), b(y) {}

// destructor
~Pareja() {}

// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};

GOMEZ PEREZ JESUS FRANCISCO


ING. EN SISTEMAS COMPUTACIONALES

You might also like