Bir Java değişkeni kendisinden nasıl farklı olabilir?


106

Bu sorunun Java'da çözülüp çözülmeyeceğini merak ediyorum (dilde yeniyim). Kod bu:

class Condition {
    // you can change in the main
    public static void main(String[] args) { 
        int x = 0;
        if (x == x) {
            System.out.println("Ok");
        } else {
            System.out.println("Not ok");
        }
    }
}

Laboratuvarımda şu soruyu aldım: x == xKoşulun kendisini değiştirmeden ilk durumu nasıl atlayabilirsiniz (yani koşulu yanlış yapabilirsiniz)?


12
Daha fazla kısıtlama olması gerektiğine inanıyorum, aksi takdirde çok açık.
Fermat'ın Küçük Öğrencisi

52
System.out.println("Gotcha!");Yorum yapmak kadar basit mi? :)
stuXnet

7
Güzel, o zaman double a = Double.NaN en kısa cevap ve "hack'im sadece bir hile;)
Christian Kuetbach

47
Bu sevimli Java trivia, ama umarım kimse bunu röportaj sorusu yapmayı düşünmez. İstihdam adaylarını düşünen insanlar, adayın ne kadar önemsiz bilgi biriktirdiğini değil, programlamayı anlayıp anlamadığını anlamak için ellerinden gelenin en iyisini yapmalıdır. Java'da 17 yıllık programlamada kayan nokta sayılarını zar zor kullandım, NaN yapısı çok daha az, == operatörü ile nasıl davrandığını ÇOK az
bildiğim için

8
@ user1158692 Görüşe göre, temel operatörlerin geçersiz kılındığı herhangi bir programdan kişisel olarak nefret ediyorum ve java'da aldığım herhangi bir kodun karıştırılmamış olmasına sevindim ( vektör çapraz çarpım ve nokta çarpım olarak geçersiz kılındığımı * gördüm çünkü her ikisi de vektör çarpma türleridir; çıldırtıcı! Java'da biri çağrılır .cross()ve diğeri .dot()vardır ve kafa karışıklığı yoktur. Ayrıca "== operatörünü geçersiz kıl ve her zaman yanlış döndürme" gerçeği, pro java gibi görünüyor
Richard Tingle

Yanıtlar:


172

Basit bir yol kullanmaktır Float.NaN:

float x = Float.NaN;  // <--

if (x == x) {
    System.out.println("Ok");
} else {
    System.out.println("Not ok");
}
Tamam değil

İle aynı şeyi yapabilirsiniz Double.NaN.


Gönderen JLS §15.21.1. Sayısal Eşitlik Operatörleri ==ve!= :

Kayan nokta eşitlik testi, IEEE 754 standardının kurallarına uygun olarak gerçekleştirilir:

  • İşlenenlerden biri NaN ise, sonucu ==şudur, falseancak sonucu !=şudur true.

    Gerçekten de, bir test x!=xolup truedeğeri ancak ve ancak xNaN.

...


157
int x = 0;
if (x == x) {
    System.out.println("Not ok");
} else {
    System.out.println("Ok");
}

63
Heh, sorulduğu gibi bu soruyu tamamen yanıtlıyor.
Dave Newton

5
@AswinMurugesh Doğru, ancak soruyu bu cevabın yaptığı gibi tam anlamıyla alıyorsak, o zaman elsetamamen silebiliriz . Bu teknik olarak sorunun şartlarını ihlal etmez.
arshajii

67
Bunun ikinci en yüksek oyu alan cevabım olduğunu düşünürsek, çok komik olduğum veya berbat bir programcı olduğum sonucuna varmak konusunda emin değilim.
Jeroen Vannevel

5
@JeroenVannevel Gereksinimler göz önüne alındığında, bunun en KISS / YAGNI / uygun cevap olduğunu düşünüyorum;)
Izkata

12
@jddsantaella: Açıkçası bu daha sonra düzenlendi. Asıl soru "Nasıl 'tamam değil' yazdırabilirim" diyordu.
Jeroen Vannevel

147

By Java Dil Özellikleri NaN için eşit değildirNaN .

Bu nedenle, xeşit olmasına neden olan herhangi bir satır NaNbuna neden olur, örneğin

double x=Math.sqrt(-1);

Java Dil Spesifikasyonlarından:

Kayan nokta operatörleri istisna oluşturmaz (§11). Taşan bir işlem, işaretli bir sonsuzluk üretir, alttan taşan bir işlem normal olmayan bir değer veya işaretli bir sıfır üretir ve matematiksel olarak kesin bir sonucu olmayan bir işlem NaN üretir. NaN ile tüm sayısal işlemler, sonuç olarak NaN üretir. Daha önce açıklandığı gibi, NaN sırasızdır, bu nedenle bir veya iki NaN içeren sayısal karşılaştırma işlemi yanlış döndürür ve NaN içeren herhangi bir! = Karşılaştırması, x NaN olduğunda x! = X dahil olmak üzere true döndürür.


@ sᴜʀᴇsʜᴀᴛᴛᴀ Adil bir nokta, "kodlama kuralı" nı bulmakla o kadar meşguldüm ki soruyu gerçekten cevaplamayı unuttum
Richard Tingle

Bu yalnızca a'nın Nesne veya çift olarak bildirilmesi durumunda geçerlidir.
Christian Kuetbach

1
@ChristianKuetbach Doğru, aksi yönde herhangi bir bilgi yoksa, yorumlanan satırın herhangi bir şey olabileceğini varsaydım
Richard Tingle

2
Hile cevabım bile doğrudur ve kuralları yerine getirir. Sadece if-cümlesinden önce düzenledim ve sadece "Gotcha! Yazdırılır. Eminim ki, bu cevap bu bilmecenin yaratıcısının zihnindeki cevap değildir. Ama bilmece iyi tanımlanmamıştır (çoğu yazılımsal proje gibi ).
Christian Kuetbach

73

Bunun bir seçenek olup olmadığından emin değilim, ancak xyerel değişkenden bir alana geçmek, diğer iş parçacığının değerini okuma sol ve sağ taraf arasında değiştirmesine izin verir.if ifadede .

İşte kısa demo:

class Test {

    static int x = 0;

    public static void main(String[] args) throws Exception {

        Thread t = new Thread(new Change());
        t.setDaemon(true);
        t.start();

        while (true) {
            if (x == x) {
                System.out.println("Ok");
            } else {
                System.out.println("Not ok");
                break;
            }
        }
    }
}

class Change implements Runnable {
    public void run() {
        while (true)
            Test.x++;
    }
}

Çıktı:

⋮
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Not ok

8
Çaba için 1, ama adam Haha ... hiçbir şekilde biri var benim böyle bir şey (eğitmen dahil) ile gelip olurdu Java laboratuarında.
William Gaul

28
@WilliamGaul Gerçekten mi? Her zaman bunun, çoklu okuma ile ilgili olası sorunları gösteren temel örneklerden biri olduğunu ve bu konunun kolay olduğunu düşünen insanların neden hiçbir şeyden sorumlu
olmamaları gerektiğini düşündüm

4
Cevabınızı okuyana kadar bu konuyu düşünmedim bile. Bunu zihinsel araç
setime

56

Değiştirilen satır okuyabilir.

double x = Double.NaN;

Bu, gotcha'nın yazdırılmasına neden olur.

Java Dil Belirtimi (JLS) diyor ki:

Kayan nokta operatörleri istisna oluşturmaz (§11). Taşan bir işlem, işaretli bir sonsuzluk üretir, alttan taşan bir işlem normal olmayan bir değer veya işaretli bir sıfır üretir ve matematiksel olarak kesin bir sonucu olmayan bir işlem NaN üretir. NaN ile tüm sayısal işlemler, sonuç olarak NaN üretir. Daha önce açıklandığı gibi, NaN sırasızdır, bu nedenle bir veya iki NaN içeren sayısal karşılaştırma işlemi yanlış döndürür ve NaN içeren herhangi bir! = Karşılaştırması, x NaN olduğunda x! = X dahil olmak üzere true döndürür.


Veya a, String a = "Nope" olarak bildirilirse, bir derleme hatasına yol açar; Bu yüzden 'a' türünü sordum
Christian Kuetbach

Yukarıdaki kod, türler hakkında hiçbir bilgi vermez, bu nedenle, a'nın önceden tanımlanmadığı varsayımını yaptım.
Mex

Bence cevabınız, bilmece yaratıcısının zihnindeydi. Ancak kurallar net değildi. Sadece iki kural verildi: 1. sadece yorum satırına ekleyin ve 2. sadece bir tane "Yakaladım!"
Yazdırın

bilmece yazarı kodu {}
Mex

30

Bundan bir almayı başardım Gotcha!:

volatile Object a = new Object();

class Flipper implements Runnable {
  Object b = new Object();

  public void run() {
    while (true)  {
      Object olda = a;
      a = b;
      a = olda;
    }
  }

}

public void test() {
  new Thread(new Flipper()).start();

  boolean gotcha = false;
  while (!gotcha) {
    // I've added everything above this - I would therefore say still legal.
    if (a == a) {
      System.out.println("Not yet...");
    } else {
      System.out.println("Gotcha!");
      // Uncomment this line when testing or you'll never terminate.
      //gotcha = true;
    }
  }
}

1
Bu, sorunun sorulduğu şekilde yorumdan daha fazlasını değiştirir.
Mex

Öyle bir şey denedim ama her zaman aynı sonucu vereceğinin garantili olduğunu düşünüyorum, değil mi?
AndreDurao

4
@Mex - Gerçekten var ama bazen a != abaşka bir iş parçacığı tarafından değiştirildiği için başka bir anahtar noktayı göstermek için orijinali yeterince koruyor . Bunun bir röportajda puan kazanacağından şüpheleniyorum.
OldCurmudgeon

Aslında oldukça zekice olsa da, bunun akarşılaştırma için birinci ve ikinci erişim arasındaki ilk iş parçacığı tarafından değiştirilen "umarak" çalıştığını varsayıyorum
Richard Tingle

4
Şüphelilere yeniden; Anahtar ififadenin üzerine yazdığınız her şeyin gerekirse tek bir korkunç satırda yazılabileceğini belirtmekte fayda var
Richard Tingle

25

Çok fazla çözüm var:

class A extends PrintStream {
    public A(PrintStream x) {super(x);}
    public void println(String x) {super.println("Not ok");}
    public static void main(String[] args) {
        System.setOut(new A(System.out));
        int x = 0;
        if (x == x) {
            System.out.println("Ok");
        } else {
            System.out.println("Not ok");
        }
    }
}

1
Bir şeyi kaçırmıyorsam, bu super.println"tamam değil" olmalı, değil mi?
Izkata

@İzkata Evet, istenen çıktının ne olması gerektiğini yeniden kontrol etmedim.
Johannes Kuhn

2
Kesinlikle harika!
Dariusz

25

Kolay bir çözüm şudur:

System.out.println("Gotcha!");if(false)
if( a == a ){
  System.out.println("Not yet...");
} else {
  System.out.println("Gotcha!");
}

Ama bu bilmecenin tüm kurallarını bilmiyorum ...

:) Bunun bir hile olduğunu biliyorum, ancak tüm kuralları bilmeden sorunun en kolay çözümü bu mu :)


1
Tek satırda yazılabilir;)
Christian Kuetbach

6
@ChristianKuetbach Tüm programlar gibi
Richard Tingle

2
@ChristianKuetbach Doğrusu, eğer gerçekten böyle bir program yapmayı denediyseniz, derleyici bilgisayarınızdaki tüm dosyaları derhal silmeli
Richard Tingle

1
Neden bu kadar zorlaştırıyorsun? if (System.out.println("Gotcha") && false)
alexis

3
hata: burada 'void' türüne izin verilmiyor eğer (System.out.println ("Gotcha") && false) Kodunuz derlenmeyecek ...
Christian Kuetbach

11

Systemİle aynı pakette kendi sınıfınızı oluşturun Condition.
Bu durumda sizin Systemsınıf gizler java.lang.Systemsınıfını

class Condition
{
    static class System
    {
        static class out
        {
            static void println(String ignored)
            {
                java.lang.System.out.println("Not ok");
            }
        }
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        int x = 0;
        if (x == x) 
        {
           System.out.println("Not ok");
        } 
        else 
        {
           System.out.println("Ok");
        }
    }
}  

Ideone DEMO


9

Başka cevaplardan aynı atlama / değiştirme çıktı yaklaşımını kullanmak:

class Condition {
    public static void main(String[] args) {
        try {
            int x = 1 / 0;
            if (x == x) {
                System.out.println("Ok");
            } else {
                System.out.println("Not ok");
            }
        } catch (Exception e) {
            System.out.println("Not ok");
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.