Informations générales sur les constructeurs
Конструктор
est une structure similaire à une méthode dont le but est de créer une instance d'une classe. Caractéristiques du concepteur :
- Le nom du constructeur doit correspondre au nom de la classe (par convention, la première lettre est en majuscule, généralement un nom) ;
- Il existe un constructeur dans n'importe quelle classe. Même si vous n'en écrivez pas, le compilateur Java créera un constructeur par défaut, qui sera vide et ne fera rien d'autre que d'appeler le constructeur de la superclasse.
- Un constructeur est similaire à une méthode, mais ce n’est pas une méthode, il n’est même pas considéré comme un membre de la classe. Par conséquent, il ne peut pas être hérité ou remplacé dans une sous-classe ;
- Les constructeurs ne sont pas hérités ;
- Il peut y avoir plusieurs constructeurs dans une classe. Dans ce cas, les constructeurs sont dits surchargés ;
- Si une classe ne définit pas de constructeur, le compilateur ajoute automatiquement un constructeur sans paramètre au code ;
- Un constructeur n'a pas de type de retour ; il ne peut même pas être un type
void
; si un type est renvoyé void
, alors ce n'est plus un constructeur mais une méthode, malgré la coïncidence avec le nom de la classe.
- L'opérateur est autorisé dans le constructeur
return
, mais uniquement vide, sans aucune valeur de retour ;
- Le constructeur permet l'utilisation de modificateurs d'accès ; vous pouvez définir l'un des modificateurs :
public
, protected
ou private
sans modificateur.
- Un constructeur ne peut pas avoir les modificateurs
abstract
, final
, ou ;native
static
synchronized
- Le mot-clé
this
fait référence à un autre constructeur de la même classe. S'il est utilisé, son appel doit être la première ligne du constructeur ;
- Le mot-clé
super
appelle le constructeur de la classe parent. Si elle est utilisée, la référence à celui-ci doit être la première ligne du constructeur ;
- Si le constructeur n'appelle pas le
super
constructeur de la classe ancêtre (avec ou sans arguments), le compilateur ajoute automatiquement du code pour appeler le constructeur de la classe ancêtre sans arguments ;
Constructeur par défaut
Il existe un constructeur dans n'importe quelle classe. Même si vous n'en écrivez pas, le compilateur Java créera un constructeur par défaut. Ce constructeur est vide et ne fait rien d'autre que d'appeler le constructeur de la superclasse. Ceux. si vous écrivez :
public class Example {}
alors cela équivaut à écrire :
public class Example
{
Example()
{
super;
}
}
Dans ce cas, la classe ancêtre n'est pas explicitement spécifiée et, par défaut, toutes les classes Java héritent de la classe,
Object
le constructeur de classe est donc appelé
Object
. Si une classe définit un constructeur paramétré, mais qu'il n'y a pas de constructeur sans paramètre surchargé, alors l'appel du constructeur sans paramètre est une erreur. Cependant, en Java depuis la version 1.5, il est possible d'utiliser des constructeurs avec des arguments de longueur variable. Et s'il existe un constructeur qui a un argument de longueur variable, alors appeler le constructeur par défaut ne sera pas une erreur. Ce ne sera pas le cas car l’argument de longueur variable peut être vide. Par exemple, l'exemple suivant ne sera pas compilé, mais si vous décommentez le constructeur avec un argument de longueur variable, il sera compilé et exécuté avec succès et entraînera l'exécution d'une ligne de code
DefaultDemo dd = new DefaultDemo()
; le constructeur sera appelé
DefaultDemo(int ... v)
. Naturellement, dans ce cas, il est nécessaire d'utiliser JSDK 1.5. Déposer
DefaultDemo.java
class DefaultDemo
{
DefaultDemo(String s)
{
System.out.print("DefaultDemo(String)");
}
public static void main(String args[])
{
DefaultDemo dd = new DefaultDemo();
}
}
Le résultat de la sortie du programme avec le constructeur sans commentaire :
DefaultDemo(int ...)
Cependant, dans le cas courant où la classe ne définit aucun constructeur, l'appel du constructeur par défaut (sans paramètres) sera nécessaire, puisque la substitution du constructeur par défaut se produit automatiquement.
Création d'objets et constructeurs
Lors de la création d'un objet, les actions suivantes sont effectuées séquentiellement :
- La classe d'objet est recherchée parmi les classes déjà utilisées dans le programme. S'il n'y est pas, il est recherché dans tous les catalogues et bibliothèques disponibles pour le programme. Une fois qu'une classe est découverte dans un répertoire ou une bibliothèque, les champs statiques de la classe sont créés et initialisés. Ceux. Pour chaque classe, les champs statiques ne sont initialisés qu'une seule fois.
- La mémoire est allouée à l'objet.
- Les champs de classe sont en cours d'initialisation.
- Le constructeur de classe s'exécute.
- Un lien vers l'objet créé et initialisé est formé. Cette référence est la valeur de l'expression qui crée l'objet. Un objet peut également être créé en appelant une méthode
newInstance()
de classe java.lang.Class
. Dans ce cas, un constructeur sans liste de paramètres est utilisé.
Surcharge des constructeurs
Les constructeurs d’une même classe peuvent avoir le même nom et une signature différente. Cette propriété est appelée combinaison ou surcharge. Si une classe possède plusieurs constructeurs, une surcharge de constructeur est présente.
Constructeurs paramétrés
La signature d'un constructeur est le nombre et les types de paramètres, ainsi que l'ordre de leurs types dans la liste des paramètres du constructeur. Le type de retour n'est pas pris en compte. Le constructeur ne renvoie aucun paramètre. Cette déclaration explique, dans un sens, comment Java fait la distinction entre des constructeurs ou des méthodes surchargés. Java distingue les méthodes surchargées non pas par leur type de retour, mais par le nombre, les types et la séquence de types de paramètres d'entrée. Un constructeur ne peut même pas renvoyer un type
void
, sinon il se transformera en une méthode régulière, même si elle est similaire au nom de la classe. L’exemple suivant le démontre. Déposer
VoidDemo.java
class VoidDemo
{
VoidDemo()
{
System.out.println("Constructor");
}
void VoidDemo()
{
System.out.println("Method");
}
public static void main(String s[])
{
VoidDemo m = new VoidDemo();
}
}
En conséquence, le programme affichera :
Constructor
Cela prouve une fois de plus qu'un constructeur est une méthode sans paramètres de retour. Cependant, le constructeur peut recevoir l'un des trois modificateurs
public
, ,
private
ou
protected
. Et l'exemple ressemblera désormais à ceci : Fichier
VoidDemo2.java
class VoidDemo2
{
public VoidDemo2()
{
System.out.println("Constructor");
}
private void VoidDemo2()
{
System.out.println("Method");
}
public static void main(String s[])
{
VoidDemo2 m = new VoidDemo2();
}
}
Il est permis d'écrire un opérateur dans un constructeur
return
, mais uniquement un opérateur vide, sans aucune valeur de retour. Déposer
ReturnDemo.java
class ReturnDemo
{
public ReturnDemo()
{
System.out.println("Constructor");
return;
}
public static void main(String s[])
{
ReturnDemo r = new ReturnDemo();
}
}
Constructeurs paramétrés avec des arguments de longueur variable
Java SDK 1.5 a introduit un outil tant attendu : des arguments de longueur variable pour les constructeurs et les méthodes. Auparavant, un nombre variable de documents étaient traités de deux manières peu pratiques. Le premier d’entre eux a été conçu pour garantir que le nombre maximum d’arguments soit limité à un petit nombre et connu à l’avance. Dans ce cas, il était possible de créer des versions surchargées de la méthode, une pour chaque version de la liste d'arguments passée à la méthode. La deuxième méthode est conçue pour quelque chose d'inconnu à l'avance et un grand nombre d'arguments. Dans ce cas, les arguments étaient placés dans un tableau, et ce tableau était passé à la méthode. Les arguments de longueur variable sont le plus souvent impliqués dans des manipulations ultérieures avec des initialisations variables. Il est pratique de remplacer l’absence de certains arguments attendus du constructeur ou de la méthode par des valeurs par défaut. L'argument de longueur variable est un tableau et est traité comme un tableau. Par exemple, le constructeur d'une classe
Checking
avec un nombre variable d'arguments ressemblerait à ceci :
class Checking
{
public Checking(int ... n)
{
}
}
La combinaison de caractères ... indique au compilateur qu'un nombre variable d'arguments sera utilisé, et que ces arguments seront stockés dans un tableau dont la valeur de référence est contenue dans la variable n. Le constructeur peut être appelé avec un nombre différent d'arguments, y compris aucun argument. Les arguments sont automatiquement placés dans un tableau et passés par n. S'il n'y a aucun argument, la longueur du tableau est 0. La liste des paramètres, ainsi que les arguments de longueur variable, peuvent également inclure des paramètres obligatoires. Dans ce cas, un paramètre contenant un nombre variable d'arguments doit obligatoirement être le dernier de la liste des paramètres. Par exemple:
class Checking
{
public Checking(String s, int ... n)
{
}
}
Une limitation très évidente concerne le nombre de paramètres de longueur variable. Il ne doit y avoir qu'un seul paramètre de longueur variable dans la liste des paramètres. Étant donné deux paramètres de longueur variable, il est impossible pour le compilateur de déterminer où se termine un paramètre et où commence l’autre. Par exemple:
class Checking
{
public Checking(String s, int ... n, double ... d)
{
}
}
Déposer
Checking.java
Par exemple, il existe des équipements capables de reconnaître les plaques d'immatriculation des voitures et de mémoriser les numéros des places de la zone où chacune des voitures s'est rendue pendant la journée. Il est nécessaire de sélectionner parmi la masse totale des voitures enregistrées celles qui ont visité pendant la journée deux places données, par exemple 22 et 15, selon la carte de la zone. Il est tout à fait naturel qu'une voiture puisse visiter plusieurs places au cours de la journée, voire une seule. Bien évidemment, le nombre de places visitées est limité par la vitesse physique de la voiture. Créons un petit programme où le constructeur de classe prendra comme arguments le numéro de voiture comme paramètre obligatoire et le nombre de places visitées de la zone, dont le nombre peut être variable. Le constructeur vérifiera si une voiture est apparue sur deux cases ; si c'est le cas, il affichera son numéro sur l'écran.
Passer des paramètres au constructeur
Il existe principalement deux types de paramètres dans les langages de programmation :
- types de base (primitifs) ;
- références à des objets.
Le terme appel par valeur signifie que le constructeur reçoit la valeur qui lui est transmise par le module appelant. En revanche, l'appel par référence signifie que le constructeur reçoit l'adresse de la variable de l'appelant. Java utilise uniquement l'appel par valeur. Par valeur de paramètre et par valeur de lien de paramètre. Java n'utilise pas l'appel par référence pour les objets (bien que de nombreux programmeurs et auteurs de certains livres le prétendent). Lors du passage d'objets à Java, les paramètres ne sont pas transmis
par référence , mais
par la valeur de la référence de l'objet ! Dans les deux cas, le constructeur reçoit des copies des valeurs de tous les paramètres. Le constructeur n'a rien à faire avec ses paramètres d'entrée :
- le constructeur ne peut pas modifier les valeurs des paramètres d'entrée des types principaux (primitifs) ;
- le constructeur ne peut pas modifier les références des paramètres d'entrée ;
- le constructeur ne peut pas réaffecter les références de paramètres d'entrée à de nouveaux objets.
Le constructeur peut faire avec ses paramètres d'entrée :
- changer l'état de l'objet passé en paramètre d'entrée.
L'exemple suivant prouve qu'en Java, les paramètres d'entrée d'un constructeur sont transmis par valeur de référence d'objet. Cet exemple reflète également que le constructeur ne peut pas modifier les références des paramètres d'entrée, mais modifie en fait les références des copies des paramètres d'entrée. Déposer
Empoyee.java
class Employee
{
Employee(String x, String y)
{
String temp = x;
x = y;
y = temp;
}
public static void main(String args[])
{
String name1 = new String("Alice");
String name2 = new String("Mary");
Employee a = new Employee(name1, name2);
System.out.println("name1="+name1);
System.out.println("name2="+name2);
}
}
Le résultat du programme est :
name1=Alice
name2=Mary
Si Java utilisait l'appel par référence pour transmettre des objets en tant que paramètres, le constructeur échangerait
name1
et dans cet exemple
name2
. Le constructeur n'échangera pas réellement les références d'objet stockées dans les variables
name1
et
name2
. Cela suggère que les paramètres du constructeur sont initialisés avec des copies de ces références. Ensuite, le constructeur échange les copies. Lorsque le constructeur termine son travail, les variables x et y sont détruites et les variables d'origine
name1
continuent
name2
de faire référence aux objets précédents.
Modification des paramètres passés au constructeur.
Le constructeur ne peut pas modifier les paramètres passés des types de base. Cependant, le constructeur peut modifier l'état de l'objet passé en paramètre. Par exemple, considérons le programme suivant : Fichier
Salary1.java
class Salary1
{
Salary1(int x)
{
x = x * 3;
System.out.println("x="+x);
}
public static void main(String args[])
{
int value = 1000;
Salary1 s1 = new Salary1(value);
System.out.println("value="+value);
}
}
Le résultat du programme est :
x=3000
value=1000
Évidemment, cette méthode ne modifiera pas le paramètre de type principal. Ainsi, après avoir appelé le constructeur, la valeur de la variable
value
reste égale à
1000
. Essentiellement, trois choses se produisent :
- La variable
x
est initialisée avec une copie de la valeur du paramètre value
(c'est-à-dire un nombre 1000
).
- La valeur de la variable
x
est triplée : elle est désormais égale à 3000
. Cependant, la valeur de la variable value
reste égale à 1000
.
- Le constructeur se termine et la variable
x
n'est plus utilisée.
Dans l'exemple suivant, le salaire de l'employé est triplé avec succès car la valeur d'une référence d'objet est transmise en tant que paramètre à la méthode. Déposer
Salary2.java
class Salary2
{
int value = 1000;
Salary2()
{
}
Salary2(Salary2 x)
{
x.value = x.value * 3;
}
public static void main(String args[])
{
Salary2 s1 = new Salary2();
Salary2 s2 = new Salary2(s1);
System.out.println("s1.value=" +s1.value);
System.out.println("s2.value="+s2.value);
}
}
Le résultat du programme est :
s1.value=3000
s2.value=1000
La valeur de la référence de l'objet est utilisée comme paramètre. Lors de l'exécution de la ligne
Salary2 s2 = new Salary2(s1)
; le constructeur
Salary2(Salary x)
recevra la valeur d'une référence à l'objet variable
s1
, et le constructeur triplera effectivement le salaire
s1.value
, puisque même la copie
(Salary x)
créée à l'intérieur du constructeur pointe vers l'objet variable
s1
.
Constructeurs paramétrés par des primitives.
Si les paramètres d'un constructeur surchargé utilisent une primitive qui peut être restreinte (par exemple
int <- double
), alors il est possible d'appeler une méthode avec une valeur restreinte, malgré le fait qu'il n'existe aucune méthode surchargée avec un tel paramètre. Par exemple : Fichier
Primitive.java
class Primitive
{
Primitive(double d)
{
d = d + 10;
System.out.println("d="+d);
}
public static void main(String args[])
{
int i = 20;
Primitive s1 = new Primitive(i);
}
}
Le résultat du programme est :
d=30.0
Malgré le fait que la classe
Primitive
n'a pas de constructeur possédant un paramètre de type
int
, un constructeur avec un paramètre d'entrée fonctionnera
double
. Avant d'appeler le constructeur, la variable
i
sera développée de type
int
en type
double
. L'option inverse, lorsque la variable
i
serait de type
double
et que le constructeur n'aurait qu'un paramètre
int
, conduirait dans cette situation à une erreur de compilation.
Appel du constructeur et opérateurnew
Le constructeur est toujours appelé par l'opérateur
new
. Lorsqu'un constructeur est appelé avec l'opérateur
new
, le constructeur génère toujours une référence à un nouvel objet. Il est impossible de forcer le constructeur à former une référence à un objet déjà existant au lieu d'une référence à un nouvel objet, sauf en substituant l'objet en cours de désérialisation. Et avec l'opérateur new, au lieu d'une référence à un nouvel objet, il est impossible de former une référence à un objet déjà existant. Par exemple : Fichier
Salary3.java
class Salary3
{
int value = 1000;
Salary3()
{
}
Salary3(Salary3 x)
{
x.value = x.value * 3;
}
public static void main(String args[])
{
Salary3 s1 = new Salary3();
System.out.println("First object creation: "+s1.value);
Salary3 s2 = new Salary3(s1);
System.out.println("Second object creation: "+s2.value);
System.out.println("What's happend with first object?:"+s1.value);
Salary3 s3 = new Salary3(s1);
System.out.println("Third object creation: "+s3.value);
System.out.println("What's happend with first object?:"+s1.value);
}
}
Le résultat du programme est :
First object creation: 1000
Second object creation: 1000
What's happend with first object?: 3000
Third object creation: 1000
What's happend with first object?: 9000
Tout d’abord, en utilisant la ligne
Salary3 s1 = new Salary3()
; un nouvel objet est créé. Ensuite, si vous utilisez la ligne
Salary3 s2 = new Salary3(s1)
; ou des chaînes
Salary3 s3 = new Salary3(s1)
; il serait possible de créer un lien vers un objet déjà existant,
s1.value s2.value
ils
s3.value
stockeraient alors la même valeur
1000
. En fait dans la file
Salary3 s2 = new Salary3(s1)
; un nouvel objet pour la variable sera créé
s2
et l'état de l'objet pour la variable changera
s1
en passant sa valeur de référence à l'objet dans le paramètre constructeur. Cela peut être vérifié par les résultats de sortie. Et lors de l'exécution de la ligne
Salary3 s3 = new Salary3(s1)
; un NOUVEL objet pour la variable sera créé
s3
et l'état de l'objet pour la variable changera à nouveau
s1
.
Constructeurs et blocs d'initialisation, séquence d'actions lors de l'appel d'un constructeur
La section
Création d'un objet et des constructeurs répertorie les actions générales effectuées lors de la création d'un objet. Parmi eux se trouvent les processus d'initialisation des champs de classe et d'élaboration du constructeur de classe, qui à leur tour ont également un ordre interne :
- Tous les champs de données sont initialisés à leurs valeurs par défaut (0, faux ou nul).
- Tous les initialiseurs de champ et blocs d'initialisation sont exécutés dans l'ordre dans lequel ils sont répertoriés dans la déclaration de classe.
- Si un autre constructeur est appelé sur la première ligne d'un constructeur, alors le constructeur appelé est exécuté.
- Le corps du constructeur est exécuté.
Le constructeur est lié à l'initialisation car en Java il existe trois manières d'initialiser un champ dans une classe :
- attribuer une valeur dans la déclaration ;
- attribuer des valeurs dans le bloc d'initialisation ;
- définir sa valeur dans le constructeur.
Naturellement, vous devez organiser le code d’initialisation de manière à ce qu’il soit facile à comprendre. La classe suivante est donnée à titre d'exemple :
class Initialization
{
int i;
short z = 10;
static int x;
static float y;
static
{
x = 2000;
y = 3.141;
}
Initialization()
{
System.out.println("i="+i);
System.out.println("z="+z);
z = 20;
System.out.println("z="+z);
}
}
Dans l'exemple ci-dessus, les variables sont initialisées dans l'ordre suivant : les variables statiques sont d'abord initialisées
x
avec
y
les valeurs par défaut. Ensuite, le bloc d'initialisation statique est exécuté. Ensuite, la variable est initialisée
i
à la valeur par défaut et la variable est initialisée
z
. Ensuite, le designer se met au travail. L’appel des constructeurs de classe ne doit pas dépendre de l’ordre dans lequel les champs sont déclarés. Cela peut conduire à des erreurs.
Constructeurs et héritage
Les constructeurs ne sont pas hérités. Par exemple:
public class Example
{
Example()
{
}
public void sayHi()
{
system.out.println("Hi");
}
}
public class SubClass extends Example
{
}
La classe
SubClass
hérite automatiquement de la méthode
sayHi()
définie dans la classe parent. Dans le même temps, le constructeur
Example()
de la classe parent n'est pas hérité par son descendant
SubClass
.
Mot-cléthis
dans les constructeurs
Les constructeurs sont utilisés
this
pour faire référence à un autre constructeur de la même classe, mais avec une liste de paramètres différente. Si le constructeur utilise le mot-clé
this
, alors il doit être sur la première ligne ; ignorer cette règle entraînera une erreur du compilateur. Par exemple : Fichier
ThisDemo.java
public class ThisDemo
{
String name;
ThisDemo(String s)
{
name = s;
System.out.println(name);
}
ThisDemo()
{
this("John");
}
public static void main(String args[])
{
ThisDemo td1 = new ThisDemo("Mary");
ThisDemo td2 = new ThisDemo();
}
}
Le résultat du programme est :
Mary
John
Dans cet exemple, il y a deux constructeurs. Le premier reçoit un argument de chaîne. Le second ne reçoit aucun argument, il appelle simplement le premier constructeur en utilisant le nom par défaut "John". Ainsi, vous pouvez utiliser des constructeurs pour initialiser les valeurs des champs de manière explicite et par défaut, ce qui est souvent nécessaire dans les programmes.
Mot-clé super
dans les constructeurs
Les constructeurs sont utilisés
super
pour appeler un constructeur de superclasse. Si le constructeur utilise
super
, alors cet appel doit être sur la première ligne, sinon le compilateur générera une erreur. Ci-dessous un exemple : Fichier
SuperClassDemo.java
public class SuperClassDemo
{
SuperClassDemo()
{
}
}
class Child extends SuperClassDemo
{
Child()
{
super();
}
}
Dans cet exemple simple, le constructeur
Child()
contient un appel
super()
qui crée une instance de la classe
SuperClassDemo
, en plus de la classe
Child
. Puisqu'il
super
doit s'agir de la première instruction exécutée dans un constructeur de sous-classe, cet ordre est toujours le même et ne dépend pas du fait que
super()
. S'il n'est pas utilisé, alors le constructeur par défaut (sans paramètres) de chaque superclasse, en commençant par la classe de base, sera exécuté en premier. Le programme suivant montre quand les constructeurs sont exécutés. Déposer
Call.java
class A
{
A()
{
System.out.println("Inside A constructor.");
}
}
class B extends A
{
B()
{
System.out.println("Inside B constructor.");
}
}
class C extends B
{
C()
{
System.out.println("Inside C constructor.");
}
}
class Call
{
public static void main(String args[])
{
C c = new C();
}
}
Résultat de ce programme :
Inside A constructor.
Inside B constructor.
Inside C constructor.
Les constructeurs sont appelés par ordre de subordination de classe. Cela a du sens. Étant donné que la superclasse n’a connaissance d’aucune sous-classe, toute initialisation qu’elle doit effectuer est distincte. Si possible, il doit précéder toute initialisation effectuée par la sous-classe. C'est pourquoi cela devrait être fait en premier.
Constructeurs personnalisables
Le mécanisme d'identification de type au moment de l'exécution est l'un des principes fondamentaux puissants du langage Java qui implémente le polymorphisme. Cependant, un tel mécanisme ne protège pas le développeur contre la conversion de type incompatible dans certains cas. Le cas le plus courant est la manipulation d'un groupe d'objets dont les différents types sont inconnus à l'avance et déterminés à l'exécution. Étant donné que les erreurs associées à une incompatibilité de type ne peuvent apparaître qu'au stade de l'exécution, elles sont difficiles à trouver et à éliminer. L'introduction de types personnalisés dans Java 2 5.0 déplace certaines de ces erreurs du moment de l'exécution vers le moment de la compilation et fournit une partie de la sécurité des types manquante. Il n'est pas nécessaire d'effectuer un transtypage de type explicite lors du passage d'un type
Object
à un type concret. Il convient de garder à l’esprit que les outils de personnalisation de type fonctionnent uniquement avec des objets et ne s’appliquent pas aux types de données primitifs situés en dehors de l’arborescence d’héritage de classe. Avec les types personnalisés, toutes les conversions sont effectuées automatiquement et en coulisses. Cela vous permet de vous protéger contre les incompatibilités de types et de réutiliser le code beaucoup plus souvent. Les types personnalisés peuvent être utilisés dans les constructeurs. Les constructeurs peuvent être personnalisés même si leur classe n'est pas un type personnalisé. Par exemple:
class GenConstructor
{
private double val;
<T extends Number> GenConstructor(T arg)
{
val = arg.doubleValue();
}
void printValue()
{
System.out.println("val: "+val);
}
}
class GenConstructorDemo
{
public static void main(String args[])
{
GenConstructor gc1 = new GenConstructor(100);
GenConstructor gc2 = new GenConstructor(123.5F);
gc1.printValue();
gc2.printValue();
}
}
Étant donné que le constructeur
GenConstructor
spécifie un paramètre de type personnalisé qui doit être une classe dérivée de class
Number
, il peut être appelé depuis n'importe quel
GO TO FULL VERSION