คำหลักดั้งเดิมใน Java คืออะไร


476

ในขณะที่เล่นปริศนานี้ (เป็นเกมเรื่องไม่สำคัญของ Java) ฉันเจอnativeคำค้นหานั้นแล้ว

คำหลักดั้งเดิมใน Java ใช้ทำอะไร


คำตอบ:


343

nativeคำหลักที่ถูกนำไปใช้วิธีการที่จะแสดงให้เห็นว่าวิธีการที่จะดำเนินการในรหัสพื้นเมืองโดยใช้ JNI (Java อินเตอร์เฟสพื้นเมือง)


3
การใช้งานจริงไม่จำเป็นต้องใช้ JNI วิธีการ JRE บางวิธีได้รับการจัดการภายในโดย JVM ในความเป็นจริงมันไม่ได้บังคับว่าการใช้งานจริงเป็นรหัสพื้นเมือง มันเป็นเพียงแค่“การดำเนินการในภาษาอื่นที่ไม่ใช่ภาษาจาวาภาษาการเขียนโปรแกรม”
Holger

444

ตัวอย่างที่เรียกใช้น้อยที่สุด

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));
    }
}

main.c

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

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

รวบรวมและเรียกใช้:

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

เอาท์พุท:

4

ทดสอบบน Ubuntu 14.04 AMD64 ยังทำงานร่วมกับ Oracle JDK 1.8.0_45

ตัวอย่างบน GitHubเพื่อให้คุณเล่นด้วย

ขีด_1ล่างในชื่อแพคเกจ / ไฟล์ Java จะต้องหลีกเลี่ยงในชื่อฟังก์ชั่น C ตามที่กล่าวไว้ที่: เรียกใช้ฟังก์ชั่น JNI ในชื่อแพคเกจ Android ที่มีขีดล่าง

การตีความ

native ช่วยให้คุณ:

  • เรียกไลบรารีที่โหลดแบบไดนามิกที่คอมไพล์แล้ว (เขียนเป็นภาษา C) ด้วยรหัสแอสเซมบลีโดยพลการจาก Java
  • และรับผลลัพธ์กลับสู่ Java

สิ่งนี้สามารถใช้เพื่อ:

  • เขียนรหัสได้เร็วขึ้นในส่วนที่สำคัญพร้อมกับคำแนะนำการประกอบ CPU ที่ดีกว่า (ไม่ใช่ CPU แบบพกพา)
  • โทรออกระบบโดยตรง (ไม่ใช่ระบบพกพา OS)

กับการแลกเปลี่ยนของการพกพาที่ต่ำกว่า

เป็นไปได้สำหรับคุณที่จะเรียก Java จาก C แต่คุณต้องสร้าง JVM ใน C: วิธีการเรียกฟังก์ชั่น Java จาก C ++?

คล้าย APIs ขยายพื้นเมืองนอกจากนี้ยังมีคนอื่น ๆ ใน "ภาษา VM" หลายคนด้วยเหตุผลเดียวกันเช่นงูหลาม , Node.js , ทับทิม

Android NDK

แนวคิดนี้เหมือนกันทุกประการในบริบทนี้ยกเว้นว่าคุณต้องใช้แผ่นฐานข้อมูล Android เพื่อตั้งค่า

ที่เก็บ NDK อย่างเป็นทางการมีตัวอย่าง "canonical" เช่นแอป hello-jni:

ในตัวคุณกับ NDK บน Android O, คุณสามารถเห็นก่อนรวบรวมที่สอดคล้องกับรหัสพื้นเมืองภายใต้unzip.apk.solib/arm64-v8a/libnative-lib.so

TODO confirm: ยิ่งไปกว่านั้นfile /data/app/com.android.appname-*/oat/arm64/base.odexบอกว่ามันเป็น shared library ซึ่งฉันคิดว่าเป็น AOT ที่คอมไพล์แล้ว. dex ที่สอดคล้องกับไฟล์ Java ใน ART ดูที่: ไฟล์ ODEX ใน Android คืออะไร? ดังนั้นบางที Java อาจทำงานผ่านnativeอินเตอร์เฟซจริงหรือ

ตัวอย่างใน OpenJDK 8

มาหา find ที่Object#cloneกำหนดไว้ใน jdk8u60-b27

เราจะสรุปได้ว่ามันจะดำเนินการกับnativeสาย

ก่อนอื่นเราพบว่า:

find . -name Object.java

ซึ่งนำเราไปสู่jdk / src / share / คลาส / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

ตอนนี้ส่วนที่ยากมาหาที่โคลนอยู่ท่ามกลางทุกทิศทาง แบบสอบถามที่ช่วยฉันคือ:

find . -iname object.c

ซึ่งจะค้นหาไฟล์ C หรือ C ++ ที่อาจใช้วิธีเนทีฟของ Object มันนำเราไปสู่jdk / share / native / 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]));
}

ซึ่งนำเราไปสู่JVM_Cloneสัญลักษณ์:

grep -R JVM_Clone

ซึ่งนำเราไปสู่ฮอตสปอต / src / share / vm / prims / jvm.cpp # l580 :

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

หลังจากขยายมาโครเป็นจำนวนมากเราก็มาถึงข้อสรุปว่านี่คือจุดนิยาม


1
คำตอบที่ยอดเยี่ยม เพียงเชิงอรรถ: หาstatic nativeวิธี Java, พารามิเตอร์ที่สองของฟังก์ชัน c ++ เป็นประเภทและไม่ได้jclass jobject
SR_

@SR_ ขอบคุณสำหรับข้อมูล คำตอบของฉันมีข้อผิดพลาดหรือเป็นเพียงข้อมูลเพิ่มเติมหรือไม่
Ciro Santilli 郝海东冠状病六四事件法轮功

2
@Ciro เป็นข้อมูลเพิ่มเติมสำหรับผู้ที่เริ่มต้นด้วยตัวอย่างของคุณ (คำตอบที่มีประมาณ 300 บน SO อาจใช้เป็นข้อมูลอ้างอิง) ฉันมีฟังก์ชั่นที่มีลายเซ็นไม่ถูกต้องที่เรียกว่ามีระเบียบบนสแต็กโดยไม่มีการรายงานข้อผิดพลาด ดังนั้นฉันคิดว่าเป็นเรื่องสำคัญที่ต้องพูดถึงให้ระมัดระวังในขั้นตอนนี้
SR_

419

มันทำเครื่องหมายวิธีที่มันจะถูกนำมาใช้ในภาษาอื่น ๆ ไม่ได้อยู่ใน Java มันทำงานร่วมกับ JNI (Java Native Interface)

วิธีการแบบเนทีฟถูกใช้ในอดีตเพื่อเขียนส่วนที่สำคัญต่อประสิทธิภาพ แต่ด้วย Java ที่ได้รับเร็วขึ้น วิธีการเนทีฟเป็นสิ่งจำเป็นในปัจจุบันเมื่อ

  • คุณต้องเรียกไลบรารีจาก Java ที่เขียนด้วยภาษาอื่น

  • คุณต้องเข้าถึงระบบหรือทรัพยากรฮาร์ดแวร์ที่สามารถเข้าถึงได้จากภาษาอื่นเท่านั้น (โดยทั่วไปคือ C) ที่จริงแล้วฟังก์ชั่นระบบจำนวนมากที่ทำงานกับคอมพิวเตอร์จริง (เช่นดิสก์และเครือข่าย IO เป็นต้น) ทำได้เพียงเพราะพวกเขาเรียกใช้เนทีฟโค้ด

ดูเพิ่มเติม ข้อมูลจำเพาะ Java Native Interface


3
นี่คือความเข้าใจของฉันฉันเขียน System.currentTimeMillis () (ซึ่งเป็นเจ้าของภาษา) ในไฟล์ java จากนั้นจึงใช้งานได้ JNI จะเรียกไลบรารีหรือฟังก์ชั่นบางอย่างที่เขียนด้วยภาษา C หรือ C ++ หรือภาษาแอสเซมบลี . ตัวอย่าง: วิธี currentTimeMillis ที่นี่จะเรียกใช้รหัสเนทีฟด้วยความช่วยเหลือของ JNI และรหัสเนทีฟพูดถึงทรัพยากรระบบ ex: ตัวจับเวลานั่งบนเมนบอร์ดและทำให้ได้รับค่าส่งคืน (เวลาระบบ) ถูกต้องฉัน
MKod

4
@MKod วิธีการเช่นcurrentTimeMillisเป็นส่วนหนึ่งของ JDK และพวกเขามีข้อเขียนด้วยnativeเพราะการดำเนินการอยู่ในซอร์สโค้ด JDK ตัวเอง ไม่น่าเป็นไปได้มากที่การใช้งานจะใช้ภาษาแอสเซมบลี มันอาจเรียกวิธีการ API ของระบบปฏิบัติการที่ JVM ทำงานอยู่ด้านบน ตัวอย่างเช่นบน Windows อาจเรียกใช้วิธี DLL GetSystemTimeใน kernel32.dll ในระบบปฏิบัติการอื่นมันจะมีการใช้งานที่แตกต่างกัน อย่างไรก็ตามเมื่อคุณใช้nativeสำหรับวิธีการที่คุณเขียน (ซึ่งตรงข้ามกับวิธี JDK) คุณจะต้องให้การใช้งานโดยใช้ JNI
Adam Burley

คำสั่งนี้เป็นสิ่งสำคัญสำหรับคำหลักดั้งเดิม ... 'คุณต้องเข้าถึงระบบหรือทรัพยากรฮาร์ดแวร์ที่เข้าถึงได้จากภาษาอื่นเท่านั้น (โดยทั่วไปคือ C)'
atiqkhaled

@Kidburla ฉันขอสิ่งที่คุณหมายถึงโดย "การใช้งานอยู่ในซอร์สโค้ด JDK ตัวเอง"? currentTimeMillisถูกทำเครื่องหมายว่าเป็นภาษาพื้นเมืองjava.lang.Systemดังนั้นจึงใช้ JNI ใช่ไหม
flow2k

1
@ flow2k ใช่สิ่งที่คุณพูดน่าจะเป็นจริงฉันไม่แน่ใจว่าทำไมฉันถึงบอกว่าในความคิดเห็นของฉัน (มากกว่า 2 ปีที่ผ่านมา)
อดัมเบอร์ลีย์

59

ตรงจากข้อมูลจำเพาะ Java Language :

วิธีการที่nativeนำมาใช้ในรหัสขึ้นอยู่กับแพลตฟอร์มโดยทั่วไปจะเขียนในภาษาการเขียนโปรแกรมอื่นเช่น C, C ++, FORTRAN หรือภาษาแอสเซมบลี เนื้อความของnativeเมธอดถูกกำหนดเป็นเซมิโคลอนเท่านั้นซึ่งบ่งชี้ว่าละเว้นการใช้งานแทนบล็อก


19

ตามที่ SLaks ตอบแล้วnativeคำสำคัญสำหรับการเรียกรหัสเนทีฟ

มันยังใช้โดยGWTสำหรับการใช้วิธีจาวาสคริปต์


13

ฟังก์ชั่นที่ใช้รหัสเนทีฟจะถูกประกาศเนทีฟ

Java Native Interface (JNI) เป็นกรอบการเขียนโปรแกรมที่เปิดใช้งานโค้ด Java ที่ทำงานใน Java Virtual Machine (JVM) ในการโทรและจะถูกเรียกโดยแอพพลิเคชั่นดั้งเดิม (โปรแกรมเฉพาะกับฮาร์ดแวร์และระบบปฏิบัติการแพลตฟอร์ม) และห้องสมุดที่เขียนด้วยภาษา ภาษาอื่นเช่น C, C ++ และชุดประกอบ

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


8

NATIVE เป็นตัวแก้ไขการเข้าถึงที่ไม่สามารถใช้ได้กับวิธีการเท่านั้น มันแสดงให้เห็นถึงการใช้งานวิธีการหรือรหัส PLATFORM - ขึ้นอยู่กับ


6

native คือคีย์เวิร์ดใน java ซึ่งใช้ในการสร้างโครงสร้าง unimplemented (method) เหมือนเป็นนามธรรม แต่มันจะขึ้นอยู่กับแพลตฟอร์มเช่นโค้ดเนมและรันจาก native stack ไม่ใช่ java stack


6
  • native เป็นคำหลักใน java มันบ่งชี้ว่าขึ้นอยู่กับแพลตฟอร์ม
  • nativeเมธอดจะทำหน้าที่เป็นอินเตอร์เฟสระหว่าง Java ( JNI ) และภาษาการเขียนโปรแกรมอื่น ๆ

3

ชวา nativeเมธอดจัดเตรียมกลไกสำหรับโค้ด Java เพื่อเรียกใช้โค้ดเนทีฟระบบปฏิบัติการเนื่องจากเหตุผลด้านการใช้งานหรือประสิทธิภาพ

ตัวอย่าง:

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();

ในRuntime.classไฟล์ที่เกี่ยวข้องใน OpenJDK อยู่ในJAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.classนั้นมีวิธีการเหล่านี้และติดแท็กพวกเขาด้วยACC_NATIVE( 0x0100) และวิธีการเหล่านี้ไม่มีแอตทริบิวต์รหัสซึ่งหมายความว่าวิธีเหล่านี้ไม่มีตรรกะการเข้ารหัสที่แท้จริงในRuntime.classไฟล์:

  • วิธีที่ 13 availableProcessors : แท็กเป็น native และไม่มี Code attribute
  • วิธีที่ 14 freeMemory : แท็กเป็นดั้งเดิมและไม่มีแอตทริบิวต์ของรหัส
  • วิธีที่ 15 totalMemory : แท็กเป็นดั้งเดิมและไม่มีแอตทริบิวต์ของรหัส
  • วิธีที่ 16 maxMemory : แท็กเป็นดั้งเดิมและไม่มีแอตทริบิวต์ของรหัส
  • วิธีที่ 17 gc: แท็กเป็นเนทิฟและไม่มีรหัสคุณลักษณะ

ป้อนคำอธิบายรูปภาพที่นี่

ตรรกะการเข้ารหัสในความเป็นจริงอยู่ในไฟล์Runtime.c ที่สอดคล้องกัน:

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  }

และCการเข้ารหัสเหล่านี้จะถูกรวบรวมเป็นไฟล์libjava.so(Linux) หรือlibjava.dll(Windows) ซึ่งอยู่ที่JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

การอ้างอิง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.