2.a.1 - Fundamentos de POO

Objetivo

Identificar los fundamentos de la programación orientada a objetos

1. Contenidos

1.1 ¿Qué es la programación orientada a objetos?

La programación orientada a objetos, o POO, es una forma de organizar el código pensando en los elementos que intervienen en un problema real. En lugar de escribir únicamente instrucciones sueltas, se crean objetos que representan entidades del dominio de la aplicación: clientes, productos, pedidos, facturas, incidencias, vehículos, habitaciones de hotel, cuentas bancarias, etc.

Cada objeto combina dos ideas fundamentales:

  • Estado: los datos que describen cómo está el objeto en un momento concreto.
  • Comportamiento: las operaciones que puede realizar el objeto o que se pueden realizar sobre él.

Ejemplo profesional: en una aplicación de gestión de pedidos, un pedido no es solo un número de referencia. También tiene cliente, fecha, líneas de producto, estado de preparación y operaciones como calcular el total, marcarlo como enviado o cancelar el pedido.

1.2 Concepto de clase

Una clase es una plantilla o modelo que define cómo serán los objetos de un determinado tipo. En una clase se indican los atributos que tendrán sus objetos y los métodos que podrán utilizar.

Podemos imaginar una clase como el diseño técnico de un producto. Por ejemplo, una empresa puede tener una clase Producto que define que todos los productos tendrán un código, un nombre, un precio y un número de unidades en stock.


class Producto {
	String codigo;
	String nombre;
	Double precio;
	Integer unidadesStock;

	void mostrarResumen() {
		System.out.println(codigo + " - " + nombre);
		System.out.println("Precio: " + precio + " €");
		System.out.println("Stock: " + unidadesStock + " unidades");
	}
}
				

En este ejemplo, Producto todavía no es un producto concreto. Es la definición general de cómo será cualquier producto que creemos a partir de esa clase.

Importante: en Java, el nombre de las clases se escribe normalmente en PascalCase: Producto, Cliente, PedidoOnline, IncidenciaTecnica.

1.3 Concepto de objeto

Un objeto es un elemento concreto creado a partir de una clase. Si la clase es el modelo, el objeto es una realización concreta de ese modelo en memoria.

Por ejemplo, a partir de la clase Producto se pueden crear muchos objetos distintos: un teclado, un monitor, una impresora o un ratón. Todos comparten la misma estructura, pero cada uno tiene sus propios valores.


class Producto {
	String codigo;
	String nombre;
	Double precio;
	Integer unidadesStock;

	void mostrarResumen() {
		System.out.println(codigo + " - " + nombre);
		System.out.println("Precio: " + precio + " €");
		System.out.println("Stock: " + unidadesStock + " unidades");
	}
}

public class DemoProductos {
	public static void main(String[] args) {
		Producto teclado = new Producto();
		teclado.codigo = "TEC-001";
		teclado.nombre = "Teclado mecánico";
		teclado.precio = 49.95;
		teclado.unidadesStock = 12;

		Producto monitor = new Producto();
		monitor.codigo = "MON-024";
		monitor.nombre = "Monitor 24 pulgadas";
		monitor.precio = 139.90;
		monitor.unidadesStock = 5;

		teclado.mostrarResumen();
		monitor.mostrarResumen();
	}
}
				

En el ejemplo anterior, teclado y monitor son dos objetos distintos. Ambos pertenecen a la clase Producto, pero cada uno tiene sus propios datos.

Nota: en los ejemplos aparecerá public static void main porque Java necesita un punto de entrada para ejecutar el programa. Los métodos estáticos no se estudian en esta página.

1.4 Atributos

Los atributos son las variables que pertenecen a una clase y que describen el estado de sus objetos. También se les puede llamar campos o, de forma general, propiedades del objeto.

En una aplicación de soporte técnico, una incidencia podría tener atributos como identificador, descripción, prioridad y estado.


class Incidencia {
	String identificador;
	String descripcion;
	String prioridad;
	String estado;
}
				

Cuando creamos objetos a partir de esa clase, cada objeto guarda sus propios valores en esos atributos.


public class DemoIncidencias {
	public static void main(String[] args) {
		Incidencia incidenciaA = new Incidencia();
		incidenciaA.identificador = "INC-2026-001";
		incidenciaA.descripcion = "El usuario no puede acceder al sistema";
		incidenciaA.prioridad = "Alta";
		incidenciaA.estado = "Abierta";

		Incidencia incidenciaB = new Incidencia();
		incidenciaB.identificador = "INC-2026-002";
		incidenciaB.descripcion = "Error al generar el informe mensual";
		incidenciaB.prioridad = "Media";
		incidenciaB.estado = "En revisión";

		System.out.println(incidenciaA.identificador + ": " + incidenciaA.estado);
		System.out.println(incidenciaB.identificador + ": " + incidenciaB.estado);
	}
}
				

Idea clave: los atributos pertenecen a cada objeto. Cambiar el estado de incidenciaA no cambia automáticamente el estado de incidenciaB.

1.5 Métodos

Los métodos son bloques de código definidos dentro de una clase. Representan el comportamiento de los objetos: acciones que pueden realizar o cálculos relacionados con sus datos.

Un método puede:

  • Mostrar información del objeto.
  • Modificar sus atributos.
  • Calcular y devolver un resultado.
  • Validar si el objeto cumple una condición.

class Pedido {
	String referencia;
	Integer unidades;
	Double precioUnitario;
	String estado;

	Double calcularTotal() {
		return unidades * precioUnitario;
	}

	void marcarComoPreparado() {
		estado = "Preparado";
	}

	Boolean tieneImporteAlto() {
		return calcularTotal() > 500.0;
	}
}
				

Después de crear un objeto, sus métodos se utilizan escribiendo el nombre del objeto, un punto y el nombre del método.


public class DemoPedidos {
	public static void main(String[] args) {
		Pedido pedido = new Pedido();
		pedido.referencia = "PED-1001";
		pedido.unidades = 8;
		pedido.precioUnitario = 79.90;
		pedido.estado = "Pendiente";

		System.out.println("Total: " + pedido.calcularTotal() + " €");
		System.out.println("Importe alto: " + pedido.tieneImporteAlto());

		pedido.marcarComoPreparado();
		System.out.println("Estado actual: " + pedido.estado);
	}
}
				

Diferencia importante: un atributo guarda un dato; un método ejecuta una acción o realiza un cálculo. estado es un atributo. marcarComoPreparado() es un método.

1.6 Clase y objeto: relación entre ambos

La relación entre clase y objeto puede resumirse así:

Concepto Qué representa Ejemplo
Clase Plantilla o definición general Cliente
Objeto Elemento concreto creado a partir de una clase clienteEmpresaA
Atributo Dato que forma parte del estado del objeto nombre, email, telefono
Método Acción o cálculo que puede realizar el objeto mostrarFicha(), actualizarEmail()

class Cliente {
	String nombre;
	String email;
	Integer puntosFidelizacion;

	void mostrarFicha() {
		System.out.println("Cliente: " + nombre);
		System.out.println("Email: " + email);
		System.out.println("Puntos: " + puntosFidelizacion);
	}

	void sumarPuntos(Integer puntos) {
		puntosFidelizacion = puntosFidelizacion + puntos;
	}
}

public class DemoClientes {
	public static void main(String[] args) {
		Cliente clienteEmpresa = new Cliente();
		clienteEmpresa.nombre = "Lucía Martínez";
		clienteEmpresa.email = "lucia.martinez@empresa.com";
		clienteEmpresa.puntosFidelizacion = 120;

		clienteEmpresa.sumarPuntos(30);
		clienteEmpresa.mostrarFicha();
	}
}
				

1.7 Clases del sistema y clases de usuario

En Java trabajamos con dos grandes tipos de clases:

  • Clases del sistema: son clases que ya proporciona Java o sus bibliotecas. No las programamos nosotros, pero podemos utilizarlas en nuestras aplicaciones.
  • Clases de usuario: son clases creadas por el equipo de desarrollo para resolver el problema concreto de la aplicación.

Algunos ejemplos de clases del sistema son String, Integer, Double, Boolean o ArrayList. Estas clases forman parte del entorno de Java y nos permiten trabajar con textos, números, valores lógicos, colecciones de datos y otros elementos habituales.


public class DemoClaseSistema {
	public static void main(String[] args) {
		String codigoCliente = " cli-2026-001 ";

		String codigoNormalizado = codigoCliente.trim().toUpperCase();
		Integer longitud = codigoNormalizado.length();

		System.out.println("Código normalizado: " + codigoNormalizado);
		System.out.println("Longitud: " + longitud);
	}
}
				

En cambio, una clase como Cliente, Pedido, Producto o Incidencia suele ser una clase de usuario, porque la crea el programador para representar conceptos específicos del proyecto.

Tipo de clase Quién la crea Para qué se usa Ejemplos
Clase del sistema Java o una biblioteca externa Resolver tareas generales String, Integer, Double, Boolean
Clase de usuario El equipo de desarrollo Representar conceptos del dominio de la aplicación Cliente, Factura, TicketSoporte

Contexto profesional: en una aplicación real se combinan ambos tipos. Puedes crear una clase de usuario Factura y, dentro de ella, utilizar clases del sistema como String para el número de factura, Double para el importe o Boolean para indicar si está pagada.

1.8 Referencias a objetos

Cuando creamos un objeto en Java, la variable no guarda directamente todo el objeto. Lo que guarda es una referencia, es decir, una forma de localizar ese objeto en memoria.

Esto explica por qué dos variables pueden apuntar al mismo objeto. Si modificamos el objeto usando una de esas variables, el cambio también se observará desde la otra.


class Cliente {
	String nombre;
	String email;
}

public class DemoReferencias {
	public static void main(String[] args) {
		Cliente clienteOriginal = new Cliente();
		clienteOriginal.nombre = "Ana Pérez";
		clienteOriginal.email = "ana@empresa.com";

		Cliente clienteReferencia = clienteOriginal;
		clienteReferencia.email = "ana.perez@empresa.com";

		System.out.println(clienteOriginal.email);
		System.out.println(clienteReferencia.email);
	}
}
				

Las dos variables, clienteOriginal y clienteReferencia, apuntan al mismo objeto. Por eso ambas muestran el mismo email actualizado.

1.9 Destrucción de objetos y liberación de memoria

En Java, los objetos se crean en memoria cuando el programa los necesita. Sin embargo, el programador no suele destruirlos manualmente. La liberación de memoria la gestiona automáticamente la máquina virtual de Java mediante un mecanismo llamado recolector de basura o garbage collector.

Un objeto puede ser liberado cuando ya no existe ninguna referencia que permita acceder a él. En ese momento, el objeto queda disponible para que el recolector de basura recupere su memoria cuando lo considere oportuno.


class TicketSoporte {
	String codigo;
	String descripcion;
}

public class DemoMemoria {
	public static void main(String[] args) {
		TicketSoporte ticket = new TicketSoporte();
		ticket.codigo = "TCK-001";
		ticket.descripcion = "No funciona el acceso remoto";

		System.out.println(ticket.codigo + ": " + ticket.descripcion);

		// La variable deja de apuntar al objeto.
		// Si no hay más referencias, el objeto podrá ser liberado por Java.
		ticket = null;
	}
}
				

También puede ocurrir que una referencia desaparezca al salir del bloque donde fue declarada. Si el objeto no queda referenciado desde ningún otro lugar, podrá ser recogido por el recolector de basura.


public class DemoAlcanceMemoria {
	public static void main(String[] args) {
		if (true) {
			TicketSoporte ticketTemporal = new TicketSoporte();
			ticketTemporal.codigo = "TCK-002";
			ticketTemporal.descripcion = "Consulta puntual del usuario";
			System.out.println(ticketTemporal.codigo);
		}

		// Fuera del bloque, ticketTemporal ya no existe como variable.
		// Si no había otra referencia al objeto, Java podrá liberar su memoria.
	}
}
				

Precaución: que Java gestione la memoria automáticamente no significa que podamos olvidarnos de todos los recursos. Si una aplicación abre ficheros, conexiones de red o conexiones a bases de datos, esos recursos deben cerrarse correctamente cuando ya no se necesitan.

Idea clave: no sabemos exactamente cuándo se liberará un objeto. Sabemos que Java podrá hacerlo cuando el objeto ya no sea accesible. Por eso no debemos escribir programas que dependan del momento exacto en que actúe el recolector de basura.

2. Ejercicios

2.1 Identificar clases, objetos, atributos y métodos

Una empresa de alquiler de vehículos quiere crear una aplicación para gestionar su flota. Analiza el siguiente contexto y responde:

La aplicación debe guardar vehículos. De cada vehículo interesa conocer matrícula, marca, modelo, precio diario y si está disponible. Además, el sistema debe poder mostrar la ficha del vehículo, marcarlo como alquilado y marcarlo como disponible.

  1. ¿Cuál podría ser la clase principal?
  2. Indica al menos cuatro atributos.
  3. Indica al menos tres métodos.
  4. Escribe dos posibles objetos concretos de esa clase.

2.2 Crear una clase de usuario sencilla

Crea una clase Empleado con los siguientes atributos:

  • String nombre
  • String departamento
  • Double salarioMensual
  • Boolean activo

Añade un método mostrarFicha() que muestre todos los datos del empleado por pantalla.

2.3 Instanciar objetos y utilizar atributos

Crea una clase DemoEmpleados que cree dos objetos de la clase Empleado. Asigna valores diferentes a sus atributos y llama al método mostrarFicha() de cada objeto.

2.4 Añadir métodos con comportamiento

Amplía la clase Empleado con un método subirSalario(Double porcentaje). El método debe aumentar el salario mensual aplicando el porcentaje recibido como parámetro.

Después, prueba el método desde DemoEmpleados subiendo el salario de uno de los empleados un 5%.

2.5 Clases del sistema frente a clases de usuario

Indica si las siguientes clases son clases del sistema o clases de usuario. Justifica brevemente cada respuesta:

  1. String
  2. Producto
  3. Integer
  4. Factura
  5. Boolean

2.6 Razonar sobre memoria y referencias

Explica con tus palabras qué ocurre en cada una de estas situaciones:

  1. Una variable que apuntaba a un objeto pasa a valer null.
  2. Dos variables apuntan al mismo objeto y se modifica un atributo usando una de ellas.
  3. Un objeto deja de tener referencias activas dentro del programa.

Reto: Gestión básica de incidencias

Desarrolla un pequeño programa en Java formado por dos clases:

  1. Incidencia: representa una incidencia registrada por un departamento de soporte técnico.
  2. DemoIncidencias: crea varios objetos de tipo Incidencia y prueba sus atributos y métodos.

La clase Incidencia debe tener, al menos, estos atributos:

Debe incluir, al menos, estos métodos:

En la clase DemoIncidencias, crea al menos tres incidencias diferentes, modifica el estado de alguna de ellas y muestra por pantalla cuáles son urgentes.

3. Bibliografía