2013-08-03 40 views
26

Nếu một phương pháp có một biến địa phương i:Java nguyên thủy có bất biến không?

int i = 10; 

và sau đó tôi gán một giá trị mới:

i = 11; 

này sẽ phân bổ một vị trí bộ nhớ mới? Hoặc chỉ cần thay thế giá trị ban đầu?

Điều này có nghĩa là nguyên thủy là không thay đổi?

+0

Nó sẽ không tạo vị trí mới trong bộ nhớ. – Maroun

+1

Nó sẽ thay thế bản gốc. Java nguyên thủy ** không phải là ** đối tượng. 'Integer' (và các lớp wrapper nguyên thủy khác) ** là ** không thay đổi. –

+3

@BrianRoach không, anh ta đã không làm vậy. Theo logic của bạn, các chuỗi có thể thay đổi: 'String str =" test "; str = "newStr"; '. Để trả lời câu hỏi của OP, họ thực tế không thay đổi được. Nếu bạn xem xét 'i ++', đó thực sự là: 'i = i + 1'. Bạn có thể thấy giá trị của 'i', thêm một và gán lại' i' cho giá trị mới này. –

Trả lời

49

Điều này có phân bổ vị trí bộ nhớ mới không? Hoặc chỉ cần thay thế giá trị ban đầu?

Java không thực sự đảm bảo rằng các biến sẽ tương ứng với vị trí bộ nhớ; ví dụ, phương pháp của bạn có thể được tối ưu hóa theo cách mà i được lưu trữ trong sổ đăng ký — hoặc thậm chí không được lưu trữ, nếu trình biên dịch có thể thấy rằng bạn không bao giờ thực sự sử dụng giá trị của nó hoặc nếu nó có thể theo dõi qua mã và sử dụng trực tiếp các giá trị thích hợp.

Nhưng hãy gạt sang một bên. . . nếu chúng ta lấy trừu tượng ở đây là biến cục bộ biểu thị vị trí bộ nhớ trên ngăn xếp cuộc gọi, thì i = 11 sẽ chỉ sửa đổi giá trị tại vị trí bộ nhớ đó. Nó sẽ không cần phải sử dụng một vị trí bộ nhớ mới, bởi vì biến số i là điều duy nhất đề cập đến vị trí cũ.

Điều này có nghĩa là nguyên thủy là không thay đổi?

Có và không: có, nguyên thủy là không thay đổi, nhưng không, không phải vì những điều trên.

Khi chúng tôi nói rằng điều gì đó có thể thay đổi, chúng tôi có nghĩa là nó có thể bị đột biến: thay đổi trong khi vẫn có cùng một danh tính. Ví dụ, khi bạn phát triển tóc của bạn, bạn đang biến đổi chính mình: bạn vẫn là bạn, nhưng một trong những thuộc tính của bạn là khác nhau.

Trong trường hợp nguyên thủy, tất cả các thuộc tính của chúng được xác định đầy đủ bằng danh tính của chúng; 1 luôn có nghĩa là 1, bất kể điều gì và 1 + 1 luôn là 2. Bạn không thể thay đổi điều đó.

Nếu biến số int nhất định có giá trị 1, bạn có thể thay đổi giá trị 2 thay thế, nhưng đó là tổng thay đổi nhận dạng: không còn giá trị như trước. Điều đó giống như thay đổi me để trỏ đến người khác thay vì cho tôi: nó không thực sự thay đổi tôi, nó chỉ thay đổi me.

Với đối tượng, tất nhiên, bạn có thể thường làm cả hai:

StringBuilder sb = new StringBuilder("foo"); 
sb.append("bar"); // mutate the object identified by sb 
sb = new StringBuilder(); // change sb to identify a different object 
sb = null; // change sb not to identify any object at all 

Trong cách nói thông thường, cả hai sẽ được mô tả là "thay đổi sb", bởi vì mọi người sẽ sử dụng "sb" cả hai để tham khảo các biến (có chứa tham chiếu) và đối tượng mà nó đề cập đến (khi nó đề cập đến một tham chiếu). Đây là loại looseness là tốt, miễn là bạn nhớ sự khác biệt khi nó quan trọng.

+8

+1 để làm cho nó cá nhân – akf

+3

Tôi đã mọc tóc, nhưng xin lỗi tôi là một người đàn ông đã thay đổi! – nawfal

6

Immutable có nghĩa là mỗi lần giá trị và đối tượng đã thay đổi tham chiếu mới sẽ được tạo cho nó trên ngăn xếp. Bạn không thể nói về bất biến trong trường hợp các kiểu nguyên thủy, chỉ có các lớp Wrapper là không thay đổi. Java sử dụng copy_by_value không theo tham chiếu.

Không có sự khác biệt nếu bạn đang chuyển biến nguyên thủy hoặc tham chiếu, bạn đang luôn truyền một bản sao của các bit trong biến. Vì vậy, đối với biến nguyên thủy, bạn đang truyền một bản sao của các bit biểu thị giá trị và nếu bạn đang truyền một biến tham chiếu đối tượng, bạn đang truyền một bản sao của các bit đại diện cho tham chiếu đến một đối tượng.

Ví dụ, nếu bạn vượt qua một biến int với giá trị 3, bạn đang đi qua một bản sao của các bit đại diện 3.

Khi một nguyên thủy đã được tuyên bố, its primitive type can never change, mặc dù giá trị của nó có thể thay đổi.

+0

@Maroun Maroun Tôi vừa thử những điều sau: int i = 10; int j = i; syso (i); // 10 syso (j); // 10 i = 11; syso (i) // 11 syso (j) // 10 Vì vậy, nếu tôi không tạo một vị trí mới trong bộ nhớ thì giá trị của j có thể giống nhau như thế nào? – fYre

+0

Trong trường hợp kiểu nguyên thủy khi gán giá trị của i đến j, các bit tương ứng với giá trị của i được sao chép, bạn không gán tham chiếu của i vì bạn không thể nói về tham chiếu trong trường hợp kiểu nguyên thủy. –

0

Có, chúng không thay đổi. Chúng hoàn toàn không thể thay đổi được.

Có giải thích tốt đẹp được chôn cất trong here. Nó dành cho Go, nhưng nó cũng giống như trong Java. Hoặc bất kỳ ngôn ngữ nào khác trong gia đình C.

+1

Không, không phải vậy. Nguyên thủy là bất biến, các biến không. – nes1983

+0

Tôi hiểu sai câu trả lời;) tệ của tôi .. giờ muộn. – Maroun

2

Đây không phải là câu trả lời đầy đủ, nhưng đó là một cách để chứng minh tính bất biến của các giá trị kiểu nguyên thủy.

Nếu giá trị nguyên thủy (literals) là có thể thay đổi, sau đó đoạn mã sau sẽ làm việc tốt:

int i = 10; // assigned i the literal value of 10 
5 = i; // reassign the value of 5 to equal 10 
System.out.println(5); // prints 10 

Tất nhiên, điều này là không đúng.

Giá trị số nguyên, chẳng hạn như 5, 10 và 11 đã được lưu trữ trong bộ nhớ. Khi bạn đặt một biến bằng một trong số chúng: nó thay đổi giá trị trong khe cắm bộ nhớ trong đó i là.

Bạn có thể thấy điều này ở đây thông qua các bytecode cho đoạn mã sau:

public void test(){ 
    int i = 10; 
    i = 11; 
    i = 10; 
} 

Bytecode:

// access flags 0x1 
public test()V 
L0 
    LINENUMBER 26 L0 
    BIPUSH 10 // retrieve literal value 10 
    ISTORE 1 // store it in value at stack 1: i 
L1 
    LINENUMBER 27 L1 
    BIPUSH 11 // same, but for literal value 11 
    ISTORE 1 
L2 
    LINENUMBER 28 L2 
    BIPUSH 10 // repeat of first set. Still references the same literal 10. 
    ISTORE 1 
L3 
    LINENUMBER 29 L3 
    RETURN 
L4 
    LOCALVARIABLE this LTest; L0 L4 0 
    LOCALVARIABLE i I L1 L4 1 
    MAXSTACK = 1 
    MAXLOCALS = 2 

Như bạn có thể nhìn thấy trong bytecode (hy vọng) nó tham chiếu đến giá trị văn chương (ví dụ : 10) và sau đó lưu trữ nó trong khe cho biến i. Khi bạn thay đổi giá trị của i, bạn chỉ đang thay đổi giá trị nào được lưu trữ trong vùng đó. Bản thân các giá trị không thay đổi, vị trí của chúng là.

Các vấn đề liên quan