Java: Programación Orientada a Objetos
Aprende los pilares de la programación orientada a objetos en Java: clases, encapsulación, herencia, polimorfismo y abstracción para código eficiente.
Aprende Java GRATIS y certifícateProgramación Orientada a Objetos en Java
La programación orientada a objetos (POO) representa un paradigma fundamental que revolucionó el desarrollo de software al permitir modelar problemas del mundo real mediante la creación de entidades que encapsulan datos y comportamientos. Java, desde su concepción, fue diseñado como un lenguaje completamente orientado a objetos, donde prácticamente todo elemento del programa es un objeto o forma parte de una clase.
Este paradigma se basa en cuatro pilares fundamentales: encapsulación, herencia, polimorfismo y abstracción. Estos conceptos no son meramente teóricos, sino herramientas prácticas que permiten crear código más organizado, reutilizable y mantenible.
Clases y objetos: los cimientos de la POO
Una clase actúa como un molde o plantilla que define las características y comportamientos que tendrán los objetos creados a partir de ella. Los objetos, por su parte, son instancias específicas de una clase que existen en memoria durante la ejecución del programa.
public class Vehiculo {
// Atributos (características)
private String marca;
private String modelo;
private int año;
// Constructor
public Vehiculo(String marca, String modelo, int año) {
this.marca = marca;
this.modelo = modelo;
this.año = año;
}
// Métodos (comportamientos)
public void acelerar() {
System.out.println("El vehículo está acelerando");
}
public String obtenerInformacion() {
return marca + " " + modelo + " (" + año + ")";
}
}
La instanciación de objetos se realiza mediante el operador new
, que reserva memoria y ejecuta el constructor correspondiente:
Vehiculo miCoche = new Vehiculo("Toyota", "Corolla", 2023);
Vehiculo motoMoto = new Vehiculo("Honda", "CBR", 2022);
// Uso de los objetos
miCoche.acelerar();
System.out.println(miCoche.obtenerInformacion());
Encapsulación: protegiendo la integridad de los datos
La encapsulación constituye el mecanismo mediante el cual se ocultan los detalles internos de implementación de una clase, exponiendo únicamente una interfaz controlada para interactuar con los objetos. Este principio se implementa principalmente a través de modificadores de acceso y métodos getter/setter.
Los modificadores de acceso en Java determinan la visibilidad de los miembros de una clase:
- private: accesible únicamente dentro de la misma clase
- protected: accesible dentro del mismo paquete y clases hijas
- public: accesible desde cualquier parte del programa
- package-private (sin modificador): accesible dentro del mismo paquete
public class CuentaBancaria {
private double saldo; // Encapsulado - no accesible directamente
private String numeroCuenta;
public CuentaBancaria(String numeroCuenta, double saldoInicial) {
this.numeroCuenta = numeroCuenta;
this.saldo = saldoInicial;
}
// Método público para acceder al saldo (getter)
public double getSaldo() {
return saldo;
}
// Método público para modificar el saldo de forma controlada
public boolean depositar(double cantidad) {
if (cantidad > 0) {
saldo += cantidad;
return true;
}
return false;
}
public boolean retirar(double cantidad) {
if (cantidad > 0 && cantidad <= saldo) {
saldo -= cantidad;
return true;
}
return false;
}
}
Herencia: reutilización y especialización
La herencia permite crear nuevas clases basadas en clases existentes, heredando sus atributos y métodos. La clase base se denomina superclase o clase padre, mientras que la clase derivada se conoce como subclase o clase hija.
public class Animal {
protected String nombre;
protected int edad;
public Animal(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
public void dormir() {
System.out.println(nombre + " está durmiendo");
}
public void comer() {
System.out.println(nombre + " está comiendo");
}
}
public class Perro extends Animal {
private String raza;
public Perro(String nombre, int edad, String raza) {
super(nombre, edad); // Llamada al constructor de la superclase
this.raza = raza;
}
// Método específico de la subclase
public void ladrar() {
System.out.println(nombre + " está ladrando");
}
// Sobrescritura de método
@Override
public void comer() {
System.out.println(nombre + " está comiendo croquetas");
}
}
La palabra clave super permite acceder a miembros de la superclase, especialmente útil en constructores y cuando se necesita llamar a la versión original de un método sobrescrito.
Polimorfismo: flexibilidad en tiempo de ejecución
El polimorfismo permite que objetos de diferentes clases respondan de manera específica a la misma interfaz o método. En Java, esto se manifiesta principalmente a través de la sobrescritura de métodos y el enlace dinámico.
public class Forma {
public double calcularArea() {
return 0;
}
public void dibujar() {
System.out.println("Dibujando una forma genérica");
}
}
public class Circulo extends Forma {
private double radio;
public Circulo(double radio) {
this.radio = radio;
}
@Override
public double calcularArea() {
return Math.PI * radio * radio;
}
@Override
public void dibujar() {
System.out.println("Dibujando un círculo");
}
}
public class Rectangulo extends Forma {
private double ancho, alto;
public Rectangulo(double ancho, double alto) {
this.ancho = ancho;
this.alto = alto;
}
@Override
public double calcularArea() {
return ancho * alto;
}
@Override
public void dibujar() {
System.out.println("Dibujando un rectángulo");
}
}
El polimorfismo permite tratar objetos de diferentes tipos de manera uniforme:
Forma[] formas = {
new Circulo(5.0),
new Rectangulo(4.0, 6.0),
new Circulo(3.0)
};
for (Forma forma : formas) {
forma.dibujar(); // Se ejecuta el método específico de cada clase
System.out.println("Área: " + forma.calcularArea());
}
Abstracción: simplificando la complejidad
La abstracción permite definir contratos o interfaces que las clases deben cumplir, sin especificar la implementación concreta. Java proporciona clases abstractas e interfaces para implementar este concepto.
Las clases abstractas no pueden ser instanciadas directamente y pueden contener métodos abstractos que deben ser implementados por las subclases:
public abstract class Empleado {
protected String nombre;
protected double salarioBase;
public Empleado(String nombre, double salarioBase) {
this.nombre = nombre;
this.salarioBase = salarioBase;
}
// Método abstracto - debe ser implementado por subclases
public abstract double calcularSalario();
// Método concreto - puede ser usado por todas las subclases
public void mostrarInformacion() {
System.out.println("Empleado: " + nombre);
System.out.println("Salario: " + calcularSalario());
}
}
public class EmpleadoTiempoCompleto extends Empleado {
public EmpleadoTiempoCompleto(String nombre, double salarioBase) {
super(nombre, salarioBase);
}
@Override
public double calcularSalario() {
return salarioBase;
}
}
public class EmpleadoPorHoras extends Empleado {
private int horasTrabajadas;
public EmpleadoPorHoras(String nombre, double tarifaPorHora, int horasTrabajadas) {
super(nombre, tarifaPorHora);
this.horasTrabajadas = horasTrabajadas;
}
@Override
public double calcularSalario() {
return salarioBase * horasTrabajadas;
}
}
La programación orientada a objetos en Java proporciona un framework conceptual que facilita el diseño de aplicaciones complejas mediante la organización lógica del código en entidades cohesivas y reutilizables.
Lecciones de este módulo de Java
Lecciones de programación del módulo Programación Orientada a Objetos del curso de Java.
Ejercicios de programación en este módulo de Java
Evalúa tus conocimientos en Programación Orientada a Objetos con ejercicios de programación Programación Orientada a Objetos de tipo Test, Puzzle, Código y Proyecto con VSCode.