Cómo está diseñado Java: Objetos, Clases, Herencia, Polimorfismo e Interfaces (Ejemplo Bancario)
Una explicación clara y cercana de cómo está diseñado Java: clases, objetos, herencia, polimorfismo, interfaces y más. Con ejemplos bancarios fáciles de entender y sin enredos.

Vamos a profundizar en cómo está diseñado Java por dentro, entonces hablemos un poco de como son vueltas en Java y cómo deberíamos pensar nosotros cuando creamos software con Java.
Vamos a desayunarnos esto con un ejemplo bancario, porque bueno he podido trabajar en entidades bancarias y no queria hablar de ejemplo de la clase Animal AJAJA, no mas algo quiero explicarlo con algo un poquis diferente.
Este post es la continuación natural del primer artículo: Primer vistazo a Java: qué tiene y cómo se inicia.
En el que te hablo un poco de como es que se creo Java y ya hablamos ahí un poco de como es que funciona Java.
☕ Antes de empezar: ¿Cómo se ejecuta un programa en Java?
Java tiene un flujo bien particular para correr el código. No va directo al sistema operativo como otros lenguajes; aquí hay una parada intermedia.
Este es el viaje del código:
Tu código (.java)
↓ (javac lo compila)
Se convierte en Bytecode (.class)
↓
La JVM se encarga de ejecutarlo
↓
Funciona en Windows, Linux, Mac… donde sea 😎
Eso significa:
Escribes una vez → corre en todas partes Gracias a la JVM, no al sistema operativo.
Por eso Java es cross-platform 🌍 Y por eso lo usan tanto en bancos, fintech, backend y sistemas grandes donde la estabilidad lo es todo.
🧱 ¿Cómo se ve la estructura básica de una clase en Java?
Cuando abrimos un archivo .java, normalmente veremos algo así:
public class MiPrimeraClase { // ← Nombre de la Clase
public static void main(String[] args) { // ← Método Principal
String nombre = "Wilmar"; // ← Código de la aplicación
System.out.println("Hola " + nombre); // ← Acción que se ejecuta
}
} // ← Llave de cierre de la clase
Ahora si empecemos con: 🧠 Pensando en Objetos
Java se basa en el paradigma orientado a objetos, que es básicamente la idea de que modelamos nuestro software como si fuera el mundo real, espoiler (Todo es objeto, asi como te trato tu ex):
Entonces:
- Si una cuenta bancaria existe → en Java, será un objeto
- Esa cuenta tiene un dueño → eso es una relación entre objetos
- Esa cuenta tiene operaciones (depositar, retirar) → esos son métodos
Normalmente así son vueltas en Java.
🗺️ Diseño del Sistema (Versión Cafetería ☕)
Imaginemos un sistema bancario sencillo:
- Tenemos un Cliente
- Tambien una CuentaBancaria
- Tambien una Transacción
- Y un Banco que administra todo
Para que quede mas claro tenenemos un digrama de clases muy sencillo:
+----------------------+
| Cliente |
+----------------------+
| - nombre : String |
| - documento : String |
+----------------------+
| + getNombre() |
+----------------------+
(1) (1..*)
Cliente ------------------> CuentaBancaria
+-------------------------------+
| CuentaBancaria |
+-------------------------------+
| - saldo : double |
+-------------------------------+
| + depositar(monto : double) |
| + retirar(monto : double) |
| + getSaldo() : double |
+-------------------------------+
|
| (1) (0..*)
v
+-------------------------------+
| Transaccion |
+-------------------------------+
| - monto : double |
| - tipo : String |
+-------------------------------+
| + ejecutar() |
+-------------------------------+
Y si estás empezando probablemente estarás pensando:
“Bueno Wil… ¿y qué mierda significa ese (1) y (1..*)?” 🤨
Tranqui, eso es más fácil de entender de lo que parece.
- (1) significa uno solo.
- (1..*) significa uno o muchos (o sea, varios).
Entonces, nuestro diagrama realmente está diciendo:
-
Un Cliente tiene una o muchas cuentas bancarias.
(Porque puedes tener cuenta de ahorro, cuenta corriente, credito de esos no me dan a mi pero ajá 😂) -
Una CuentaBancaria tiene muchas transacciones.
(Cada depósito, retiro o transferencia queda registrado.) -
Y así como en la vida real:
Cada movimiento deja un rastro 💸
(El banco siempre sabe donde estamos dejando nuestra platica 👀😈)
🧱 Clases y Objetos
Clase → es el molde Objeto → es lo que sale de ese molde
Ejemplo: Una clase es como el molde de una arepa. El objeto es la arepa que sale de ese molde. Con el mismo molde puedes hacer muchas arepas, igual pasa con los objetos.
Código
// Clase = el molde
public class Cliente {
String nombre;
String documento;
}
// Objeto = el cliente real creado a partir del molde
Cliente c = new Cliente(); // aquí estamos “sacando una arepa del molde”
c.nombre = "Wilmar"; // le ponemos nombre
c.documento = "123456789"; // y le asignamos identificación
Resumen
| Concepto | Cómo pensarlo | Ejemplo |
|---|---|---|
| Clase | Molde / Receta | Cliente |
| Objeto | El resultado real que podemos usar | c = new Cliente() |
Si no entendiste deja un comentario y vemos como resolvemos.
🛠️ Constructores — El Objeto “recién nacido”
Cuando creamos un objeto con new (en una palabra reservada), ese objeto nace.
El constructor es el que se encarga de recibir los datos necesarios para que el objeto nazca listo para usarse.
public class Cliente {
String nombre;
String documento;
// Constructor: aquí el objeto llega al mundo con nombre y documento
public Cliente(String nombre, String documento) {
this.nombre = nombre;
this.documento = documento;
}
}
// Aquí estamos creando un cliente ya “completico”
Cliente c = new Cliente("Wilmar", "123456789");
Pa' que sirve esto de los contructores:
- Si no usas constructor, el objeto nace pelado (sin datos).
- Si usas constructor, el objeto nace armado, listo para trabajar.
Es como cuando uno se levanta: Sin constructor → te levantas sin café, sin energía, sin dirección 😵 Con constructor → te levantas, café en mano, listo pa’ la vida ☕😌
🔐 Encapsulación — Protegiendo lo que no se debe tocar
Pensemos en algo simple: En un banco nadie debería poder meter mano en tu saldo así porque sí, ¿cierto? Pues en Java hacemos lo mismo: protegemos los datos importantes para que no los manipule cualquiera.
public class CuentaBancaria {
private double saldo; // esto es privado, no se toca desde afuera
public double getSaldo() { // mostramos el saldo, pero sin exponerlo
return saldo;
}
public void depositar(double monto) { // permitimos depositar de forma segura
saldo += monto;
}
public void retirar(double monto) { // retiramos solo si alcanza
if (monto <= saldo) saldo -= monto;
else System.out.println("Fondos insuficientes 😬");
}
}
¿Qué está pasando aquí?
private saldo→ El saldo está guardado, bien cuidadito, como plata debajo del colchón 😅- Solo lo podemos ver con
getSaldo() - Y solo lo podemos modificar desde métodos como
depositar()oretirar()
En palabras más entendibles:
Encapsular es como decir:
“Que miedo dejar que mi mujerrr me maneje la plata jaja… Si necesita hacer algo, me pide el favor, y yo lo hago mas bien.”
🧬 Herencia — Reutilizando lo que ya existe
En un banco hay varios tipos de empleados, pero todos comparten cosas en común: tienen nombre, documento, trabajan para el mismo banco, etc. La diferencia está en lo que hacen.
Entonces, en vez de repetir ese mismo código en cada clase (que pereza 😮💨), creamos una clase base y las demás heredan de esa.
// Clase base (el papá)
class Empleado {
String nombre;
void saludar() {
System.out.println("Hola, soy " + nombre);
}
}
// Hijo 1
class Cajero extends Empleado {
void atenderCliente() {
System.out.println("Atendiendo en ventanilla 🏦");
}
}
// Hijo 2
class Asesor extends Empleado {
void asesorar() {
System.out.println("Explicando productos financieros 📄");
}
}
¿Qué está pasando aquí?
Empleadoes la clase baseCajeroyAsesorheredan todo lo queEmpleadotiene- Cada uno luego agrega su propia personalidad
Explicado “a lo paisa”:
Herencia es como cuando en tu casa todos cojen la misma olla para hacer fríjoles, pero cada uno perpará los fríjoles de maneras diferentes.
Mismo origen → comportamiento diferente.
Beneficio clave
✔️ Reutilizamos código ✔️ Evitamos copiar / pegar ✔️ Simplificamos el mantenimiento
🎭 Ahora viene el papá de los conceptos Polimorfismo — La misma orden, diferentes acciones
Polimorfismo suena a palabra de universidad que da miedo… pero en realidad es esto:
La misma acción, pero ejecutada de forma distinta según quién la haga.
En el banco pasa todo el tiempo: “Ejecutar transacción” no significa lo mismo para un depósito y para un retiro.
class Transaccion {
void ejecutar() { System.out.println("Ejecutando transacción..."); }
}
class Deposito extends Transaccion {
@Override
void ejecutar() { System.out.println("Realizando depósito 💰"); }
}
class Retiro extends Transaccion {
@Override
void ejecutar() { System.out.println("Realizando retiro 💸"); }
}
Transaccion t = new Deposito();
t.ejecutar(); // 💰
t = new Retiro();
t.ejecutar(); // 💸
Si aun no me entiendes que es el Polimofismo intentenmos con este ejemplo:**
Durante la semana, parce soy el mas serio de la empresa, bien juicioso, pero el fin de semana me convierto en el dios de la perdición 😂
Mis acciones cambian dependiendo del papel que estoy jugando.
Eso es polimorfismo.
Misma instrucción (ejecutar()), pero quién la ejecuta cambia el resultado.
🎯 Beneficio real:
- Podemos programar el sistema pensando en lo general (
Transaccion) - Y cada tipo de transacción decide cómo hace su trabajo.
Si mañana aparece Transferencia, solo creamos otra clase que implemente ejecutar().
El banco no colapsa. No lloramos. No tocamos mil archivos.
Escalable. Limpio. Hermoso. 😌
🧩 Interfaces — Definiendo contratos
Una interface dice qué se debe hacer, pero no cómo. Es como un contrato: “Si implementa esto, me garantiza estos métodos”. El cómo lo haga ya es cuento suyo.
¿Cuándo usar interfaces?
- Cuando distintas clases (que no comparten herencia directa) deben ofrecer el mismo comportamiento.
- Cuando quieres programar contra la abstracción: usar el contrato sin amarrarte a una implementación específica.
Ejemplo bancario: Transferible
Queremos que cualquier cuenta que implemente este contrato pueda transferir dinero.
// El contrato: define lo que hay que hacer
interface Transferible {
void transferir(double monto, CuentaBancaria destino);
}
// Una implementación concreta
class CuentaAhorros extends CuentaBancaria implements Transferible {
@Override
public void transferir(double monto, CuentaBancaria destino) {
if (monto <= 0) throw new IllegalArgumentException("Monto inválido");
this.retirar(monto); // valida saldo y descuenta
destino.depositar(monto); // acredita en la cuenta destino
}
}
// Otra implementación con reglas distintas (ej: cobra comisión)
class CuentaCorriente extends CuentaBancaria implements Transferible {
private static final double COMISION = 900; // pesos, por ejemplo
@Override
public void transferir(double monto, CuentaBancaria destino) {
double total = monto + COMISION;
this.retirar(total); // descuenta monto + comisión
destino.depositar(monto);
}
}
Fíjate en el beneficio:
Tu código puede trabajar con el tipo Transferible sin saber si es CuentaAhorros o CuentaCorriente.
void pagarServicio(Transferible cuenta, double valor, CuentaBancaria empresa) {
cuenta.transferir(valor, empresa); // me da igual la clase concreta
}
Tips rápidos (de la casa)
- Interface = “qué” / Clase = “cómo”.
- Puedes implementar varias interfaces en la misma clase (flexibilidad full).
- Si necesitas compartir código entre varias clases, piensa en una clase abstracta; si solo quieres el contrato, interface.
- Desde Java 8, las interfaces permiten métodos
default(útiles para comportamientos comunes sin romper implementaciones).
interface Notificable {
default void notificar(String msg) {
System.out.println("[NOTI] " + msg); // comportamiento por defecto
}
}
class CuentaEmpresarial extends CuentaBancaria
implements Transferible, Notificable {
@Override
public void transferir(double monto, CuentaBancaria destino) {
this.retirar(monto);
destino.depositar(monto);
notificar("Transferencia OK por $" + monto);
}
}
Resumen: La interface es el acuerdo: “si vos firmas conmigo, me debe de cumplir con esos acuerdos del contrato (métodos)”. Así podemos cambiar la clase concreta sin reventar el resto del sistema. 💼✅
Listo, los dejamos claros, cortos y con tu tono, sin repetir lo ya dicho y sin sonar a manual académico.
🔠 Enums — Listas de valores fijos (pa’ no embarrarla)
En un sistema bancario hay cosas que no cambian, como los tipos de transacción. Para eso usamos un enum: una lista cerrada de valores válidos.
enum TipoTransaccion {
DEPOSITO, RETIRO, TRANSFERENCIA
}
Así evitamos horrores como:
String tipo = "retirOOoooo"; // 😭😭😭
Con enum Java te obliga a usar algo correcto y conocido.
Menos errores → más paz mental. 😌
🎁 Generics — Listas seguras (sin meter cosas raras)
Cuando manejamos colecciones, Java nos deja decir qué tipo de objetos pueden entrar en la lista.
List<CuentaBancaria> cuentas = new ArrayList<>();
- Sin generics → cualquiera podía meter lo que quisiera (un gato, una papa, un entero… lo que fuera 🤡)
- Con generics → solo aceptamos lo que tiene sentido (
CuentaBancariaen este caso)
Generics = orden y respeto en la lista ✨
🚀 Cierre
Java no es solo escribir código. Java es modelar el mundo real, paso a paso:
- Objetos representan entidades
- Métodos representan acciones
- Herencia y polimorfismo nos ayudan a reutilizar
- Interfaces definen contratos
- La JVM nos garantiza que nuestro código vive en cualquier parte
Si entiendes esto… ya no solo programas — diseñas software 🤝
📦 Código del Blog (Repositorio)
Si quieres ver todo el código funcionando, compilarlo y jugar con él, lo subí a este repo público:
👉 https://github.com/WilDevp/learning-java-with-wil
Ahí vas a encontrar:
- Ejemplos organizados por temas
- Código listo para ejecutar
- Y ejercicios que se irán agregando con el tiempo 👀
Dale una mirada, dale una estrellita ⭐ y sígueme para recibir los próximos posts 🤝
Comentarios
Inicia sesión para dejar un comentario
Sin comentarios aún. Sé el primero en compartir tu opinión.
Escrito por
Wilmar Garcia Valderrama
Líder Técnico de Desarrollo en QUIND y Fundador de WillDevp. Apasionado por la arquitectura limpia, microservicios y buenas prácticas de ingeniería.
Artículos relacionados

Excepciones en Java: Cuando las cosas salen mal (y cómo no dejar que se cuele algo)
Aprende a manejar excepciones en Java: try-catch, try-with-resources, excepciones personalizadas y mejores prácticas con ejemplos reales.

Colecciones en Java: Pensando como Algoritmista (sin morir en el intento)
Una guía clara y algorítmica sobre las Colecciones en Java. Aprende a leer enunciados, crear pseudocódigo, hacer test de escritorio y resolver usando List, Set y Map.

Primer vistazo a Java: qué tiene y cómo se inicia
Introducción sencilla a Java: ecosistema, JVM, clases, paquetes, módulos y manejo básico de excepciones — te lo explico así como mi abuelita me enseño.