Wir wissen, dass dies in JavaScript möglich ist .
Aber ist es möglich, die Meldung "Erfolg" unter der unten angegebenen Bedingung in Java zu drucken?
if (a==1 && a==2 && a==3) {
System.out.println("Success");
}
Jemand schlug vor:
int _a = 1;
int a = 2;
int a_ = 3;
if (_a == 1 && a == 2 && a_ == 3) {
System.out.println("Success");
}
Auf diese Weise ändern wir jedoch die tatsächliche Variable. Gibt es einen anderen Weg?
&&
ist ein logischerand
Operator, was bedeutet,a
dass er gleichzeitig den Wert 1, 2 und 3 haben sollte, was logisch unmöglich ist. Die Antwort ist NEIN, nicht möglich. Möchten Sie eineif
Anweisung schreiben , die prüft, oba
einer der Werte 1, 2 ODER 3 vorliegt?yes
_
, außer dass Sie es nicht sehen können.if(a==1 && a==2 && a==3)
nicht unbedingt gleichzeitig ausgewertet. Und das kann verwendet werden, damit dies funktioniert, ohne auf Unicode-Tricks zurückgreifen zu müssen.Antworten:
Ja, es ist ziemlich einfach, dies mit mehreren Threads zu erreichen, wenn Sie die Variable
a
als flüchtig deklarieren .Ein Thread ändert ständig die Variable a von 1 auf 3, und ein anderer Thread testet dies ständig
a == 1 && a == 2 && a == 3
. Es kommt oft genug vor, dass ein kontinuierlicher Stream von "Success" auf der Konsole gedruckt wird.(Wenn Sie eine
else {System.out.println("Failure");}
Klausel hinzufügen , werden Sie feststellen, dass der Test weitaus häufiger fehlschlägt als erfolgreich.)In der Praxis funktioniert es auch, ohne es
a
als flüchtig zu deklarieren , aber nur 21 Mal auf meinem MacBook. Ohnevolatile
darf der Compiler oder HotSpota
dieif
Anweisung zwischenspeichern oder durch ersetzenif (false)
. Höchstwahrscheinlich wird HotSpot nach einer Weile aktiviert und zu Assembly-Anweisungen kompiliert, die den Wert von zwischenspeicherna
. Mitvolatile
druckt es "Erfolg" für immer.quelle
volatile
, aber im Prinzip kann dies sogar ohne dasvolatile
Schlüsselwort geschehen und es kann beliebig oft vorkommen, während es andererseits keine Garantie gibt, dass es jemals passieren wird, selbst mitvolatile
. Aber natürlich ist es ziemlich beeindruckend, wenn es in der Praxis passiert…volatile
. Die zur Implementierung erstellten Speicherbarrierenvolatile
verlangsamen die Threads und erhöhen die Wahrscheinlichkeit, dass sie für kurze Zeit synchron arbeiten. Es passiert viel öfter als ich erwartet hatte. Es ist sehr zeitempfindlich, aber ich sehe ungefähr zwischen 0,2% und 0,8% der Bewertungen der(a == 1 && a == 2 && a == 3)
Renditetrue
.Mit Konzepten (und Code) aus einer brillanten Code-Golf-Antwort können
Integer
Werte durcheinander gebracht werden.In diesem Fall kann
int
s gegossen werden,Integer
um gleich zu sein, wenn dies normalerweise nicht der Fall wäre:Leider ist es nicht ganz so elegant wie Erwin Bolwidts Multithread-Antwort (da diese ein
Integer
Casting erfordert ) , aber es finden trotzdem einige lustige Spielereien statt.quelle
Integer
. Es ist eine Schande über das Casting, aber es ist immer noch cool.a
auf 1/2/3 gesetzt zu werden wird befriedigena == 1
, aber es geht nicht in die andere RichtungJava
. Die am wenigsten hässliche Version konnte ich war zu bedienena.equals(1) && a.equals(2) && a.equals(3)
, die Kräfte1
,2
und3
als autoboxed werdenInteger
s.a
eine Klasse mit machen würdestboolean equals(int i){return true;}
?Integer a = 1;
in der vorherigen Zeile ist immer noch klar, dass es sicha
wirklich um eine Ganzzahl handelt.In dieser Frage schlägt @aioobe die Verwendung des C-Präprozessors für Java-Klassen vor (und rät davon ab).
Obwohl es extrem betrügerisch ist, ist das meine Lösung:
Bei Ausführung mit den folgenden Befehlen wird genau einer ausgegeben
Success
:quelle
a
, dass es sich um eine Variable handelt, es kann sich jedoch um einen beliebigen Code in Sprachen mit einem Präprozessor handeln.Da wir bereits wissen, dass es dank der großartigen Antworten von Erwin Bolwidt und phflack möglich ist , diesen Code als wahr auszuwerten , wollte ich zeigen, dass Sie bei der Behandlung einer Bedingung, die wie die vorgestellte aussieht, ein hohes Maß an Aufmerksamkeit auf sich ziehen müssen in der Frage, da manchmal das, was Sie sehen, möglicherweise nicht genau das ist, was Sie denken, dass es ist.
Dies ist mein Versuch zu zeigen, dass dieser Code
Success!
auf der Konsole gedruckt wird. Ich weiß, dass ich ein bisschen geschummelt habe , aber ich denke immer noch, dass dies ein guter Ort ist, um es hier zu präsentieren.Egal, wozu das Schreiben von Code wie diesen dient - es ist besser zu wissen, wie man mit der folgenden Situation umgeht und wie man prüft, ob man mit dem, was man zu sehen glaubt, nicht falsch liegt.
Ich habe das kyrillische 'a' verwendet, das sich vom lateinischen 'a' unterscheidet. Sie können die in der if-Anweisung verwendeten Zeichen hier überprüfen .
Dies funktioniert, weil die Namen der Variablen aus verschiedenen Alphabeten stammen. Sie sind unterschiedliche Bezeichner, wodurch zwei unterschiedliche Variablen mit jeweils unterschiedlichen Werten erstellt werden.
Beachten Sie, dass, wenn dieser Code ordnungsgemäß funktionieren soll, die Zeichenkodierung in eine geändert werden muss, die beide Zeichen unterstützt, z. B. alle Unicode-Kodierungen (UTF-8, UTF-16 (in BE oder LE), UTF-32, sogar UTF-7) ) oder Windows-1251, ISO 8859-5, KOI8-R (danke - Thomas Weller und Paŭlo Ebermann - für den Hinweis):
(Ich hoffe, Sie werden sich in Zukunft nie mehr mit solchen Problemen befassen müssen.)
quelle
а
unda
funktioniert, solange Sie Ihrem Editor mitteilen, in welcher Kodierung es sich befindet (und möglicherweise auch dem Compiler). Alle Unicode-Codierungen funktionieren (UTF-8, UTF-16 (in BE oder LE), UTF-32, sogar UTF-7) sowie z. B. Windows-1251, ISO 8859-5, KOI8-R.Es gibt eine andere Möglichkeit, dies zu erreichen (zusätzlich zu dem zuvor veröffentlichten Ansatz für flüchtige Datenrennen), bei dem PowerMock verwendet wird. Mit PowerMock können Methoden durch andere Implementierungen ersetzt werden. Wenn dies mit dem automatischen Entpacken kombiniert wird, kann der ursprüngliche Ausdruck
(a == 1 && a == 2 && a == 3)
ohne Änderung wahr gemacht werden.Die Antwort von @ phflack basiert auf der Änderung des Auto-Boxing-Prozesses in Java, der den
Integer.valueOf(...)
Aufruf verwendet. Der folgende Ansatz basiert auf dem Ändern des automatischen Entpackens durch Ändern desInteger.intValue()
Anrufs.Der Vorteil des folgenden Ansatzes besteht darin, dass die ursprüngliche if-Anweisung des OP in der Frage unverändert verwendet wird, was ich für die eleganteste halte.
quelle
access$nnn
sie zum Lesen vonprivate
Feldern innerer / äußerer Klassen verwendet werden? Das würde einige andere interessante Varianten erlauben (die sogar mit einerint
Variablen funktionieren )…(Integer)2
) boxt das int. Suchen Sie mehr in Reflexion , es sieht aus wie es nicht möglich ist , dies zu tun mit Unboxing mit Reflexion, kann aber möglich sein , mit Instrumentation statt (oder mit PowerMock, wie es in dieser Antwort)access$0
und die Existenz einer Methode bei der Registrierung überprüft wird. Der Ersatz wird jedoch niemals aufgerufen.Da dies eine Fortsetzung dieser JavaScript-Frage zu sein scheint , ist es erwähnenswert, dass dieser Trick und ähnliches auch in Java funktioniert:
Auf Ideone
Beachten Sie jedoch, dass dies nicht das Schlimmste ist, was Sie mit Unicode tun können. Wenn Sie Leerzeichen oder Steuerzeichen verwenden, die gültige Bezeichnerteile sind, oder verschiedene Buchstaben verwenden, die gleich aussehen, werden immer noch Bezeichner erstellt, die unterschiedlich sind und erkannt werden können, z. B. bei einer Textsuche.
Aber dieses Programm
verwendet zwei Bezeichner, die zumindest aus Unicode-Sicht identisch sind. Sie verwenden nur verschiedene Methoden, um dasselbe Zeichen
ä
mitU+00E4
und zu codierenU+0061 U+0308
.Auf Ideone
Je nachdem, welches Tool Sie verwenden, sehen sie möglicherweise nicht nur gleich aus. Unicode-fähige Textwerkzeuge melden möglicherweise nicht einmal einen Unterschied und finden bei der Suche immer beide. Möglicherweise haben Sie sogar das Problem, dass die verschiedenen Darstellungen beim Kopieren des Quellcodes auf eine andere Person verloren gehen und möglicherweise versuchen, Hilfe für das „seltsame Verhalten“ zu erhalten, wodurch es für den Helfer nicht reproduzierbar wird.
quelle
int ᅠ2 = 3;
ist es beabsichtigt? Weil ich überall sehr seltsamen Code sehea
), während es sich um Leerzeichen handelt und die noch älteren Antworten auf die zugehörige JavaScript-Frage berücksichtigt werden . Beachten Sie, dass mein Kommentar dort sogar älter ist als die Java-Frage (um einige Tage)…Inspiriert von der hervorragenden Antwort von @ Erwin habe ich ein ähnliches Beispiel geschrieben, aber die Java Stream API verwendet .
Und eine interessante Sache ist, dass meine Lösung funktioniert, aber in sehr seltenen Fällen (weil der
just-in-time
Compiler einen solchen Code optimiert).Der Trick besteht darin,
JIT
Optimierungen mit der folgendenVM
Option zu deaktivieren :In dieser Situation steigt die Anzahl der Erfolgsfälle erheblich an. Hier ist der Code:
PS Parallele Streams werden
ForkJoinPool
unter der Haube verwendet, und die Variable a wird ohne Synchronisation von mehreren Threads gemeinsam genutzt. Deshalb ist das Ergebnis nicht deterministisch.quelle
In ähnlicher Weise , indem ein Float (oder Double) durch Division (oder Multiplikation) durch eine große Zahl zum Unterlauf (oder Überlauf) gezwungen wird:
quelle