Clases y Constructores

Anuncio
CLASES
El elemento básico de la programación orientada a objetos en Java es la clase.
Una clase define la forma y comportamiento de un objeto. Cualquier concepto que
se desee representar en un programa en Java está encapsulado en una clase.
Para crear una clase sólo se necesita un archivo fuente que contenga la palabra
clave class seguida de un identificador y un par de llaves para el cuerpo.
class Punto {
// ... Cuerpo de la Clase }
La clase se almacena en un archivo fuente con el mismo nombre de la clase y la
extensión java, en este caso sería Punto.java.
Las clases en Java incluyen variables y métodos de instancia. Los programas en
Java constan por lo general de varias clases de Java provenientes de distintos archivos
fuente.
Una clase es una plantilla para un objeto. Una clase define la estructura de un
objeto y su interfaz funcional, conocida como métodos. Cuando se ejecuta un
programa en Java, el sistema utiliza definiciones de clase para crear instancias de las
clases, que son los objetos reales. La forma general de una definición de clase se
muestra a continuación:
class nombre_de_clase extends nombre_de_superclase {
type variable_de_instancia1;
type variable_de_instancia2;
type variable_de_instanciaN;
type nombre-de método1 (lista_de_parámetros) {
// ... cuerpo-del-método; }
type nombre de método2 (lista-de parámetros)
// ... cuerpo-del-método; }
type nombre de_métodoN (lista_de_parámetros) {
// ... cuerpo_del_método; }
{
}
La palabra clave extends se utiliza para indicar que nombre de clase será
una subclase de nombre de superclase. En la raíz de la jerarquía de clases de Java
se encuentra la clase Object, si se desea realizar una subclase de Object
directamente, se puede o mitir la cláusula extends porque el compilador la incluirá
automáticamente.
Referencia a objetos
Cada nueva clase que se crea añade un nuevo tipo que se puede utilizar igual que
los tipos simples. Por lo tanto, cuando se declara una nueva variable, se puede utilizar
un nombre de clase como tipo. A estas variables se las conoce como referencia a
objeto .
Una instancia u objeto es una copia individual de la plantilla de la clase, con
su propio conjunto de datos llamado variables de instancia. Cuando se declara
que el tipo de una variable es una clase, tiene como valor por omisión el null, que es
una referencia al tipo Obiect, y, por lo tanto, es compatible en tipo con todas las
otras clases. Declaramos una variable p cuyo tipo es de la clase Punto de la siguiente
forma:.
Punto p ;
Aquí, la variable p tiene un valor null.
null
p
Una referencia a un objeto es simplemente un puntero a memoria. Java
que no permite manipular estos punteros como si fueran enteros, porque se
provocaría que una referencia a objeto apuntase a posiciones de memoria
arbitrarias. De hecho, la instancia real de una clase a la que se referencia no se
almacena en la dirección de una referencia a objeto. Las referencias a objeto
apuntan a una estructura de datos intermedia que almacena la información del
tipo junto con la dirección en el montículo actual de los datos de instancia
reales.
V a r i a bl es d e i ns t a nc i a
Los datos se encapsulan dentro de una clase declarando las variables dentro de
las llaves de apertura y cierre de la declaración de la clase: { } . A las variables que se
declaran en este ámbito se las conoce como variables de instancia. Las variables
de instancia se declaran fuera del ámbito de un método. Por ejemplo, si se declara
una clase de nombre Punto, con dos variables de instancia enteras llamadas x e y,
tendremos:
class Punto {
int x, y;
}
El operador new
El operador new crea una instancia de una clase y devuelve una referencia a
ese objeto. Por ejemplo en:
Punto p = new Punto();
se crea una nueva instancia de Punto y se almacena en una variable p. Aquí p es
una referencia a una instancia de Punto, es decir, la variable p es una referencia al
objeto, realmente no lo contiene. Se pueden crear múltiples referencias al mismo
objeto. Presentamos aquí un ejemplo, que crea un único objeto Punto, pero crea
dos variables que lo referencían.
Punto p = new Punto();
Punto p2 = p;
Cualquier cambio realizado en el objeto referenciado por p2 afectará al mismo
objeto al cual se refiere p. La asignación de p a p2 no asignó memoria ni copió nada
del objeto original. De hecho, las asignaciones posteriores a p simplemente
desligarán a p del objeto original sin afectar al propio objeto, como se muestra a
continuación.
Punto p = new Punto();
Punto p2 = p;
p = null;
Aunque se haya asignado p a null, p2 todavía apunta al objeto creado por el
operador new.
Cuando ya no haya ninguna variable que haga referencia a un objeto,
Java reclama automáticamente la memoria utilizada por ese objeto. A esto se
le llama recolección automática de basura .
En el ejemplo anterior, hemos creado un único objeto y lo hemos referenciado
dos veces. Esto permitía que dos variables afectaran al mismo objeto. Se obtiene un
conjunto distinto de variables de instancia cada vez que se crea un nuevo objeto.
Cada objeto tiene su propia copia de las variables de instancia de su clase, por lo que
los cambios sobre las variables de instancia de un objeto no tienen efecto sobre las
variables de instancia de otro.
Ahora crearemos dos objetos Punto diferentes y les pondremos distintos
valores a cada uno:
class DosPuntos {
public static void main(String args[]) {
Punto pl = new Punto();
Punto p2 = new Punto();
pl.x = 10; pl.y = 20;
p2.x = 42; p2.y = 99;
System.out.println("x = " + pl.x + 'y = " + pl.y); System.out.println("x = "
+ p2.x + " y = " + p2.y);
}
}
Este ejemplo reutiliza la clase Punto , pero crea dos puntos y establece los
valores de x e y. El aspecto de la salida cuando lo ejecutamos es:.
C:\> java TwoPuntos
x = 10 y = 20
x = 42 y = 99
Dado que main sólo se ejecuta en la clase que se indica en la línea de
comandos, se ignora completamente el método main de la clase Punto en este
caso.
El operador punto ( . )
El operador punto ( . ) se utiliza para acceder a las variables de instancia y los
métodos contenidos en un objeto. Esta es la forma general de acceder a las variables
de instancia utilizando el operador punto:
referencia_a_objeto.nombre _de_variable
Aquí referencia_a_objeto es una referencia a un objeto y
nombre_de_variable es el nombre de la variable de instancia contenida en el
objeto al que se desea acceder. El fragmento de código siguiente muestra cómo se
puede utilizar el operador punto para almacenar valores en variables de instancia:
p.x = 10; p.y = 20;
La línea siguiente muestra cómo referirnos a valores de variables de instancia
utilizando el operador punto:
System.out.println("x = " + p.x + " y = " + p.y);
En el siguiente código añadimos un método main a la clase Punto creamos
un Punto, almacenamos algunos valores en él e imprimimos después los valores
resultantes:
class Punto {
int x, y;
public static void main(String args[]) {
Punto p = new Punto();
p.x = 10; p.y = 20;
System.out.println("x = " + p.x + " y = " + p.y);
}
}
Cuando se ejecuta este programa, se observa la siguiente salida
C:\> java Punto
x = 10 y = 20
Declaración de método
Un método es la interfaz funcional de una clase. Los métodos son subrutinas
unidas a una definición de clase específica. Se declaran dentro de una definición de
clase al mismo nivel que las variables de instancia.
En la declaración de los métodos se define que devuelven un valor de un tipo
concreto y que tienen un conjunto de parámetros de entrada. La forma general de una
declaración de método es
tipo nombre_del_método ( lista-formal-de-parámetros )
{ cuerpo-del-método; }
Aquí,. tipo es el tipo que el método va a devolver, incluyendo void en el caso
de que no se desee devolver ningún valor. El nombre_del_método es cualquier
identificador distinto de los ya utilizados por los nombres de clase en el ámbito
actual. La lista-formal-de-parámetros es una secuencia de parejas de tipo e
identificador separadas por comas. Si no se desean parámetros, la declaración del
método debería incluir un par de paréntesis vacío.
Continuando con nuestro ejemplo Punto, se podría utilizar el método siguiente para inicializar las dos variables de instancia a la vez. El método se declara dentro
de las llaves de apertura y cierre de la clase, en el mismo ámbito de las dos variables
de instancia.
class Punto {
int x, , y;
void iniciar (int a, int b) {
x = a; y= b;
}
}
Nos podemos referir directamente a x e y sin tener que utilizar p1. x debido a
que los métodos se pueden referir directamente a las variables de instancia. Como
iniciar no devuelve ningún valor se antecede del tipo void .
Llamada a un método
Se llama a los métodos dentro de una instancia de una clase utilizando el
operador punto ( . ). La forma general de una llamada a método es:
referencia_a_objeto . nombre_del_método ( lista-de-parámetros );
Aquí, referencia_a_objeto es cualquier variable que se refiere a un objeto,
nombre_del_método es el nombre de un método de la clase con la que se declaró
referencia_a_objeto y lista-de-parámetros es una lista de valores o expresiones
separados por comas que coinciden exactamente en número y tipo con cualquiera de
los métodos declarados en la clase.
En este caso, podríamos llamar al método iniciar sobre cualquier objeto Punto
para establecer x e y. Este es un fragmento de código que muestra cómo funciona:
Punto p = new Punto();
p.iniciar (10, 20);
Este ejemplo crea una instancia nueva de Punto, almacenando la referencia en
p. A continuación se utiliza el operador punto para llamar al método iniciar
sobre la instancia, pasando 10 y 20 a los parámetros a y b respectivamente. Dentro
del método iniciar, x e y se refieren directamente a las variables de instancia
del objeto referenciado por p, mientras que a y b toman el valor 10 y 20
respectivamente. Las asignaciones de x a 10 y de y a 20 vienen a continuación y el
método termina.
No hay ningún modo en Java de pasar un tipo primitivo por referencia,
ya que todos los tipos primitivos se pasan por valor, lo que significa que un
método no tiene acceso a la variable que fue utilizada para pasar el valor. Las
referencias a instancias de objeto se pasan también por valor, lo qué significa
que no se puede cambiar la variable que hace referencia al objeto, pero de
hecho se puede cambiar el contenido del objeto al que se refiere la referencia,
dado que todos los objetos se pasan por referencia.
This
Java incluye un valor de referencia especial llamado this, que se utiliza
dentro de cualquier método para referirse al objeto actual. El valor this se
refiere al objeto sobre el que ha sido llamado el método actual. Se puede utilizar
this siempre que se requiera una referencia a un objeto del tipo de la clase actual.
En el código ejemplo anterior, llamamos a p. iniciar. Una vez dentro del método
iniciar, this apuntará al mismo objeto al que apunte p. Si hay otros objetos que
utilicen el mismo código, seleccionados a través de otras instancias, cada uno
tiene su propio concepto único de this.
Ocultar variables de instancia
En Java es ilegal declarar dos variables locales con el mismo nombre dentro
del mismo ámbito o uno que lo incluya. Sí se permite el declarar variables
locales, incluyendo parámetros formales de métodos, que se solapen con los
nombres de las variables de instancia, pero se ocultarían dichas variables. Para
accesarlas se usa el valor de referencia this.
Esta es otra versión de iniciar , que utiliza x e y como nombres de
parámetro formales y después utiliza this para acceder a las variables de
instancia del objeto actual.
void iniciar (int x, int y) {
this.y = x;
this.y = y;
}
Si lo hubiésemos hecho sin this, entonces x se hubiera referido al parámetro
formal, ocultando la variable de instancia x. this nos permite referirnos
directamente al objeto en sí, en lugar de que el ámbito actual defina a que variable
nos referimos.
El ejemplo DosPuntos se podría modificar para usar el nuevo método
iniciar, que ahora cuenta con la referencia this, como se muestra aquí:
class Punto {
int x, y;
void iniciar(int x, int y) {
this.x = x;
this.y = y;
}
}
class DosPuntosIniciar {
public static void main(String args[]) {
Punto. p1 = new Punto();
Punto. p2 = new Punto();
p1.iniciar(10, 20);
p2.iniciar(42, 99);
System.out.println("x = " + p1.x + " y = " + p1.y);
System.out.println("x = “ + p2.x + " y = " + p2.y);
}
}
Este ejemplo muestra que se crean dos objetos Punto y se llama a sus
respectivos métodos iniciar con un par de valores diferente. La salida de este
programa es idéntica a la del ejemplo DosPuntos anterior.
Constructores
Un constructor es un método especial que inicializa un objeto inmediatamente
después de su creación. Tiene exactamente el mismo nombre de la clase en la que
reside; de hecho, ningún otro método puede tener su nombre igual al de la clase a la
que pertenece. Después de crear el objeto se llama automáticamente al constructor,
antes de que termine el operador new.
Los constructores no devuelven ningún tipo, ni siquiera void. Esto se debe a que
el tipo implícito que devuelve un constructor de clase es el propio tipo de la clase. Es
tarea del constructor inicializar todo el estado interno de un objeto para que el código
que crea una instancia con el operador new tenga un objeto íntegro y utilizable
inmediatamente.
Retomando el ejemplo Punto, podemos inicializar las dos variables de
instancia cuando construimos el objeto. Aquí, sustituiremos el método iniciar por un
constructor:
class Punto {
int x, y;
Punto(int x, int y) {
this.y = x; this.y = y;
}
}
class PuntoCreate {
public static void main(String args[]) {
Punto p = new Punto(10, 20);
System.out.println("x = " + p.x + " y = " + p,y);
}
}
Se llama al método del constructor justo después de crear la instancia y antes de
que new vuelva al punto de la llamada. La lista de parámetros especificada después
del nombre de la clase en una sentencia new se utiliza para pasar parámetros al
constructor correspondiente.
Sobrecarga de métodos
Se pueden crear más de un método con el mismo nombre, pero con listas de
parámetros distintas. A esto se le llama sobrecarga de método. La sobrecarga de
métodos se utiliza para soportar el polimorfismo en Java. Se sobrecarga un método
siempre que se crea un método en una clase que ya tiene un método con el mismo
nombre. Por ejemplo, podemos añadir a la clase Punto dos constructores utilizando
la sobrecarga de métodos:
class Punto {
int x, y;
Punto(int x, int y) {
this.y = x; this.y = y;
}
Punto() {
x = 0;
y = 0;
}
}
class CreaPunto {
public static void main(String args[}) {
Punto p = new Punto();
System.out.println("x = " + p.x + " y = " + p.y);
}
}
Este ejemplo crea un objeto Punto que llama al segundo constructor sin
parámetros en vez de al primero. Esta es la salida.
C:\> java CreaPunto x = 0 y = 0
En las llamadas a los constructores éstos se seleccionan en base al número
y tipo de parámetros que se les pase. Al número de parámetros con tipo de una
secuencia específica se le llama signatura de tipo . Java utiliza estas signaturas
de tipo para decidir a qué método llamar. En cualquier llamada a un método la
signatura de tipo debe coincidir exactamente. Es ilegal declarar dos métodos en
la misma clase con el mismo nombre, compartiendo las mismas signaturas de
tipo. No se consideran los nombres de los parámetros formales de los métodos
cuando se distingue entre métodos, sólo sus tipos.
This en los constructores
Un refinamiento adicional es que un constructor llame a otro para construir la
instancia correctamente. Por ejemplo:
class Punto {
int x, y;
Punto(int x, int y) {
this.y = x; this.y = y;
}
Punto() {
this(0, 0);
El segundo constructor llama ahora al primero para terminar de inicializar la
instancia.
También se pueden crear métodos sin constructor que utilicen la sobrecarga. Se
muestra aquí un ejemplo que añade dos versiones de un método llamado distancia a
la clase Punto. La función distancia devuelve la distancia euclidiana entre dos
puntos. Un método toma un par x, e y el otro toma otro objeto Punto. En este
ejemplo, se utiliza el método estático sqrt de la clase Math para calcular la raíz
cuadrada de su parámetro.
class Punto {
int x, y;
Punto(int x, int y) {
this.y = x;
this.y = y;
}
double distancia(int x, int y) {
int dx = this.y - x;
int dy = this.y - y;
return Math.sgrt(dx*dx + dy*dy);
}
double distancia(Punto p) {
return distancia(p.x, p.y);
}
class DistPunto {
public static void main(String args[]) {
Punto pl = new Punto(0, 0);
Punto p2 = new Punto(30, 40);
System.out.println("p1 = " + pl.x + + pl.y);
System.out.println("p2 = " + p2.x + + p2.y);
System.out.println("pl.distancia(p2) _ " + pl.distancia(p2));
System.out.println("pl.distancia(60, 80) _ " + pl.distancia(60, 80));
Este ejemplo muestra cómo se puede sobrecargar un método para tener dos
maneras alternativas de invocar el mismo cálculo. Observe que la segunda forma de
distancia llama a la primera para obtener el valor que devuelve. Esta es la salida de
este ejemplo:
C:\> java DistPunto
P1 = 0, 0
p2 = 30, 40
p1.distancia(p2) = 50
p1.distancia(60, 80) = 100
Java no se toma como criterio de selección de un método sobrecargado el tipo que
devuelve dicho método. Dos métodos no pueden compartir la misma signatura de
tipos, independientemente de los tipos que devuelvan.
Descargar