Conceptos de programación orientada a objetos en Java

1. Información general

En este artículo, analizaremos los conceptos de programación orientada a objetos (OOP) en Java. Discutiremos clases, objetos, abstracción, encapsulación, herencia y polimorfismo .

2. Clases

Las clases son el punto de partida de todos los objetos y podemos considerarlas como la plantilla para crear objetos. Una clase normalmente contiene campos de miembros, métodos de miembros y un método constructor especial.

Usaremos el constructor para crear objetos de la clase:

public class Car { // member fields private String type; private String model; private String color; private int speed; // constructor public Car(String type, String model, String color) { this.type = type; this.model = model; this.color = color; } // member methods public int increaseSpeed(int increment) { this.speed = this.speed + increment; return this.speed; } // ... }

Tenga en cuenta que una clase puede tener más de un constructor. Podemos leer más sobre las clases en nuestro artículo de clases.

3. Objetos

Los objetos se crean a partir de clases y se denominan instancias de la clase. Creamos objetos a partir de clases usando sus constructores:

Car veyron = new Car("Bugatti", "Veyron", "crimson"); Car corvette = new Car("Chevrolet", "Corvette", "black"); 

Aquí, hemos creado dos instancias de la clase Car. Lea más sobre ellos en nuestro artículo de objetos.

4. Abstracción

La abstracción oculta las complejidades de la implementación y expone interfaces más simples.

Si pensamos en una computadora típica, solo se puede ver la interfaz externa, que es más esencial para interactuar con ella, mientras que los chips y circuitos internos están ocultos para el usuario.

En OOP, la abstracción significa ocultar los detalles complejos de implementación de un programa, exponiendo solo la API requerida para usar la implementación. En Java, logramos la abstracción mediante el uso de interfaces y clases abstractas.

Podemos leer más sobre abstracción en nuestra clase abstracta y artículos de interfaz.

5. Encapsulación

La encapsulación oculta el estado o la representación interna de un objeto al consumidor de una API y proporciona métodos de acceso público vinculados al objeto para el acceso de lectura y escritura. Esto permite ocultar información específica y controlar el acceso a la implementación interna.

Por ejemplo, los campos de miembros de una clase están ocultos para otras clases y se puede acceder a ellos mediante los métodos de miembros. Una forma de hacer esto es hacer que todos los campos de datos sean privados y solo sean accesibles mediante el uso de métodos de miembros públicos :

public class Car { // ... private int speed; public int getSpeed() { return color; } public void setSpeed(int speed) { this.speed = speed; } // ... }

Aquí, la velocidad del campo se encapsula usando el modificador de acceso privado , y solo se puede acceder usando los métodos públicos getSpeed ​​() y setSpeed ​​() . Podemos leer más sobre modificadores de acceso en nuestro artículo de modificadores de acceso.

6. Herencia

La herencia es el mecanismo que permite que una clase adquiera todas las propiedades de otra clase heredando la clase. Llamamos a la clase heredada una clase hija y a la clase heredada como la superclase o clase padre.

En Java, hacemos esto ampliando la clase padre. Por lo tanto, la clase secundaria obtiene todas las propiedades del padre:

public class Car extends Vehicle { //... }

Cuando ampliamos una clase, formamos una relación IS-A. El coche es un vehículo . Entonces, tiene todas las características de un Vehículo .

Podemos hacer la pregunta, ¿por qué necesitamos la herencia ? Para responder a esto, consideremos un fabricante de vehículos que fabrica diferentes tipos de vehículos, como automóviles, autobuses, tranvías y camiones.

Para facilitar el trabajo, podemos agrupar las características y propiedades comunes de todos los tipos de vehículos en un módulo (una clase en el caso de Java). Y podemos permitir que los tipos individuales hereden y reutilicen esas propiedades:

public class Vehicle { private int wheels; private String model; public void start() { // the process of starting the vehicle } public void stop() { // process to stop the vehicle } public void honk() { // produces a default honk } }

El tipo de vehículo Coche ahora heredará de la clase de vehículo principal :

public class Car extends Vehicle { private int numberOfGears; public void openDoors() { // process to open the doors } }

Java admite la herencia única y la herencia multinivel. Esto significa que una clase no puede extenderse directamente desde más de una clase, pero puede usar una jerarquía:

public class ArmoredCar extends Car { private boolean bulletProofWindows; public void remoteStartCar() { // this vehicle can be started by using a remote control } }

Aquí, ArmouredCar extiende Car y Car extiende Vehicle . Por lo tanto, ArmouredCar hereda propiedades tanto del automóvil como del vehículo .

Si bien heredamos de la clase principal, un desarrollador también podría anular la implementación de un método de la clase principal. Esto se conoce como anulación de método.

En nuestro ejemplo anterior de la clase Vehicle , existe el método honk () . La clase Car que extiende la clase Vehicle puede anular este método e implementarlo de la manera que quiera producir el bocinazo:

public class Car extends Vehicle { //... @Override public void honk() { // produces car-specific honk } }

Tenga en cuenta que esto también se denomina polimorfismo en tiempo de ejecución, como se explica en la siguiente sección. Podemos leer más sobre herencia en nuestros artículos sobre herencia y herencia y composición de Java.

7. Polimorfismo

El polimorfismo es la capacidad de un lenguaje de programación orientada a objetos para procesar datos de manera diferente dependiendo de sus tipos de entradas. En Java, este puede ser el mismo nombre de método que tiene diferentes firmas de método y realiza diferentes funciones:

public class TextFile extends GenericFile { //... public String read() { return this.getContent() .toString(); } public String read(int limit) { return this.getContent() .toString() .substring(0, limit); } public String read(int start, int stop) { return this.getContent() .toString() .substring(start, stop); } }

En este ejemplo, podemos ver que el método read () tiene tres formas diferentes con diferentes funcionalidades. Este tipo de polimorfismo es estático o polimorfismo en tiempo de compilación y también se denomina sobrecarga de método.

También hay tiempo de ejecución o polimorfismo dinámico, donde la clase secundaria anula el método principal :

public class GenericFile { private String name; //... public String getFileInfo() { return "Generic File Impl"; } }

Una clase secundaria puede extender la clase GenericFile y anular el método getFileInfo () :

public class ImageFile extends GenericFile { private int height; private int width; //... getters and setters public String getFileInfo() { return "Image File Impl"; } }

Lea más sobre polimorfismo en nuestro artículo sobre polimorfismo en Java.

8. Conclusión

En este artículo, aprendimos sobre los conceptos fundamentales básicos de POO con Java.

Los ejemplos de código de este artículo están disponibles en Github.