Làm thế nào một biến Java có thể khác với chính nó?


106

Tôi đang tự hỏi liệu câu hỏi này có thể được giải quyết bằng Java không (tôi mới sử dụng ngôn ngữ này). Đây là mã:

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");
        }
    }
}

Tôi đã nhận được câu hỏi sau trong phòng thí nghiệm của mình: Làm thế nào bạn có thể bỏ qua trường hợp đầu tiên (tức là đặt x == xđiều kiện sai) mà không sửa đổi chính điều kiện?


12
Tôi tin rằng cần phải hạn chế nhiều hơn, nếu không thì quá thoáng.
Fermat's Little Student,

52
Nó có đơn giản như System.out.println("Gotcha!");thay vì nhận xét? :)
stuXnet

7
Tốt, sau đó là đôi a = Double.NaN câu trả lời ngắn nhất và tôi "hack chỉ là một cheat;)
Christian Kuetbach

47
Đây là một câu đố vui về Java, nhưng tôi hy vọng không ai coi nó là một câu hỏi phỏng vấn. Những người xem xét ứng viên cho việc làm nên cố gắng hết sức có thể để tìm hiểu xem ứng viên có hiểu về lập trình hay không, chứ không phải là anh ta tích lũy được bao nhiêu câu đố. Tôi đã hầu như không sử dụng số dấu chấm động trong 17 năm lập trình trong Java, ít hơn nhiều các cấu trúc NaN, NHIÊU ít biết cách ứng xử với các nhà điều hành == ...
Arcy

8
@ user1158692 Vấn đề ý kiến, cá nhân tôi ghét bất kỳ chương trình nào mà các toán tử cơ bản bị ghi đè và rất vui vì bất kỳ mã nào tôi nhận được trong java không bị nhầm lẫn (tôi đã thấy * được ghi đè là sản phẩm chéo vectorsản phẩm dấu chấm vì cả hai đều là loại phép nhân vectơ; thật tức giận! Trong khi trong java một cái được gọi .cross()và cái kia được gọi và .dot()không có sự nhầm lẫn. Ngoài ra, thực tế là "ghi đè toán tử == và luôn trả về sai" không thể xảy ra có vẻ như pro java
Richard Tingle

Câu trả lời:


172

Một cách đơn giản là sử dụng Float.NaN:

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

if (x == x) {
    System.out.println("Ok");
} else {
    System.out.println("Not ok");
}
Không ổn

Bạn có thể làm tương tự với Double.NaN.


Từ JLS §15.21.1. Toán tử bình đẳng số ==!= :

Kiểm tra bình đẳng dấu phẩy động được thực hiện theo các quy tắc của tiêu chuẩn IEEE 754:

  • Nếu một trong hai toán hạng là NaN, thì kết quả của ==falsenhưng kết quả của !=true.

    Thật vậy, thử nghiệm x!=xtruenếu và chỉ khi giá trị của xlà NaN.

...


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

63
Heh, điều này hoàn toàn trả lời câu hỏi như đã hỏi.
Dave Newton

5
@AswinMurugesh Đúng, nhưng nếu chúng ta đang xem câu hỏi hoàn toàn theo nghĩa đen như câu trả lời này, thì chúng ta có thể xóa elsehoàn toàn. Điều này sẽ không vi phạm về mặt kỹ thuật các điều khoản của câu hỏi.
arshajii

67
Xem xét đây là câu trả lời được bình chọn cao thứ hai của tôi, tôi không chắc nên kết luận rằng tôi rất hài hước hay là một lập trình viên dở hơi.
Jeroen Vannevel

5
@JeroenVannevel Với các yêu cầu, tôi nghĩ đây là câu trả lời KISS / YAGNI / thích hợp nhất;)
Izkata 17/10/13

12
@jddsantaella: rõ ràng là cái này đã được chỉnh sửa sau đó. Câu hỏi ban đầu cho biết "Làm thế nào tôi có thể in 'không ổn'".
Jeroen Vannevel,

147

Bởi Đặc điểm kỹ thuật ngôn ngữ Java NaN không bằng NaN.

Do đó, bất kỳ dòng nào gây ra xbằng NaNsẽ gây ra điều này, chẳng hạn như

double x=Math.sqrt(-1);

Từ Thông số kỹ thuật ngôn ngữ Java:

Toán tử dấu phẩy động không tạo ra ngoại lệ (§11). Một phép toán tràn tạo ra giá trị vô cực có dấu, một phép toán tràn dòng tạo ra giá trị không chuẩn hóa hoặc một số 0 có dấu và một phép toán không có kết quả xác định về mặt toán học tạo ra NaN. Kết quả là tất cả các phép toán số với NaN như một toán hạng tạo ra NaN. Như đã được mô tả, NaN không có thứ tự, vì vậy phép toán so sánh số liên quan đến một hoặc hai NaN sẽ trả về false và bất kỳ! = So sánh nào liên quan đến NaN đều trả về true, bao gồm x! = X khi x là NaN.


@ sᴜʀᴇsʜᴀᴛᴛᴀ Một điểm công bằng, tôi đã quá bận rộn đi tắt để tìm nói "mã hóa ước" mà tôi quên để thực sự trả lời câu hỏi
Richard Tingle

Điều này chỉ hợp lệ nếu a được khai báo là Object hoặc double.
Christian Kuetbach

1
@ChristianKuetbach Đúng vậy, trong sự vắng mặt của bất kỳ thông tin ngược lại tôi đã giả định dòng nhận xét ra có thể được bất cứ điều gì
Richard Tingle

2
Ngay cả câu trả lời bị lừa của tôi là chính xác và đáp ứng các quy tắc. Tôi chỉ chỉnh sửa trước khi câu lệnh if và chỉ "Gotcha! Được in ra. Tôi chắc chắn rằng câu trả lời này không phải là câu trả lời trong suy nghĩ của người tạo ra câu đố này. Nhưng câu đố không được xác định rõ ràng (như hầu hết các dự án phần mềm ).
Christian Kuetbach

73

Không chắc đây có phải là một tùy chọn hay không nhưng việc thay đổi xtừ biến cục bộ thành một trường sẽ cho phép luồng khác thay đổi giá trị của nó giữa phần đọc bên trái và bên phải trong ifcâu lệnh.

Đây là bản demo ngắn:

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++;
    }
}

Đầu ra:

⋮
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Not ok

8
Haha +1 cho nỗ lực, nhưng trời ơi ... không đời nào có ai trong phòng thí nghiệm Java của tôi nghĩ ra thứ như thế này (bao gồm cả người hướng dẫn).
William Gaul

28
@WilliamGaul Thật không? Tôi luôn mặc dù nó là một trong những ví dụ cơ bản cho thấy các vấn đề có thể với đa luồng và tại sao người nghĩ rằng vấn đề này rất dễ dàng không bao giờ nên chịu trách nhiệm về bất cứ điều gì :)
Pshemo

4
Tôi thậm chí đã không nghĩ về vấn đề này cho đến khi tôi đọc câu trả lời của bạn. Cảm ơn bạn đã thêm cái này vào bộ công cụ tinh thần của tôi :)
Behe

56

Dòng được thay thế có thể đọc.

double x = Double.NaN;

Điều này sẽ làm cho gotcha được in.

Đặc tả ngôn ngữ Java (JLS) cho biết:

Toán tử dấu phẩy động không tạo ra ngoại lệ (§11). Một phép toán tràn tạo ra giá trị vô cực có dấu, một phép toán tràn dòng tạo ra giá trị không chuẩn hóa hoặc một số 0 có dấu và một phép toán không có kết quả xác định về mặt toán học tạo ra NaN. Kết quả là tất cả các phép toán số với NaN như một toán hạng tạo ra NaN. Như đã được mô tả, NaN không có thứ tự, vì vậy phép toán so sánh số liên quan đến một hoặc hai NaN sẽ trả về false và bất kỳ! = So sánh nào liên quan đến NaN đều trả về true, bao gồm x! = X khi x là NaN.


Hoặc dẫn đến lỗi biên dịch, nếu a được khai báo là String a = "Nope"; Đó là lý do tại sao tôi hỏi cho các loại 'a'
Christian Kuetbach

Đoạn mã trên không cung cấp thông tin về các loại, do đó tôi đã giả định rằng a chưa được xác định.
Mex

Tôi nghĩ rằng câu trả lời của bạn là câu trả lời, đó là trong tâm trí của người tạo ra câu đố. Nhưng các quy tắc không rõ ràng. Chỉ có hai quy tắc được đưa ra: 1. chỉ chèn vào phù hợp với những nhận xét và 2. chỉ nhận được một "Gotcha in ra!.
Christian Kuetbach

tác giả câu đố có thể đã luôn luôn hợp lệ bằng cách đặt mã trong {}
Mex

30

Tôi quản lý để có được một Gotcha!từ này:

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
Điều này thay đổi nhiều hơn là chỉ nhận xét như câu hỏi yêu cầu.
Mex

Tôi đã thử một cái gì đó như vậy nhưng tôi nghĩ rằng nó được đảm bảo rằng nó sẽ tạo ra cùng một kết quả, phải không?
AndreDurao

4
@Mex - Đúng là như vậy, nhưng nó bảo tồn đủ bản gốc để chứng minh một điểm quan trọng khác mà đôi khi a != avì nó đã bị thay đổi bởi một luồng khác. Tôi nghi ngờ điều này sẽ giành được điểm trong một cuộc phỏng vấn.
OldCurmudgeon

Đây thực sự là mặc dù khá thông minh, tôi giả sử công trình này bằng cách "hy vọng" mà ađược thay đổi bởi thread đầu tiên ở giữa việc tiếp cận đầu tiên và thứ hai để so sánh
Richard Tingle

4
Lại những nghi ngờ của bạn; nó đáng chú ý là tất cả những gì bạn đã viết trên phím iftuyên bố có thể được viết bằng một dòng khủng khiếp duy nhất nếu cần thiết
Richard Tingle

25

Có rất nhiều giải pháp:

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
Trừ khi tôi thiếu thứ gì đó, nếu super.printlnkhông thì đó phải là "Không ổn", phải không?
Izkata

@Izkata Có, đã không kiểm tra lại kết quả đầu ra mong muốn.
Johannes Kuhn

2
Hoàn toàn rực rỡ!
Dariusz

25

Một giải pháp dễ dàng là:

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

Nhưng tôi không biết tất cả các quy tắc cho câu đố này ...

:) Tôi biết rằng đây là một trò gian lận, nhưng không biết tất cả các quy tắc, đây có phải là giải pháp dễ nhất cho câu hỏi :)


1
Có thể được viết trong một dòng;)
Christian Kuetbach

6
@ChristianKuetbach Như tất cả các chương trình
Richard Tingle

2
@ChristianKuetbach Trong công bằng tất cả các trình biên dịch nên xóa ngay lập tức tất cả các tập tin trên máy tính của bạn nếu bạn đã cố gắng để thực sự chương trình như vậy
Richard Tingle

1
Tại sao làm cho nó khó khăn như vậy? if (System.out.println("Gotcha") && false)
alexis

3
lỗi: 'khoảng trống' loại không được phép ở đây if (System.out.println ( "Gotcha") && false) Mã của bạn sẽ không biên dịch ...
Christian Kuetbach

11

Tạo lớp học của riêng bạn Systemtrong cùng một gói với Condition.
Trong trường hợp này, Systemlớp của bạn sẽ ẩn java.lang.Systemlớp

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

Sử dụng cùng cách tiếp cận đầu ra bỏ qua / thay đổi từ các câu trả lời khác:

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");
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.