2010-01-11 29 views
22

Tôi có đoạn mã sau:Java: Tại sao phương thức hoán đổi này không hoạt động?

public class Main { 

    static void swap (Integer x, Integer y) { 
     Integer t = x; 
     x = y; 
     y = t; 
    } 

    public static void main(String[] args) { 
     Integer a = 1; 
     Integer b = 2; 
     swap(a, b); 
     System.out.println("a=" + a + " b=" + b); 
    } 
} 

Tôi hy vọng nó sẽ in a = 2 b = 1, nhưng nó in ngược lại. Vì vậy, rõ ràng phương thức hoán đổi không hoán đổi một giá trị a và b. Tại sao?

+8

Vui lòng tham khảo chênh lệch giữa cuộc gọi bằng giá trị và gọi bằng cách tham khảo. –

+1

Trong phương thức hoán đổi, bạn đang truyền 'giá trị' của đối tượng và không tham chiếu đến đối tượng thực, bất cứ điều gì bạn làm bên trong phương thức hoán đổi sẽ không ảnh hưởng đến biến a và b. –

Trả lời

42

Điều này không liên quan gì đến tính bất biến của số nguyên; nó phải làm với thực tế là Java is Pass-by-Value, Dammit!(Không khó chịu, chỉ tiêu đề của bài viết: p)

Tóm lại: Bạn thực sự không thể thực hiện một phương thức hoán đổi trong Java. Bạn chỉ cần thực hiện trao đổi bản thân, bất cứ nơi nào bạn cần; mà chỉ là ba dòng mã anyways, vì vậy không nên có nhiều của một vấn đề :)

Thing tmp = a; 
    a = b; 
    b = tmp; 
+4

Tại sao bỏ phiếu xuống? Tôi đã hiểu nhầm điều gì chưa? – Svish

+0

Nhưng nếu Integer có thể thay đổi và có ví dụ một trường setValue, hoán đổi các giá trị bằng cách gọi setValue sẽ là một thay đổi hiển thị. Vì vậy, nó có một cái gì đó để làm với mutability trong đó bạn vẫn có thể có một phương pháp void mà đạt được kết quả auther muốn. –

+7

Nhưng bạn sẽ không thực sự hoán đổi các số nguyên, mà dường như là mục tiêu. Nếu tôi có một bãi đậu xe với hai chiếc xe và sau đó làm cho chiếc xe đầu tiên trông giống hệt như chiếc xe thứ hai và chiếc xe thứ hai chính xác như chiếc xe đầu tiên, tôi sẽ đổi chỗ những chiếc xe? Không hẳn. Tôi sẽ chỉ làm * rất nhiều công việc để làm cho nó xuất hiện theo cách đó. – Svish

0

Số nguyên không thay đổi - bạn không thể thay đổi giá trị của chúng. Sự hoán đổi xảy ra bên trong hàm hoán đổi là các tham chiếu, chứ không phải các giá trị.

Bạn sẽ cần phải trả lại cả hai tài liệu tham khảo trong một mảng để đạt được những gì bạn muốn

static Integer[] swap(Integer a, Integer b) { 
    return new Integer[]{b, a}; 
} 

public static void main(String[] args) { 
    Integer a = 1; 
    Integer b = 2; 

    Integer[] intArray = swap(a, b); 

    a = intArray[0]; 
    b = intArray[1]; 

    System.out.println("a=" + a + " b=" + b); 
} 

Nếu Integer có một phương pháp setValue, bạn có thể làm một cái gì đó như thế này.

static void swap(Integer a, Integer b) { 
    int temp = a.intValue(); 
    a.setValue(b.intValue()); 
    b.setValue(temp); 
} 

Nhưng không - để đạt được những gì bạn muốn, trả về mảng.

+8

Tính bất biến số nguyên không phải là vấn đề ở đây. – Svish

6

Mọi thứ trong Java được truyền theo giá trị và các giá trị của các biến luôn nguyên thủy hoặc tham chiếu đến đối tượng.

1

Bạn cần chuyển các tham số theo tham chiếu, điều này không thể thực hiện được trong java. Ngoài ra số nguyên là inmutables, vì vậy bạn không thể trao đổi các giá trị như bạn không có một phương thức setValue.

2

Khi Svish và những người khác chỉ ra nó gọi bằng giá trị, không phải bằng cách tham chiếu trong Java. Vì bạn không có con trỏ trong Java, bạn cần một số loại đối tượng chủ để thực sự trao đổi các giá trị theo cách này. Ví dụ:

static void swap(AtomicReference<Integer> a, AtomicReference<Integer> b) { 

    Integer c = a.get(); 
    a.set(b.get()); 
    b.set(c); 

} 

public static void main(String[] args) { 

    AtomicReference<Integer> a = new AtomicReference<Integer>(1); 
    AtomicReference<Integer> b = new AtomicReference<Integer>(2); 

    System.out.println("a = " + a); 
    System.out.println("b = " + b); 

    swap(a, b); 

    System.out.println("a = " + a); 
    System.out.println("b = " + b); 

} 
+1

P.S. Sử dụng AtomicReference có thể không có ý nghĩa nhiều đối với bạn vì nó là một thành ngữ đồng thời. Viết chủ của riêng bạn nếu bạn không cần hành vi an toàn chỉ. – yawn

+0

"bạn không có con trỏ trong Java". Tôi đoán Java có khái niệm về con trỏ nhưng nó không theo ý của các lập trình viên để sử dụng. –

+2

Theo như tôi biết, bạn có con trỏ trong Java.Chúng chỉ được gọi là tài liệu tham khảo và bạn không thể thao tác chúng như bạn có thể bằng nhiều ngôn ngữ khác nhau ở các mức độ khác nhau. – Svish

2

Nếu bạn muốn thực hiện một phương pháp hoán đổi cho các đối tượng Integer, bạn phải quấn các giá trị vào một mảng (hoặc ArrayList) và trao đổi bên trong mảng. Dưới đây là một sự thích nghi của mã của bạn:

public class Main { 

    static void swap (Integer[] values) { 
     if ((values == null) || (values.length != 2)) { 
      throw new IllegalArgumentException("Requires an array with exact two values"); 
     } 

     Integer t = values[0]; 
     values[0] = values[1]; 
     values[1] = t; 
    } 

    public static void main(String[] args) { 
     Integer a = 1; 
     Integer b = 2; 
     Integer[] integers= new Integer[]{a,b}; 
     swap(integers); 
     System.out.println("a=" + integers[0] + " b=" + integers[1]); 
    } 
} 

(Chỉ cần thêm câu trả lời này vì Svish đề cập, rằng "Bạn có thể không thực sự tạo ra một phương pháp trao đổi trong Java"fg)

0

Như tất cả các kẻ đã đề cập đến một điều Pass-By-Value của nó.

Chỉ thích thêm: bạn có thể sử dụng phương pháp hoán đổi số nguyên GLOBAL này.

private void swap(){ 
    a ^= b; 
    b ^= a; 
    a ^= b; 
} 

Nó giúp loại bỏ việc sử dụng các biến khác, và nó chỉ mát :)

+2

Nó có thể được mát mẻ, nhưng nó không phải là rất dễ đọc. –

+0

Phiên bản hoán đổi tuyệt vời - không cần thêm biến, khéo léo và tốt để hỏi sinh viên cách làm điều đó ;-), nhưng ... nó không hoạt động trong Java :-(Hoặc là? – WildWezyr

+0

@WildWezyr phải không? rằng a và b nên toàn cầu ở đây, nếu không bạn sẽ cần phải sử dụng các phương pháp được đề cập bởi những kẻ ở trên – medopal

0

Sử dụng toán tử XOR là một ý tưởng rất xấu:

Đầu tiên, nó là ít có thể đọc được. Thứ hai, có những lúc điều này nhanh hơn nhưng ngày nay ngược lại là trường hợp. Xem

Wikipedia

để tham khảo.

+2

FYI, vì SO reshuffles câu trả lời khi họ nhận được lên/xuống bình chọn nó thường là một ý tưởng tốt để sử dụng "thêm bình luận" liên kết để thêm một bình luận cho câu trả lời bạn đang đề cập đến thay vì sau đó viết bình luận trong một câu trả lời mới. Làm cho nó dễ dàng hơn để tìm ra những gì bạn đang bình luận. – Fredrik

0

mã Java:

class swap { 

    int n1; 
    int n2; 
    int n3; 

    void valueSwap() { 
     n3 = n1; 
     n1 = n2; 
     n2 = n3; 
    } 

    public static void main(String[] arguments) { 

     Swap trial = new Swap(); 
     trial.n1 = 2; 
     trial.n2 = 3; 

     System.out.println("trial.n1 = " + trial.n1); 
     System.out.println("trial.n2 = " + trial.n2); 

     trial.valueSwap(); 

     System.out.println("trial.n1 = " + trial.n1); 
     System.out.println("trial.n2 = " + trial.n2); 

    } 
} 

Output:

trial.n1 = 2 
trial.n2 = 3 
trial.n1 = 3 
trial.n2 = 2 
0

Sử dụng Scanner:

import java.util.*; 
public class Swap { 
public static void main(String[] args){ 
    int i,temp,Num1,Num2; 
    Scanner sc=new Scanner(System.in); 
    System.out.println("Enter Number1 and Number2"); 
    Num1=sc.nextInt(); 
    Num2=sc.nextInt(); 
    System.out.println("Before Swapping Num1="+Num1+" Num2="+Num2); 
    temp=Num1; 
    Num1=Num2; 
    Num2=temp; 
    System.out.println("After Swapping Num1="+Num1+" Num2="+Num2); 
}  
} 
Các vấn đề liên quan