1. The Mental Filter: "Is a" vs "Has a"
Inheritance (extends) creates the strongest coupling in OOP. If the domain relationship fails the strict "X is a Y" test, NEVER inherit: compose via a private field ("X has a Y").
// Herencia limpia: Auto ES UN Vehículo
public class Auto extends Vehiculo {
private Motor motor; // Composición interna
} 2. The Heap in Layers and super() Chaining
Executing new Auto("Toyota") does NOT instantiate two objects. It allocates a SINGLE block in the Heap with concentric state layers. The JVM enforces that super() initializes the superclass state before subclass code executes.
public Auto(String marca) {
super(marca); // <-- ¡Debe ser la 1ra sentencia!
this.baulAbierto = false;
} 3. Overload vs Override: Compile-Time vs Runtime
Overload: same class, same name, different parameters; resolved at compile-time by javac. Override: subclassing, identical signature; resolved dynamically at runtime by JVM according to the concrete instance.
// El compilador verifica que la firma coincida
@Override
public void arrancar() {
System.out.println("Auto arrancando con llave codificada");
} 4. Dynamic Method Dispatch and the vtable
With `Vehiculo v = new Auto()`, the compiler checks the static reference type (Vehiculo). But when calling `v.arrancar()`, the JVM looks up the vtable of the concrete Heap instance and jumps straight to Auto code.
Vehiculo v = new Auto("Toyota");
v.arrancar(); // JVM consulta vtable -> Auto.arrancar() 5. Polymorphic Arrays and Pattern Matching
A polymorphic `Vehicle[]` array handles different vehicles uniformly without switch or if-chains. When accessing subclass-specific methods, modern Java 16+ provides Pattern Matching for instanceof.
for (Vehiculo v : flota) {
v.arrancar(); // Polimorfismo puro
// Java 16+ Pattern Matching (sin cast manual):
if (v instanceof Auto a) {
a.abrirBaul();
}
}