2010-03-18 35 views
8

Có cách nào khác trong java để thực hiện cuộc gọi lại ngoài các lớp bên trong không? Sự khác biệt giữa callbacks và closures là gì?Đóng cửa và gọi lại

Trả lời

10

Đóng cửa là cách bạn tạo, gọi lại là cách bạn sử dụng.

Gọi lại có thể được thực hiện dưới dạng đóng (bằng ngôn ngữ có) hoặc triển khai giao diện (trong Java, dưới dạng lớp bên trong ẩn danh hoặc lớp thông thường).

Gọi lại có nghĩa là bạn chuyển một đoạn mã vào một hàm, để hàm có thể gọi đoạn mã đó sau đó. Nó là một loại tham số đặc biệt.

Đoạn mã có thể là con trỏ hàm hoặc đóng hoặc đối tượng có phương pháp nổi tiếng, tùy thuộc vào ngôn ngữ cung cấp.

+0

Đây là câu trả lời tôi đã cố gắng để viết khi Neeraj đầu tiên bỏ câu hỏi nhưng không thể nhận ra trong một thời trang mạch lạc. Thanh danh. –

0

Tôi không nghĩ vậy.

Nếu có, thì có lẽ nó kém hơn một cách nào đó, nếu không các lớp bên trong vô danh sẽ không được sử dụng rộng rãi.

0

Không có sự khác biệt.

Đóng cửa có thể được định nghĩa là một khối mã giữ ngữ cảnh gốc có thể được thực hiện dễ dàng.

Thực tế, sự khác biệt duy nhất tôi biết giữa chúng là dễ viết. Một điển hình groovy/ruby ​​đóng cửa thực sự là nhỏ hơn để viết hơn một lớp ẩn danh Java.

Tuy nhiên, xem xét Java framworks như guava và có sử dụng tự do của các tầng lớp vô danh/giao diện, đặc biệt đối với việc đóng cửa điển hình trường hợp sử dụng như filter (so sánh với groovy của implementation), tôi có thể nói hoàn toàn không có sự khác biệt thiết kế.

+0

Nếu không có sự khác biệt thì tại sao hai tên này tồn tại. Tôi là clueless – Neeraj

0

Đáng buồn là cách hợp lý duy nhất là các lớp bên trong/ẩn danh.

Bạn cũng có thể làm điều đó với sự phản chiếu, nhưng thường là chậm hơn và khó bảo trì hơn (không làm nổi bật cú pháp, khó tìm tài liệu tham khảo trong IDE, v.v.). Ví dụ:

myButton.addActionListener(EventHandler.create(ActionListener.class, handlerObject, "onClick")); 
1

Gọi lại chỉ là bất kỳ mã thực thi nào được chuyển thành tham số cho mã khác. Trong sử dụng thường xuyên, mã thực thi đó là một đóng cửa, nhưng nó không nhất thiết phải.

Việc đóng từ bị lạm dụng một phần và nhiều người chỉ sử dụng từ này làm từ đồng nghĩa cho "chức năng ẩn danh", nhưng ít nhất là according to Wikipedia, đó là việc lạm dụng thuật ngữ đó. Bài viết trên Wikipedia giải thích điều này tốt hơn tôi có thể làm một cách nhanh chóng.

5

Cả hai bao đóng và các lớp bên trong vô danh (và các lớp khác) có thể được sử dụng làm gọi lại. Một callback chỉ là một số mã được chuyển như một đối số cho mã khác.

Sự khác biệt lớn về bao đóng, so với các lớp bên trong vô danh của Java, là (trong ngôn ngữ bắt buộc), việc đóng có thể sửa đổi các biến của phạm vi xung quanh.Wikipedia cung cấp ví dụ sau:

var f, g; 
function foo() { 
    var x = 0; 
    f = function() { return ++x; }; 
    g = function() { return --x; }; 
    x = 1; 
    alert('inside foo, call to f(): ' + f()); // "2" 
} 
foo(); 
alert('call to g(): ' + g()); // "1" 
alert('call to f(): ' + f()); // "2" 
+0

Mặc dù điều này có thể được mô phỏng bởi 'ObjRef cuối cùng x = new ObjRef (0);' với 'ObjRef' được thực hiện dưới dạng tham chiếu có thể thay đổi. –

+0

Thực ra Scala thực hiện một cái gì đó như thế để thực hiện các bao đóng trên JVM, bởi vì JVM (và Java) không hỗ trợ chúng một cách tự nhiên. –

1

Nếu bạn cần đóng bằng java bạn có thể thử lambdaj. Here bạn có thể xem nó cho phép xác định bao đóng thông qua một DSL rất đơn giản.

+1

Thực ra, lambdaj không hỗ trợ việc tạo bao đóng. Tốt nhất nó hỗ trợ việc tạo ra một số loại biểu thức lambda không phải là đóng. –

0

Dưới đây là hai triển khai sử dụng bao đóng và gọi lại.

Và đây là một ví dụ tốt hơn (có thể được tìm thấy ở đây http://www.caglargonul.com/2013/04/10/is-it-really-a-closure-yes-it-is/) cho sự hiểu biết những gì đóng cửa là. Điều quan trọng là

đóng cửa đi kèm với môi trường tham chiếu không chỉ là mã chức năng.

Cách tốt nhất để thực hiện đóng cửa trong Java 7 trở xuống là sử dụng giao diện. Trong ví dụ này, một cuộc gọi lại được thực hiện như là đóng.

Trước tiên, bạn khai báo giao diện sẽ giữ đóng của bạn.

public interface CallBack { 
    void m(int e); 
} 

Và cho phép thêm lớp học để thêm và xóa đóng cửa và chức năng công khai sẽ gọi các chức năng bên trong bao đóng khi xảy ra sự kiện.

public class CCallBack { 

    List<CallBack> cbs = new ArrayList<>(); 

    public void registerCallBack(CallBack f){ 
     cbs.add(f); 
    } 

    public void removeCallBack(CallBack f){ 
     if(cbs.contains(f)){ 
      cbs.remove(f); 
     } 
    } 

    public void onAction(int i){ 
     for (CallBack callBack : cbs) { 
      callBack.m(i); 
     } 
    } 
} 

Và đây là phần huyền diệu. Xem môi trường tham chiếu đang hoạt động.

public class CallBackTester { 
    CCallBack cb = new CCallBack(); 

    @Test 
    public void test_callback(){ 

     CallBack cb1 = new CallBack() { 
      int x = 1; 
      @Override 
      public void m(int e) { 
       if(e==1){ 
        System.out.println("You register this callback " + x + " time/times"); 
        x++; 
       } 
      } 
     }; 

     cb.registerCallBack(cb1); 
     cb.registerCallBack(cb1); 
     cb.registerCallBack(cb1); 
     cb.removeCallBack(cb1); 

     cb.onAction(1); 
    } 

} 

Ở trên khi chúng tôi khai báo cb1, chúng tôi sẽ thêm môi trường tham chiếu bao gồm biến x. Khi chúng ta gọi hàm bên trong phần đóng này, chúng ta sẽ tăng biến này lên một. Nếu nó là một hàm bình thường, x sẽ được khai báo là 1 khi chúng ta gọi hàm. NHƯNG KHÔNG PHẢI LÀ CHỨC NĂNG BÌNH THƯỜNG. CNTT là một sự kết thúc. Vì vậy x không được khai báo mỗi khi chúng ta gọi hàm trong phần đóng. Như bạn có thể thấy từ đầu ra mỗi khi chúng ta gọi nó, x là tăng dần.

You register this callback 1 time/times 
You register this callback 2 time/times