Từ khóa gốc trong Java để làm gì?


Câu trả lời:


343

Các nativetừ khóa được áp dụng cho một phương pháp để chỉ ra rằng phương pháp này được thực hiện trong mã nguồn gốc sử dụng JNI (Java Native Interface).


3
Việc triển khai thực tế không phải sử dụng JNI. Các phương thức JRE nhất định được JVM xử lý nội tại. Trong thực tế, thậm chí không bắt buộc rằng việc triển khai thực sự là mã gốc . Nó chỉ được triển khai bằng một ngôn ngữ khác với ngôn ngữ lập trình Java .
Holger

444

Ví dụ runnable tối thiểu

Main.java

public class Main {
    public native int square(int i);
    public static void main(String[] args) {
        System.loadLibrary("Main");
        System.out.println(new Main().square(2));
    }
}

C chính

#include <jni.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_square(
    JNIEnv *env, jobject obj, jint i) {
  return i * i;
}

Biên dịch và chạy:

sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
  -I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main

Đầu ra:

4

Đã thử nghiệm trên Ubuntu 14.04 AMD64. Cũng đã làm việc với Oracle JDK 1.8.0_45.

Ví dụ trên GitHub để bạn chơi cùng.

Các dấu gạch dưới trong tên tệp / gói của Java phải được thoát bằng _1tên hàm C như đã đề cập tại: Gọi các hàm JNI trong tên gói của Android có chứa dấu gạch dưới

Diễn dịch

native cho phép bạn:

  • gọi một thư viện được tải động được biên dịch (ở đây được viết bằng C) với mã lắp ráp tùy ý từ Java
  • và nhận kết quả trở lại vào Java

Điều này có thể được sử dụng để:

  • viết mã nhanh hơn trên một phần quan trọng với hướng dẫn lắp ráp CPU tốt hơn (không phải CPU di động)
  • thực hiện cuộc gọi hệ thống trực tiếp (không phải hệ điều hành di động)

với sự đánh đổi của tính di động thấp hơn.

Bạn cũng có thể gọi Java từ C, nhưng trước tiên bạn phải tạo JVM trong C: Làm thế nào để gọi các hàm Java từ C ++?

Tương tự như các API mở rộng bản địa cũng có mặt trong nhiều "ngôn ngữ VM" khác vì những lý do tương tự, ví dụ như Python , Node.js , của Ruby .

Android NDK

Khái niệm này hoàn toàn giống nhau trong bối cảnh này, ngoại trừ việc bạn phải sử dụng bản tóm tắt Android để thiết lập nó.

Kho lưu trữ NDK chính thức chứa các ví dụ "chuẩn" như ứng dụng hello-jni:

Trong bạn unzipmột .apkvới NDK trên Android O, bạn sẽ nhìn thấy tiền biên dịch .sotương ứng với mã gốc dưới lib/arm64-v8a/libnative-lib.so.

TODO xác nhận: Hơn nữa, file /data/app/com.android.appname-*/oat/arm64/base.odex, nói nó là một thư viện chia sẻ, mà tôi nghĩ là AOT precompiled .dex tương ứng với các file Java trong ART, xem thêm: file Odex trong Android là gì? Vì vậy, có lẽ Java thực sự cũng chạy qua một nativegiao diện?

Ví dụ trong OpenJDK 8

Hãy tìm tìm nơi Object#cloneđược định nghĩa trong jdk8u60-B27.

Chúng tôi sẽ kết luận rằng nó được thực hiện với một nativecuộc gọi.

Đầu tiên chúng tôi tìm thấy:

find . -name Object.java

mà dẫn chúng ta đến jdk / src / share / lớp / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Bây giờ đến phần khó khăn, tìm nơi bản sao là giữa tất cả các tình huống. Truy vấn giúp tôi là:

find . -iname object.c

sẽ tìm thấy các tệp C hoặc C ++ có thể triển khai các phương thức gốc của Object. Nó dẫn chúng ta đến jdk / share / igen / java / lang / Object.c # l47 :

static JNINativeMethod methods[] = {
    ...
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

dẫn chúng ta đến JVM_Clonebiểu tượng:

grep -R JVM_Clone

dẫn chúng tôi đến hotspot / src / share / vm / prims / jvm.cpp # l580 :

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
    JVMWrapper("JVM_Clone");

Sau khi mở rộng một loạt các macro, chúng tôi đi đến kết luận rằng đây là điểm định nghĩa.


1
Câu trả lời tuyệt vời. Chỉ là một chú thích: đối với một static nativephương thức Java, tham số thứ hai của hàm C ++ là kiểu jclassvà không jobject.
SR_

@SR_ cảm ơn vì thông tin. Có một lỗi trong câu trả lời của tôi, hoặc nó chỉ là một số thông tin bổ sung?
Ciro Santilli 郝海东 冠状 病 事件 法轮功

2
@Ciro đó là một số thông tin bổ sung cho những người bắt đầu với ví dụ của bạn (câu trả lời với khoảng 300 trên SO có thể dùng làm tài liệu tham khảo). Tôi đã có một hàm có chữ ký không chính xác được gọi với một mớ hỗn độn trên ngăn xếp, không có lỗi nào được báo cáo (tại bất kỳ thời gian biên dịch, liên kết hoặc thời gian chạy nào). Vì vậy, tôi thấy điều quan trọng cần đề cập là phải cẩn thận trong bước này.
SR_

419

Nó đánh dấu một phương thức, rằng nó sẽ được thực hiện bằng các ngôn ngữ khác, không phải bằng Java. Nó hoạt động cùng với JNI (Giao diện gốc Java).

Các phương thức gốc đã được sử dụng trong quá khứ để viết các phần quan trọng về hiệu năng nhưng với Java ngày càng nhanh hơn thì điều này bây giờ ít phổ biến hơn. Phương pháp bản địa hiện đang cần khi

  • Bạn cần gọi một thư viện từ Java được viết bằng ngôn ngữ khác.

  • Bạn cần truy cập tài nguyên hệ thống hoặc phần cứng chỉ có thể truy cập từ ngôn ngữ khác (thường là C). Trên thực tế, nhiều chức năng hệ thống tương tác với máy tính thực (ví dụ IO đĩa và mạng) chỉ có thể thực hiện việc này vì chúng gọi mã gốc.

Xem thêm Đặc tả giao diện gốc Java


3
Theo hiểu biết của tôi, tôi viết System.cienTimeMillis () (có nguồn gốc) trong tệp java và sau đó, nó sẽ hoạt động, JNI sẽ gọi các thư viện hoặc một số hàm được viết bằng C hoặc C ++ hoặc ngôn ngữ hợp ngữ và sau đó trả lại một số giá trị cho mã java của tôi . ví dụ: ở đây phương thức currentTimeMillis gọi mã gốc với sự trợ giúp của JNI và mã gốc đó nói chuyện với tài nguyên hệ thống ex: bộ đếm thời gian ngồi trên bo mạch chủ và do đó nhận được giá trị trả về (thời gian hệ thống). Làm ơn sửa cho tôi?
MKod

4
Các phương thức @MKod giống như currentTimeMillislà một phần của JDK và chúng được chú thích nativebởi vì việc triển khai nằm trong chính mã nguồn JDK. Rất khó có khả năng triển khai sử dụng ngôn ngữ lắp ráp; nó có thể gọi một phương thức API của hệ điều hành mà JVM đang chạy trên đầu trang. Ví dụ: trên Windows, nó có thể gọi một phương thức DLL GetSystemTimetrong kernel32.dll. Trên một hệ điều hành khác, nó sẽ có một triển khai khác. Tuy nhiên, khi bạn sử dụng nativecho một phương thức bạn đang viết (trái ngược với phương thức JDK), bạn phải cung cấp việc triển khai bằng JNI.
Adam Burley

Tuyên bố này là câu hỏi quan trọng đối với từ khóa gốc ... 'Bạn cần truy cập tài nguyên phần cứng hoặc hệ thống chỉ có thể truy cập từ ngôn ngữ khác (thường là C)'.
atiqkhaled

@Kidburla Tôi có thể hỏi ý bạn là gì khi "triển khai trong chính mã nguồn JDK" không? currentTimeMillisđược đánh dấu là bản địa java.lang.Systemđể nó sử dụng JNI, phải không?
Flow2k

1
@ Flow2k vâng, những gì bạn đã nói có lẽ là sự thật, tôi không chắc tại sao tôi lại nói như vậy trong nhận xét của tôi (hơn 2 năm trước)
Adam Burley

59

Trực tiếp từ các kỹ thuật Java Ngôn ngữ :

Một phương thức nativeđược triển khai theo mã phụ thuộc nền tảng, thường được viết bằng ngôn ngữ lập trình khác như C, C ++, FORTRAN hoặc ngôn ngữ hợp ngữ. Phần thân của một nativephương thức được đưa ra dưới dạng dấu chấm phẩy, chỉ ra rằng việc thực hiện bị bỏ qua, thay vì một khối.


19

Như SLaks đã trả lời, nativetừ khóa là để gọi mã gốc.

Nó cũng được sử dụng bởi GWT để thực hiện các phương thức javascript.


13

các hàm thực hiện mã gốc được khai báo riêng.

Giao diện gốc Java (JNI) là một khung lập trình cho phép mã Java chạy trong Máy ảo Java (JVM) để gọi và được gọi bởi các ứng dụng gốc (các chương trình dành riêng cho nền tảng hệ điều hành và phần cứng) và các thư viện được viết bằng các ngôn ngữ khác như C, C ++ và lắp ráp.

http://en.wikipedia.org/wiki/Java_Native_Interface


8

NATIVE là không truy cập modifier.it chỉ có thể được áp dụng cho PHƯƠNG PHÁP. Nó chỉ ra việc thực hiện PLATFORM-DEPENDENT của phương thức hoặc mã.


6

bản địa là một từ khóa trong java, được sử dụng để làm cho cấu trúc (phương thức) chưa được thực hiện giống như trừu tượng nhưng nó sẽ là một nền tảng phụ thuộc như mã gốc và thực thi từ ngăn xếp gốc chứ không phải ngăn xếp java.


6
  • native là một từ khóa trong java, nó chỉ ra nền tảng phụ thuộc.
  • nativecác phương thức đóng vai trò là giao diện giữa Java ( JNI ) và các ngôn ngữ lập trình khác.

3

nativePhương thức Java cung cấp một cơ chế cho mã Java để gọi mã gốc của hệ điều hành, vì lý do chức năng hoặc hiệu năng.

Thí dụ:

606  public native int availableProcessors();
617  public native long freeMemory();
630  public native long totalMemory();
641  public native long maxMemory();
664  public native void gc();

Trong Runtime.classtệp tương ứng trong OpenJDK, nằm trong JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, chứa các phương thức này và được gắn thẻ chúng với ACC_NATIVE( 0x0100) và các phương thức này không chứa thuộc tính Code , có nghĩa là các phương thức này không có logic mã hóa thực tế nào trong Runtime.classtệp:

  • Phương pháp 13 availableProcessors: được gắn thẻ là thuộc tính gốc và không có Mã
  • Phương pháp 14 freeMemory: được gắn thẻ là thuộc tính gốc và không có Mã
  • Phương thức 15 totalMemory: được gắn thẻ là thuộc tính gốc và không có Mã
  • Phương pháp 16 maxMemory: được gắn thẻ là thuộc tính gốc và không có Mã
  • Phương pháp 17 gc: được gắn thẻ là thuộc tính gốc và không có Mã

nhập mô tả hình ảnh ở đây

Thực tế logic mã hóa nằm trong tệp Runtime.c tương ứng :

42  #include "java_lang_Runtime.h"
43
44  JNIEXPORT jlong JNICALL
45  Java_java_lang_Runtime_freeMemory(JNIEnv *env, jobject this)
46  {
47      return JVM_FreeMemory();
48  }
49
50  JNIEXPORT jlong JNICALL
51  Java_java_lang_Runtime_totalMemory(JNIEnv *env, jobject this)
52  {
53      return JVM_TotalMemory();
54  }
55
56  JNIEXPORT jlong JNICALL
57  Java_java_lang_Runtime_maxMemory(JNIEnv *env, jobject this)
58  {
59      return JVM_MaxMemory();
60  }
61
62  JNIEXPORT void JNICALL
63  Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
64  {
65      JVM_GC();
66  }
67  
68  JNIEXPORT jint JNICALL
69  Java_java_lang_Runtime_availableProcessors(JNIEnv *env, jobject this)
70  {
71      return JVM_ActiveProcessorCount();
72  }

Và các Cmã hóa này được biên dịch thành tệp libjava.so(Linux) hoặc libjava.dll(Windows), đặt tại JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Tài liệu tham khảo

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.