写点什么

native 关键字作用到底是什么?

发布于: 2020 年 11 月 21 日
native关键字作用到底是什么?

今天一不小心跟进 Object 的源码中,发现一个native关键字,一脸蒙蔽,怎么我从来没有用过。

// 这是计算对象的hsahcode的方法,涉及到内存地址public native int hashCode();
复制代码



1.汇编生c,c生万物,其实 java 要实现对底层的控制,还是需要c/c++帮忙,老大毕竟是老大。


2.native关键字我们开发应用的时候是用不到的,那什么时候用到呢?那些开发 java 语言的时候用到,native关键字是与c++联合开发的时候使用的,要不 java 控制不了底层啊,比如内存。所以还是那句:汇编生c,c生万物,c++c的升级版。


3.这是java调用其他地方的接口的一个声明关键字,意思是这个方法不是 java 实现的,有挺多的编程语言都有这样的特性,比如c++里面使用extern "c"来表示告诉 c++编译器去调用 c 里面已经实现好的函数,而不是自己去实现。native方法有点像java 里面的interface,都不用去实现,而是有别人去实现,但是interface是谁实现接口谁实现,native方法是直接交给c/c++来实现。java只能调用,由操作系统实现。


4.native方法不能与abstract方法一起使用,因为native表示这些方法是有实现体的,但是abstract却表示这些方法是没有实现体的,那么两者矛盾,肯定也不能一起使用。


1.怎么调用到 native 方法的呢?

上面说native表示这个方法不是java实现的,那么就不是原生态方法,也就不会存在这个文件中,而是存在其他地方,那么 java 要怎么调用才能调用到呢?


* JNI(Java Native Interface)这是一个本机编程的接口,它也是 java jdk(开发工具包)的一部分,JNI 可以支持 java 中使用其他语言,java 要调用其他语言的接口,需要经过他处理。java 所谓的跨平台,在一定程度上放弃了底层操作,因为不同的硬件或者操作系统底层的操作都是不一样的。



那么我们现在来写一个程序:helloWorld.java(我的所有写的文件都放在桌面,同个文件夹即可)


public class helloworld{  static  {    System.loadLibrary("cSayHello");  }  public static native void hello();  @SuppressWarnings("static-access")  public static void main(String[] args){    new helloworld().hello();  }}
复制代码

直接在编译器运行这段代码会出现下面错误:




上面的错误是说找不到cSayHello:no cSayHello in java.library.path,所以啊,这个c/c++的方法我们要自己实现,毕竟我们用的不是操作系统以及定义好的方法。

所以我们先来,使用 cmd 在 helloworld.java 所在的目录下 使用命令行:

javac helloworldjavah helloworld
复制代码



然后我们可以看到在 helloworld.java 所在的目录下多了两个文件,一个是 helloworld.class 文件,一个是 helloworld.h 文件。


打开 helloworld.h,里面引用了 jni.h 这个文件,这个文件在我们安装的java目录下面的include文件下:


/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class helloworld */
#ifndef _Included_helloworld#define _Included_helloworld#ifdef __cplusplusextern "C" {#endif/* * Class: helloworld * Method: hello * Signature: ()V */JNIEXPORT void JNICALL Java_helloworld_hello (JNIEnv *, jclass);
#ifdef __cplusplus}#endif#endif
复制代码


我的java是装在D盘下面:



我们来写需要引入的c文件cSayHello,我也是放在桌面,反正同一个文件夹就可以

#include "helloworld.h"#include <stdio.h>JNIEXPORT void JNICALL Javahelloworldhello(JNIEnv *env, jclass jc){    printf("java helloworld");    
}在`windows`系统上,需要下载安装`WinGW Gcc`,安装教程参考https://www.jianshu.com/p/535a3131ccd8, 安装成功`cmd`输入:``` shellgcc -m64 -Wl,--add-stdcall-alias -I"D:\Java\jdk1.8.0_111\include" -I"D:\Java\jdk1.8.0_111\include\win32" -shared -o cSayHello.dll helloworld.c
复制代码

然后直接运行,就可以看到输出了

java helloworld
复制代码


2. java 调用自定义 native 方法步骤

在 java 中使用 native 的步骤:

1.在 java 代码中声明 native 方法

2.执行 javah 来生成一个.h 文件

3.写.cpp 文件来实现 native 导出的方法,需要包含上面第二步产生的.h 文件,同时也包含了 jdk 自带的 jni.h

4.将第三步的.cpp 文件通过 gcc 编译成动态链接库文件

5.在 java 中使用的用 System.loadLibrary()方法加载第四步产生的动态链接库文件,这个 native()方法就可以在 Java 中被访问

一般情况下,我们 jdk 中声明的 native 方法,在编译的时候都会自动去加载动态链接库文件,而不需要我们自己去操作了。


3.使用 native 的缺点

使用 native 的缺点:可移植性差,把对底层的控制权交给其他语言,那么也会出现不稳定性,庆幸的是现在操作系统的底层实现基本不会改变。上面 hsahcode()的计算真是通过内存所在的内存块来计算的,java 是无法直接操作内存的。


【作者简介】

秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界希望一切都很快,更快,但是我希望自己能走好每一步,写好每一篇文章,期待和你们一起交流。


此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者核实删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~


发布于: 2020 年 11 月 21 日阅读数: 27
用户头像

纵使缓慢,驰而不息。 2018.05.17 加入

慢慢走,比较快。公众号:秦怀杂货店

评论

发布
暂无评论
native关键字作用到底是什么?