2017-01-04 19 views
10

Giả sử rằng chúng ta cần triển khai một số phương thức java trong mã gốc và hiển thị nó cho người dùng. Chúng tôi biết rằng tất cả công việc được thực hiện theo khía cạnh gốc, nghĩa là trách nhiệm duy nhất của mã java là chuyển đối số do người dùng cung cấp tới mã gốc và trả lại kết quả. Theo đó, lớp java có thể được thực hiện theo hai cách:Phương pháp gốc Java. Công khai và riêng tư

  • Bằng cách sử dụng các phương pháp tự nhiên được tiếp xúc trực tiếp với người sử dụng:

    public native Object doSmth(Object arg0, Object arg1); 
    
  • Bằng cách sử dụng các wrapper công cộng mỏng xung quanh phương pháp có nguồn gốc tin :

    public Object doSmth(Object arg0, Object arg1) { 
        return nativeDoSmth(arg0, arg1); 
    } 
    
    private native Object nativeDoSmth(Object arg0, Object arg1); 
    

tôi đã nhìn thấy cả hai phương pháp trong các dự án thực tế và thậm chí cả cựu và sau này trong cùng một dự án. Vì vậy, câu hỏi của tôi là: có bất kỳ lựa chọn thay thế được đề cập có một số lợi thế kỹ thuật hoặc hiệu suất hoặc bảo trì, mà nên khuyến khích chỉ sử dụng một biến thể. Hay có lẽ đó chỉ là vấn đề về hương vị?

+5

Phương thức 'công khai' là một phần của API đối tượng. Phương thức 'nguyên gốc 'là một quyết định thực hiện. Không được hiển thị chi tiết triển khai cho API công khai. Tùy chọn 2 ẩn triển khai khỏi API. – Andreas

+1

Bạn sẽ tìm thấy tùy chọn 2 được sử dụng độc quyền trong JDK, không phải tùy chọn 1. Tôi nghĩ đó là một ý tưởng hay, nó mang lại cho bạn một mức độ tự do khác khi thiết kế và duy trì lớp JNI của bạn. – EJP

+0

Câu hỏi của bạn giả định rằng chữ ký giống nhau. Điều này thường không phải là trường hợp bởi vì những gì tự nhiên cho API của lớp học có thể là rất nhiều công việc trong mã JNI. Trong nhiều trường hợp, việc chuyển đổi các đầu vào và đầu ra đơn giản hơn bằng cách sử dụng Java thành các kiểu dữ liệu dễ dàng hơn trong JNI. –

Trả lời

3

Vì vậy, câu hỏi của tôi là: có bất kỳ giải pháp thay thế nào được đề cập có một số lợi thế về kỹ thuật hoặc hiệu suất hoặc bảo trì, khuyến khích chỉ sử dụng một biến thể.

Lợi thế bảo trì là chìa khóa ở đây. Như đã nêu trong các bình luận, đối tượng phơi bày hành vi của nó. Làm thế nào nó được thực hiện không phải là kinh doanh của người dùng. Điều này giúp bạn linh hoạt hơn.

Giả sử rằng trong tương lai (xem: bảo trì) bạn thấy rằng bạn muốn/cần điều chỉnh phương pháp sao cho nó hoạt động trước và/hoặc sau cuộc gọi gốc. Trong phương pháp đầu tiên, bạn sẽ cần phải ngừng sử dụng phương thức này và tạo phương thức mới. Trong phương pháp thứ hai, bạn chỉ cần thêm bất cứ thứ gì bạn cần trong phương thức và người dùng không quan tâm.

Đối với hiệu suất, về mặt lý thuyết, cách tiếp cận đầu tiên nhanh hơn vì đó là 1 cuộc gọi ít hơn. Trong thực tế, nó hoàn toàn không đáng kể.

+0

Không cần phải từ chối phương thức, vì bạn có thể chỉ cần thay đổi từ biến thể đầu tiên sang biến thể thứ hai mà không cần bất kỳ mã khách hàng nào nhận thấy. Vì vậy, không cần phải sử dụng thứ hai trước khi thực sự là cần thiết. Tất nhiên, nó sẽ yêu cầu biên dịch lại mã nguồn gốc, nhưng điều này phải nằm trong tầm kiểm soát của bạn. – Holger

+0

@ Holger Tôi không hiểu. Trong phương pháp tiếp cận đầu tiên bạn muốn thực hiện các thay đổi trong mã gốc? Những thay đổi tương tự bạn đã thực hiện ở phía Java nếu bạn đang sử dụng phương pháp thứ hai? – user1803551

+0

Không. Khi có nhu cầu trang trí phương thức ở phía Java, bạn chỉ có thể thay đổi biến thể 1 thành biến thể 2, nhận được tất cả lợi ích của biến thể thứ hai. Vì tên của phương thức 'nguyên gốc 'khác nhau ở cả hai biến thể, nên tên của mã gốc phải được điều chỉnh hoặc một đại biểu với tên mới được tạo. Trong cả hai trường hợp, mã gốc sẽ cần phải được biên dịch lại, nhưng không thay đổi đáng kể. – Holger

2

Tôi nghĩ rằng đó chủ yếu là lựa chọn kiểu cá nhân. Nếu bạn xem xét các đoạn mã sau:

rattias-MacBookPro: tst rattias $ diff Test1.cl Test1.class rattias-MacBookPro: tst rattias $ vi Test1.java

public class Test1 { 
    public static void main(String[] args) { 
    Test2 t = new Test2(); 
    t.m(); 
    } 
} 

public class Test2 { 
    public native void m(); 
} 

Biên dịch này tạo ra một Test1.class mà là giống hệt với một tạo ra khi Test2 được định nghĩa như sau:

public class Test2 { 
    public void m() { 
    } 
} 

Điều này có nghĩa rằng bạn có thể thay đổi việc thực hiện được nguồn gốc, java tinh khiết, một java wrapper tinh khiết đến một phương pháp riêng bản xứ, tại bất kỳ thời điểm nào mà không ảnh hưởng đến người dùng. Có thể có câu hỏi về việc liệu toàn bộ hàm API công khai có phải là bản địa hay không, so với chỉ một phần của tính toán, nhưng lại có thể thay đổi tại bất kỳ thời điểm nào.

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