C# versus Java

Introduction

Combien de fois n'a t-on pas entendu les questions ou réflexions suivantes : "mais qu'est-ce que ça fait de plus que Java, ce C# ? " ou encore "C# ? Ah bah oui, c'est le Java propriétaire de Microsoft pour contrer Sun" et combien de fois n'avez vous pas eu envie d'expliquer ou de convaincre à ces personnes, au demeurant de bonne foi, que C# méritait plus d'estime car il possédait de multiples facettes et qualités souvent trop longues à énumérer ou à résumer au détour d'un forum de discussions. D'ailleurs, dans la majeure partie des cas, ce dédain face à un nouveau langage, qui plus est développé par Microsoft (quel sacrilège ;-)), n'est qu'un moyen de dissimuler une certaine forme d'ignorance.

Cet article intitulé "C# versus Java" se propose de vous faire connaître C# à travers un ensemble de caractéristiques communes ou différentes de Java (Exceptions, Héritages, ...) avec un regard serein et objectif. Devant la multitude de sujets proposés, nous avons essayé de regrouper les fonctionnalités qui présentaient des similitudes, celles qui différaient de part leur implémentation et enfin, celles qui avaient un caractère novateur.

La plupart des exemples ont été testés avec  Microsoft .NET Framework beta 2 et Java 2 Standard Edition.

L'auteur de l'article original est Dare Obasanjo qui a eu la gentillesse de nous autoriser à enrichir et à traduire ses écrits. Certaines parties ont été totalement revisitées par nos soins pour plus de clarté et de simplicité mais en aucun cas le sens et la teneur de l'article original n'ont été modifiés. Nous espérons qu'après avoir lu ces quelques pages vous serez plus à même de comprendre ce qu'est C#, mais aussi d'analyser ou de mieux juger par vous même ses multiples caractéristiques et fonctionnalités.  

 

Index Rapide

  1. Plus les choses évoluent plus elles tendent à se ressembler
    Cette section décrit les concepts et les caractéristiques très proches de C# et Java
    1. Nous sommes tous des objets
    2. Synthèse des mots-clés
    3. A propos des machines virtuelles
    4. Gestion de la mémoire (ramasse miettes)
    5. Les tableaux
    6. Pas de méthodes globales
    7. Les interfaces, Oui. L'héritage multiple, Non.
    8. Les chaînes de caractères ne peuvent être modifiées
    9. Les classes non extensibles
    10. Levée et Capture d'Exceptions
    11. Initialisation de membres et constructeurs statiques
  2. La même chose mais en différent
    Cette section décrit les concepts et caractéristiques des langages qui diffèrent soit au niveau de la syntaxe soit dans la façon d'être implémentés.
    1. La méthode Main
    2. La syntaxe de l'héritage  
    3. L'opérateur d'identification de type  (is operator)
    4. Les Namespaces ou packages
    5. Constructeurs, Destructeurs et Finaliseurs
    6. Synchronisation de méthodes
    7. Accessibilité à la classe
    8. La Reflection
    9. Déclaration de constantes
    10. Les types primitifs
    11. La déclaration de tableaux
    12. Chaînage et appel du constructeur père
  3. Comme un air de "Déjà Vu
    Cette section décrit les concepts et les caractéristiques de C# existants dans JAVA mais avec une importante différence au niveau de leur implémentation.
    1. Les classes imbriquées
    2. Les threads et les membres volatiles
    3. La surcharge d'opérateurs
    4. L'instruction "switch"
    5. Les Assemblies
    6. Collections
    7. Goto (plus considéré comme dangereux)
    8. Les méthodes virtuelles (et finales)
    9. Fichiers Entrée/Sortie
    10. La sérialisation
    11. La génération de la documentation à partir du code source
    12. Plusieurs classes dans un même fichier
    13. L'import de bibliothèques
    14. Les évènements
    15. Intéropérabilité inter-langages
  4. Maintenant, des choses totalement différentes
    Cette section décrit des fonctionnalités existantes dans C# n'ayant aucun équivalent en Java.
    1. La libération déterministe d'objets
    2. L'ordre Delegate
    3. Enumérations
    4. Les types valeur
    5. Le Boxing et Unboxing
    6. Identification de type dynamique (operator "as")
    7. L'instruction "for each"
    8. Les propriétés
    9. Les attributs
    10. Les indexeurs
    11. Les directives de pré-processing
    12. Les aliases
    13. Génération de code dynamique
    14. Pointeur et code non protégé(unsafe)
    15. Passage par référence
    16. Les listes variables de paramètres
    17. Les caractères spéciaux
    18. Détection de débordement
    19. Implémentation explicite d'interface
  5. Concepts avancés
    Cette section décrit les concepts avancés de C# et Java
    1. La portabilité multi-plateformes (Write Once, Run Anywhere)
    2. Les extensions
    3. Le chargement dynamique de classe
    4. Les interfaces contenant des champs
    5. Les classes anonymes
    6. Le versionning des Assemblies
  1. Conclusion
  2. Ressources
  3. Remerciements

q       Plus les choses évoluent plus elles tendent à se ressembler

1.     Nous sommes tous des objets !

Comme Java, C# possède une super classe, mère de tous les objets : System.Object. La classe équivalent s'appelle java.lang.object. Les méthodes présentent dans ces deux classes sont très similaires (ex: toString()) excepté wait(), notify() et les autres méthodes liées à la synchronisation.

NOTE: En C#, une classe de type objet peut soit être écrite sous la forme "object" en minuscule ou "Object". En fait, à la compilation ces deux types sont remplacés par System.Object.

2.     Synthèse des mots-clés

Il y a énormément de similitudes entre les deux langages, presque tous les mots-clés Java ont un équivalent en C# à part quelques exceptions telles que transient, throws et strictfp. La table ci-dessous vous illustre les mots-clés présents des deux cotés

mot-clé C#

mot-clé Java

mot-clé C#

mot-clé Java

mot-clé C#

mot-clé Java

mot-clé C#

mot-clé Java

abstract

abstract

explicit

N/A

object

N/A

this

this

as

N/A

extern

native

operator

N/A

throw

throw

base

super

finally

finally

out

N/A

true

true

bool

boolean

fixed

N/A

override

N/A

try

try

break

break

float

float

params

N/A

typeof

N/A

byte

N/A

for

for

private

private

uint

N/A

case

case

foreach

N/A

protected

N/A

ulong

N/A

catch

catch

get

N/A

public

public

unchecked

N/A

char

char

goto

goto1

readonly

N/A

unsafe

N/A

checked

N/A

if

if

ref

N/A

ushort

N/A

class

class

implicit

N/A

return

return

using

import

const

const1

in

N/A

sbyte

byte

value

N/A

continue

continue

int

int

sealed

final

virtual

N/A

decimal

N/A

interface

interface

set

N/A

void

void

default

default

internal

protected

short

short

while

while

delegate

N/A

is

instanceof

sizeof

N/A

:

extends

do

do

lock

synchronized

stackalloc

N/A

:

implements

double

double

long

long

static

static

N/A

strictfp

else

else

namespace

package

string

N/A

N/A

throws

enum

N/A

new

new

struct

N/A

N/A

transient

event

N/A

null

null

switch

switch

N/A

volatile

3.     A propos des machines virtuelles

De la même manière que Java est compilé en byte-code et s'exécute dans un environnement d'exécution managé (Machine Virtuelle JVM), C# est compilé en MSIL s'exécutant dans la CRL (Common Langage Runtime). Les deux plate-formes supportent la compilation Just In Time (JIT). Toutefois, il existe une légère différence entre les deux plate-formes, les compilateurs Java permettent de désactiver totalement le JIT en fonctionnant uniquement en mode interprété alors que les compilateurs .NET en général intègre nativement le JIT. Enfin, il existe des deux cotés la possibilité de pré-compiler en code natif le source. .

4.     Gestion de la mémoire (ramasse miettes)

Tous les objets Java sont créés sur le tas en utilisant le mot-clé new. Il en va de même pour la plupart des objets C# n'étant pas des types de valeurs (ValueType).

Le ramasse miettes en C# implémente un algorithme bien connu appelé Mark and Compact garbage collection algorithm.

5.     Les tableaux

Dans les langages tels que C ou C++, la dimension de chaque sous tableau doit être identique dans les tableaux à plusieurs dimensions. En Java et C#, les tableaux n'ont pas à se plier à cette contrainte car ils peuvent être créés comme des tableaux à une dimension référençant d'autres tableaux. Ils sont appelés "Jagged Arrays". Pour cette raison, les tailles initiales des lignes et colonnes de ce type de tableaux peuvent-être différentes. C'est ce que montre le code suivant :

int [][]myArray = new int[2][];

myArray[0] = new int[3];

myArray[1] = new int[9];

 

Le code précédent est valide pour Java et C#.

6.     Pas de méthodes globales

Comme en Java et contrairement à C++, les méthodes en C# doivent être intégrées dans une classe.

7.     Les Interfaces, Oui. L'héritage multiple, Non

C#, comme Java, supporte le concept d'interface qui est assimilé à une classe abstraite pure. De la même façon, C# et Java autorisent l'héritage multiple d'interface et simple d'implémentation.

8.     Les chaînes de caractères ne peuvent être modifiées

C# possède une classe System.String qui est équivalente à java.lang.String. Les deux classes sont "immuables", c'est à dire qu'une fois les objets créés, il n'est pas possible de modifier leur valeur. Ceci dans le but de protéger le mécanisme d'encapsulation ô combien fondamental.

C# Code

string csString = "Apple Jack";

csString.ToLower(); /* Does not modify string, instead returns lower case copy of string */

 
Java Code

String jString = "Grapes";

jString.toLowerCase(); /* Does not modify string, instead returns lower case copy of string */

 

Pour créer une chaîne de caractères autorisant la modification avec la même référence, il est conseillé d'utiliser  les classes System.Text.StringBuilder pour C# et java.lang.StringBuffer pour Java.


NOTE: En C#, la classe chaîne peut être écrite sous la forme string ou String.

9.     Les classes non extensibles

Les deux langages proposent des mécanismes consistant à interdire toute extension d'une classe. Soit par souci d'optimisation, soit par souci de sécurité. Ainsi, il est interdit de les dériver pour redéfinir des méthodes ou simplement réutiliser l'implémentation. En C#, vous utilisez le mot-clé sealed  et en Java le mot-clé final.

C# Code

sealed class Student

{

         string fname;

         string lname;

         int uid;

         void attendClass() {}

}

 

Java Code

final class Student

{

    String fname;

    String lname;

    int uid;

    void attendClass() {}

}

 

10.                       Levée et Capture d'Exceptions

Les exceptions en C# et Java partagent énormément de caractéristiques. Les deux langages supportent l'utilisation de l'ordre try pour indiquer qu'un bloc est susceptible de lever une exception et catch pour capturer l'exception en question. De plus, finally est implémenté de la même manière pour spécifier qu'une région de code doit, dans tous les cas être exécutée (exception ou pas). Cela permet de libérer des ressources proprement. Les deux langages proposent une hiérarchie de classes d'Exceptions dérivant d'une super classe : System.Exception pour C# et java.lang.Exception pour Java. Aussi, il est possible de chaîner la levée ou la capture d'exception (throw dans un catch) de part et d'autre. Cela permet, lors de la levée d'une exception, de retourner à l'appelant un type d'exception correspondant à son contexte et à sa couche d'architecture. Par exemple, une ligne non trouvée dans une table se traduira par une SQLException que le développeur prendra soin de renvoyer à l'interface graphique sous la forme d'un ObjectNotFoundException.

NOTE: Cependant, il existe une différence fondamentale entre C# et Java. Le mot-clé throws n'existe pas en C# car vous n'êtes pas contraint de spécifier dans la signature d'une méthode le fait qu'elle est susceptible de lever une exception. Il n'y a, contrairement à Java, aucune vérification de faite à l'exécution.

C# Code

using System;

using System.IO;

 

class MyException: Exception

{

  public MyException(string message): base(message){ }

  public MyException(string message, Exception innerException):

         base(message, innerException){ }

}

 

public class ExceptionTest

{

  static void DoStuff()

  { 

         throw new FileNotFoundException(); 

  }

  public static int Main()

  {

         try

         {           

                 try

                 {       

                         DoStuff();

                         return 0;  //won't get to execute

                 }

                 catch(IOException ioe)

                 { /* parent of FileNotFoundException */

                         throw new MyException("MyException occured", ioe);
                    /* rethrow new exception with inner exception specified */

                 }

         }

         finally

         {

                 Console.WriteLine("***Finally block executes even though MyException not caught***");

         }

  }//Main(string[])

} // ExceptionTest

 
Java Code

class MyException extends Exception{

    public MyException(String message){ super(message); }

    public MyException(String message, Exception innerException){ super(message, innerException); }

}

 

public class ExceptionTest {

    static void doStuff(){ 

    throw new ArithmeticException();   

    }

 

    public static void main(String[] args) throws Exception{

    try{           

        try{       

        doStuff();

        return;  //won't get to execute

        }catch(RuntimeException re){ /* parent of ArithmeticException */

        throw new MyException("MyException occured", re); /* rethrow new exception with cause specified */

        }

    }finally{

        System.out.println("***Finally block executes even though MyException not caught***");

    }

}//main(string[])

} // ExceptionTest

 

11.  &