Types de données (C# et Java)

Mise à jour : novembre 2007

Cette rubrique présente quelques-unes des principales similitudes et différences dans la façon dont les données sont représentées, allouées et récupérées par le garbage collector en Java et en C#.

Types de données composés

Le concept d'une classe en tant que type de données composé avec des champs, des méthodes, et des événements est semblable en Java et C#. (L'héritage de classes est discuté séparément dans la rubrique intitulée Héritage et classes dérivées (C# et Java).) C# introduit le concept d'un struct comme type de données composé alloué par pile qui ne prend pas en charge l'héritage. Dans la plupart des autres aspects, les struct sont très semblables aux classes. Ils proposent un moyen facile de regrouper des champs et des méthodes connexes à utiliser dans des boucles serrées et d'autres scénarios où les performances sont importantes.

C# vous permet de créer une méthode de destructeur qui est appelée avant que les instances d'une classe soient récupérées par le garbage collector. En Java, une méthode finalize peut être utilisée pour contenir un code qui nettoie les ressources avant que l'objet ne soit récupéré par le garbage collector. En C#, cette fonction est exécutée par le destructeur de classe. Le destructeur ressemble à un constructeur sans arguments et précédé d'un caractère tilde (~).

Types de données intégrées

C# fournit tous les types de données qui sont disponibles en Java et assure la prise en charge des chiffres non signés et d'un nouveau type virgule flottante 128 bits de haute précision.

Pour chaque type de données primitif en Java, la bibliothèque de classes principale fournit une classe wrapper pour le représenter comme un objet Java. Par exemple, la classe Int32 encapsule le type de données int, et la classe Double encapsule le type de données double.

En revanche, tous les types de données primitifs en C# sont des objets dans l'espace de noms System. Pour chaque type de données, un nom court, ou alias, est fourni. Par exemple, int est le nom court pour System.Int32 et double est l'abréviation de System.Double.

La liste des types de données C# et de leurs alias est fournie dans le tableau suivant. Comme vous le constatez, les huit premiers correspondent aux types primitifs disponibles en Java. Notez toutefois que le boolean de Java est appelé bool en C#.

Nom court

.NET Class

Type

Largeur

Plage (bits)

byte

Byte

Entier non signé

8

0 à 255

sbyte

SByte

Entier signé

8

- 128 à 127

int

Int32

Entier signé

32

- 2 147 483 648 à 2 147 483 647

uint

UInt32

Entier non signé

32

0 à 4294967295

short

Int16

Entier signé

16

- 32 768 à 32 767

ushort

UInt16

Entier non signé

16

0 à 65535

long

Int64

Entier signé

64

- 922337203685477508 à 922337203685477507

ulong

UInt64

Entier non signé

64

0 à 18446744073709551615

float

Single

Type virgule flottante à simple précision

32

-3.402823e38 à 3.402823e38

double

Double

Type virgule flottante à double précision

64

-1.79769313486232e308 à 1.79769313486232e308

char

Char

Caractère Unicode unique

16

Symboles Unicode utilisés dans le texte

bool

Boolean

Type booléen logique

8

True ou false

object

Object

Type de base de tous les autres types

string

String

Séquence de caractères

decimal

Decimal

Type fractionnaire ou intégral précis qui peut représenter des nombres décimaux avec 29 bits significatifs

128

±1,0 × 10e-28 à ±7,9 × 10e28

Étant donné que C# représente tous les types de données primitifs comme des objets, il est possible d'appeler une méthode d'objet sur un type de données primitif. Par exemple :

static void Main()
{
    int i = 10;
    object o = i;
    System.Console.WriteLine(o.ToString());
}    

Cela est réalisé à l'aide des conversions boxing et unboxing automatiques. Pour plus d'informations, consultez Conversion boxing et unboxing (Guide de programmation C#).

Constantes

Java et C# permettent tous deux de déclarer une variable dont la valeur est spécifiée au moment de la compilation et ne peut pas être changée pendant l'exécution. Java utilise le modificateur de champ final pour déclarer cette variable, alors que C# utilise le mot clé const. Outre const, C# fournit le mot clé readonly pour déclarer des variables auxquelles une valeur peut être assignée une fois au moment de l'exécution, soit dans l'instruction de déclaration soit dans le constructeur. Après l'initialisation, la valeur d'une variable readonly ne peut pas changer. Un scénario dans lequel les variables readonly sont utiles est lorsque les modules qui ont été compilés séparément doivent partager des données telles qu'un numéro de version. Si le module A est mis à jour et recompilé avec un nouveau numéro de version, le module B peut être initialisé avec cette nouvelle valeur de constante sans devoir être recompilé.

Énumérations

Des énumérations, ou enums, sont utilisées pour grouper des constantes nommées, un peu comme elles sont utilisées en C et C++. Elles ne sont pas disponibles en Java. L'exemple suivant définit une énumération Color simple.

public enum Color
{
    Green,   //defaults to 0
    Orange,  //defaults to 1
    Red,     //defaults to 2
    Blue     //defaults to 3
}  

Des valeurs intégrales peuvent également être assignées aux énumérations, comme l'illustre la déclaration enum suivante :

public enum Color2
{
    Green = 10,
    Orange = 20,
    Red = 30,
    Blue = 40
}

L'exemple de code suivant appelle la méthode GetNames du type Enum pour afficher les constantes disponibles pour une énumération. Il assigne ensuite une valeur à une énumération et affiche la valeur.

class TestEnums
{
    static void Main()
    {
        System.Console.WriteLine("Possible color choices: ");

        //Enum.GetNames returns a string array of named constants for the enum.
        foreach(string s in System.Enum.GetNames(typeof(Color)))
        {
            System.Console.WriteLine(s);
        }

        Color favorite = Color.Blue;

        System.Console.WriteLine("Favorite Color is {0}", favorite);
        System.Console.WriteLine("Favorite Color value is {0}", (int) favorite);
    }
}

Sortie

Possible color choices:

Green

Orange

Red

Blue

Favorite Color is Blue

Favorite Color value is 3

Chaînes

Les types de chaîne en Java et C# manifestent un comportement identique, à quelques différences près. Les deux types de chaînes sont immuables, ce qui signifie que les valeurs des chaînes ne peuvent plus être changées une fois les chaînes créées. Dans les deux instances, les méthodes qui semblent modifier le contenu réel d'une chaîne créent en fait une nouvelle chaîne à retourner, et laissent la chaîne d'origine inchangée. Le processus de comparaison de valeurs de chaîne est différent en C# et en Java. Pour comparer des valeurs de chaîne en Java, les développeurs doivent appeler la méthode equals sur un type de chaîne puisque l'opérateur == compare les types référence par défaut. En C#, les développeurs peuvent utiliser les opérateurs == ou != pour comparer directement les valeurs de chaîne. Bien qu'une chaîne soit un type référence en C#, l'opérateur == et != comparera, par défaut, les valeurs de chaîne plutôt que les références.

Comme en Java, les développeurs C# ne doivent pas utiliser le type chaîne pour concaténer des chaînes et éviter de devoir créer de nouvelles classes de chaîne chaque fois que la chaîne est concaténée. À la place, les développeurs peuvent utiliser la classe StringBuilder, qui fonctionne comme la classe StringBuffer de Java.

Littéraux de chaîne

C# permet d'éviter l'utilisation de séquences d'échappement comme "\t" pour tabulation ou "\" pour barre oblique inverse dans les constantes de chaîne. Pour ce faire, il vous suffit de déclarer la chaîne mot pour mot à l'aide du symbole @ pour précéder l'assignation de la valeur de chaîne. Les exemples suivants montrent comment utiliser les caractères d'échappement et comment assigner les littéraux de chaîne :

static void Main()
{
    //Using escaped characters:
    string path1 = "\\\\FileShare\\Directory\\file.txt";
    System.Console.WriteLine(path1);

    //Using String Literals:
    string path2 = @"\\FileShare\Directory\file.txt";
    System.Console.WriteLine(path2);
}

Conversion et casting

Java et C# suivent tous deux des règles similaires pour la conversion automatique et le casting de types de données.

Comme Java, C# prend en charge les conversions de types implicites et explicites. Dans le cas de conversions étendues, les conversions sont implicites. Par exemple, la conversion suivante entre int et long est implicite, comme en Java :

int int1 = 5;
long long1 = int1;  //implicit conversion

Ci-dessous une liste de conversions implicites entre types de données .NET Framework :

Type de source

Type de cible

Byte

short, ushort, int, uint, long, ulong, float, double ou decimal

Sbyte

short, int, long, float, double ou decimal

Int

long, float, double ou decimal

Uint

long, ulong, float, double ou decimal

Short

int, long, float, double ou decimal

Ushort

int, uint, long, ulong, float, double ou decimal

Long

float, double ou decimal

Ulong

float, double ou decimal

Float

double

Char

ushort, int, uint, long, ulong, float, double ou decimal

Vous effectuez un cast des expressions que vous souhaitez convertir explicitement à l'aide de la même syntaxe que Java :

long long2 = 5483;
int int2 = (int)long2;  //explicit conversion

Le tableau suivant répertorie les conversions explicites.

Type de source

Type de cible

Byte

sbyte ou char

Sbyte

byte, ushort, uint, ulong ou char

Int

sbyte, byte, short, ushort, uint, ulong ou char

Uint

sbyte, byte, short, ushort, int ou char

Short

sbyte, byte, ushort, uint, ulong ou char

Ushort

sbyte, byte, short ou char

Long

sbyte, byte, short, ushort, int, uint, ulong ou char

Ulong

sbyte, byte, short, ushort, int, uint, long ou char

Float

sbyte, byte, short, ushort, int, uint, long, ulong, char ou decimal

Double

sbyte, byte, short, ushort, int, uint, long, ulong, char, float ou decimal

Char

sbyte, byte ou short

Decimal

sbyte, byte, short, ushort, int, uint, long, ulong, char, float ou double

Types valeur et référence

C# prend en charge deux sortes de types de variables :

  • Types valeur

    Ce sont les types de données primitifs intégrés, tels que char, int et float, ainsi que des types définis par l'utilisateur déclarés avec struct.

  • Types référence

    Les classes et autres types de données complexes qui sont construits à partir de types primitifs. Les variables de ces types ne contiennent pas d'instance du type, mais une référence à cette instance.

Si vous créez deux variables de type valeur, i et j, comme suit, i et j sont complètement indépendants l'un de l'autre :

int i = 10;
int j = 20;

Ils reçoivent des emplacements de mémoire distincts :

Si vous modifiez la valeur de l'une de ces variables, l'autre n'en sera aucunement affectée. Par exemple, si vous avez une expression telle que la suivante, il n'y a toujours pas de connexion entre les variables :

int k = i;

C'est-à-dire que si vous modifiez la valeur de i, k conservera la valeur que i avait au moment de son assignation.

i = 30;

System.Console.WriteLine(i.ToString());  // 30
System.Console.WriteLine(k.ToString());  // 10

En revanche, les types référence fonctionnent différemment. Par exemple, vous pouvez déclarer deux variables comme suit :

Employee ee1 = new Employee();
Employee ee2 = ee1;

Maintenant, parce que les classes sont des types référence en C#, ee1 est désigné comme étant une référence à Employee. La première des deux lignes précédentes crée une instance de Employee en mémoire et définit ee1 pour la référencer. Ainsi, lorsque vous définissez ee2 pour égaler ee1, elle contient une copie de la référence à la classe en mémoire. Si vous modifiez à présent les propriétés sur ee2, les propriétés sur ee1 reflètent ces modifications, car tous deux pointent vers le même objet en mémoire, comme le montre l'exemple suivant :

Conversions boxing et unboxing

Le processus de la conversion d'un type valeur en un type référence s'appelle la conversion boxing. Le processus inverse, la conversion d'un type référence en un type valeur, s'appelle la conversion unboxing. C'est ce que montre le code suivant :

int i = 123;      // a value type
object o = i;     // boxing
int j = (int)o;  // unboxing

Dans Java, vous devez effectuer ces conversions manuellement. Les types de données primitifs peuvent être convertis en objets de classes wrapper par construction de ces objets, ou par conversion boxing. De même, les valeurs des types de données primitifs peuvent être extraites des objets de classes wrapper en appelant une méthode appropriée sur les objets de ce type ou en effectuant une conversion unboxing. Pour plus d'informations sur les conversions boxing et unboxing, consultez Conversion boxing et unboxing (Guide de programmation C#).

Voir aussi

Concepts

Guide de programmation C#

Référence

Types (Guide de programmation C#)

Autres ressources

Visual C#

Langage de programmation C# pour les développeurs Java