L'héritage est un concept fondamental de la programmation orientée objet car il permet la création d'une nouvelle classe à partir d'une classe existante.

Dans le langage Java, l'héritage multiple n'est pas possible, puisqu'une classe ne peut posséder qu'une seule et unique superclasse. Par contre, une classe parente peut avoir une à plusieurs sous-classes.

Les classes héritant d'autres classes sont dites dérivées ou étendues, voire même directement appelées des sous-classes et la classe parente est parfois appelée superclasse ou générique.

Le mot-clé extends est utilisé dans une déclaration de classe dérivée, pour spécifier une superclasse.

modificateur_acces SuperClasse {
  //...
}

modificateur_acces class ClasseDerivee extends SuperClasse{
  //...
}

Par défaut, toutes les classes héritent de la superclasse la plus élevée dans la hiérarchie, c'est à dire de la classe Object.

//Hiérarchie de classes pour la classe Applet
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
            |
            +--java.awt.Panel
                  |
                  +--java.applet.Applet

Une classe dérivée hérite de toutes les méthodes et propriétés de la superclasse. La sous-classe peut ainsi définir de nouveaux membres qui ajouteront de nouvelles fonctionnalités à celles existantes, mais aussi de redéfinir des membres hérités à l'aide de la surcharge des méthodes, du mot clé super ou de la réaffectation des variables.

class super_classe {
  // Déclarations des attributs
  type attribut_1;
  type ...
  type attribut_N;

  // Déclarations des fonctions
  public type nom_methode_1 (type param_1, ..., type param_N){
    //Bloc d'instructions...
  }
  ...
  public type nom_methode_N (type param_1, ..., type param_N){
    //Bloc d'instructions...
  }
}

class nouvelle_classe extends super_classe {
  // Déclarations des nouveaux attributs
  type attribut_1;
  type ...
  type attribut_N;

  // Déclarations des nouvelles fonctions
  public type nom_methode_1 (type param_1, ..., type param_N){
    //Bloc d'instructions...
  }
  ...
  public type nom_methode_N (type param_1, ..., type param_N){
    //Bloc d'instructions...
  }
}

Un mécanisme spécifique appelé liaison dynamique (ou liaison tardive) détermine à l'exécution d'un programme (runtime) quelles sont les méthodes les plus appropriées à appeler, lorsque ces dernières ont été surchargées. Ces méthodes doivent possèder un modificateur d'accès soit public, soit protected. Si les méthodes sont privées, statiques ou finales alors elles sont directement invoquées sans utiliser la liaison dynamique.

class Animal {
  public void manger(){
    //...
  }
  public void seDeplacer(){
    //...
  }
}
class Bison extends Animal {
  public void manger(){
    //...
  }
  public void seDeplacer(){
    //...
  }
  public void brouter(){
    //...
  }
  public void transhumer(){
    //...
  }
}
class Tigre extends Animal {
  public void manger(){
    //...
  }
  public void deplacer(){
    //...
  }
  public void devorer(){
    //...
  }
}
Animal animal = new Animal();
Tigre tigre = new Tigre();
Bison bison = new Bison();

//Appel de la méthode déclarée au sein de la superclasse Animal
animal.manger();

//Appel des méthodes surchargées déclarées au sein des sous-classes
bison.manger();
tigre.manger();

//Appel de la méthode surchargée déclarée au sein de la sous-classe Tigre
animal = tigre;
animal.manger();

//Appel de la méthode surchargée déclarée au sein de la sous-classe Bison
animal = new Bison();
animal.manger();

La JVM se fonde sur le type dynamique d'un objet pour déterminer les méthodes à invoquer et non sur son type référence.

En ce qui concerne les propriétés surchargées, le fonctionnement est radicalement différent.

class Animal {
  public float poids = 0;
}
class Bison extends Animal {
  public float poids = 400;
}
class Tigre extends Animal {
  public float poids = 250;
}
Animal animal = new Animal();
Tigre tigre = new Tigre();
Bison bison = new Bison();

//Appel du champ déclaré au sein de la superclasse Animal
System.out.println(animal.poids;); //0

//Appel des champs surchargés déclarés au sein des sous-classes
System.out.println(bison.poids;); //400
System.out.println(tigre.poids;); //250

//Appel du champ déclaré au sein de la superclasse Animal
animal = tigre;
System.out.println(animal.poids;); //0

//Appel du champ surchargé déclaré au sein de la superclasse Animal
animal = new Bison();
System.out.println(animal.poids;); //0

Lors du processus de compilation, le mécanisme de typage statique contraint les propriétés d'un objet à suivre le type référence de ce dernier.