Nous savons que c'est possible en JavaScript .
Mais est-il possible d'imprimer le message "Success" à la condition donnée ci-dessous en Java?
if (a==1 && a==2 && a==3) {
System.out.println("Success");
}
Quelqu'un a suggéré:
int _a = 1;
int a = 2;
int a_ = 3;
if (_a == 1 && a == 2 && a_ == 3) {
System.out.println("Success");
}
Mais en faisant cela, nous modifions la variable réelle. Est-ce qu'il y a un autre moyen?
&&
est unand
opérateur logique , ce qui signifie qu'ila
doit avoir les valeurs 1, 2 et 3 en même temps, ce qui est logiquement impossible. La réponse est NON, pas possible. Voulez-vous écrire uneif
instruction qui vérifie sia
a l'une des valeurs 1, 2 OU 3?yes
_
, sauf que vous ne pouvez pas le voir.if(a==1 && a==2 && a==3)
n'est pas nécessairement évalué en même temps. Et cela peut être utilisé pour que cela fonctionne sans avoir à recourir à des astuces Unicode.Réponses:
Oui, il est assez facile d'y parvenir avec plusieurs threads, si vous déclarez la variable
a
comme volatile.Un thread change constamment la variable a de 1 à 3, et un autre thread le teste constamment
a == 1 && a == 2 && a == 3
. Il arrive assez souvent d'avoir un flux continu de "Succès" imprimé sur la console.(Notez que si vous ajoutez une
else {System.out.println("Failure");}
clause, vous verrez que le test échoue beaucoup plus souvent qu'il ne réussit.)En pratique, cela fonctionne également sans se déclarer
a
volatile, mais seulement 21 fois sur mon MacBook. Sansvolatile
, le compilateur ou HotSpot est autorisé à mettre en cachea
ou à remplacer l'if
instruction parif (false)
. Très probablement, HotSpot démarre après un certain temps et le compile en instructions d'assemblage qui mettent en cache la valeur dea
. Avecvolatile
, il continue à imprimer "Success" pour toujours.la source
volatile
, mais en principe, cela peut même se produire sans levolatile
mot - clé et cela pourrait arriver un nombre arbitraire de fois, alors que, d'une part, il n'y a aucune garantie que cela se produira jamais, même avecvolatile
. Mais bien sûr, l'avoir en pratique, c'est assez impressionnant…volatile
. Les barrières de mémoire créées pour implémentervolatile
ralentissent les threads et rendent plus probable leur fonctionnement synchronisé pendant de courtes périodes. Cela arrive beaucoup plus souvent que prévu. C'est très sensible au timing, mais je vois à peu près qu'entre 0,2% et 0,8% des évaluations de(a == 1 && a == 2 && a == 3)
rendementtrue
.En utilisant les concepts (et le code) d'une réponse brillante au code de golf , les
Integer
valeurs peuvent être perturbées.Dans ce cas, cela peut rendre
int
s castésInteger
égaux alors qu'ils ne le seraient pas normalement:Malheureusement, ce n'est pas aussi élégant que la réponse multithread d'Erwin Bolwidt (car celle-ci nécessite un
Integer
casting) , mais des manigances amusantes ont toujours lieu.la source
Integer
. C'est dommage pour le casting mais c'est quand même cool.a
être réglé sur 1/2/3 satisferaa == 1
, mais cela ne va pas dans l'autre sensJava
. La version la moins moche que j'ai pu trouver était d'utilisera.equals(1) && a.equals(2) && a.equals(3)
, qui force1
,2
et3
d'être autobox commeInteger
s.a
un cours avecboolean equals(int i){return true;}
?Integer a = 1;
sur la ligne avant, il est toujours clair que c'esta
vraiment un entier.Dans cette question, @aioobe suggère (et déconseille) l'utilisation du préprocesseur C pour les classes Java.
Bien que ce soit extrêmement triche, c'est ma solution:
S'il est exécuté à l'aide des commandes suivantes, il en produira exactement une
Success
:la source
a
c'est une variable, mais cela peut être n'importe quel morceau de code arbitraire dans des langages avec un préprocesseur.Comme nous le savons déjà, il est possible de rendre ce code évalué à vrai grâce aux excellentes réponses d' Erwin Bolwidt et phflack , je voulais montrer que vous devez garder un haut niveau d'attention lorsque vous traitez avec une condition qui ressemble à celle présentée dans la question, car parfois ce que vous voyez n'est peut-être pas exactement ce que vous pensez.
C'est ma tentative pour montrer que ce code s'imprime
Success!
sur la console. Je sais que j'ai un peu triché , mais je pense toujours que c'est un bon endroit pour le présenter ici.Quels que soient les objectifs d'écrire un code comme celui-ci, il vaut mieux savoir comment gérer la situation suivante et comment vérifier si vous ne vous trompez pas avec ce que vous pensez voir.
J'ai utilisé le cyrillique «a» qui est un caractère distinct du latin «a». Vous pouvez inspecter les caractères utilisés dans l'instruction if ici .
Cela fonctionne car les noms des variables proviennent de différents alphabets. Ce sont des identifiants distincts, créant deux variables distinctes avec une valeur différente dans chacune.
Notez que si vous voulez que ce code fonctionne correctement, le codage des caractères doit être remplacé par un codage prenant en charge les deux caractères, par exemple tous les codages Unicode (UTF-8, UTF-16 (en BE ou LE), UTF-32, même UTF-7 ), ou Windows-1251, ISO 8859-5, KOI8-R (merci - Thomas Weller et Paŭlo Ebermann - de l'avoir signalé):
(J'espère que vous n'aurez plus jamais à faire face à ce genre de problème à l'avenir.)
la source
а
eta
fonctionne, tant que vous dites à votre éditeur dans quel encodage il se trouve (et peut-être aussi le compilateur). Tous les encodages Unicode fonctionnent (UTF-8, UTF-16 (en BE ou LE), UTF-32, même UTF-7), ainsi que par exemple Windows-1251, ISO 8859-5, KOI8-R.Il existe une autre façon d'aborder cela (en plus de l'approche de course de données volatile que j'ai publiée plus tôt), en utilisant la puissance de PowerMock. PowerMock permet de remplacer les méthodes par d'autres implémentations. Lorsque cela est combiné avec le déballage automatique, l'expression d'origine
(a == 1 && a == 2 && a == 3)
, sans modification, peut être rendue vraie.La réponse de @ phflack repose sur la modification du processus d'auto-boxing en Java qui utilise l'
Integer.valueOf(...)
appel. L'approche ci-dessous repose sur la modification du déballage automatique en modifiant l'Integer.intValue()
appel.L'avantage de l'approche ci-dessous est que l'instruction if originale donnée par l'OP dans la question est utilisée sans changement, ce qui est à mon avis le plus élégant.
la source
access$nnn
méthodes utilisées pour lire lesprivate
champs des classes internes / externes? Cela permettrait d'autres variantes intéressantes (qui fonctionnent même avec uneint
variable)…(Integer)2
) encadre l'int. En regardant plus dans la réflexion , il semble qu'il n'est pas possible de le faire avec unboxing utilisant la réflexion, mais cela peut être possible avec Instrumentation à la place (ou avec PowerMock, comme dans cette réponse)access$0
et que l'existence d'une méthode soit vérifiée lors de l'enregistrement. Mais le remplacement n'est jamais invoqué.Puisque cela semble être un suivi de cette question JavaScript , il convient de noter que cette astuce et d'autres fonctionnent également en Java:
Sur Ideone
Mais notez que ce n'est pas la pire chose que vous puissiez faire avec Unicode. L'utilisation d'espaces blancs ou de caractères de contrôle qui sont des parties d'identifiants valides ou l' utilisation de lettres différentes qui se ressemblent crée toujours des identifiants différents et qui peuvent être repérés, par exemple lors d'une recherche de texte.
Mais ce programme
utilise deux identificateurs identiques, au moins du point de vue Unicode. Ils utilisent simplement différentes manières pour encoder le même caractère
ä
, en utilisantU+00E4
etU+0061 U+0308
.Sur Ideone
Ainsi, en fonction de l'outil que vous utilisez, ils peuvent non seulement se ressembler, mais les outils de texte compatibles Unicode peuvent même ne pas signaler de différence, trouvant toujours les deux lors de la recherche. Vous pouvez même avoir le problème que les différentes représentations se perdent lors de la copie du code source à quelqu'un d'autre, essayant peut-être d'obtenir de l'aide pour le «comportement étrange», le rendant non reproductible pour l'assistant.
la source
int ᅠ2 = 3;
est-ce intentionnel? Parce que je vois du code très étrange tout autoura
), alors qu'il s'agit d'espaces blancs, et bien, cela donne du crédit aux réponses encore plus anciennes sur la question JavaScript associée. Notez que mon commentaire est encore plus ancien que la question Java (de plusieurs jours)…Inspiré par l'excellente réponse de @ Erwin , j'ai écrit un exemple similaire, mais en utilisant l' API Java Stream .
Et une chose intéressante est que ma solution fonctionne, mais dans de très rares cas (car le
just-in-time
compilateur optimise un tel code).L'astuce consiste à désactiver toutes les
JIT
optimisations à l'aide de l'VM
option suivante :Dans cette situation, le nombre de cas de réussite augmente considérablement. Voici le code:
PS Les flux parallèles utilisent
ForkJoinPool
sous le capot, et la variable a est partagée entre plusieurs threads sans aucune synchronisation, c'est pourquoi le résultat est non déterministe.la source
Dans le même ordre d'idées , en forçant un flottant (ou double) à déborder (ou à déborder) par division (ou multiplication) par un grand nombre:
la source