« Programmation Java/Transtypage » : différence entre les versions

Contenu supprimé Contenu ajouté
DannyS712 (discussion | contributions)
m <source> -> <syntaxhighlight> (phab:T237267)
Ligne 8 :
==== Cas des types primitifs ====
Dans le cas des [[../Types de base|types primitifs]], la hiérarchie est la suivante : byte est plus bas que short, short plus bas que int, char plus bas que int, int plus bas que long, long plus bas que float, float plus bas que double. Le type boolean est incomparable avec les autres types de base. On peut par exemple assigner à une variable de type float une expression de type int égale à 3 : l'expression 3 sera, avant affectation, convertie en float (3.0). Cette forme de conversion est réversible : on peut, après passage de int à float, reconvertir l'expression de type float résultante en int par une conversion explicite (voir ci-dessous) et retrouver la même valeur.
<sourcesyntaxhighlight lang="java">
int n;
float f;
n = 3;
f = n; // 3 est converti en 3.0
</syntaxhighlight>
</source>
Le type déterminé statiquement pour les arguments d'opérateurs arithmétiques est le premier type à partir de int dans lequel peuvent être convertis les types de tous les arguments. Les expressions constantes
sont d'autre part typées statiquement en le premier type à partir de int permettant leur représentation.
<sourcesyntaxhighlight lang="java">
short s;
s = 15; // <-- erreur générée, 15 est typé statiquement de type int
Ligne 27 :
n = s; // correct : conversion implicite
n = n + l; // <-- erreur générée, la sous-expression gauche est convertie en long
</syntaxhighlight>
</source>
 
===== Typage par suffixe =====
Ligne 54 :
* Si J est une interface étendant l'interface I, toute expression de type "référence vers J" peut être implicitement convertie en le type "référence vers I".
Dans l'exemple ci-dessous, on fait pointer trois références a, i, j, b, c vers un même objet de classe C :
<sourcesyntaxhighlight lang="java">
class A { ... }
interface I { ... }
Ligne 83 :
i = j // <-- J n'est pas une extension de I
b = a // <-- B n'est pas ancêtre de A
</syntaxhighlight>
</source>
La même règle permet de convertir toute référence en une référence de type Object :
<sourcesyntaxhighlight lang="java">
class A extends ... implements ... { ... } // extends Object implicite
...
Object o = new A();
</syntaxhighlight>
</source>
 
==== Visibilité des champs et méthodes après transtypage, liaison dynamique ====
Soit r une référence de type "référence vers X", pointant vers un certain objet de classe C. D'après les règles ci-dessus, X est donc soit une classe (concrète ou abstraite) ancêtre de C, soit une interface implémentée par C :
* Les seuls champs accessibles via r sont ceux visibles dans X (déclarés dans X ou hérités, et visibles dans le contexte de r). La valeur liée à r.''champ'' est celle liée à this.''champ'' dans X.
<sourcesyntaxhighlight lang="java">
class A {
int x = 0:
Ligne 119 :
... a.z... // l'objet possède bien un champ z, mais il n'est
// pas visible dans A
</sourcesyntaxhighlight>
* Seules les méthodes dont le nom est visible (par déclaration ou par héritage) dans X sont invocables sur r. L'implémentation exécutée lors d'une invocation de la forme r.''méthode(..)'' sera ''l'implémentation de la méthode de même nom et de même signature dans la classe de l'objet'', et non l'implémentation vue dans X. Le nom de la méthode est dit ''lié dynamiquement'' à l'implémentation de cette méthode dans la classe de l'objet.
<sourcesyntaxhighlight lang="java">
class A {
void m() {
Ligne 161 :
a.m(); // affiche "implémentation de m dans C" (liaison dynamique)
a.n(); // <--- erreur : la méthode n n'est pas visible dans A
</syntaxhighlight>
</source>
 
==== Cas des conversions vers String ====
Ligne 170 :
(''nouveau_type'')''expression''
Où <code>''expression''</code> est l'expression à convertir. S'il s'agit d'une expression composée, il faut l'encadrer par des parenthèses. La conversion explicite d'une expression doit être utilisée à chaque fois que l'on souhaite convertir une expression dans un type qui n'est pas plus haut dans la hiérarchie des types. Dans le cas des types numériques, cette conversion n'est sans pertes que si le type cible permet de représenter la même valeur. Dans le cas contraire, la valeur choisie dépend du type initial et du type cible. Dans le passage de float à int, la valeur choisie est par exemple la valeur entière de la valeur initiale :
<sourcesyntaxhighlight lang="java">
int n;
float f;
Ligne 180 :
f = f + 1.5; // f passe à 5.5
n = (int) f; // 5.5 est arrondi en 5 : n vaut 5.
</syntaxhighlight>
</source>
Pour les types de références, la conversion est libre : une référence de type quelconque peut être explicitement convertie en toute référence dont le type permet de manipuler l'objet référencé, selon les règles ci-dessus. La non-validité de cette conversion n'est en général pas détectable avant l'exécution :
<sourcesyntaxhighlight lang="java">
interface I { ... }
class A { ... }
Ligne 193 :
B b = (B) a; // valide
C c = (C) o; // invalide : C n'est pas ancêtre de B
</syntaxhighlight>
</source>
 
Ces conversions "descendantes" sont bien sûr propices aux erreurs.
L'opérateur <code>instanceof</code> permet de vérifier la validité d'une conversion avant de l'effectuer :
<sourcesyntaxhighlight lang="java">
if (r instanceof C) {
c = (C) r;
Ligne 207 :
...
}
</syntaxhighlight>
</source>
 
L'opérateur <code>instanceof</code> et les conversions supportent également les [[../Tableaux|tableaux]] (à partir d'un objet de type <code>Object</code>) :
<sourcesyntaxhighlight lang="java">
Object r = getObject();
if (r instanceof int[]) {
Ligne 219 :
...
}
</syntaxhighlight>
</source>
 
=== Autoboxing ===
Ligne 226 :
 
Avant Java 5, il fallait écrire :
<sourcesyntaxhighlight lang="java">
List integers = methodeRenvoyantDesIntegers();
for(int i = 0; i < integers.size(); i++) {
Ligne 233 :
methodNecessitantUnInt(actuel);
}
</syntaxhighlight>
</source>
Alors qu'avec Java 5, il n'est plus nécessaire de passer par <code>parseInt()</code> :
<sourcesyntaxhighlight lang="java5">
List integers = methodeRenvoyantDesIntegers();
for(int i = 0; i < integers.size(); i++) {
Ligne 241 :
methodNecessitantUnInt(actuel);
}
</syntaxhighlight>
</source>
On voit que les <code>int</code> et les <code>Integer</code> sont utilisés indifféremment.
 
Ligne 248 :
 
Exemple :
<sourcesyntaxhighlight lang="java5">
ArrayList<Integer> counters = new ArrayList<Integer>();
counters.add(500);
int n = counters.get(0);
</syntaxhighlight>
</source>
 
 
Les limites de l'autoboxing est qu'il ne concerne que chaque type primitif et sa classe englobante respective. Par exemple le code suivant renvoie l'erreur <code>inconvertible types</code> en voulant passer du ''String'' au ''Float'' :
<sourcesyntaxhighlight lang="java5">
public static void main(String[] args) {
for(int i = 0; i < args.length; i++) {
Ligne 262 :
}
}
</syntaxhighlight>
</source>
Il faut donc écrire<ref>http://docs.oracle.com/javase/tutorial/java/data/converting.html</ref> :
<sourcesyntaxhighlight lang="java5">
public static void main(String[] args) {
for(int i = 0; i < integers.size(); i++) {
System.out.println((Float.valueOf(args[i])).floatValue());
}
</syntaxhighlight>
</source>
 
==Références==