Tutorial Java Básico sobre escritura y sobre carga de métodos (Method overriding / overloading)


En este post se explicarán los usos de la sobrecarga y sobre escritura de métodos, sus diferencias así como algunas reglas que se deben seguir para utilizarlos.

Sobre escritura

Cuando se hereda de una clase se heredan algunos de sus métodos,  la sobre escritura de métodos es la posibilidad de una clase de cambiar el comportamiento de los métodos heredados. Esto se realiza debido a que puede que el comportamiento genérico que se hereda del padre no sea suficiente para la clase hija, veamos un ejemplo:

public class Vehicle {
	void run() {
		System.out.println("I'm running fast");
	}
}

class Car extends Vehicle {
	@Override
	void run() {
		System.out.println("I'm running in my 4 wheels");
	}
}

class Bike extends Vehicle {
	@Override
	void run() {
		System.out.println("I'm running in my 2 wheels");
	}
}

En este ejemplo se tienen las clases Bicicleta y Auto que heredan de Vehículo, como se puede observar la clase padre define el método run que imprime la leyenda “I’m running fast” pero las dos sub clases Bicicleta y Auto que sobre escriben el comportamiento del método run y cambian la leyenda que se imprime.

A continuación se presentan algunas reglas al momento de utilizar sobre escritura de métodos:

  • No es posible sobre escribir un método final
  • No es posible sobre escribir un método static
  • La lista de argumentos debe ser la misma que la del método sobre escrito
  • El valor de retorno debe ser del mismo tipo o un sub tipo que la del método sobre escrito
  • El nivel de acceso no puede ser más restrictivo que el método sobre escrito
  • El nivel de acceso puede ser menos restrictivo que el método sobre escrito
  • Es posible sobre escribir métodos solo si son heredados, por la sub clase, por ejemplo, los métodos privados no se heredan
  • Los métodos sobre escritos pueden arrojar cualquier tipo de excepción check
  • Los métodos sobre escritos no pueden arrojar ninguna excepción check nueva

Palabra reservada super

La palabra reservada super es utilizada para referirse a la clase padre, de este modo es posible ejecutar desde la sub clase métodos definidos en la clase padre. Modifiquemos el código mostrado en el ejemplo anterior:

class Car extends Vehicle {
	@Override
	void run() {
		super.run();
		System.out.println("I'm running in my 4 wheels");
	}
}

En este ejemplo, el método sobre escrito definido en la clase Car, ejecutará el método run de la clase Vehicle primero y después imprimirá el mensaje I’m running in my 4 wheels.

Sobre carga de métodos

La sobre carga de métodos permite tener multiples versiones de un método en una clase utilizando diferentes argumentos, imaginemos el siguiente escenario:

public class Calculator {

	int sum(int x, int y) {
		return x + y;
	}

	int sum(int x, int y, int z) {
		return x + y + z;
	}

	int sum(int[] x) {
		int sum = 0;
		for (int i : x) {
			sum += i;
		}
		return sum;
	}
}

En el ejemplo anterior se definen 3 métodos sum que reciben diferentes parámetros, de este modo podemos mantener un código limpio sin tener que crear métodos como sumThreeArguments(), sumTwoArguments(), etc.

A continuación se presentan algunas reglas al momento de utilizar sobre carga de métodos:

  • Es posible sobre cargar un método heredado
  • Un método sobre cargado debe cambiar la lista de argumentos
  • Un método sobre cargado puede cambiar el valor de retorno
  • Un método sobre cargado puede cambiar el modificador de acceso
  • Un método sobre cargado puede declarar excepciones nuevas

Los libros recomendados para este tema son:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Tutorial Java Básico Polimorfismo


El polimorfismo significa muchas formas, por esto debemos recordar que cualquier objeto en Java puede pasar la regla ES-UN con más de una clase (Para más información de esta regla ver el post Tutorial Java Básico Herencia). Esto significa que un objeto puede ser de más de un tipo, veamos un ejemplo:

class Animal {
}
class Dog extends Animal {
}

En este ejemplo tenemos dos clases Animal y Perro, de tal modo que si creamos un objeto se puede decir lo siguiente basado en la regla ES-UN:

  • Un Perro es un Perro
  • Un Perro es un Animal
  • Un Perro es un Objeto
  • Un Animal es un Objeto
  • Un Objeto es un Objeto

Entonces, ¿Cómo se ve esto utilizando Java ?

	Dog d = new Dog();        //Un Perro es un Perro
	Animal a = new Dog();     // Un Perro es un Animal
	Object o = new Dog();     //Un Perro es un Objeto

	Object oa = new Animal(); //Un Animal es un Objeto
	Object od = new Dog();    //Un Objeto es un Objeto

Viendo esto, podemos decir que siempre existe polimorfismo ya que todas las clases heredan de object y pueden ser tratados como por su tipo y como por el tipo Object.

Referencias

Como se puede observar las referencias son un punto clave cuando se habla de polimorfismo, ya que son estas las que pueden apuntar a multiples tipos de objetos, por esto mencionemos algunas reglas que se tienen en el uso de referencias:

  1. Una referencia apunta a un objeto en memoria
Dog d = new Dog();

La referencia de tipo Dog es “d” y apunta a un objeto en memoria de tipo Dog

  1. Una referencia puede ser re asignada a un objeto diferente en memoria (a menos que este declarada como final)
Dog d = new Dog();
d = new Dog();

La referencia de tipo Dog es “d” y apunta inicialmente a un objeto de tipo Dog, después, la misma referencia apunta a un nuevo objeto de tipo Dog.

  1. La referencia que se utiliza define los métodos del objeto que pueden ser invocados
class Animal {
	void born() {
	}
}

class Dog extends Animal {
	void bark() {
	}
}

En este ejemplo se tiene la clase Animal que cuenta con el método nacer, y la clase Perro que cuenta con el método ladrar, ahora veamos el siguiente método main:

Captura de pantalla 2017-06-28 a las 5.44.06 p.m.

Como se puede observar en la imagen se creó un objeto de tipo perro y se tienen los dos métodos disponibles, ladrar y nacer, ahora veamos lo siguiente:

Captura de pantalla 2017-06-28 a las 5.45.55 p.m.

Si creamos el mismo objeto perro pero ahora se utiliza una referencia de tipo Animal solo se tendrá disponible el método nacer. Con esto se demuestra que la referencia define los métodos disponibles.

  1. Una referencia puede apuntar a un objeto de su tipo o sub tipo
Animal d = new Animal();
d = new Dog();

En este ejemplo se puede observar con se crea una referencia de tipo Animal apuntando a un objeto de tipo animal y después se apunta a un objeto del tipo Perro el cuál hereda de Animal.

  1. Es posible crear una referencia utilizando una clase o una interfaz
interface Funny {
	void smile();
}

class Animal {
	void born() {
	}
}

class Dog extends Animal implements Funny {
	void bark() {
	}
	@Override
	public void smile() {
	}
}

Si se cuenta con las clases e interfaces mencionadas es posible hacer lo siguiente:

Funny f = new Dog();

Pero solo estará disponible para su uso el método smile().

Caso de ejemplo

Una vez que ya se entiende el concepto de polimorfismo y se entiende como utilizar las referencias de distintas formas, la pregunta es ¿Cómo lo utilizo en mi aplicación?, veamos un ejemplo:

interface Figure {
	double calculateArea();
}

class Circle implements Figure {
	private double radius;

	public Circle(double radius) {
		this.radius = radius;
	}

	@Override
	public double calculateArea() {
		return Math.PI * (Math.pow(radius, 2));
	}

}

class Square implements Figure {
	private double side;

	public Square(double side) {
		this.side = side;
	}

	@Override
	public double calculateArea() {
		return side * side;
	}

}

public class Triangle implements Figure {
	private double base;
	private double height;

	public Triangle(double base, double height) {
		this.base = base;
		this.height = height;
	}

	@Override
	public double calculateArea() {
		return (base * height) / 2;
	}

Como se puede observar se cuenta con 3 clases y una interfaz Figura, Cuadrado, Triángulo y Circulo. La interfaz Figura define el método  public double calculateArea() y las 3 figuras implementan ese método de forma diferente.  Ahora imaginemos que deseamos crear una clase que calcule el area de multiples figuras, en este momento solo son 3 pero se espera que podamos tener 300 figuras más en la aplicación.

Entonces la pregunta sería,  ¿tendremos que crear 300 métodos para las 300 figuras? La respuesta es no, a continuación se muestra como se resolvería el problema haciendo uso del polimorfismo:

public double calcAreas(Figure []figures){
	double area=0;
	for (Figure figure : figures) {
		area=figure.calculateArea();
	}
	return area;
}

Como se puede observar el método calcAreas no sabe que figuras existen, este solo hace uso de una arreglo de Figuras y con esto calcula todas las areas que requiere, entonces no importa cuantos tipos de Figuras creemos este método será capaz de calcular el área de todas ellas.

Los libros recomendados para este tema son:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Tutorial Java Básico Herencia


La herencia se encuentra en todos lados en Java, utilizando esta característica de la Programación Orientada a Objetos podemos transmitir atributos y métodos de una clase a otra.

¿Cómo utilizar herencia en Java?

En Java no existe la multi herencia, de tal modo que solo es posible heredar de una sola clase, para hacerlo se debe hacer lo siguiente :

class ClassName extends ParentClass{}

Para hacer herencia en Java se utiliza la palabra reservada extends.

¿Cuándo utilizar herencia?

Uno de los errores más comunes de los desarrolladores es utilizar herencia en un par de clases donde no existe esa relación, entonces, ¿Cuándo utilizar herencia? Debemos utilizar herencia cuando entre un par de clases se cumple la relación ES-UN, veamos algunos ejemplos:

Mal uso

/**
 * @author maagapi
 *
 */
class NoteBook {
}

class Book extends NoteBook {
}

Este es uno de los errores más comunes, en este ejemplo tenemos la clase libro y cuaderno, podríamos pensar que un ambas tiene características similares y pensar que uno puede heredar del otro. Para resolver esta duda tenemos que aplicar la regla ES-UN.

  • Book ES-UN NoteBook : No un libro no es un cuaderno, por eso podemos decir que no existe herencia entre ambos.
/**
 * @author maagapi
 *
 */
class Car {
}

class Bus extends Car {
}

En este ejemplo podríamos tener una confusión similar ya que podríamos pensar que como ambos pueden tener llantas, color, etc. Puede uno heredar del otro, así que para resolver la duda aplicaremos de nuevo la regla ES-UN:

  • Un Bus es un Auto :No ambos son similares pero no podemos decir que un auto bus es un auto, para resolver este caso se podría crear una clase padre llamada LandVehicle, de este modo tanto auto bus como auto podrían heredar de vehículo terrestre.

Buen uso

/**
 * @author maagapi
 *
 */
class Animal {
}

class Dog extends Animal {
}

En este ejemplo se tienen dos clases, Animal es la clase padre y Perro es la clase hija, así que aplicaremos la regla ES-UN:

  • Un Perro es un Animal : La respuesta es si, de tal modo que se puede aplicar herencia sin ningún problema
class Number {
....
}

class Double extends Number {
....
}

Este es un ejemplo que viene en el api de Java, tenemos dos clases la clase Number y la clase Double, así que aplicaremos la regla:

  • Un double es un Number: La respuesta es si, de tal modo que Double puede heredar de Number.

Notas importantes sobre herencia

  • La herencia permite transmitir métodos y atributos de una clase a una sub clase.
  • Solo se heredan los métodos y atributos públicos, protected y default.
  • No se puede heredar de una clase final.
  • Es posible tener múltiples niveles de herencia.
  • Todas las clases en Java son sub clases de Object, aunque no hereden directamente de ella ya que si vamos hacia arriba en el árbol de herencia, eventualmente llegaremos a una clase que no herede de ninguna otra y esa hereda de Object.
  • El operador instanceof devolverá true cuando se utilice una referencia con su clase y todas sus clases padres para más información de instanceof ver Tutorial Java Básico Operador instanceof.

Los libros recomendados para este tema son:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Tutorial Java Básico Operador instanceof


La herencia se encuentra en todos lados en Java, en este post se hablará del operador instanceof, este es utilizado sobre referencias y determinará si una referencia apunta a un objeto es de un tipo en especial. Cuando se habla de herencia se habla del operador ES-UN, instanceof será la forma en la que seremos capaces de hacer esta evaluación en java.

Ejemplo


/**
 * @author maagapi
 *
 */
public class InstanceOfExample {
	public static void main(String[] args) {
		String cad = "Hello world !";
		System.out.println(cad instanceof String);
	}
}

Output:

true

Como se puede observar la salida es true, lo cual significa que la referencia cad apunta a un objeto de la clase String, con esto se puede decir que la variable cad ES-UN String.

Operador instanceof en la herencia

El operador instanceof se puede utilizar también para determinar si la referencia es de un super tipo, recordemos que este operador realizará la validación ES-UN

Ejemplo


/**
 * @author maagapi
 *
 */
public class InstanceOfExample {
	public static void main(String[] args) {
		String cad = "Hello world !";
		System.out.println(cad instanceof String);
		System.out.println(cad instanceof Object);
	}
}

Salida:

true
true

Si observamos la salida podremos ver que esta imprime verdadero para ambos casos, lo cual significa que la referencia cad ES-UN String pero también cad ES-UN Object.

Reglas importantes

A continuación se listan algunas de las reglas más importantes al utilizar el operador:

  • instanceof es una palabra reservada, por tanto no se debe utilizar como identificador en las aplicaciones.
  • solo es posible utilizarlo sobre referencias y clases que pertenecen al mismo árbol de herencia, de tal modo que si se trata de hacer lo siguiente resultará en un error de compilación:

/**
 * @author maagapi
 *
 */
public class InstanceOfExample {
	public static void main(String[] args) {
		String cad = "Hello world";
		System.out.println(cad instanceof Integer);
	}
}

Salida:

Incompatible conditional operand types String and Integer
  • Por esto solo es posible utilizar el operador con su clase correspondiente o con alguno de sus super tipos.
  • Si se aplica el operador instanceof a una referencia apuntando a null, sin importar la clase con la que se valide el resultado siempre será false.

Los libros recomendados para este tema son:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com