Ce sont des langues très différentes, particulièrement dans ce domaine. Disons que vous avez une classe. Dans ce cas, nous allons en faire un contrôle utilisateur, quelque chose comme une zone de texte. Appelez-le UIControl. Maintenant, nous voulons mettre cela dans une autre classe. Dans ce cas, puisque nous utilisons une interface utilisateur pour notre exemple, nous l'appellerons la classe CleverPanel. Notre instance CleverPanel voudra savoir ce qui se passe dans son instance UIControl pour diverses raisons. Comment faire ça?
En C #, l’approche de base consiste à rechercher différents événements, en définissant des méthodes à exécuter lorsque chaque événement intéressant est déclenché. En Java, où il manque des événements, la solution habituelle consiste à transmettre un objet avec différentes méthodes de traitement "d'événement" à une méthode UIControl:
boolean stillNeedIt = ... ;
uiControl.whenSomethingHappens( new DoSomething() {
public void resized( Rectangle r ) { ... }
public boolean canICloseNow() { return !stillNeedIt; }
public void closed() { ... }
...
} );
Jusqu'à présent, la différence entre C # et Java n'est pas profonde. Cependant, nous avons l'interface DoSomething qui n'est pas nécessaire en C #. En outre, cette interface peut inclure de nombreuses méthodes qui ne sont pas nécessaires la plupart du temps. En C #, nous ne gérons tout simplement pas cet événement. En Java, nous créons une classe qui fournit une implémentation nulle pour toutes les méthodes d'interface, DoSomethingAdapter. Maintenant, nous remplaçons DoSomething par DoSomethingAdapter et nous n’avons besoin d’écrire aucune méthode pour une compilation propre. Nous finissons par ignorer les méthodes dont nous avons besoin pour que le programme fonctionne correctement. Nous finissons donc par avoir besoin d’une interface et d’ utiliser l’héritage en Java pour correspondre à ce que nous avons fait avec les événements en C #.
Ceci est un exemple, pas une discussion exhaustive, mais il explique en gros pourquoi il y a tant d'héritage en Java par opposition à C #.
Maintenant, pourquoi Java fonctionne-t-il de cette façon? Souplesse. L'objet transmis à whenSomethingHappens aurait pu être transmis à CleverPanel d'un autre endroit complètement. Plusieurs instances de CleverPanel doivent peut-être passer à leurs objets de type UIControl pour aider un objet CleverWindow quelque part. Ou bien UIControl pourrait le transférer à l’un de ses composants.
En outre, au lieu d'un adaptateur, il peut exister une implémentation de DoSomething comportant des milliers de lignes de code. Nous pourrions créer une nouvelle instance de cela et la transmettre. Nous pourrions avoir besoin de remplacer une méthode. Une astuce courante en Java est d’avoir une grande classe avec une méthode comme:
public class BigClass implements DoSomething {
...many long methods...
protected int getDiameter() { return 5; }
}
Puis dans CleverlPanel:
uiControl.whenSomethingHappens( new BigClass() {
@Override
public int getDiameter() { return UIPanel.currentDiameter; }
} );
La plate-forme Java open source fait beaucoup de cela, ce qui a tendance à pousser les programmeurs à en faire plus - à la fois parce qu'ils suivent l'exemple et simplement pour l'utiliser. Je pense que la conception de base du langage repose sur la conception de la structure de Sun et sur celle du programmeur Java qui utilise les techniques sans utiliser la structure.
Il est très facile de créer une classe à la volée en Java. La classe, anonyme ou nommée, ne doit être référencée que dans un petit bloc de code enfoui au cœur d'une méthode. Il peut être créé complètement nouveau ou par de légères modifications d'une très grande classe existante. (Et la classe existante peut être de niveau supérieur dans son propre fichier, ou imbriquée dans une classe de niveau supérieur, ou définie uniquement dans un seul bloc de code). La nouvelle instance de classe peut avoir un accès complet à toutes les données de l'objet en cours de création. Et la nouvelle instance peut être transmise et utilisée dans tout le programme, représentant l'objet qui l'a créée.
(Soit dit en passant, notez qu'une grande utilisation de l'héritage ici - comme dans d'autres endroits en Java - est simplement destinée à la DRY. Cela permet à différentes classes de réutiliser le même code. Notez également la facilité d'héritage en Java qui l'encourage. )
Encore une fois, ce n’est pas une discussion complète; Je ne fais que gratter la surface ici. Mais oui, il existe une différence surprenante dans l'utilisation de l'héritage entre Java et C #. Ce sont des langues très différentes à cet égard. Ce n'est pas ton imagination.