¿Qué son una clase y un objeto?
Una clase es una categoría, una clasificación. Abstractamos los objetos que nos rodean para convertirlos en un tipo único. Por ejemplo, abstraemos a todos los seres humanos del mundo en la clase «Persona». Una persona concreta como Bob o Tom es un objeto.
Una clase funciona como un «plano» o una «plantilla» que define la estructura y el comportamiento de los objetos.
Tomemos de nuevo la clase Persona como ejemplo: esta plantilla establece qué tiene una persona y qué puede hacer. Tiene nombre, extremidades y órganos; puede hablar y pensar. Datos como el nombre o la edad son las propiedades de la clase, mientras que acciones como hablar o pensar son su comportamiento. En resumen, una clase extrae un esquema común de los elementos reales. Con esta plantilla podemos crear objetos distintos como Jack o Jim.
Las propiedades de una clase (nombre, edad) y sus comportamientos (hablar, pensar) se representan mediante variables y funciones respectivamente.
Especifica las propiedades (variables) y los métodos (funciones) que debe tener cada objeto.
Una clase se puede comparar con un molde de pan: no es un producto terminado. Con un mismo molde se fabrican muchos panes reales, igual que con una clase se generan múltiples objetos.
Al principio de la historia de la programación no existía el concepto de clase. El lenguaje C es un ejemplo típico: solo cuenta con funciones, variables e instrucciones, lo que se denomina programación procedimental. A medida que los software se volvían más complejos, los desarrolladores detectaron muchos inconvenientes en este paradigma: gran cantidad de código duplicado, organización desordenada, falta de jerarquía y legibilidad. Más tarde surgió un nuevo enfoque: abstraer la lógica del programa en objetos, al igual que el mundo real. Podemos compararlo con una pequeña empresa: al principio el jefe gestiona todas las tareas solo. Cuando contrata personal, delega la contabilidad al departamento financiero y el reclutamiento a recursos humanos. Al repartir funciones, la organización queda mucho más clara.
Un objeto es una instancia de una clase.
Cuando usas la palabra clave new o un constructor, la clase genera un objeto.
El objeto es una entidad concreta capaz de almacenar datos y llamar métodos.
Relación entre clases y objetos
- La clase es el plano arquitectónico; el objeto es la casa construida a partir de ese plano.
- Una misma clase permite crear varios objetos, cada uno con sus propios datos independientes.
- Todos los objetos derivados de una misma clase comparten los comportamientos (métodos) definidos en la clase.

Ahora pasemos al lenguaje Dart
Vamos a tratar los siguientes puntos
Dart es un lenguaje totalmente orientado a objetos: todo valor es una instancia de clase. Salvo Null, todas las clases heredan de la clase base Object.
Dart implementa la herencia mediante la combinación de clases y Mixins
Herencia simple: cada clase solo puede tener una clase padre, pero los Mixins permiten reutilizar varios bloques de lógica de distintas clases
Métodos de extensión: agregar funcionalidades a una clase sin modificar su código fuente ni crear una subclase
Modificadores de clase: controlan si otras bibliotecas pueden heredar o implementar esta clase
Comencemos a estudiar las clases en Dart
Miembros de clase
Los miembros de una clase agrupan sus métodos y variables: son los elementos que componen la clase.
Usa el operador . para acceder a los miembros de instancia; el operador de seguridad nula ?. evita excepciones de puntero nulo
Aquí tienes un ejemplo completo que muestra cómo definir una clase, instanciar un objeto desde ella y llamar a sus miembros mediante el nombre del objeto
// Definir una clase, equivale a crear un molde
class Point {
double x, y;
Point(this.x, this.y);
// Método de instancia: calcular el cuadrado de la distancia entre dos puntos
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
// Crear el objeto p a partir de la clase Point para realizar operaciones
var p = Point(2, 2);
// Leer una variable de instancia (getter implícito)
print(p.y); //2.0
// Llamar a un método de instancia
double dist = p.distanceTo(Point(4, 4));
print(dist); // 8.0
// Acceso seguro con ?.
Point? nullablePoint;
var a = nullablePoint?.y; // Si el objeto es null, a recibe null sin errores
print(a); // null
}Lenguaje del código: JavaScript (javascript)

Constructores
Constructores estándar
Dart se diferencia de otros lenguajes tipo C al admitir constructores con nombre. En la mayoría de los lenguajes derivados de C el constructor debe tener el mismo nombre que la clase, mientras que Dart permite definir constructores con un identificador distinto al nombre de la clase.
Sintaxis: NombreClase() / NombreClase.identificador() ;
La palabra clave new es opcional (disponible desde Dart 2)
class Point {
double x, y; // Dos variables miembro que almacenan las propiedades de la clase
// Constructor por defecto: inicializar las variables x e y
Point(this.x, this.y);
// Constructor con nombre Point.fromJson: inicializar x e y desde datos JSON
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']!;
}
void main() {
var p1 = Point(2, 2);// Llamada al constructor por defecto, x=2 e y=2 para p1
var p2 = Point.fromJson({'x': 1, 'y': 2}); // Usar el constructor con nombre fromJson con un JSON
// new es opcional, el comportamiento es idéntico
var p3 = new Point(3, 3); // Usar el constructor por defecto
print("p1:(${p1.x},${p1.y}), p2:(${p2.x},${p2.y}), p3:(${p3.x},${p3.y})");
// Salida: p1:(2.0,2.0), p2:(1.0,2.0), p3:(3.0,3.0)
}Lenguaje del código: JavaScript (javascript)
Constructores constantes con const
Antepon la palabra clave const a un constructor para crear objetos constantes en tiempo de compilación; las constantes con parámetros idénticos reutilizan la misma instancia.
class ImmutablePoint {
final double x, y;
// Regla del constructor constante: todos los miembros deben marcarse con final
const ImmutablePoint(this.x, this.y);
}
void main() {
// Creación de instancias constantes
var a = const ImmutablePoint(1, 1); // La palabra clave const es obligatoria aquí
var b = const ImmutablePoint(1, 1);
print(identical(a, b)); // true, hacen referencia al mismo objeto
var m = const ImmutablePoint(1, 1);
var n = const ImmutablePoint(2, 1);
print(identical(m, n)); // false, valores distintos generan objetos separados
// Sin const: objeto ordinario, sin compartir instancia
var c = ImmutablePoint(1, 1);
print(identical(a, c)); //false
// Dentro de un contexto const se puede omitir el const interno
const pointMap = {
'p1': [ImmutablePoint(0, 0)],
'p2': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)]
};
print(pointMap); //{p1: [Instance of 'ImmutablePoint'], p2: [Instance of 'ImmutablePoint', Instance of 'ImmutablePoint']}
print(identical(p1, p2)); // false
print(identical(p2, p3)); // false
print(identical(p1, p3)); // false
}Lenguaje del código: PHP (php)
Un constructor constante solo reutiliza una instancia si todos los parámetros proporcionados coinciden exactamente; un solo parámetro distinto crea dos objetos independientes.
Obtener el tipo de ejecución de un objeto con runtimeType
Obtén el tipo en tiempo de ejecución mediante objeto.runtimeType; prefiere el operador de comprobación de tipo is en lugar de comparaciones sobre runtimeType
class Point {
double x, y;
Point(this.x, this.y);
// Método de instancia: calcular el cuadrado de la distancia entre dos puntos
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
var p = Point(2, 3);
print("Tipo de p: ${p.runtimeType}"); // Point
// Método recomendado y estable
if (p is Point) {
print("p es una instancia de Point");
}
// No recomendado para código de producción
if (p.runtimeType == Point) {
print("p es una instancia de Point ");
}
}Lenguaje del código: JavaScript (javascript)
Variables de instancia Instance Variables
- Los tipos anulables no inicializados valen por defecto
null; los tipos no anulables deben inicializarse obligatoriamente - Todas las variables de instancia generan automáticamente un getter; las variables no final o late final sin inicialización generan un setter automático
- Las expresiones de inicialización clásicas de variables de instancia no pueden acceder a this; las variables late permiten acceder a this en su inicialización
- Las variables de instancia final solo pueden recibir un valor una vez: en la declaración, por parámetro de constructor o en la lista de inicialización del constructor
Getters y setters implícitos
class Point {
double? x; // Valor inicial null, getter + setter generados automáticamente
double? y;
double z = 0; // Inicializado en 0
}
void main() {
var point = Point();
point.x = 4; // Llamada al setter implícito
assert(point.x == 4); // Llamada al getter implícito
assert(point.y == null);
print(point.z); // 0
}
Lenguaje del código: JavaScript (javascript)
Restricción de acceso a this en expresiones de inicialización
double globalX = 1.5;
class Point {
// Permitido: acceder a una variable global externa sin recurrir a this
double? x = globalX;
// Error de compilación: la inicialización estándar no autoriza this
// double? y = this.x;
// Permitido: las variables late pueden usar this en su inicialización
late double? z = this.x;
// Permitido: el azúcar sintáctico this.x de los parámetros de constructor no es una expresión de inicialización
Point(this.x, this.y);
double? y;
}
void main() {
var p = Point(null, 5);
print(p.z); // null
}
Lenguaje del código: JavaScript (javascript)
Tres formas de inicializar variables de instancia final
class ProfileMark {
// Forma 1: inicialización directa en la declaración
final DateTime start = DateTime.now();
final String name;
// Forma 2: asignación por parámetro de constructor
ProfileMark(this.name);
// Forma 3: asignación en la lista de inicialización del constructor; el constructor con nombre unnamed asigna una cadena vacía por defecto a name
ProfileMark.unnamed() : name = '';
}
void main() {
var m1 = ProfileMark("user1");
var m2 = ProfileMark.unnamed();
print(m1.name);
print(m2.name);
}
Lenguaje del código: PHP (php)
Interfaces implícitas Implicit interfaces
Cada clase Dart posee una interfaz implícita que agrupa todos sus miembros de instancia públicos.
implements: implementar una interfaz, hay que redefinir la totalidad de los métodos de la interfazextends: heredar de una clase padre para reutilizar su implementación- Las variables privadas prefijadas con
_xxxno se exponen en la interfaz
1 Implementar una sola interfaz
class Person {
final String _name;
Person(this._name);
// Método público de la interfaz
String greet(String who) => "Hello $who, I'm $_name";
}
// Implementar la interfaz Person: obligación de redefinir todos sus miembros
class Impostor implements Person {
String get _name => "";
@override
String greet(String who) => "Hi $who, guess who?";
}
String greetBob(Person p) => p.greet("Bob");
void main() {
print(greetBob(Person("Kathy")));
print(greetBob(Impostor()));
}
Lenguaje del código: PHP (php)
Cuando una subclase redefine un método de la interfaz padre, usa la anotación @override, al igual que en Java. Para implementar una interfaz se usa la palabra clave implements.

2 Implementar varias interfaces
// Clase abstracta
abstract class Comparable {
int compareTo(Object other);
}
// Clase abstracta
abstract class Location {
double get x;
double get y;
}
// Implementar dos interfaces simultáneamente
class Point implements Comparable, Location {
@override
double x, y;
Point(this.x, this.y);
@override
int compareTo(Object other) {
if (other is Point) {
return (x + y).compareTo(other.x + other.y);
}
return -1;
}
}
void main() {
var p = Point(2, 3);
print(p.x);
print(p.compareTo(Point(1, 1)));
}
Lenguaje del código: PHP (php)
@override
double x, y;
Esta anotación significa que estas dos propiedades redefinen los getters abstractos declarados en la interfaz padre Location.
Variables estáticas & métodos estáticos static
1. Variables estáticas static (variables de clase, únicas a nivel global)
- Pertenecen a la clase y no a las instancias; inicialización diferida: solo se crean en el primer acceso
- Se recomienda nombrar las constantes estáticas en camelCase minúsculo
class Queue {
static const initialCapacity = 16; // Constante estática
static int count = 0; // Variable estática mutable
Queue() {
count++;
}
}
void main() {
assert(Queue.initialCapacity == 16); // Se inicializa al acceder, valor por defecto 16
Queue(); // Incrementar count en 1
Queue();
print(Queue.count); // 2
}
Lenguaje del código: JavaScript (javascript)
2. Métodos estáticos static (métodos de clase)
- No tienen referencia
this, por lo que no pueden acceder a miembros de instancia; solo a variables estáticas - Llamada directa mediante la sintaxis
NombreClase.metodo() - Pueden transmitirse como constantes de compilación a constructores constantes
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
// Método estático: calcular la distancia directa entre dos puntos
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var dist = Point.distanceBetween(a, b);
print(dist); // ~2,828
}Lenguaje del código: JavaScript (javascript)

Los métodos estáticos pertenecen a la clase, por lo que hay que llamarlos mediante el nombre de la clase y pasar dos instancias de Point como parámetros.