Java基础-基础语法-native方法

Java工程师知识树 / Java基础

概念

native是一个计算机函数,一个Native Method就是一个Java调用非Java代码的接口。方法的实现由非Java语言实现,比如C或C++。

JDK中如何运行native方法

首先举个例子看一下在JDK中如何运行native方法的

    1. java源码中的native方法是不能直接在jdk中看到的,因为jdk不是开源的,要看到的话需要sun授权才行,现在只有openjdk是被sun公司授权,所以要查看的话,下载完整的OpenJDK源码包
    1. 下载或查看完整的OpenJDK源码
      官网:OpenJDK
      Java基础-基础语法-native方法_第1张图片
      image.png

      Java基础-基础语法-native方法_第2张图片
      image.png

      Java基础-基础语法-native方法_第3张图片
      image.png

      Java基础-基础语法-native方法_第4张图片
      image.png
    1. 找一个JDK中使用native方法的实例
TimeZone.getDefault();//Java读取默认时区  java.util.TimeZone

class文件中的源码为

  public static TimeZone getDefault() {
      return (TimeZone) getDefaultRef().clone();// 第一步
  }
 ...
static TimeZone getDefaultRef() {
        TimeZone defaultZone = defaultTimeZone;
        if (defaultZone == null) {
            // Need to initialize the default time zone.
            defaultZone = setDefaultZone();// 如果没有设置时区的话 第二步
            assert defaultZone != null;
        }
        // Don't clone here.
        return defaultZone;
    }

    private static synchronized TimeZone setDefaultZone() {
        TimeZone tz;
        // get the time zone ID from the system properties
        String zoneID = AccessController.doPrivileged(
                new GetPropertyAction("user.timezone"));

        // if the time zone ID is not set (yet), perform the
        // platform to Java time zone ID mapping.
        if (zoneID == null || zoneID.isEmpty()) {
            String javaHome = AccessController.doPrivileged(
                    new GetPropertyAction("java.home"));
            try {
                zoneID = getSystemTimeZoneID(javaHome);// 如果没有设置时区的话 第三步
                if (zoneID == null) {
                    zoneID = GMT_ID;
                }
            } catch (NullPointerException e) {
                zoneID = GMT_ID;
            }
        }

        // Get the time zone for zoneID. But not fall back to
        // "GMT" here.
        tz = getTimeZone(zoneID, false);

        if (tz == null) {
            // If the given zone ID is unknown in Java, try to
            // get the GMT-offset-based time zone ID,
            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
            String gmtOffsetID = getSystemGMTOffsetID();
            if (gmtOffsetID != null) {
                zoneID = gmtOffsetID;
            }
            tz = getTimeZone(zoneID, true);
        }
        assert tz != null;

        final String id = zoneID;
        AccessController.doPrivileged(new PrivilegedAction() {
            @Override
                public Void run() {
                    System.setProperty("user.timezone", id);
                    return null;
                }
            });

        defaultTimeZone = tz;
        return tz;
    }
...
    /**
     * Gets the platform defined TimeZone ID.
     **/
    private static native String getSystemTimeZoneID(String javaHome);

第三步中调用的getSystemTimeZoneID(String javaHome)这个方法就是native方法.

-4. 通过OpenJDK查看下getSystemTimeZoneID这个方法是什么

Java基础-基础语法-native方法_第5张图片
jdk.png

Java基础-基础语法-native方法_第6张图片
share 平台无关的共通代码.png

Java基础-基础语法-native方法_第7张图片
image.png

然后根据java.util.TimeZone的路径找到对应的native包下的信息


Java基础-基础语法-native方法_第8张图片
image.png

Java基础-基础语法-native方法_第9张图片
image.png

在java层面我们仅仅须要dll文件,.c文件的目的仅仅是为了生成dll文件.
这个时候回头看下整个流程:

  • 执行TimeZone.getDefault();
  • JVM加载TimeZone字节码到内存,同时因为getSystemTimeZoneID(String javaHome)方法描述符内有native,这个描述符块将有一个指向该方法的实现的指针;
  • src/share/native/java/util/TimeZone.c文件编译后生成DLL文件,而方法的实现就在这个DLL文件中;
  • 在执行getSystemTimeZoneID(String javaHome)方法的同时DLL文件会被操作系统加载到java程序的地址空间;
  • JVM完成对Java外的环境交互.

总结:

JVM如何运行Native方法

一个类第一次被使用到时,这个类的字节码会被加载到内存,并且只会加载一次。在这个被加载的字节码的入口维持着一个该类所有方法描述符的list,这些方法描述符包含这样一些信息:方法代码存于何处,它有哪些参数,方法的描述符(public之类)等等。

如果一个方法描述符内有native,这个描述符块将有一个指向该方法的实现的指针;这些实现在一些DLL文件内,但是它们会被操作系统加载到java程序的地址空间;
当一个带有本地方法的类被加载时,其相关的DLL并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些DLL才会被加载,这是通过调用java.system.loadLibrary()实现的。

为什么需要Native方法呢

  • 有些功能Java实现不易.比如读取默认时区,使用Java实现是不太容易的.
  • 使用C语言或者C++等其他语言执行效率会更高

你可能感兴趣的:(Java基础-基础语法-native方法)