JDK最底層源碼,掌握native用法!
???作者簡(jiǎn)介:大家好,我是小虛竹。Java領(lǐng)域優(yōu)質(zhì)創(chuàng)作者??,CSDN博客專家??,華為云享專家??,掘金年度人氣作者??
??技術(shù)活,該賞
??點(diǎn)贊 ?? 收藏 ?再看,養(yǎng)成習(xí)慣
?
場(chǎng)景
有探索欲的同學(xué),應(yīng)該會(huì)跟我一樣,在看JDK源碼時(shí),跟到最后,會(huì)出現(xiàn)native方法,類似下面這個(gè)方法
?/**
?????*?Gets?the?platform?defined?TimeZone?ID.
?????**/
????private?static?native?String?getSystemTimeZoneID(String?javaHome);
看到這個(gè)native ,說(shuō)明已經(jīng)挖到核心了,到了這一步,還是不清楚是怎么獲取系統(tǒng)的默認(rèn)時(shí)區(qū)的,那怎么辦,JDK代碼只能跟到這里。
轉(zhuǎn)戰(zhàn)OpenJDK,源碼下載方式:https://gitee.com/mirrors/openjdk
什么是native
native是一個(gè)計(jì)算機(jī)函數(shù),一個(gè)Native Method就是一個(gè)Java調(diào)用非Java代碼的接口。方法的實(shí)現(xiàn)由非Java語(yǔ)言實(shí)現(xiàn),比如C或C++。
native的源碼怎么看呢
以**private static native String getSystemTimeZoneID(String javaHome)**為例
getSystemTimeZoneID方法所在的package?java.util.TimeZone;
如圖所示,找到TimeZone.c下的getSystemTimeZoneID方法


/*
?*?Gets?the?platform?defined?TimeZone?ID
?*/
JNIEXPORT?jstring?JNICALL
Java_java_util_TimeZone_getSystemTimeZoneID(JNIEnv?*env,?jclass?ign,
????????????????????????????????????????????jstring?java_home,?jstring?country)
{
????const?char?*cname;
????const?char?*java_home_dir;
????char?*javaTZ;
????if?(java_home?==?NULL)
????????return?NULL;
????java_home_dir?=?JNU_GetStringPlatformChars(env,?java_home,?0);
????if?(java_home_dir?==?NULL)
????????return?NULL;
????if?(country?!=?NULL)?{
????????cname?=?JNU_GetStringPlatformChars(env,?country,?0);
????????/*?ignore?error?cases?for?cname?*/
????}?else?{
????????cname?=?NULL;
????}
????/*
?????*?Invoke?platform?dependent?mapping?function
?????*/
????javaTZ?=?findJavaTZ_md(java_home_dir,?cname);
????free((void?*)java_home_dir);
????if?(cname?!=?NULL)?{
????????free((void?*)cname);
????}
????if?(javaTZ?!=?NULL)?{
????????jstring?jstrJavaTZ?=?JNU_NewStringPlatform(env,?javaTZ);
????????free((void?*)javaTZ);
????????return?jstrJavaTZ;
????}
????return?NULL;
}
重點(diǎn):調(diào)用不同平臺(tái)相關(guān)的映射函數(shù)
??/*
?????*?Invoke?platform?dependent?mapping?function
?????*/
????javaTZ?=?findJavaTZ_md(java_home_dir,?cname);
去查找findJavaTZ_md方法時(shí),發(fā)現(xiàn)存在分別在solaris和windows兩個(gè)目錄下。

查了下這兩個(gè)目錄的差別:
因?yàn)镺penJDK里,Java標(biāo)準(zhǔn)庫(kù)和部分工具的源碼repo(jdk目錄)里,BSD和Linux的平臺(tái)相關(guān)源碼都是在solaris目錄里的。
原本Sun JDK的源碼里平臺(tái)相關(guān)的目錄就是從solaris和windows這兩個(gè)目錄開(kāi)始的,后來(lái)Unix系的平臺(tái)相關(guān)代碼全都放在solaris目錄下了,共用大部分代碼。
作者:RednaxelaFX
鏈接:https://www.zhihu.com/question/58982441/answer/170264788
來(lái)源:知乎
「簡(jiǎn)單的理解就是:」
「window系統(tǒng)下,使用windows目錄下編譯的JDK代碼」
「unix相關(guān)的平臺(tái)下,使用solaris目錄下編譯的JDK代碼」
了解不同系統(tǒng)下findJavaTZ_md方法執(zhí)行
windows系統(tǒng)
/*
?*?Detects?the?platform?time?zone?which?maps?to?a?Java?time?zone?ID.
?*/
char?*findJavaTZ_md(const?char?*java_home_dir,?const?char?*country)
{
????char?winZoneName[MAX_ZONE_CHAR];
????char?winMapID[MAX_MAPID_LENGTH];
????char?*std_timezone?=?NULL;
????int??result;
????winMapID[0]?=?0;
????result?=?getWinTimeZone(winZoneName,?winMapID);
????if?(result?!=?VALUE_UNKNOWN)?{
????????if?(result?==?VALUE_GMTOFFSET)?{
????????????std_timezone?=?_strdup(winZoneName);
????????}?else?{
????????????std_timezone?=?matchJavaTZ(java_home_dir,?result,
???????????????????????????????????????winZoneName,?winMapID,?country);
????????}
????}
????return?std_timezone;
}
注釋寫(xiě)得很清楚,獲取“Time Zones”注冊(cè)表中的當(dāng)前時(shí)區(qū)
/*
?*?Gets?the?current?time?zone?entry?in?the?"Time?Zones"?registry.
?*/
static?int?getWinTimeZone(char?*winZoneName,?char?*winMapID)
{
...
}
時(shí)區(qū)的設(shè)置方式:

那時(shí)區(qū)上的選擇值是從哪取到的,上面有說(shuō)了,是在注冊(cè)表中取值
打開(kāi)注冊(cè)表 :Regedit-->
計(jì)算機(jī)\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows?NT\CurrentVersion\Time?Zones\
unix相關(guān)的平臺(tái)
findJavaTz_md()方法的注釋上寫(xiě)得很清楚了:將平臺(tái)時(shí)區(qū)ID映射為Java時(shí)區(qū)ID
/*
?*?findJavaTZ_md()?maps?platform?time?zone?ID?to?Java?time?zone?ID
?*?using?/lib/tzmappings.?If?the?TZ?value?is?not?found,?it
?*?trys?some?libc?implementation?dependent?mappings.?If?it?still
?*?can't?map?to?a?Java?time?zone?ID,?it?falls?back?to?the?GMT+/-hh:mm
?*?form.?`country',?which?can?be?null,?is?not?used?for?UNIX?platforms.
?*/
/*ARGSUSED1*/
char?*
findJavaTZ_md(const?char?*java_home_dir,?const?char?*country)
{
????char?*tz;
????char?*javatz?=?NULL;
????char?*freetz?=?NULL;
????tz?=?getenv("TZ");
#ifdef?__linux__
????if?(tz?==?NULL)?{
#else
#ifdef?__solaris__
????if?(tz?==?NULL?||?*tz?==?'\0')?{
#endif
#endif
????????tz?=?getPlatformTimeZoneID();
????????freetz?=?tz;
????}
????/*
?????*?Remove?any?preceding?':'
?????*/
????if?(tz?!=?NULL?&&?*tz?==?':')?{
????????tz++;
????}
#ifdef?__solaris__
????if?(strcmp(tz,?"localtime")?==?0)?{
????????tz?=?getSolarisDefaultZoneID();
????????freetz?=?tz;
????}
#endif
????if?(tz?!=?NULL)?{
#ifdef?__linux__
????????/*
?????????*?Ignore?"posix/"?prefix.
?????????*/
????????if?(strncmp(tz,?"posix/",?6)?==?0)?{
????????????tz?+=?6;
????????}
#endif
????????javatz?=?strdup(tz);
????????if?(freetz?!=?NULL)?{
????????????free((void?*)?freetz);
????????}
????}
????return?javatz;
}
步驟:
1、使用< Java home>/lib/tzmappings,。如果沒(méi)有找到"TZ"變量,就進(jìn)行第2步
2、 ?tz = getPlatformTimeZoneID(); 執(zhí)行Linux特定的映射,如果找到,返回一個(gè)時(shí)區(qū)ID,否則返回null
【Linux】Centos7修改系統(tǒng)時(shí)區(qū)timezone方式:
timedatectl

修改時(shí)區(qū)
timedatectl??set-timezone?Asia/Shanghai

3、對(duì)比/etc/localtime與"/usr/share/zoneinfo目錄下的文件,如果一致,就返回時(shí)區(qū)ID,沒(méi)有則到第4步
4、返回到GMT

