亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于jdk1.8的Java源碼詳解 Integer

 更新時(shí)間:2019年06月18日 08:52:32   作者:rainple  
這篇文章主要介紹了基于jdk1.8的Java源碼詳解 Integer,Integer是int的Warpper類,是面向?qū)ο蟮募碠OP的對(duì)象類型,,需要的朋友可以參考下
public final class Integer extends Number implements Comparable<Integer>

Integer 由final修飾了,所以該類不能夠被繼承,同時(shí) Integer 繼承了Number類,因此可以將Integer轉(zhuǎn)換成 int 、double、float、long、byte和short類型的數(shù)據(jù),另外,也實(shí)現(xiàn)了comparable接口,因此Integer類也可以進(jìn)行自然排序。

構(gòu)造方法只有兩個(gè):

public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}

我們主要看第二個(gè)構(gòu)造方法,傳入一個(gè)字符串,然后調(diào)用parseInt方法,接下來進(jìn)入parseInt的源碼:

public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
// //是否為負(fù)數(shù)
boolean negative = false;
int i = 0, len = s.length();
//這里加個(gè)負(fù)號(hào)是防止數(shù)據(jù)溢出,int的數(shù)值范圍 -2的31次方到2的31次方減一
int limit = -Integer.MAX_VALUE;
//最小基數(shù)
int multmin;
//十進(jìn)制數(shù)字
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
//第一個(gè)字符小于0,有可能是"-","+"或其他字符
if (firstChar < '0') { // Possible leading "+" or "-"
//為負(fù)數(shù)
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')//非數(shù)字
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
/**
* 最小基數(shù),主要防止 result *= radix; 這個(gè)操作時(shí)數(shù)據(jù)過大
* 導(dǎo)致數(shù)據(jù)丟失的問題,因?yàn)樗詭Х?hào)32位int類型整數(shù)為-2147483648~2147483647
*/
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
//轉(zhuǎn)換十進(jìn)制,這里獲取的是radix進(jìn)制下相對(duì)應(yīng)的10進(jìn)制數(shù)字,如:
//Character.digit('a',16),則返回 10;
//若輸入字符不在進(jìn)制的范圍之內(nèi),則返回 -1:
//Character.digit('t',16),返回 -1,Character.digit('a',10),返回 -1
digit = Character.digit(s.charAt(i++),radix);
//返回-1說明字符非法
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
//超過了數(shù)據(jù)范圍
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
/**
*在轉(zhuǎn)換時(shí)從高位向地位方向轉(zhuǎn)換
*/
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}

這個(gè)方法中最核心的步驟是1、result *= radix; 2、result -= digit; 經(jīng)過這兩個(gè)步驟將字符串轉(zhuǎn)換成數(shù)值類型。大概流程是這樣的:

  1. 假如字符串"1234" 轉(zhuǎn)換成int類型,result 的初始值為0,radix默認(rèn)為10;
  2. 首先截取字符串的第一個(gè)字符1(這里忽略各種檢查),經(jīng)過第一步計(jì)算 result = 0*10 = 0;第二部計(jì)算 result = 0 - 1 = -1;
  3. 第一遍循環(huán)結(jié)束后,result 的值 變成了 -1
  4. 截取第二個(gè)字符 2 ,result = -1 * 10 = -10,result = -10 - 2 = -12;
  5. 截取第三個(gè)字符 3 ,result = -12 * 10 = -120,result = -120 - 3 = -123;
  6. 截取第四個(gè)字符 4 ,result = -123 * 10 = -1230 ,result = -1230-4 = -1234;
  7. 循環(huán)結(jié)束,此時(shí)result的值為 -1234,完成字符串向整數(shù)型的轉(zhuǎn)換,返回是取反即可。

面我將從一個(gè)面試題引出問題,然后通過閱讀源碼來解決這個(gè)問題。

public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
Integer i5 = Integer.valueOf(100);
Integer i6 = Integer.valueOf(100);
Integer i7 = new Integer(100);
System.out.println("i1 == i2 的結(jié)果是:" + (i1 == i2));
System.out.println("i3 == i4 的結(jié)果是:" + (i3 == i4));
System.out.println("i5 == i6 的結(jié)果是:" + (i5 == i6));
System.out.println("i1 == i5 的結(jié)果是:" + (i1 == i5));
System.out.println("i1 == i7 的結(jié)果是:" + (i1 == i7));
}

運(yùn)行結(jié)果為:

i1 == i2 的結(jié)果是:true
i3 == i4 的結(jié)果是:false
i5 == i6 的結(jié)果是:true
i1 == i5 的結(jié)果是:true
i1 == i7 的結(jié)果是:false

我們先來看第一和第二條結(jié)果,同樣是比較兩個(gè)相同數(shù)值,為什么會(huì)有不同的結(jié)果呢?接下我將通過源碼來解釋原因。

首先,我們通過編譯獲取到class文件的字節(jié)碼

從圖中我們可以看到,在執(zhí)行 Integer i1 = 100 這條命令的時(shí)候,編譯器會(huì)調(diào)用Integer中的靜態(tài)方法 valueOf,接下來我們看看 valueOf方法是怎么實(shí)現(xiàn)的吧。

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

這個(gè)代碼看起來很簡(jiǎn)單,Integer 中有一個(gè)靜態(tài)內(nèi)部類 IntegerCache,調(diào)用該方法時(shí)首先會(huì)判斷該值是否在緩存的范圍內(nèi),如果在則直接將緩存中的數(shù)值返回,否則返回一個(gè)新對(duì)象。看到這里我們似乎已經(jīng)知道了上面的問題的答案了,接下來繼續(xù)看靜態(tài)內(nèi)部類吧

private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
//緩存范圍最?。ㄒ彩悄J(rèn)范圍)為 (-128)~ 127,如果配置java.lang.Integer.IntegerCache.high
//high 的值可從配置文件中讀取
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
//獲取配置文件和127之間的最大值
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
//最大值范圍
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
//創(chuàng)建緩存數(shù)組
cache = new Integer[(high - low) + 1];
int j = low;
//將數(shù)字緩存起來默認(rèn) -128 ~ 127
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}

我們知道內(nèi)部類只有在所在類實(shí)例化時(shí)才會(huì)被實(shí)例化,而且只會(huì)實(shí)例化一次,緩存操作是在靜態(tài)代碼塊中完成,也就是說在類被實(shí)例化的時(shí)候數(shù)據(jù)就已經(jīng)被緩存好了,接下使用的時(shí)候可以直接使用緩存的數(shù)據(jù)。

現(xiàn)在我們回歸到上面的問題,結(jié)果1中兩個(gè)數(shù)據(jù)均為 100,在緩存的范圍中,因此i1和i2都指向的是同一個(gè)內(nèi)存地址,因此返回true。結(jié)果2中 兩個(gè)數(shù)都是200,超出了緩存的范圍,所以直接new 出了兩個(gè)對(duì)象,因此他們的內(nèi)存地址不一致,返回結(jié)果為false;另外,使用valueOf 和 使用 = 操作符賦值時(shí)一樣的,所以結(jié)果3和結(jié)果4返回結(jié)果為 true,結(jié)果5中 是直接使用new關(guān)鍵字創(chuàng)建對(duì)象,所以他們的內(nèi)存地址肯定不一致,結(jié)果為false。

那么,現(xiàn)在問題又來了,那我怎么判斷兩個(gè)整數(shù)的大小呢?繼續(xù)看源碼

/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public int intValue() {
return value;
}

是的,沒錯(cuò),比較兩個(gè)數(shù)值大小時(shí)可以使用equals方法來比較,源碼中value的類型為 int型,intValue返回的也是value,因此可以判斷兩個(gè)數(shù)的大小。

public static void main(String[] args) {
Integer i1 = 200;
Integer i2 = 200;
System.out.println("i1 == i2 的結(jié)果是:" + i1.equals(i2)); //true
}

補(bǔ)充:equals 與 == 的區(qū)別:

equals 比較的是兩個(gè)數(shù)值的大小,== 有兩種情況,如果比較的是 基本數(shù)據(jù)類型,則 == 跟equals一樣都是比較的大小,如果是引用類型或數(shù)組,則比較是內(nèi)存地址。

getChars方法:

static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;

if (i < 0) {
sign = '-';
i = -i;
}

// Generate two digits per iteration
//每次循環(huán)獲取后兩位數(shù)
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
//使用位移運(yùn)算的效率高于乘法運(yùn)算,r為后兩位數(shù)
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
//獲取后兩位數(shù)的個(gè)位
buf [--charPos] = DigitOnes[r];
//十位
buf [--charPos] = DigitTens[r];
}

// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
//每次只取個(gè)位數(shù)
for (;;) {
//相當(dāng)于i*(52429/524288)=i*0.10000038146972656=i*0.1=i/10
//這里選 52429 和 2的19次方相除,得到的結(jié)果精度更加高,更加接近于 i/10的結(jié)果
//之所以要這樣轉(zhuǎn)換,是因?yàn)樵谟?jì)算機(jī)運(yùn)算中位移的效率 > 乘法效率 > 除法效率
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例

    RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2022-08-08
  • Spring整合Struts2的兩種方法小結(jié)

    Spring整合Struts2的兩種方法小結(jié)

    下面小編就為大家?guī)硪黄猄pring整合Struts2的兩種方法小結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • java中抽象類和接口的相同和不同點(diǎn)介紹

    java中抽象類和接口的相同和不同點(diǎn)介紹

    大家好,本篇文章主要講的是java中抽象類和接口的相同和不同點(diǎn)介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • java打包成可執(zhí)行的jar或者exe的詳細(xì)步驟

    java打包成可執(zhí)行的jar或者exe的詳細(xì)步驟

    Java程序完成以后,對(duì)于Windows操作系統(tǒng),習(xí)慣總是想雙擊某個(gè)exe文件就可以直接運(yùn)行程序,現(xiàn)我將一步一步的實(shí)現(xiàn)該過程.最終結(jié)果是:不用安裝JRE環(huán)境,不用安裝數(shù)據(jù)庫(kù),直接雙擊一個(gè)exe文件,就可以運(yùn)行程序
    2014-04-04
  • Java?OpenCV圖像處理之背景切換

    Java?OpenCV圖像處理之背景切換

    這篇文章主要介紹了利用Java?OpenCV實(shí)現(xiàn)圖像背景的切換,文中的示例代碼講解詳細(xì)。對(duì)我們學(xué)習(xí)OpenCV有一定幫助,感興趣的同學(xué)可以了解一下
    2022-01-01
  • Java字符串格式化,{}占位符根據(jù)名字替換實(shí)例

    Java字符串格式化,{}占位符根據(jù)名字替換實(shí)例

    這篇文章主要介紹了Java字符串格式化,{}占位符根據(jù)名字替換實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java異常處理學(xué)習(xí)心得

    Java異常處理學(xué)習(xí)心得

    本篇文章給大家詳細(xì)講述了學(xué)習(xí)Java異常處理學(xué)習(xí)的心得以及原理介紹,對(duì)此有興趣的朋友參考下吧。
    2018-01-01
  • Java8 Lambda表達(dá)式詳解及實(shí)例

    Java8 Lambda表達(dá)式詳解及實(shí)例

    這篇文章主要介紹了Java8 Lambda表達(dá)式詳解的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • mybatis update set 多個(gè)字段實(shí)例

    mybatis update set 多個(gè)字段實(shí)例

    這篇文章主要介紹了mybatis update set 多個(gè)字段實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • SpringBoot指標(biāo)監(jiān)控的實(shí)現(xiàn)

    SpringBoot指標(biāo)監(jiān)控的實(shí)現(xiàn)

    本文主要介紹了SpringBoot指標(biāo)監(jiān)控的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評(píng)論