Última actualización: julio 24
La herencia es un proceso mediante el cual heredamos una serie de características de nuestros antecesores. La herencia en Java la podemos definir como un mecanismo para definir una clase nueva a partir de otra ya existente. La clase nueva hereda de la existente sus parámetros y métodos, que no hace falta definirlos de nuevo, sencillamente los hereda. Además, dicha clase nueva puede incluir nuevos parámetros y métodos propios, extendiendo la clase ya existente.
Se denomina clase padre o superclass a la clase existente de la que hereda la nueva clase que es conocida como clase hija.
Para entender y practicar con la herencia de clases, vamos a emplear el siguiente esquema:

En este esquema, la superclase es “Vehículo rodado”, de la que heredan dos clases: “Coche” y “Bicicleta”. Además, tenemos otras dos clases: “Descapotable” y “Sedan”, que heredan de la clase “Coche”, que para aquellas dos clases sería la superclase.
Actividad: Practicando con la herencia en Java
- Abrimos un nuevo proyecto en nuestro IDE de trabajo.
- Seleccionamos Java Application como tipo de proyecto y hacemos clic en Next.
- Ponemos de nombre al proyecto: “AprendiendoHerencia” y lo guardamos en alguna carpeta de nuestro ordenador de la que luego podamos recuperarlo fácilmente. Clicamos en finish
- Si queremos configurar nuestro entorno de trabajo, podemos hacerlo en el menú “Tool-Options”. En mi caso, voy al menú “Fonts & Colors” y aumento el tamaño de letra.
- Ya podemos empezar con el código. Lo primero que haremos será programar la clase padre del esquema: “VehiculoRodado”. Sabemos de cuadernos anteriores que la clase debe definirse en un archivo independiente con el mismo nombre que la clase y la extensión “java”. Entonces creamos un nuevo fichero de tipo Java Class con el nombre “VehiculoRodado.java” (menú : File-New File)
- Nos aparece un cuadro de dialogo donde se nos pregunta el tipo de fichero que queremos crear. Seleccionamos el tipo: “Java Class” y clicamos en Next.
- En la siguiente ventana, tenemos que introducir el nombre de la clase e indicar el proyecto y el paquete donde queremos que se aloje nuestro nuevo fichero. Vamos a dejar ambos valores por defecto, lo que nos aparece en la ventana. No hay que preocuparse por el paquete (package), es en realidad una especie de carpeta que nos permite ordenar nuestro distintos ficheros java. Clicamos en Finish.
- Este proceso descrito para NetBeans sería muy similar para cualquier otro IDE, pudiendo incluso coincidir literalmente los nombres de los menús.
La superclase: VehiculoRodado
- Empezamos a teclear el código de la super clase. Lo primero será definir los parámetros:
private int numeroDeRuedas;
private int añoFabricacion;
- Definimos también un constructor. Necesitamos al menos uno:
public VehiculoRodado(int numeroDeRuedas, int añoFabricacion) {
this.numeroDeRuedas = numeroDeRuedas;
this.añoFabricacion = añoFabricacion;
}
- Los primeros métodos que programaremos serán los getters and setters
public int getNumeroDeRuedas() {
return numeroDeRuedas;
}
public void setNumeroDeRuedas(int numeroDeRuedas) {
this.numeroDeRuedas = numeroDeRuedas;
}
public int getAñoFabricacion() {
return añoFabricacion;
}
public void setAñoFabricacion(int añoFabricacion) {
this.añoFabricacion = añoFabricacion;
}
- Puedes teclear los métodos getters y setters manualmente o puedes dejar a NetBeans que haga este trabajo por ti. Coloca el cursor del ratón en la zona donde quieras incluir el código de estos métodos, luego clicas el botón derecho y te aparece un menú de contexto. Selecciona la opción Insert code y la opción de generar los métodos getters and setters.
- Adicionalmente, definimos el método venta con el que podríamos proceder a la venta del vehículo. Pero para ello, tenemos que definir algunos parámetros más en la clase: propietario, vendedor y precioVenta. La declaración de estos parámetro quedaría:
private String propietario, vendedor;
private float precioVenta;
- Ahora podríamos crear todos los métodos getters y setters para estos nuevos parámetros. En este caso, no crearemos los métodos setters porque queremos que el único camino para establecer los valores de estos parámetros sea a través del método venta. Sin embargo, si crearemos los métodos getters, ya que queremos poder consultar los valores de estos parámetros.
- Los métodos Getters quedarían:
public String getPropietario() {
return propietario;
}
public String getVendedor() {
return vendedor;
}
public float getPrecioVenta() {
return precioVenta;
}
- Y el método venta quedaría:
public void venta(String vendedor, String propietario, float precio){
this.vendedor=vendedor;
this.propietario=propietario;
this.precioVenta=precio;
}
- Una vez creada nuestra clase VehiculoRodado, vamos a chequearla usándola desde el método main de la clase AprendiendoHerencia. Teclea el siguiente código:
public class AprendiendoHerencia {
public static void main(String[] args) {
VehiculoRodado vehiculo1 = new VehiculoRodado(4,2010);
System.out.println("**************************************");
System.out.println("número de ruedas: "+vehiculo1.getNumeroDeRuedas());
System.out.println("año de fabricación: "+vehiculo1.getAñoFabricacion());
System.out.println("propietario: "+vehiculo1.getPropietario());
System.out.println("vendedor: "+vehiculo1.getVendedor());
System.out.println("precio de venta: "+vehiculo1.getPrecioVenta());
vehiculo1.venta("Pedro", "Juan", 500);
System.out.println("**************************************");
System.out.println("número de ruedas: "+vehiculo1.getNumeroDeRuedas());
System.out.println("año de fabricación: "+vehiculo1.getAñoFabricacion());
System.out.println("propietario: "+vehiculo1.getPropietario());
System.out.println("vendedor: "+vehiculo1.getVendedor());
System.out.println("precio de venta: "+vehiculo1.getPrecioVenta());
}
}
- Lo primero que hacemos es definir un objeto VehiculoRodado e imprimimos el valor de sus parámetros. Como en el constructor no definimos todos los parámetros, alguno de estos nos aparecerá nulos o ceros, dependiendo del tipo de parámetro. Posteriormente, con el método venta, todos los parámetros quedan definidos y si ahora volvemos a imprimir los valores de los parámetros, ya obtendríamos valores para todos.
- El resultado de ejecutar el programa sería:
run:
**************************************
número de ruedas: 4
año de fabricación: 2010
propietario: null
vendedor: null
precio de venta: 0.0
**************************************
número de ruedas: 4
año de fabricación: 2010
propietario: Juan
vendedor: Pedro
precio de venta: 500.0
BUILD SUCCESSFUL (total time: 0 seconds)
- Sin embargo, este código está lejos de ser eficiente. Repetimos un par de veces todas las instrucciones para imprimir por pantalla los datos del vehiculo1. Vamos a llevarnos esta función a un método que ubicaremos en la clase VehiculoRodado. Teclea en dicha clase:
public void dibujarDatos(){
System.out.println("**************************************");
System.out.println("número de ruedas: "+this.getNumeroDeRuedas());
System.out.println("año de fabricación: "+this.getAñoFabricacion());
System.out.println("propietario: "+this.getPropietario());
System.out.println("vendedor: "+this.getVendedor());
System.out.println("precio de venta: "+this.getPrecioVenta());
}
- Y ahora empleamos este nuevo método en nuestro programa principal. Podemos borrar todas las sentencias print y llamar a este método siempre que queramos imprimir los parámetros de un objeto de la clase. El nuevo código en el método main sería:
public class AprendiendoHerencia {
public static void main(String[] args) {
VehiculoRodado vehiculo1 = new VehiculoRodado(4,2010);
vehiculo1.dibujarDatos();
vehiculo1.venta("Pedro", "Juan", 500);
vehiculo1.dibujarDatos();
}
}
La clase que hereda: Coche
- Lo siguiente es desarrollar la clase Coche que heredará de VehiculoRodado. Recordemos brevemente la estructura de las clases que queríamos crear:

- Para programar la clase Coche, necesitamos crear un archivo nuevo del tipo Java Class. Ya sabemos cómo hacer esto, de los puntos 7 y 8.
- El código de la nueva clase Coche sería:
public class Coche extends VehiculoRodado {
public Coche(int numeroDeRuedas, int añoFabricacion) {
super(numeroDeRuedas, añoFabricacion);
}
}
Línea 1: En la declaración de la clase Coche indicamos que esta extiende la clase VehiculoRodado, empleando para ello la palabra reservada extends. La clase VehiculoRodado será la superclase de la clase Coche.
Línea 2: El constructor.
Línea 3: con la palabra reservada super, llamamos al constructor de la superclase. Esto hay que hacerlo siempre, ya que la clase hereda de la superclase y hay que crear también la superclase.
- Ahora pasamos a usar la clase Coche en el método main.
public class AprendiendoHerencia {
public static void main(String[] args) {
Coche miCoche;
miCoche = new Coche (5,2012);
miCoche.dibujarDatos();
}
}
Línea 3: Declaramos el objeto miCoche de tipo Coche.
Línea 4: instanciamos el objeto miCoche, pasando al constructor los parámetros requeridos: Numero de puertas y año de fabricación. Estos están heredados de la clase padre, de la superclase.
Línea 5: Empleando un método dibujarDatos heredado de la superclase, dibujamos los datos del objeto por pantalla.
- Si ejecutamos el programa, el resultado es:
run:
**************************************
número de ruedas: 5
año de fabricación: 2012
propietario: null
vendedor: null
precio de venta: 0.0
BUILD SUCCESSFUL (total time: 0 seconds)
- Ahora definiremos algunas características adicionales de la clase Coche, aquellas que no tiene sentido definirlas en la superclase porque no aplicarían a todos los Vehiculos rodados, sino solamente a los coches. Por ejemplo: combustible. Este parámetro no tendría sentido definirlo al nivel Vehiculos rodados, ya que no todos los vehículos rodados lo tendrían. La bicicleta no emplea combustible.
- Declaramos el parámetro combustible y creamos sus métodos getter y setter. La nueva clase Coche quedaría:
public class Coche extends VehiculoRodado {
private String combustible;
public Coche(int numeroDeRuedas, int añoFabricacion) {
super(numeroDeRuedas, añoFabricacion);
}
//metodos getters y setters
public String getCombustible() {
return combustible;
}
public void setCombustible(String combustible) {
this.combustible = combustible;
}
}
- Es el momento de crear un segundo constructor usando la característica de la sobrecarga. En este nuevo constructor añadiríamos el parámetro combustible.
public Coche(String combustible, int numeroDeRuedas, int añoFabricacion) {
super(numeroDeRuedas, añoFabricacion);
this.combustible = combustible;
}
- Y empleamos este nuevo constructor en el método main:
public class AprendiendoHerencia {
public static void main(String[] args) {
Coche miCoche;
miCoche = new Coche (5,2012);
miCoche.dibujarDatos();
Coche tuCoche;
tuCoche = new Coche("gasolina",3,2002);
tuCoche.dibujarDatos();
}
}
El resultado de la ejecución es:
run:
**************************************
número de ruedas: 5
año de fabricación: 2012
propietario: null
vendedor: null
precio de venta: 0.0
**************************************
número de ruedas: 3
año de fabricación: 2002
propietario: null
vendedor: null
precio de venta: 0.0
BUILD SUCCESSFUL (total time: 0 seconds)
- Para dibujar por pantalla los datos de tuCoche, objeto creado con el segundo constructor que incluye el parámetro combustible. He empleado el método dibujarDatos que la clase Coche hereda de la superclase. Al ser un método heredado, no utiliza el parámetro combustible que es especifico de la clase Coche, y por tanto, la clase padre no lo conoce.
- Empleando sobrecarga de métodos, vamos a definirnos un método dibujarDatos en la clase Coche, que nos imprima también la información del parámetro combustible.
- En primer término, vemos que si simplemente copiamos el método tal cual lo tenemos en VehiculoRodado, el programa funciona:
public void dibujarDatos(){
System.out.println("**************************************");
System.out.println("número de ruedas: "+this.getNumeroDeRuedas());
System.out.println("año de fabricación: "+this.getAñoFabricacion());
System.out.println("propietario: "+this.getPropietario());
System.out.println("vendedor: "+this.getVendedor());
System.out.println("precio de venta: "+this.getPrecioVenta());
}
- No obstante, esto no tiene ningún sentido ya que este método lo teníamos ya accesible porque lo habíamos heredado. En cualquier caso, nos sirve para entender que la sobrecarga de métodos aplica sólo entre los métodos de una Clase. En clases diferentes puede haber métodos idénticos. Y entre clases que hereden, iremos de abajo a arriba, es decir, primero buscamos el método en la clase con la que estemos trabajando, y si no lo encontramos ahí iremos a la superclase.
- Añadimos ahora una línea que nos imprima el combustible.
public void dibujarDatos(){
System.out.println("**************************************");
System.out.println("número de ruedas: "+this.getNumeroDeRuedas());
System.out.println("año de fabricación: "+this.getAñoFabricacion());
System.out.println("propietario: "+this.getPropietario());
System.out.println("vendedor: "+this.getVendedor());
System.out.println("precio de venta: "+this.getPrecioVenta());
System.out.println("el combustible empleado es: "+this.combustible);
}
- En cualquier caso, podemos escribir este método de una manera mucho más eficiente, haciendo una llamada al método de la clase padre, y así no tener que repetir tanto código. Nuestro método quedaría.
public void dibujarDatos(){
super.dibujarDatos();
System.out.println("el combustible empleado es: "+this.combustible);
}
Para practicar estos conceptos, puedes realizar los ejercicios que te propongo en el siguiente post.
NOTA:
Este post es parte de la colección “Java”. Puedes ver el índice de esta colección aquí.