Explorando la herencia en el lenguaje de programación Java

La herencia es uno de los conceptos centrales de la programación orientada a objetos. En programación, la palabra herencia representa una relación en la que una clase secundaria asume el estado y comportamiento de una clase principal.

El propósito de la herencia en el desarrollo de software es facilitar la reutilización de software seguro y confiable. Uno de los principales beneficios de usar la herencia es que elimina el código redundante en sus programas.

Cómo funciona la herencia

La idea detrás de la herencia es que muchas clases u objetos tienen el mismo conjunto de atributos y métodos. Por lo tanto, con el espíritu de producir software confiable, las nuevas clases ahora pueden extraerse de clases relacionadas preexistentes y, si es necesario, expandirse en estados y comportamientos existentes.

Un ejemplo del mundo real de cómo funciona la herencia sería considerar las frutas. Esta es una etiqueta amplia que sirve para encapsular una variedad de elementos diferentes.

Una manzana es una fruta y también lo es una naranja. Sin embargo, una naranja no es una manzana, por lo que no tendría frutas como uno de sus artículos de stock si tuviera una tienda. Quizás podría tener una sección de frutas en su inventario, y debajo de esa sección, tendría artículos más específicos como manzanas y naranjas.

Así es como funciona la herencia.

Uso de la herencia en Java

La herencia se puede utilizar en cualquier lenguaje de programación que utilice el paradigma de programación orientada a objetos . Sin embargo, la forma exacta en que se utiliza la herencia depende del lenguaje de programación específico.

Por ejemplo, C ++ también es un lenguaje de programación orientado a objetos . C ++ admite lo que se conoce como herencia múltiple, mientras que Java solo admite herencia única.

Lo que esto significa es que en Java una clase principal puede tener muchas clases secundarias, pero cada clase secundaria solo puede tener una clase principal única (herencia única). Sin embargo, existe una forma de lograr una herencia múltiple indirecta en Java mediante la creación de una relación de abuelo, padre e hijo.

Creación de la clase principal en Java

El proceso de seleccionar una clase principal de un documento de requisitos de software se conoce como análisis orientado a objetos. Durante este proceso, la frase "es un" se utiliza a menudo para identificar posibles relaciones de herencia. Basándose en nuestro ejemplo anterior, debería poder ver que la fruta sería nuestra clase principal.

Ejemplo de clase principal de fruta

 
public class Fruit {
//Variable Declaration
protected String seed;
protected String skinColor;
protected String taste;
//Default Constructor
public Fruit(){
seed = "";
skinColor ="";
taste ="";
}
//Primary Constructor
public Fruit(String seed, String skinColor, String taste){
this.seed = seed;
this.skinColor = skinColor;
this.taste = taste;
}
//getters and setters
public String getSeed() {
return seed;
}
public void setSeed(String seed) {
this.seed = seed;
}
public String getSkinColor() {
return skinColor;
}
public void setSkinColor(String skinColor) {
this.skinColor = skinColor;
}
public String getTaste() {
return taste;
}
public void setTaste(String taste) {
this.taste = taste;
}
//eat method
public void eat(){
//general code on how to eat a fruit
}
//juice method
public void juice() {
//general code on how to juice a fruit
}
}

Uno de los aspectos más notables de la clase principal anterior es el modificador de acceso que se usa con cada declaración de variable. El modificador de acceso "protegido" es ideal para usar en clases principales porque evita que las clases que no son secundarias obtengan acceso a los atributos de datos de la clase principal.

Más abajo en el código, se le presentan los constructores, captadores y definidores que son bloques de construcción generales para cualquier clase de Java. Finalmente, se le presentan dos métodos (jugo y comer) que se crean en la clase principal de nuestro programa porque son universales para todas las frutas: todas las frutas se pueden comer y exprimir.

Creación de clases secundarias en Java

Las clases secundarias generalmente se denominan clases especializadas o derivadas porque heredan el estado y el comportamiento de un padre y, a menudo, personalizan estos atributos para que sean más específicos.

Continuando con nuestro ejemplo, debería poder ver por qué el naranja sería una clase infantil adecuada de la clase de frutas anterior.

Ejemplo de clase infantil naranja

 
public class Orange extends Fruit{
//variable declaration
private int supremes;
//default constructor
public Orange() {
supremes = 0;
}
//primary constructor
public Orange(String seed, String skinColor, String taste, int supremes){
super(seed, skinColor, taste);
this.supremes = supremes;
}
//getters and setters
public int getsupremes() {
return supremes;
}
public void setsupremes(int supremes) {
this.supremes = supremes;
}
//eat method
public void eat(){
//how to eat an orange
}
//juice method
public void juice() {
//how to juice and orange
}
//peel method
public void peel(){
//how to peel an orange
}
}

Hay una diferencia entre el aspecto de una declaración de clase Java normal y lo que tenemos en nuestro código anterior. La palabra clave "extiende" es lo que se utiliza en Java para hacer posible la herencia.

En nuestro ejemplo anterior, la clase secundaria (naranja) extiende la clase principal (fruta). Por lo tanto, la clase naranja ahora puede acceder y modificar el estado y el comportamiento de la clase de frutas.

El atributo único que tiene nuestra clase naranja se identifica con el nombre de la variable supremas (que es el nombre oficial de los pequeños segmentos que se encuentran en las naranjas). Aquí es donde entra en juego la especialización; no todas las frutas tienen supremas pero todas las naranjas sí, por lo que es lógico reservar la variable suprema para la clase naranja.

Agregar el método de "pelar" a los métodos preexistentes de "comer" y "jugo" también es lógico porque, aunque no todas las frutas se pueden pelar, las naranjas a menudo se pelan.

Debe tener en cuenta que si no tuviéramos la intención de alterar los métodos existentes de "comer" y "jugo", no necesitaríamos incluirlos en nuestra clase de naranja. Los métodos de la clase naranja anulan cualquier método similar en la clase de frutas. Entonces, si todas las frutas se comen y exprimen de la misma manera, no necesitaríamos crear estos métodos en la clase naranja.

El papel que juegan los constructores en la herencia

De forma predeterminada, las clases secundarias heredan los constructores de clases principales. Por lo tanto, si se crea un objeto de clase secundaria, esto significa que también se crea automáticamente un objeto de clase principal.

Volviendo a nuestro ejemplo, cada vez que se crea un nuevo objeto naranja, también se crea un objeto fruta porque una naranja es una fruta.

Detrás de escena, cuando se crea un objeto de clase secundaria, primero se llama al constructor de la clase principal seguido del constructor de la clase secundaria. En nuestra clase secundaria naranja anterior, si se crea un objeto naranja sin ningún parámetro, se llamará a nuestro constructor de clase de fruta predeterminado, seguido de nuestro contratista de clase naranja predeterminado.

El método “super” en nuestro constructor primario anterior es necesario porque especifica que el constructor primario — y no el constructor predeterminado — de la clase de fruta padre debe ser llamado siempre que se cree un objeto naranja con parámetros.

Ahora puede utilizar la herencia en Java

A partir de este artículo, pudo aprender qué es la herencia, cómo funciona y por qué es un concepto tan importante en la programación. Ahora puede crear sus relaciones de herencia utilizando el lenguaje de programación Java. Además, ahora sabe cómo sortear la regla de herencia única de Java creando una relación de abuelos.

Crédito de la imagen: Andreas Wohlfahrt / Pexels