2010-03-06 28 views
27

làm cách nào để tôi thực hiện chức năng hoán đổi của mình trong java nếu không có phương pháp nào để chúng tôi có thể chuyển qua tham chiếu? Ai đó có thể cho tôi một mã?làm cách nào để tôi thực hiện chức năng hoán đổi trong java?

swap(int a, int b) 
{ 
    int temp = a; 
    a = b; 
    b = temp; 
} 

nhưng sự thay đổi sẽ không được phản xạ trở lại kể từ java đi theo giá trị

+3

Bạn sẽ phải nêu rõ cụ thể hơn những gì bạn đang cố gắng hoàn thành nếu bạn muốn được trợ giúp về vấn đề này. –

+1

Xem bài viết này: http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html –

+1

Tất cả các thông số trong Java được truyền theo giá trị. –

Trả lời

14

Bạn không thể tạo một phương thức hoán đổi, để sau khi gọi swap(x,y) các giá trị của x và y sẽ được hoán đổi. Bạn có thể tạo một phương thức như vậy cho các lớp có thể thay đổi bằng cách hoán đổi nội dung của chúng¹, nhưng điều này sẽ không thay đổi nhận dạng đối tượng của chúng và bạn không thể định nghĩa một phương thức chung cho việc này.

Tuy nhiên, bạn có thể viết một phương thức hoán đổi hai mục trong một mảng hoặc danh sách nếu đó là những gì bạn muốn. Ví dụ, bạn có thể tạo một phương thức hoán đổi có hai danh sách và sau khi thực hiện phương thức, danh sách x sẽ có nội dung trước đó trong danh sách y và danh sách y sẽ có nội dung trước đó trong danh sách x.

+4

Bạn có thể tạo [phương thức] (http://stackoverflow.com/questions/2393906/how-do-i-make-my-swap-function-in-java/20600020#20600020) được gọi là 'y = swap (x, x = y) 'để hoán đổi x và y. – dansalmo

14

Nó phụ thuộc vào những gì bạn muốn làm. Mã này hoán đổi hai phần tử của một mảng.

void swap(int i, int j, int[] arr) { 
    int t = arr[i]; 
    arr[i] = arr[j]; 
    arr[j] = t; 
} 

Một cái gì đó như thế này hoán đổi nội dung của hai int[] có độ dài bằng nhau.

void swap(int[] arr1, int[] arr2) { 
    int[] t = arr1.clone(); 
    System.arraycopy(arr2, 0, arr1, 0, t.length); 
    System.arraycopy(t, 0, arr2, 0, t.length); 
} 

Something như thế này giao dịch hoán đổi nội dung của hai BitSet (sử dụng XOR swap algorithm):

void swap(BitSet s1, BitSet s2) { 
    s1.xor(s2); 
    s2.xor(s1); 
    s1.xor(s2); 
} 

Something như thế này giao dịch hoán đổi các xy lĩnh vực của một số lớp Point:

void swapXY(Point p) { 
    int t = p.x; 
    p.x = p.y; 
    p.y = t; 
} 
+0

là mảng được truyền bằng tham chiếu? – higherDefender

+0

Không. Mọi thứ trong Java được truyền theo giá trị, bao gồm _references to_ array trong Java. Mảng không khác với bất kỳ đối tượng nào khác trong trường hợp này. – polygenelubricants

+2

@ D.J .: Mảng (giống như tất cả các đối tượng) là kiểu tham chiếu. Điều này có nghĩa là bất kỳ thay đổi nào được thực hiện cho đối tượng bên trong một phương thức sẽ hiển thị ở bên ngoài (nó cũng có nghĩa là truyền một đối tượng đến một phương thức không sao chép nội dung của đối tượng, vì vậy việc truyền mảng 1M không sao chép các đối tượng 1M). Tuy nhiên gán lại biến tham chiếu đến mảng sẽ không hiển thị ở bên ngoài (nghĩa là nếu bạn làm một cái gì đó như 'arr1 = arr2' bên trong phương thức, điều này sẽ không có bất kỳ hiệu ứng nhìn thấy nào ở bên ngoài). – sepp2k

1

Tôi có thể làm một số việc như sau. Tất nhiên, với sự giàu có của các lớp học Bộ sưu tập, tôi không thể tưởng tượng bao giờ cần phải sử dụng điều này trong bất kỳ mã thực tế.

public class Shift { 
    public static <T> T[] left (final T... i) { 
    if (1 >= i.length) { 
     return i; 
    } 
    final T t = i[0]; 
    int x = 0; 
    for (; x < i.length - 1; x++) { 
     i[x] = i[x + 1]; 
    } 
    i[x] = t; 
    return i; 
    } 
} 

Được gọi với hai đối số, đó là trao đổi.

Nó có thể được sử dụng như sau:

int x = 1; 
int y = 2; 
Integer[] yx = Shift.left(x,y); 

Hoặc:

Integer[] yx = {x,y}; 
Shift.left(yx); 

Sau đó

x = yx[0]; 
y = yx[1]; 

Lưu ý: nó tự động hộp nguyên thủy.

+0

Cám dỗ xuống bạn, vì (a) nó không thực sự hữu ích - kết quả là một mảng; bản gốc x, y vẫn chưa được hoán đổi.(b) trao đổi là một hoạt động phổ biến, mà một trong những sẽ viết một chức năng tùy chỉnh để trao đổi, không sử dụng chức năng này thay đổi mục đích chung hơn. – ToolmakerSteve

+1

@ToolmakerSteve Bạn có nhận thấy rằng một trao đổi tiêu chuẩn đã được cung cấp cũng như một câu trả lời thích hợp, rằng nó không phải là có thể theo một cách tiêu chuẩn? Vì vậy, thay vì sao chép câu trả lời đã được cung cấp, câu trả lời của tôi là một loại "trao đổi" khác nhau. Điểm của câu trả lời là cung cấp các tùy chọn, không chỉ cho tất cả mọi người để khuấy động cùng một câu trả lời hơn và hơn. Vì vậy, sử dụng một sự thay đổi cho một trao đổi là một loại hợp lệ của trao đổi và không phải là một câu trả lời đã được cung cấp, vì vậy tôi đã gửi nó. – nicerobot

+0

Tôi vẫn không đồng ý: nó không hữu ích trong ngữ cảnh của câu hỏi. Có lẽ trong một số câu hỏi khác nhau. Và những quan sát tôi thực hiện đứng. Tuy nhiên, như tôi đã nói, sự không đồng ý của tôi không đủ mạnh để bác bỏ câu trả lời của bạn. – ToolmakerSteve

53

Tôi nghĩ rằng đây là gần nhất bạn có thể tới một trao đổi đơn giản, nhưng nó không có một mô hình sử dụng đơn giản:

int swap(int a, int b) { // usage: y = swap(x, x=y); 
    return a; 
} 

y = swap(x, x=y); 

Nó dựa trên thực tế là x sẽ vượt qua thành swap trước y được gán đến x, sau đó x được trả lại và gán cho y.

Bạn có thể làm cho nó chung chung và trao đổi bất kỳ số lượng các đối tượng cùng loại:

<T> T swap(T... args) { // usage: z = swap(a, a=b, b=c, ... y=z); 
    return args[0]; 
} 

c = swap(a, a=b, b=c) 
+2

Đó thực sự là một ý tưởng hay. – Sunspawn

+3

Tôi đồng ý, một ý tưởng hay, nhưng cũng rất nguy hiểm ... Vì nó dựa vào việc gán tham số trên lời gọi, bất kỳ dự án nào có phương pháp này sẽ sớm hay muộn chạy vào một lỗi vì nó. Không cho phép điều đó trong mã sản xuất nếu tôi dẫn đầu. –

+2

Thông minh. QUÁ thông minh. Dựa vào ai đó viết mẫu này chính xác. Vô cùng không rõ ràng để đọc sau. Tôi cũng sẽ phủ quyết một đoạn mã trong sản xuất. Nhưng tôi đồng ý rằng nó rất hấp dẫn. Vì vậy, đóng ... – ToolmakerSteve

-5
public class Swap1 { 
    public static void main(String[] args){ 
     int x =7; 
     int y = 3; 

     swap(x,y); 

     System.out.println("x = " + x); 
     System.out.println("y = " + y); 
    } 

    public static void swap(int x, int y) { 
     int temp = x; 
     x = y; 
     y = temp; 
    } 
} 
+0

Không hoạt động, các tham số được truyền theo giá trị, không tham chiếu, x và y không được hoán đổi. – gulchrider

+2

nghiêm túc, bạn thậm chí ĐỌC câu hỏi gốc? OP đã có chính xác chức năng này, và đã hỏi tại sao nó không hoạt động. Và bạn cẩn thận in ra các giá trị, nhưng rõ ràng là không thực sự chạy mã của bạn, để xem giá trị là gì. – ToolmakerSteve

+0

Java sử dụng lược đồ truyền theo giá trị có nghĩa là khi biên dịch chương trình lên để hoán đổi (x, y), nó sẽ là x, y mới được gán trong bộ nhớ và do đó bạn đang tham chiếu biến mới được tạo. Sau khi bước được thực hiện, vì nó không xuất hiện sau đó, nó sẽ được thu thập và biến mất. Do đó không có thay đổi nào được thực hiện sau khi hoán đổi (x, y). Hãy thử sử dụng một mảng để làm cho nó hoạt động. – CHANist

4

Rõ ràng tôi không có đủ điểm danh tiếng để bình luận trên Dansalmo's answer, nhưng nó là một tốt nhất, mặc dù mis-named. Câu trả lời của anh ta thực sự là một K-combinator.

int K(int a, int b) { 
    return a; 
} 

JLS is specific about argument evaluation when passing to methods/ctors/etc. (Đây có phải là số liệu cũ không?)

Đã cấp, đây là một thành ngữ chức năng, nhưng rõ ràng là đủ để những người nhận ra nó. (Nếu bạn không hiểu mã bạn tìm thấy, đừng khỉ nó lên!)

y = K(x, x=y); // swap x and y 

Bộ kết hợp K được thiết kế đặc biệt cho loại điều này. AFAIK không có lý do gì nó không nên vượt qua một đánh giá mã.

$ 0,02 của tôi.

+2

Bây giờ bạn đã có đủ danh tiếng, hãy chuyển bài viết này vào một bình luận. Cảm ơn! –

+0

Tôi đồng ý, vui lòng thêm nhận xét của bạn ở trên. Tôi đã thực sự rất nhiều trong việc học các kỹ năng chức năng vào thời điểm đó và có thể đã vô tình áp dụng chúng mà không nhận ra khuôn mẫu. Bạn cũng có thể thấy điều này thú vị. http://pure-fn.appspot.com/about – dansalmo

2

AFAIS, không ai đề cập đến atomic reference.

Integer

public void swap(AtomicInteger a, AtomicInteger b){ 
    a.set(b.getAndSet(a.get())); 
} 

Chuỗi

public void swap(AtomicReference<String> a, AtomicReference<String> b){ 
    a.set(b.getAndSet(a.get())); 
} 
+0

Bạn không cần loại nguyên tử để thực hiện việc này. Bất kỳ lớp chủ sở hữu có thể thay đổi nào cũng sẽ làm. Ngay cả một phần tử mảng nguyên thủy hoặc tài liệu tham khảo. –

0

Hãy thử diệu

public static <T> void swap(T a, T b) { 
    try { 
     Field[] fields = a.getClass().getDeclaredFields(); 
     for (Field field : fields) { 
      field.setAccessible(true); 
      Object temp = field.get(a); 
      field.set(a, field.get(b)); 
      field.set(b, temp); 
     } 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } 
} 

này và thử nghiệm nó!

System.out.println("a:" + a); 
    System.out.println("b:" + b); 
    swap(a,b); 
    System.out.println("a:" + a); 
    System.out.println("b:" + b); 
Các vấn đề liên quan