Introduction
I believe that every programmer has a dream of becoming a C++ master. After all, a C++ programmer is at the top of the programmer's contempt chain, and he can look down on programmers in any other language.
But the fact is that countless programmers from beginners to give up, in view of the difficulty of C++, finally put into the arms of java. JAVA has accepted a group of programmers who cannot reach the top of C++ with his broad mind.
Just kidding, the advantage of C and C++ lies in the interaction with the bottom layer of the system and the speed and efficiency of its operation. The advantage of JAVA lies in the extensive application framework, which can quickly build the required applications. Both have their strengths.
The advantage of the framework is that it reduces the difficulty of program development and allows applications to be quickly replicated in batches.
As we all know, the bottom layer of the JVM is written in C and C++, and the JAVA bytecode is suitable for JVM interaction, so intuitively, JAVA can interact with the underlying C++ code. So how to interact? Will it be complicated?
Today, this article will take you to reveal them one by one.
JDK native methods
The so-called native methods are methods that call the operating system or other underlying libraries. These methods belong to the external interface of the system and are used for interaction between the program and the operating system. Think about it, what are the native methods in the JDK?
The first thing that comes to mind should be file operations, because file operations must depend on the IO interface provided by the bottom layer of the system. Let's first look at the implementation of File's delete method:
public boolean delete() {
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkDelete(path);
}
if (isInvalid()) {
return false;
}
return fs.delete(this);
}
The delete method of File first calls SecurityManager to judge the permissions to see if it can be deleted. If it can be deleted, continue to call the delete method of FileSystem.
We continue to look at the delete method of FileSystem:
public abstract boolean delete(File f);
You can see that the delete method in FileSystem is an abstract method that requires a concrete implementation.
And this implementation is related to the platform. If you are a linux or mac system, then its implementation class is UnixFileSystem, and its delete method is as follows:
public boolean delete(File f) {
if (useCanonCaches) {
cache.clear();
}
if (useCanonPrefixCache) {
javaHomePrefixCache.clear();
}
return delete0(f);
}
private native boolean delete0(File f);
It can be seen that the delete method will eventually call the delete0 method, and this method is a native method, indicating that the method needs to call the system local method.
JDK provides an implementation of JAVA calling local system methods, called JNI, the full name is Java Native Interface, which is a technology introduced from JAVA1.1. It allows Java code to interact with code written in other languages.
In order to verify the feasibility of JNI, we next implement a native method and call it in java to see if it can be successful.
custom native method
Defining a native method in JAVA is very simple. We only need to add the native keyword in front of the method description. This method does not require any implementation. A specific example is as follows:
public class JNIUsage {
public native void printMsg();
public static void main(String[] args) {
//加载C文件
System.loadLibrary("JNIUsage");
JNIUsage jniUsage = new JNIUsage();
jniUsage.printMsg();
}
}
In the above example, we define a native printMsg, and then first load the Library file containing the implementation in main, and then call it like a normal JAVA method.
So how to implement this native method?
Friends who are familiar with or not familiar with C++ should have heard the concept of header file. Generally speaking, we define the method to be implemented in the header file, and then implement the method defined in the header file in the specific content file.
So the header file needs to include the printMsg method, and the javah command can be used to generate the header file.
First go to the root directory of the JNIUsage source file and run the following command:
javah -classpath . -jni com.flydean.JNIUsage
This command generates a com_flydean_JNIUsage.h file in the root directory of the project source code. Open it and see, the specific content is as follows:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_flydean_JNIUsage */
#ifndef _Included_com_flydean_JNIUsage
#define _Included_com_flydean_JNIUsage
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_flydean_JNIUsage
* Method: printMsg
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_flydean_JNIUsage_printMsg
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
To put it simply, the head file defines a Java_com_flydean_JNIUsage_printMsg method that needs to be implemented.
Next, we need to implement this header file.
Here we use JetBrain's Clion development tool, first create a C++ project:
Note that the type of this item needs to be a shared type.
Then copy the com_flydean_JNIUsage.h file to the root directory of the project.
At this time, it cannot be compiled, and you will find many errors in dependent packages. We also need to put the jni.h file and jni_md.h file in the include directory in the JDK home directory (if it is a windows platform, the file is in the win32 directory, If it is a mac platform, the file is in the darwin directory) and copied to the root directory of the project.
This way the compilation errors are gone.
Finally, we modify the default library.cpp file, introduce com_flydean_JNIUsage.h and implement the method as follows:
#include "com_flydean_JNIUsage.h"
#include <iostream>
JNIEXPORT void JNICALL Java_com_flydean_JNIUsage_printMsg
(JNIEnv *, jobject){
printf("this is www.flydean.com!");
}
So far, the code structure of the project should look like this:
<img src="https://img-blog.csdnimg.cn/ee0512f8cab94d47ae8a13fd6a062e92.png" style="zoom:50%"/>
Then build-->Build 'JNIUsage', generate the libJNIUsage.dylib file:
====================[ Build | JNIUsage | Debug ]================================
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build /Users/flydean/data/git/cplus/JNIUsage/cmake-build-debug --target JNIUsage
[2/2] Linking CXX shared library libJNIUsage.dylib
Build finished
With libJNIUsage.dylib, we also need to add it to the path in the JAVA project:
<img src="https://img-blog.csdnimg.cn/f5b938e8a753482d86fc792e870b8fe7.png" style="zoom:50%"/>
Select the java-jni module, select JARs or Directories in the dependencies, and select the libJNIUsage.dylib directory just now.
After saving, you can run the JAVA code, and the results are as follows:
/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home/bin/java -Djava.library.path=/Users/flydean/data/git/cplus/JNIUsage/cmake-build-debug -Dfile.encoding=UTF-8 -classpath /Users/flydean/data/git/learn-java-base-9-to-20/java-jni/target/classes: com.flydean.JNIUsage
this is www.flydean.com!
Or you can add libJNIUsage.dylib to the classpath where java runs on the command line.
Summarize
The above is a simple example of calling native methods using JAVA. As you can see, the steps are quite complicated, so is there any other simpler way to let JAVA call the native method? Yes, this is JNA, and we will introduce it in depth in subsequent articles.
The code of this article can refer to https://github.com/ddean2009/learn-java-base-9-to-20.git
This article has been included in http://www.flydean.com/01-jni-overview/
The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!
Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。