Trong khi chơi câu đố này (Đó là một trò chơi đố từ khóa Java), tôi đã bắt gặp native
từ khóa này.
Từ khóa gốc trong Java được sử dụng để làm gì?
Trong khi chơi câu đố này (Đó là một trò chơi đố từ khóa Java), tôi đã bắt gặp native
từ khóa này.
Từ khóa gốc trong Java được sử dụng để làm gì?
Câu trả lời:
Các native
từ 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).
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 _1
tê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:
Điều này có thể được sử dụ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 unzip
một .apk
với NDK trên Android O, bạn sẽ nhìn thấy tiền biên dịch .so
tươ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 native
giao 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 native
cuộ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_Clone
biể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.
static
native
phương thức Java, tham số thứ hai của hàm C ++ là kiểu jclass
và không jobject
.
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
currentTimeMillis
là một phần của JDK và chúng được chú thích native
bở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 GetSystemTime
trong 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 native
cho 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.
currentTimeMillis
được đánh dấu là bản địa java.lang.System
để nó sử dụng JNI, phải không?
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ộtnative
phươ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.
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.
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.
native
Phươ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.class
tệ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.class
tệp:
availableProcessors
: được gắn thẻ là thuộc tính gốc và không có MãfreeMemory
: được gắn thẻ là thuộc tính gốc và không có MãtotalMemory
: được gắn thẻ là thuộc tính gốc và không có MãmaxMemory
: được gắn thẻ là thuộc tính gốc và không có Mãgc
: được gắn thẻ là thuộc tính gốc và không có Mã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 C
mã 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
:
Tài liệu tham khảo