What is a native implementation in Java? [duplicat

2019-01-07 09:34发布

This question already has an answer here:

If we look at the Java Object class then we can find some of the methods like:

public native int hashCode()
protected native Object clone()

What are these natives and how do these methods work?

标签: java jni
5条回答
Root(大扎)
2楼-- · 2019-01-07 09:46

Native methods in Java are implemented using the 'Java Native Interface', known as JNI.

查看更多
The star\"
3楼-- · 2019-01-07 09:48

Native methods are implemented mostly in C and compiled to native code which runs directly on the machine. This is in contrast to normal methods, which are implemented in Java and compiled to Java byte code, which is executed by the Java Virtual Machine (JVM).

To interface to these methods from Java you need to use the Java Native Interface (JNI).

Native code is mostly needed for accessing low-level stuff. In the case of hashCode this is the address of the object in memory. My guess for clone is that it copies the raw memory from a give object to the cloned one. Other uses of native code are for access to OS features or hardware.

The drawback of using native code is that you lose the safety and security of the JVM, i.e. your program might crash or have security holes due to bugs in the native code.

查看更多
干净又极端
4楼-- · 2019-01-07 10:01

What are these natives and how do these methods work?

Minimal example to make things clearer:

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

Compile and run:

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

Output:

4

Tested on Ubuntu 14.04. Also worked with Oracle JDK 1.8.0_45.

Example on GitHub for you to play with.

Interpretation:

It allows you to:

  • call a compiled dynamically loaded library (here written in C) with arbitrary assembly code from Java
  • and get results back into Java

This could be used to:

  • write faster code on a critical section with better CPU assembly instructions (not CPU portable)
  • make direct system calls (not OS portable)

with the tradeoff of lower portability.

It is also possible for you to call Java from C, but you must first create a JVM in C: How to call Java functions from C++?

Example in the OpenJDK 8

Let's find find where Object#clone is defined in jdk8u60-b27.

First we find:

find . -name Object.java

which leads us to jdk/src/share/classes/java/lang/Object.java#l212:

protected native Object clone() throws CloneNotSupportedException;

Now comes the hard part, finding where clone is amidst all the indirection. The query that helped me was:

find . -iname object.c

which would find either C or C++ files that might implement Object's native methods. It leads us to 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]));
}

which leads us to the JVM_Clone symbol:

grep -R JVM_Clone

which leads us to hotspot/src/share/vm/prims/jvm.cpp#l580:

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

After expanding a bunch of macros, we come to the conclusion that this is the definition point.

查看更多
等我变得足够好
5楼-- · 2019-01-07 10:05

These methods are either Intrinsic or written outside Java in "native" code, that is, specific to the given machine.

The ones you mention are Intrinsic and part of the JDK but you can also write native methods yourself using the Java Native Interface (JNI). This would normally use C to write the methods, but a lot of other languages, such as python allow you to write methods this way fairly easily. Code is written this way either for performance, or because it needs to access platform specific infrastructure which cannot be done in plain java.

In the case of hashcode(), this is implemented by the JVM. This is because often the hashcode will be related to something only the JVM knows. On early JVMs this was related to the object's location in memory - on other JVMs the Object may move in memory, and so a more complicated (but still very fast) scheme may be used.

查看更多
女痞
6楼-- · 2019-01-07 10:07

Most native methods are implemented using JNI as mentioned in other answers.

However, performance critical methods such as Object.hashCode are typically implemented as intrinsics. When the byte code is compiled into machine code, the Java compiler recognises the method call and inlines appropriate code directly. This is obviously going to be much faster than going through JNI for a trivial method.

Many people will claim that Object.hashCode will return the address of the object representation in memory. In modern implementations objects actually move within memory. Instead an area of the object header is used to store the value, which may be lazily derived from the memory address at the time that the value is first requested.

查看更多
登录 后发表回答