🏗️ ¿Qué es una clase en programación?
En el paradigma de la programación orientada a objetos (POO), una clase es la unidad fundamental de diseño. Funciona como un molde o plantilla que describe las características y el comportamiento que tendrán los objetos creados a partir de ella. Mientras que un objeto es algo concreto que existe en memoria durante la ejecución del programa, la clase es la definición abstracta que establece qué datos almacenará (sus atributos) y qué acciones podrá realizar (sus métodos).
Una analogía clásica y muy útil: si pensamos en la construcción de viviendas, la clase sería el plano del arquitecto. El plano describe cuántas habitaciones tendrá la casa, dónde irán las puertas y ventanas, cómo será la distribución. Pero el plano no es una casa — es la especificación a partir de la cual se construyen casas reales. Cada casa construida sería un objeto (o instancia) de esa clase.
📘 Concepto clave: en Java, todo el código se organiza dentro de clases. Incluso el método main que inicia la ejecución debe estar dentro de una clase. Java es un lenguaje puramente orientado a objetos en este sentido.
Formalmente, una clase encapsula dos elementos esenciales:
Atributos (también llamados campos, propiedades o variables de instancia): representan el estado del objeto. Por ejemplo, un objeto Coche podría tener atributos como marca, modelo, color y velocidadActual.
Métodos (también llamados operaciones o funciones miembro): representan el comportamiento del objeto. El mismo Coche podría tener métodos como acelerar(), frenar() y obtenerVelocidad().
🔄 Clase vs. objeto: la diferencia fundamental
Uno de los conceptos que más confusión genera a los principiantes es la distinción entre clase y objeto. Aunque están íntimamente relacionados, son conceptos distintos:
| Característica | Clase | Objeto |
|---|---|---|
| Naturaleza | Abstracta (definición) | Concreta (instancia en memoria) |
| Existencia | Tiempo de compilación | Tiempo de ejecución |
| Cantidad | Se define una vez | Se pueden crear múltiples |
| Memoria | No ocupa memoria de datos | Ocupa espacio en el heap |
| Analogía | Plano del arquitecto | Casa construida |
En Java, una clase se define con la palabra reservada class y un objeto se crea con el operador new. Veamos un ejemplo sencillo:
// Definición de la clase (el plano)
class Perro {
String nombre;
String raza;
int edad;
void ladrar() {
System.out.println(nombre + " dice: ¡Guau!");
}
}
// Creación de objetos (instancias concretas)
Perro miPerro = new Perro(); // Primer objeto
miPerro.nombre = "Luna";
miPerro.raza = "Labrador";
miPerro.edad = 3;
miPerro.ladrar(); // Luna dice: ¡Guau!
Perro otroPerro = new Perro(); // Segundo objeto
otroPerro.nombre = "Rocky";
otroPerro.raza = "Pastor Alemán";
otroPerro.edad = 5;
otroPerro.ladrar(); // Rocky dice: ¡Guau!
Observa cómo una única clase Perro ha permitido crear dos objetos distintos (miPerro y otroPerro), cada uno con sus propios valores de atributos. Este es el poder fundamental de las clases: ✅ definir una vez, instanciar muchas veces.
🔬 Anatomía de una clase en Java
Toda clase en Java sigue una estructura bien definida. Conocerla es fundamental para escribir código organizado y profesional:
// 1. Declaración del paquete (opcional)
package com.ciberaula.ejemplo;
// 2. Importaciones (opcional)
import java.util.ArrayList;
// 3. Declaración de la clase
public class NombreClase {
// 4. Atributos (variables de instancia)
private String atributo1;
private int atributo2;
// 5. Constantes
public static final int MAX_VALOR = 100;
// 6. Constructor(es)
public NombreClase(String atributo1, int atributo2) {
this.atributo1 = atributo1;
this.atributo2 = atributo2;
}
// 7. Métodos getter y setter
public String getAtributo1() {
return atributo1;
}
public void setAtributo1(String atributo1) {
this.atributo1 = atributo1;
}
// 8. Métodos de comportamiento
public void realizarAccion() {
System.out.println("Ejecutando acción...");
}
// 9. Método toString (representación como texto)
@Override
public String toString() {
return "NombreClase{" + atributo1 + ", " + atributo2 + "}";
}
}
▶️ Convenciones de nomenclatura
Java establece convenciones claras que todo programador profesional debe seguir:
| Elemento | Convención | Ejemplo |
|---|---|---|
| Nombre de clase | PascalCase (mayúscula inicial) |
CuentaBancaria |
| Atributos | camelCase (minúscula inicial) |
saldoActual |
| Métodos | camelCase + verbo |
calcularInteres() |
| Constantes | UPPER_SNAKE_CASE |
TASA_INTERES_MAXIMA |
📦 Atributos: los datos de la clase
Los atributos (también conocidos como campos o variables de instancia) representan el estado interno de un objeto. Cada objeto creado a partir de una clase posee su propia copia independiente de los atributos, lo que permite que objetos del mismo tipo almacenen datos diferentes.
🔹 Tipos de atributos
En Java existen dos categorías principales de atributos según su ámbito:
Atributos de instancia: pertenecen a cada objeto individual. Cada vez que se crea un objeto con new, se reserva memoria para estos atributos. Son los más comunes y definen el estado específico de cada objeto.
Atributos de clase (static): pertenecen a la clase en sí, no a las instancias individuales. Todos los objetos comparten el mismo valor. Son útiles para contadores, constantes de configuración o valores compartidos.
public class Empleado {
// Atributo de clase: compartido por todos los objetos
private static int contadorEmpleados = 0;
// Atributos de instancia: únicos para cada objeto
private String nombre;
private double salario;
private int id;
public Empleado(String nombre, double salario) {
contadorEmpleados++; // Se incrementa para todos
this.id = contadorEmpleados;
this.nombre = nombre;
this.salario = salario;
}
public static int getTotalEmpleados() {
return contadorEmpleados;
}
}
// Uso:
Empleado e1 = new Empleado("Ana", 35000);
Empleado e2 = new Empleado("Luis", 42000);
System.out.println(Empleado.getTotalEmpleados()); // 2
🔹 Valores por defecto de los atributos
Cuando se crea un objeto en Java, sus atributos de instancia reciben automáticamente valores por defecto si no se inicializan explícitamente:
| Tipo de dato | Valor por defecto |
|---|---|
int, long, short, byte | 0 |
float, double | 0.0 |
boolean | false |
char | '\u0000' (carácter nulo) |
Objetos (String, arrays, etc.) | null |
⚠️ Precaución: las variables locales (declaradas dentro de métodos) no reciben valores por defecto. Si intentas usar una variable local sin inicializar, el compilador producirá un error. Solo los atributos de instancia y de clase tienen valores por defecto.
⚙️ Métodos: el comportamiento de la clase
Los métodos definen las acciones que puede realizar un objeto. Son bloques de código que operan sobre los atributos de la clase y proporcionan la lógica de negocio del programa. Un buen diseño de métodos es clave para crear clases reutilizables y fáciles de mantener.
▶️ Sintaxis de un método
modificadorAcceso tipoRetorno nombreMetodo(parámetros) {
// Cuerpo del método
return valor; // Si tipoRetorno no es void
}
// Ejemplo concreto:
public double calcularBonificacion(double porcentaje) {
return this.salario * (porcentaje / 100.0);
}
🔹 Métodos getter y setter
Cuando los atributos son privados (como recomienda el principio de encapsulamiento), se necesitan métodos de acceso para leer y modificar sus valores. Estos métodos siguen una convención estándar en Java:
public class CuentaBancaria {
private String titular;
private double saldo;
// Getter: devuelve el valor del atributo
public double getSaldo() {
return saldo;
}
// Setter con validación: controla qué valores se asignan
public void setSaldo(double nuevoSaldo) {
if (nuevoSaldo < 0) {
System.out.println("Error: el saldo no puede ser negativo.");
} else {
this.saldo = nuevoSaldo;
}
}
// Getter para String
public String getTitular() {
return titular;
}
// Setter para String con validación
public void setTitular(String titular) {
if (titular != null && !titular.isEmpty()) {
this.titular = titular;
}
}
}
💡 Buena práctica: los setters no son simples asignaciones. Su verdadero valor está en la validación: puedes impedir que un salario sea negativo, que un nombre esté vacío o que una edad supere un límite razonable. Esto protege la integridad de los datos del objeto.
🔹 Sobrecarga de métodos
Java permite definir varios métodos con el mismo nombre pero diferentes parámetros. El compilador selecciona automáticamente la versión correcta según los argumentos proporcionados en la llamada. Esto se conoce como sobrecarga de métodos (method overloading):
public class Calculadora {
public int sumar(int a, int b) {
return a + b;
}
public double sumar(double a, double b) {
return a + b;
}
public int sumar(int a, int b, int c) {
return a + b + c;
}
}
Calculadora calc = new Calculadora();
System.out.println(calc.sumar(3, 5)); // 8 (versión int, int)
System.out.println(calc.sumar(3.5, 2.1)); // 5.6 (versión double, double)
System.out.println(calc.sumar(1, 2, 3)); // 6 (versión int, int, int)
🔧 Constructores: inicializar objetos correctamente
Un constructor es un método especial que se invoca automáticamente cuando se crea un objeto con new. Su propósito es inicializar el objeto, asegurando que sus atributos tengan valores válidos desde el primer momento. Los constructores tienen tres características distintivas:
✅ Llevan el mismo nombre que la clase. ✅ No tienen tipo de retorno (ni siquiera void). ✅ Se ejecutan automáticamente al usar new.
▶️ Constructor por defecto vs. constructor personalizado
Si no defines ningún constructor, Java proporciona automáticamente un constructor por defecto sin parámetros que inicializa los atributos con sus valores por defecto. Sin embargo, en cuanto defines al menos un constructor personalizado, el constructor por defecto ya no se genera automáticamente.
public class Libro {
private String titulo;
private String autor;
private int paginas;
private double precio;
// Constructor sin parámetros (por defecto explícito)
public Libro() {
this.titulo = "Sin título";
this.autor = "Desconocido";
this.paginas = 0;
this.precio = 0.0;
}
// Constructor con parámetros básicos
public Libro(String titulo, String autor) {
this.titulo = titulo;
this.autor = autor;
this.paginas = 0;
this.precio = 0.0;
}
// Constructor completo
public Libro(String titulo, String autor, int paginas, double precio) {
this.titulo = titulo;
this.autor = autor;
this.paginas = paginas;
this.precio = precio;
}
}
// Tres formas de crear un Libro:
Libro l1 = new Libro(); // Constructor vacío
Libro l2 = new Libro("Java", "Ángel Roldán"); // Dos parámetros
Libro l3 = new Libro("Java", "Ángel Roldán", 450, 29.90); // Completo
🔹 Encadenamiento de constructores con this()
Para evitar la duplicación de código entre constructores, se puede usar this() para llamar a otro constructor de la misma clase. La llamada a this() debe ser la primera instrucción del constructor:
public class Producto {
private String nombre;
private double precio;
private int stock;
// Constructor completo (el único que asigna directamente)
public Producto(String nombre, double precio, int stock) {
this.nombre = nombre;
this.precio = precio;
this.stock = stock;
}
// Delegación al constructor completo
public Producto(String nombre, double precio) {
this(nombre, precio, 0); // stock por defecto = 0
}
// Delegación en cadena
public Producto() {
this("Sin nombre", 0.0); // Llama al constructor de 2 parámetros
}
}
🛡️ Modificadores de acceso: público, privado y protegido
Los modificadores de acceso controlan la visibilidad de atributos y métodos desde otras clases. Son la base del encapsulamiento, uno de los cuatro pilares de la POO. Java define cuatro niveles de acceso:
| Modificador | Misma clase | Mismo paquete | Subclase | Cualquier clase |
|---|---|---|---|---|
private |
✅ | ❌ | ❌ | ❌ |
| (sin modificador) | ✅ | ✅ | ❌ | ❌ |
protected |
✅ | ✅ | ✅ | ❌ |
public |
✅ | ✅ | ✅ | ✅ |
💡 Regla de oro del encapsulamiento: los atributos deben ser siempre private y los métodos de acceso public. Así proteges los datos internos y solo expones las operaciones que otros necesitan usar. Esta práctica se resume en: «datos privados, interfaz pública».
🚀 Instanciación: de la clase al objeto
El proceso de crear un objeto a partir de una clase se denomina instanciación. En Java, se realiza con el operador new, que ejecuta tres acciones en secuencia:
1️⃣ Reserva memoria en el heap para almacenar los atributos del nuevo objeto. 2️⃣ Ejecuta el constructor correspondiente para inicializar esos atributos. 3️⃣ Devuelve una referencia (dirección de memoria) que se almacena en la variable declarada.
// Declaración: se crea la variable (referencia)
Coche miCoche;
// Instanciación: se crea el objeto en memoria
miCoche = new Coche("Toyota", "Corolla", 2024);
// Declaración + instanciación en una sola línea (lo más habitual):
Coche miCoche = new Coche("Toyota", "Corolla", 2024);
// Acceso a métodos del objeto:
miCoche.acelerar(60);
System.out.println(miCoche.getVelocidad()); // 60
⚠️ Error común: declarar una variable de tipo objeto sin usar new y luego intentar acceder a sus métodos. Esto produce un NullPointerException porque la variable contiene null (no apunta a ningún objeto en memoria).
🎯 Ejemplo integrador: sistema de gestión de productos
A continuación presentamos un ejemplo completo que integra todos los conceptos: atributos privados, constructores sobrecargados, getters y setters con validación, métodos de lógica de negocio y un atributo de clase estático.
public class Producto {
// Atributo de clase (compartido)
private static int contadorProductos = 0;
// Atributos de instancia (privados)
private int id;
private String nombre;
private double precio;
private int stock;
private String categoria;
// ---- Constructores ----
public Producto(String nombre, double precio, int stock, String categoria) {
contadorProductos++;
this.id = contadorProductos;
setNombre(nombre); // Usa setter para validar
setPrecio(precio);
setStock(stock);
this.categoria = categoria;
}
public Producto(String nombre, double precio) {
this(nombre, precio, 0, "General");
}
// ---- Getters ----
public int getId() { return id; }
public String getNombre() { return nombre; }
public double getPrecio() { return precio; }
public int getStock() { return stock; }
public String getCategoria() { return categoria; }
public static int getTotalProductos() {
return contadorProductos;
}
// ---- Setters con validación ----
public void setNombre(String nombre) {
if (nombre != null && !nombre.trim().isEmpty()) {
this.nombre = nombre.trim();
} else {
throw new IllegalArgumentException("El nombre no puede estar vacío.");
}
}
public void setPrecio(double precio) {
if (precio >= 0) {
this.precio = precio;
} else {
throw new IllegalArgumentException("El precio no puede ser negativo.");
}
}
public void setStock(int stock) {
if (stock >= 0) {
this.stock = stock;
} else {
throw new IllegalArgumentException("El stock no puede ser negativo.");
}
}
// ---- Métodos de negocio ----
public boolean hayDisponibilidad() {
return stock > 0;
}
public void vender(int cantidad) {
if (cantidad <= 0) {
throw new IllegalArgumentException("La cantidad debe ser positiva.");
}
if (cantidad > stock) {
throw new IllegalStateException("Stock insuficiente. Disponible: " + stock);
}
stock -= cantidad;
System.out.println("Vendidas " + cantidad + " unidades de " + nombre);
}
public double calcularValorInventario() {
return precio * stock;
}
@Override
public String toString() {
return String.format("[%d] %s - %.2f€ (Stock: %d)", id, nombre, precio, stock);
}
}
public class TestProducto {
public static void main(String[] args) {
// Crear productos
Producto p1 = new Producto("Teclado mecánico", 79.99, 50, "Informática");
Producto p2 = new Producto("Ratón inalámbrico", 29.99, 120, "Informática");
Producto p3 = new Producto("Cable USB-C", 9.99); // stock=0, categoría=General
// Mostrar información
System.out.println(p1); // [1] Teclado mecánico - 79.99€ (Stock: 50)
System.out.println(p2); // [2] Ratón inalámbrico - 29.99€ (Stock: 120)
System.out.println(p3); // [3] Cable USB-C - 9.99€ (Stock: 0)
// Vender unidades
p1.vender(5);
System.out.println("Valor inventario p1: " + p1.calcularValorInventario() + "€");
// Total de productos creados
System.out.println("Total productos: " + Producto.getTotalProductos()); // 3
}
}
📌 Buenas prácticas en el diseño de clases
El diseño de clases bien estructuradas es una habilidad que se perfecciona con la experiencia. Estas directrices, ampliamente aceptadas en la industria, te ayudarán a crear código profesional desde el principio:
Principio de responsabilidad única: cada clase debe tener un solo propósito. Si tu clase Producto también gestiona la conexión a base de datos, algo está mal. Separa responsabilidades en clases distintas.
Atributos siempre privados: declara todos los atributos como private y proporciona getters y setters según sea necesario. No todos los atributos necesitan setter — un id generado automáticamente, por ejemplo, solo debería tener getter.
Validación en constructores y setters: nunca asumas que los datos entrantes son correctos. Valida siempre y lanza excepciones claras cuando se violen las reglas de negocio.
Implementa toString(): sobreescribir este método facilita enormemente la depuración y el registro de información (logging). Es una práctica que todo programador profesional sigue.
Nombres descriptivos: una clase llamada GestorPedidos es infinitamente mejor que GP o Clase1. Invierte tiempo en elegir buenos nombres — tu yo del futuro te lo agradecerá.
🐛 Errores frecuentes al trabajar con clases
Estos son los errores más comunes que cometen los programadores cuando empiezan a trabajar con clases en Java. Reconocerlos te ayudará a evitarlos:
🔸 Error 1: Olvidar el new al crear objetos
Producto p;
p.getNombre(); // ¡NullPointerException! La variable p es null.
// ✅ Corrección:
Producto p = new Producto("Teclado", 79.99);
p.getNombre(); // Funciona correctamente
🔸 Error 2: Confundir = con == en objetos
Producto p1 = new Producto("Teclado", 79.99);
Producto p2 = new Producto("Teclado", 79.99);
System.out.println(p1 == p2); // false (compara referencias)
System.out.println(p1.equals(p2)); // Depende de si equals() está sobreescrito
🔸 Error 3: Atributos públicos sin protección
// MAL: atributos públicos permiten valores inválidos
public class Producto {
public double precio; // Cualquiera puede poner -999
}
Producto p = new Producto();
p.precio = -999; // ¡Nadie lo impide!
// ✅ Corrección: atributos privados + setter con validación
private double precio;
public void setPrecio(double precio) {
if (precio >= 0) this.precio = precio;
}
🔸 Error 4: No definir constructor por defecto cuando hay constructores personalizados
public class Producto {
public Producto(String nombre) { /* ... */ }
// No hay constructor sin parámetros
}
Producto p = new Producto(); // ¡Error de compilación!
// Java ya no genera el constructor por defecto
// ✅ Corrección: añadir constructor vacío explícitamente
public Producto() { this("Sin nombre"); }
✏️ Ejercicios prácticos
Ejercicio 1 — Clase Estudiante
Crea una clase Estudiante con los atributos privados nombre (String), matricula (String) y notaMedia (double). Implementa un constructor completo, getters, un setter para notaMedia que valide que esté entre 0 y 10, y un método estaAprobado() que devuelva true si la nota media es mayor o igual a 5. Crea dos estudiantes y muestra si están aprobados.
public class Estudiante {
private String nombre;
private String matricula;
private double notaMedia;
public Estudiante(String nombre, String matricula, double notaMedia) {
this.nombre = nombre;
this.matricula = matricula;
setNotaMedia(notaMedia);
}
public String getNombre() { return nombre; }
public String getMatricula() { return matricula; }
public double getNotaMedia() { return notaMedia; }
public void setNotaMedia(double nota) {
if (nota >= 0 && nota <= 10) {
this.notaMedia = nota;
} else {
throw new IllegalArgumentException("La nota debe estar entre 0 y 10.");
}
}
public boolean estaAprobado() {
return notaMedia >= 5.0;
}
@Override
public String toString() {
return matricula + " - " + nombre + " (Nota: " + notaMedia + ")";
}
public static void main(String[] args) {
Estudiante e1 = new Estudiante("María López", "MAT001", 7.5);
Estudiante e2 = new Estudiante("Carlos Ruiz", "MAT002", 4.2);
System.out.println(e1 + " - Aprobado: " + e1.estaAprobado()); // true
System.out.println(e2 + " - Aprobado: " + e2.estaAprobado()); // false
}
}
Ejercicio 2 — Clase Rectangulo con sobrecarga
Crea una clase Rectangulo con atributos base y altura (ambos double). Implementa tres constructores: uno sin parámetros (cuadrado unitario 1×1), uno con un parámetro (cuadrado de lado n), y uno con dos parámetros. Añade métodos calcularArea(), calcularPerimetro() y esCuadrado(). Crea tres rectángulos y muestra sus propiedades.
public class Rectangulo {
private double base;
private double altura;
public Rectangulo() {
this(1.0, 1.0);
}
public Rectangulo(double lado) {
this(lado, lado);
}
public Rectangulo(double base, double altura) {
if (base <= 0 || altura <= 0) {
throw new IllegalArgumentException("Las dimensiones deben ser positivas.");
}
this.base = base;
this.altura = altura;
}
public double calcularArea() {
return base * altura;
}
public double calcularPerimetro() {
return 2 * (base + altura);
}
public boolean esCuadrado() {
return base == altura;
}
@Override
public String toString() {
return String.format("Rectángulo(%.1f x %.1f) - Área: %.2f",
base, altura, calcularArea());
}
public static void main(String[] args) {
Rectangulo r1 = new Rectangulo(); // 1x1
Rectangulo r2 = new Rectangulo(5); // 5x5
Rectangulo r3 = new Rectangulo(4, 7); // 4x7
System.out.println(r1 + " - Cuadrado: " + r1.esCuadrado()); // true
System.out.println(r2 + " - Cuadrado: " + r2.esCuadrado()); // true
System.out.println(r3 + " - Cuadrado: " + r3.esCuadrado()); // false
System.out.println("Perímetro r3: " + r3.calcularPerimetro()); // 22.0
}
}
Ejercicio 3 — Clase CuentaBancaria completa
Diseña una clase CuentaBancaria con: atributo de clase contadorCuentas, atributos de instancia numeroCuenta (autogenerado), titular y saldo. Implementa métodos depositar(), retirar() (con validación de saldo suficiente) y transferir() (que retire de una cuenta y deposite en otra). Prueba creando dos cuentas y realizando una transferencia.
public class CuentaBancaria {
private static int contadorCuentas = 0;
private String numeroCuenta;
private String titular;
private double saldo;
public CuentaBancaria(String titular, double saldoInicial) {
contadorCuentas++;
this.numeroCuenta = "ES-" + String.format("%04d", contadorCuentas);
this.titular = titular;
if (saldoInicial >= 0) {
this.saldo = saldoInicial;
} else {
throw new IllegalArgumentException("El saldo inicial no puede ser negativo.");
}
}
public CuentaBancaria(String titular) {
this(titular, 0.0);
}
public String getNumeroCuenta() { return numeroCuenta; }
public String getTitular() { return titular; }
public double getSaldo() { return saldo; }
public void depositar(double cantidad) {
if (cantidad <= 0) {
throw new IllegalArgumentException("La cantidad debe ser positiva.");
}
saldo += cantidad;
System.out.println("Depósito de " + cantidad + "€ en " + numeroCuenta);
}
public void retirar(double cantidad) {
if (cantidad <= 0) {
throw new IllegalArgumentException("La cantidad debe ser positiva.");
}
if (cantidad > saldo) {
throw new IllegalStateException("Saldo insuficiente. Disponible: " + saldo + "€");
}
saldo -= cantidad;
System.out.println("Retiro de " + cantidad + "€ de " + numeroCuenta);
}
public void transferir(CuentaBancaria destino, double cantidad) {
this.retirar(cantidad);
destino.depositar(cantidad);
System.out.println("Transferencia completada: " + numeroCuenta
+ " → " + destino.getNumeroCuenta());
}
@Override
public String toString() {
return String.format("%s (%s) - Saldo: %.2f€",
numeroCuenta, titular, saldo);
}
public static void main(String[] args) {
CuentaBancaria cuenta1 = new CuentaBancaria("Ana García", 1000);
CuentaBancaria cuenta2 = new CuentaBancaria("Luis Martínez", 500);
System.out.println("--- Estado inicial ---");
System.out.println(cuenta1);
System.out.println(cuenta2);
cuenta1.transferir(cuenta2, 250);
System.out.println("\n--- Después de la transferencia ---");
System.out.println(cuenta1); // Saldo: 750.00€
System.out.println(cuenta2); // Saldo: 750.00€
}
}
❓ Preguntas frecuentes sobre La Clase en POO: definición, atributos y métodos con Java
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre La Clase en POO: definición, atributos y métodos con Java? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!