Hagamos algo...

Bueno, vamos a hacer una pequeña aplicación para practicar un poco.

Para empezar, vamos a desarrollar un poquito una clase para trabajar con números complejos.

La clase Complejo

// grabar como Complejo.java
// compilar con "javac Complejo.java"
public final class Complejo extends Number {

	// atributos:
		private float x;
		private float y;

	// constructores:
	public Complejo() {
		x = 0;
		y = 0;
	}
	public Complejo(float  rx, float iy) {
		x = rx;
		y = iy;
	}

	// métodos:
	// Norma
	public final float Norma() {
		return (float)Math.sqrt(x*x+y*y);
	}
	public final float Norma(Complejo c) {
		return (float)Math.sqrt(c.x*c.x+c.y*c.y);
	}
	// Conjugado
	public final Complejo Conjugado() {
		Complejo r = new Complejo(x,-y);
		return r;
	}
	public final Complejo Conjugado(Complejo c) {
		Complejo r = new Complejo(c.x,-c.y);
		return r;
	}
	// obligatorios (son abstractos en Number):
	public final double doubleValue() {
		return (double)Norma();
	}
	public final float floatValue() {
		return Norma();
	}
	public final int intValue() {
		return (int)Norma();
	}
	public final long longValue() {
		return (long)Norma();
	}
	public final String toString() {
		if (y<0)
			return x+"-i"+(-y);
		else
			return x+"+i"+y;
	}
	// Operaciones matemáticas
	public static final Complejo Suma(Complejo c1, Complejo c2) {
		return new Complejo(c1.x+c2.x,c1.y+c2.y);
	}
	public static final Complejo Resta(Complejo c1, Complejo c2) {
		return new Complejo(c1.x-c2.x,c1.y-c2.y);
	}
	public static final Complejo Producto(Complejo c1, Complejo c2) {
		return new Complejo(c1.x*c2.x-c1.y*c2.y,c1.x*c2.y+c1.y*c2.x);
	}
	// Nos va a venir bien para aprender excepciones...
	// como división por cero!
	public static final Complejo DivEscalar(Complejo c, float f) {
		return new Complejo(c.x/f,c.y/f);
	}
	public static final Complejo Cociente(Complejo c1, Complejo c2) {
		float x = c1.x*c2.x+c1.y*c2.y;
		float y = -c1.x*c2.y+c1.y*c2.x;
		float n = c2.x*c2.x+c2.y*c2.y;
		Complejo r = new Complejo(x,y);
		return DivEscalar(r,n);
	}
}


Podemos hacer algunos comentarios...

Primero: no hay include aquí, ya que la única biblioteca que usamos es java.lang y se incluye automáticamente.

Segundo: la clase es public final, lo que implica que cualquier clase en éste u otros paquetes puede utilizarla, pero ninguna clase puede heredarla (o sea que es una clase estéril...).

Hagamos un resumen de los atributos y métodos de la clase:

	// atributos:
		private float x;
		private float y;

Siendo privados, no podemos acceder a ellos desde el exterior. Como además la clase es final, no hay forma de acceder a x e y. Además, al no ser static, cada instancia de la clase tendrá su propio x e y.

	// constructores:
	public Complejo()
	public Complejo(float  rx, float iy)

La clase tiene dos constructores, que se diferencian por su "firma" (signature), o sea por la cantidad y tipo de parámetros. El primero nos sirve para crear un objeto de tipo Complejo y valor indefinido (aunque en realidad el método lo inicializa en cero); con el segundo, podemos definir el valor al crearlo.

	// métodos:
	public final float Norma()
	public final float Norma(Complejo c)
	public final Complejo Conjugado()
	public final Complejo Conjugado(Complejo c)

Estos métodos también son duales; cuando los usamos sin parámetros devuelven la norma o el conjugado del objeto individual (instancia):

v = miComplejo.Norma();			// por ejemplo
		otroComplejo = miComplejo.Conjugado();

Con parámetros, en cambio, devuelven la norma o el conjugado del parámetro:

		v = unComplejo.Norma(miComplejo);
		otroComplejo = unComplejo.Conjugado(miComplejo);

Notar que lo siguiente es inválido:

otroComplejo = Complejo.Norma(miComplejo); // NO SE PUEDE!

...porque el método no es static, por lo tanto debe llamarse para una instancia en particular (en este caso, unComplejo).

	// obligatorios (son abstractos en Number):
	public final double doubleValue()
	public final float floatValue()
	public final int intValue()
	public final long longValue()

Estos métodos es obligatorio definirlos, ya que en la clase madre Number son métodos abstractos, o sea que debemos implementarlos aquí.

Como todos los métodos de esta clase son final, o sea que no puede ser redefinido. No es importante en realidad puesto que la clase no puede tener descendientes...

	public final String toString()

Este método nos sirve para representar el complejo como una cadena de caracteres, de la forma x+iy.

	// Operaciones matemáticas
	public static final Complejo Suma(Complejo c1, Complejo c2)
	public static final Complejo Resta(Complejo c1, Complejo c2)
	public static final Complejo Producto(Complejo c1, Complejo c2)
	public static final Complejo DivEscalar(Complejo c, float f)
	public static final Complejo Cociente(Complejo c1, Complejo c2)

Aquí definimos varias operaciones matemáticas. Notar que se han definido como static, o sea que los métodos son únicos independientemente de las instancias. Esto permite que los podamos ejecutar sobre una instancia o directamente sobre la clase:

miComplejo = unComplejo.Suma(comp1,comp2);	// vale
miComplejo = Complejo.Suma(comp1,comp2);		// TAMBIEN VALE!

Por ejemplo, la siguiente aplicación nos muestra cómo podemos usar algunos de estos métodos:

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

public class Ejemplo5 {

  public static void main(String args[]) {
    Complejo c1 = new Complejo(4,-3);
    System.out.println(c1+"\tNorma="+c1.Norma());
    Complejo c2 = new Complejo(-2,5);
    System.out.println(c2+"\tNorma="+c2.Norma()+"\n");

    System.out.println("("+c1+")/4 :"+Complejo.DivEscalar(c1,4));
    System.out.println("Suma  : "+Complejo.Suma(c1,c2));
    System.out.println("Resta : "+Complejo.Resta(c1,c2).toString());
    System.out.println("Multip: "+Complejo.Producto(c1,c2).toString());
    System.out.println("Divis : "+Complejo.Cociente(c1,c2).toString());
  }
}

Hay varias cosas para notar: por ejemplo, que podemos declarar las variables a la vez que las creamos:

Complejo c1 = new Complejo(4,-3);

c1 y c2 son dos objetos (instancias) de la clase Complejo.

Notar también que no hace falta poner para imprimir:

System.out.println(c1.toString().......);

ya que println automáticamente usa el método toString() de la clase para imprimir. Basta con poner c1, como en el programa, aunque c1.toString() también es válido.

También se ve el uso de los métodos static, accediéndolos directamente por la clase, en:

System.out.println("Suma  : "+Complejo.Suma(c1,c2));

Y tampoco aquí usamos toString(), aunque no está mal si se usa Complejo.Suma(c1,c2).toString().

Algo sobre los métodos

Analicemos un poco ahora cómo implementamos los métodos de la clase Complejo.

	public final int intValue() {
		return (int)Norma();
	}

Ya que no podemos convertir así nomás un complejo en un entero, para implementar estos métodos hemos elegido usar como valor de retorno la norma del complejo. En este caso, y dado que el método Norma() devuelve un float, usamos typecasting, es decir, lo convertimos en entero precediéndolo con (int).

	public final String toString() {
		if (y<0)
			return x+"-i"+(-y);
		else
			return x+"+i"+y;
	}

Aquí representamos el complejo en forma de cadena de caracteres. Hemos usado el if para representar adecuadamente el signo de la parte imaginaria. Noten también la asombrosa ayuda que nos brinda Java, al convertir automáticamente las variables x e y a String para la concatenación (mediante el signo "+")!

	public static final Complejo Cociente(Complejo c1, Complejo c2) {
		float x = c1.x*c2.x+c1.y*c2.y;
		float y = -c1.x*c2.y+c1.y*c2.x;
		float n = c2.x*c2.x+c2.y*c2.y;
		Complejo r = new Complejo(x,y);
		return DivEscalar(r,n);
	}

Aquí tengan en cuenta que las variables x e y, definidas como float, no tienen nada que ver con las variables (atributos) de la clase que están definidas al principio de la misma, sino que son variables locales al método.

Podemos usar return DivEscalar(r,n), ya que DivEscalar es un método propio de la clase; no hace falta poner Complejo.DivEscalar.

Qué pasa con r, el new Complejo(x,y) que creamos? Nada; cuando un objeto no se usa más, el "recogedor de basura" de Java lo elimina automáticamente (tarde o temprano) de la memoria.

	public final float Norma(Complejo c) {
		return (float)Math.sqrt(c.x*c.x+c.y*c.y);
	}

Aquí estamos usando otra clase, Math, que nos permite realizar varias operaciones matemáticas. Esta clase dispone de las constantes E y PI, y los métodos:

abs(x)			valor absoluto
acos(x)			arco coseno
asin(x)			arco seno
atan(x)			arco tangente
atan2(x,y)		componente angular de la representación polar de x,y
ceil(x)			menor entero mayor que x
cos(x)			coseno
exp(x)			ex
floor(x)		mayor entero menor que x
IEEEremainder(x,y)	resto de la división x/y según el estándar IEEE 754
log(x)			logaritmo natural
max(x,y)		el mayor de x e y
min(x,y)		el menor de x e y
pow(x,y)		xy
random()		número aleatorio entre 0 y 1
rint(x)			entero más cercano a x (devuelve un doble)
round(x)		entero más cercano a x (devuelve un entero o un long)
sin(x)			seno
sqrt(x)			raíz cuadrada
tan(x)			tangente

Algunos de estos métodos disparan excepciones, como sqrt o log de números negativos. Más adelante veremos cómo se usan las excepciones.

Otra clase que hemos estado usando mucho es la PrintStream, a la que pertenece el método println. En

		System.out.println(...)

out es un atributo de la clase System, del tipo (clase) PrintStream:

public final class System extends Object
{
        // Fields
    public static PrintStream err;
    public static InputStream in;
    public static PrintStream out;

        // Methods
.............
}

Veremos otras bibliotecas (para entrada/salida, gráficos, etc) muy pronto. Nos vemos en el capítulo VII.

<> Página de tutoriales <> Página Anterior <> Siguiente Capitulo <>