Professional Documents
Culture Documents
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.
Nombre_Clase.Nombre_Procedimiento_o_Funcion
//=============
TYPE
//=============
TPregunta = clase
protegido
_CodPregunta: cadena;
_CodCampo: cadena;
funcion _LeeValor(): variante;
procedimiento _EscribeValor(_valor: variante);
publico
//=============================
// 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
//====
VAR
//====
Nombre, Apellido1, Apellido2, NombreCompleto: TPregunta;
// Preguntas de la prospección
//=================
// CODIGO PRINCIPAL
//=================
INICIO
FinProspeccion(Cierto, '1');
FIN.
Otros ejemplos
(...)
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();
//***************************************//
//** Implementación de clase TProducto **//
//***************************************//
constructor TProducto.Crear();
inicio
_RegId := 0;
fin;
destructor TProducto.Destruir();
inicio
Si _RegId <> 0 entonces
LiberarRegistro(_RegId);
fin;
LiberarRegistro(_RegId);
_HaCambiado := Cierto;
fin;
(...)
TIPO
TParejaEnteros = clase
Privado
procedimiento _Intercambia();
Protegido
_a, _b: entero;
_asignada: booleano;
_ordenar: 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._Intercambia();
var
c: entero;
inicio
c := _b;
_b := _a;
_a := c;
fin;
procedimiento TParejaEnteros.InterCambia();
inicio
si NO _ordenar entonces _InterCambia();
fin;
fin;
fin;
procedimiento TParejaEnteros.Acerar();
inicio
_a := 0;
_b := 0;
fin;
INICIO
...
FIN.
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.
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.
...
...
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.
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.
...
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.
...
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.
[ implements NombredeInterface ] {
...
Los puntos entre [ y ] son opcionales. Una declaración de clase define los
siguientes aspectos de una clase.
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).
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.
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.
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.
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:
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
native no no yes no no
transient no yes no no no
volatile no yes no no no
Programa Java
Ejemplo:
Por consola:
Hola Jesus
Modificadores de acceso
• public
• protected
• private
• internal
• protected internal
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
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
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;
}
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
}
class SampleClass
{
public int x; // No access restrictions.
}
.
// 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:
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();
Ejemplo
// protected_keyword_2.cs
using System;
class Point
{
protected int x;
protected int y;
}
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.
// private_keyword.cs
using System;
class Employee
{
private string name = "FirstName, LastName";
private double salary = 100.0;
class MainClass
{
static void Main()
{
Employee e = new Employee();
Los modificadores de acceso sirven para restringir el acceso a los campos o a los
métodos de una clase.
• 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.
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;
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
clase no es pública entonces la clase sólo puede ser usada dentro del paquete
que la contiene.
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.
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
puesta en práctica pueden cambiar en cualquier tiempo sin afectar otras partes
del programa.
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.
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.
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
Fecha unaFecha;
unaFecha.anho = 2004;
unaFecha.mes = 1;
unaFecha.dia = 25;
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);
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.
Con lo contado hasta ahora evitamos tener que cambiar código en caso de
cambiar parámetros.
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).
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.
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.
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.
#include <InterfaceFecha.h>
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;
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.
class InterfaceFecha
{
public:
#include <InterfaceFecha.h>
#include <Fecha.h>
InterfaceFecha *InterfaceFecha::dameNuevaFecha()
{
return new Fecha();
}
#include <InterfaceFecha.>
...
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.
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:
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.
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.
native, son métodos escritos es otro lenguaje. Java soporta actualmente C y C++.
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.
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.
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
}
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
miObjeto.miMetodoDeInstancia();
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
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();
MiClase::miMetodoDeClase();
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
}
}
class UnaClase {
int var;
UnaClase() {
var = 5;
}
unMetodo() {
var += 5;
}
}
Paso de parámetros
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.
// Clase principal
class java515 {
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.
public: indica que es un método accesible a través de una instancia del objeto.
Un tipo básico.
Métodos
Estructuración en Java
Llamada a un método
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
Ejemplo
import java.io.*;
class suma
{
public static void main(String arg[ ]) throws IOException
{
int x,y;
int s = suma(x,y);
Salida a pantalla
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");
}
}
{
boolean p = false;
if (num % 2 == 0)
{
p = true;
}
return p;
}
}
Ejemplo
Código fuente
import java.io.*;
class palindromes
{
public static void main(String Arg[ ]) throws IOException
{
int numero = 0;
int contador = 0;
numero++;
}
}
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;
}
}
**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
---------
FIN
INICIO
cont <-- 0
leer a , b
FIN
ALGORITMO
---------
RETORNAR sum
FIN
INICIO
leer a , b
s <-- sumatoria(a,b)
escribir "El valor de la sumatoria de " + a + " hasta " + b + " es : " + s
FIN
return cnt;
}
…………………
}
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.
Asignaciones a variables
laCuenta.cnt = 0;
Operaciones matemáticas
Binarios: + - * / % …..etc.
GOMEZ PEREZ JESUS FRANCISCO
ING. EN SISTEMAS COMPUTACIONALES
CUESTIONARIO UNIDAD 5
Multiplicativos * / %
Aditivos + -
Igualdad == !=
OR lógico ||
Condicional ? :
Algunos ejemplos:
<= devuelve "true" si un valor es menor o igual que otro: total <= maximo;
Llamadas a métodos
// 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() {
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+")";
}
}
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.*;
return (float)Math.sqrt(x*x+y*y);
Nombre_de_la_Clase<punto>Nombre_del_Método(parámetros)
Práctica
return edad;
edad = laEdad;
return nombre;
nombre = elNombre;
tipo nombreParámetro
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.
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.
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.
Está función recibe dos parámetros, ambos de tipo entero, uno el divisor y otro
el dividendo.
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.
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.
Estos valores que se pasan del cuerpo principal del programa al procedimiento
se llaman parametros.
{ cuerpo de instrucciones; };
prog13.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
PrintWriter pagina;
HttpServletResponse response)
pagina =response.getWriter();
response.setContentType("text/html");
pagina.println("<HTML>");
double beta=3.1416;
pagina.println("</HTML>");
pagina.close();
};
double c = a + b;
};
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.
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.
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.
cambiarObjeto(ValorOReferencia objeto)
objeto es una copia de la referencia pass, es otra referencia que apunta al mismo
lugar. Al ejecutar la sentencia
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)
Al ejecutar la sentencia
Hay que tener claro entonces, que cuando se escribe una sentencia del estilo
cualquierFuncion(CualquierTipo argumento);
public SSuma() {}
class Arychan
{
//ATRIBUTOS
private String nombre;
private String descripción;
private String formaDeSer;
private double salario;
//METODOS
//...
public Arboles() {
System.out.println("Un árbol genérico");
}
Clase Arboles
• Como en todo programa Java , primeramente se define la Clase a través
del vocablo class.
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.
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.
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.Suma_a_i( 10 );
MiClase objeto;
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:
class MiClase {
int varInstancia;
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 ) );
}
Herencia
super( parametros_opcionales );
class SuperClase {
int varInstancia;
void verVarInstancia() {
System.out.println( "El Objeto contiene " + varInstancia );
}
}
class java508 {
public static void main( String args[] ) {
System.out.println( "Lanzando la aplicacion" );
Control de Acceso
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
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++.
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á:
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:
super.finalize();
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
class Punto {
int x , y ;
Punto ( int a , int b ) {
x=a;y=b;
}
}
Constructor no-args.
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
Por ejemplo:
class Punto {
int x , y ;
Punto ( int a , int b ) {
x=a;y=b;
}
Punto () {
x = 0 ; y = 0;
}
}
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
Clases:
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:
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
struct Coordenadas
{
int x,y,z;
void main(void)
{
struct Coordenadas coo; //Se define una variable, (coo), de tipo
Coordenadas.
class Coordenadas
{
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();
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:
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
};
void main(void)
{
Coordenadas coo;
....
}
class Coordenadas
{
int x,y,z;
public:
Coordenadas(int p, int q, int t) {x=p; y=q; z=t;} //Constructor común.
};
void main(void)
{
Coordenadas coo(6,7,22); //Se le pasa los valores 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.
Coordenadas(const Coordenadas c) //Constructor de copia.
{
x=c.x;
y=c.y;
z=c.z;
}
};
void main(void)
{
Funciones InLine:
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:
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 main(void)
{
Coordenadas coo;
coo.Cargar();
coo.Mostrar();
}
Destructores:
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.
En Ppal.h:
#include "ObjGraf.h"
En Ppal.cpp:
//--------------------------------------------------
//--------------------------------------------------
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:
Creación Dinámica
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:
//--------------------------------------------------
//--------------------------------------------------
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ó.
En Ppal.cpp:
//--------------------------------------------------
# include <iostream.h>
class Caja {
double longitud, anchura, altura;
public:
Caja (double dim1, double dim2, double dim3);
~Caja (void);
double volumen (void);
};
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';
}
#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;
};
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.
Ejemplo de Destructor
<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "Destroying " . $this->name . "\n";
}
}
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()
~Second()
~Third()
class TestDestructors
Resultados
class TestDestructors
{
static void Main()
{
Third t = new Third();
}
}
Resultados
Third's destructor is called
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.
public:
// constructor de base ( nulo )
Pareja() {}
// constructror parametrizado
// destructor
~Pareja() {}
// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};