一元運(yùn)算符之正負(fù)號(hào)
Java支持多種一元運(yùn)算符,一元運(yùn)算符中的“一元”是指一個(gè)操作數(shù)。我們初中學(xué)過(guò)的正負(fù)號(hào)就屬于一元運(yùn)算符,因?yàn)檎?fù)號(hào)后面只有一個(gè)數(shù)字。
正數(shù)使用+
表示,其中+
可以省略;負(fù)數(shù)使用-
表示。如果變量的值是數(shù)值類(lèi)型,也可以在變量前面加上正負(fù)號(hào)。
/**
* 正負(fù)號(hào)的表示
*
* @author iCode504
* @date 2023-10-06 19:49
*/
public class PlusAndMinusSign {
public static void main(String[] args) {
int intValue1 = 20; // 正數(shù),加號(hào)可忽略
int intValue2 = -40; // 負(fù)數(shù)
System.out.println("intValue1 = " + intValue1);
System.out.println("intValue2 = " + intValue2);
// 變量的前面也可以加上正負(fù)號(hào)
int intValue3 = 40;
int intValue4 = -intValue3;
System.out.println("intValue3 = " + intValue3);
System.out.println("intValue4 = " + intValue4);
// 加上符號(hào)的變量也可以參與運(yùn)算,以下兩個(gè)變量相乘得到的結(jié)果是相同的
int intValue5 = intValue3 * intValue4; // 推薦寫(xiě)法
int intValue6 = intValue3 * -intValue3; // 不推薦,可讀性變差
System.out.println("intValue5 = " + intValue5);
System.out.println("intValue6 = " + intValue6);
// 負(fù)數(shù)前面加上負(fù)號(hào)為正數(shù)(負(fù)負(fù)得正)
int intValue7 = -(-20);
int intValue8 = -intValue4; // intValue4本身的值就是負(fù)數(shù)
System.out.println("intValue7 = " + intValue7);
System.out.println("intValue8 = " + intValue8);
}
}
運(yùn)行結(jié)果:
根據(jù)intValue7
和intValue8
的輸出結(jié)果我們可以得知,負(fù)號(hào)可以改變數(shù)值的正負(fù),正數(shù)加了負(fù)號(hào)變負(fù)數(shù),負(fù)數(shù)加負(fù)號(hào)可以變正數(shù)(負(fù)負(fù)得正)。
編寫(xiě)代碼不推薦int intValue6 = intValue3 * -intValue3;
這種寫(xiě)法,雖然能得到預(yù)期結(jié)果,但是右側(cè)計(jì)算的表達(dá)式可讀性變差,可能會(huì)造成誤解。
算數(shù)運(yùn)算符
算術(shù)運(yùn)算符的基本使用
在大多數(shù)編程語(yǔ)言中,算術(shù)運(yùn)算符基本上由加+
、減-
、乘*
、除/
、取余%
(也稱(chēng)“取模”,也就是兩個(gè)數(shù)相除的余數(shù))組成,以上五個(gè)運(yùn)算符在Java中也完全適用。
/**
* 算術(shù)運(yùn)算符--加減乘除、取余
*
* @author iCode504
* @date 2023-10-08 7:01
*/
public class MathOperators1 {
public static void main(String[] args) {
int intValue1 = 22;
int intValue2 = 5;
// 加減乘除運(yùn)算
int result1 = intValue1 + intValue2;
System.out.println("intValue1 + intValue2 = " + result1);
int result2 = intValue1 - intValue2;
System.out.println("intValue1 - intValue2 = " + result2);
int result3 = intValue1 * intValue2;
System.out.println("intValue1 * intValue2 = " + result3);
// 兩個(gè)整除相除,只保留整數(shù)部分,不會(huì)進(jìn)行四舍五入操作
int result4 = intValue1 / intValue2;
System.out.println("intValue1 / intValue2 = " + result4);
// 兩個(gè)整數(shù)取余:22對(duì)5取余得到的結(jié)果是2
int result5 = intValue1 % intValue2;
System.out.println("intValue1 % intValue2 = " + result5);
}
}
運(yùn)行結(jié)果:
兩個(gè)整數(shù)運(yùn)算得到的結(jié)果是整數(shù),兩個(gè)浮點(diǎn)數(shù)運(yùn)算得到的結(jié)果是浮點(diǎn)數(shù),整數(shù)和浮點(diǎn)數(shù)進(jìn)行運(yùn)算時(shí)得到的結(jié)果是浮點(diǎn)數(shù)(因?yàn)檎麛?shù)類(lèi)型會(huì)自動(dòng)提升為浮點(diǎn)類(lèi)型)。
/**
* 整數(shù)和浮點(diǎn)數(shù)的運(yùn)算、byte/short/char類(lèi)型的運(yùn)算
*
* @author iCode504
* @date 2023-09-28 15:47:46
*/
public class MathOperators2 {
public static void main(String[] args) {
// 定義兩個(gè)變量intValue1,intValue2并賦值
int intValue1 = 20;
int intValue2 = 40;
// 直接輸出intValue1和intValue2相加的和
// 注意:下方輸出時(shí),需要對(duì)要計(jì)算的表達(dá)式加上括號(hào),防止intValue1和intValue2轉(zhuǎn)換成字符串類(lèi)型
System.out.println("intValue1 + intValue2 = " + (intValue1 + intValue2));
System.out.println("----------分割線----------");
// byte、short、char進(jìn)行運(yùn)算時(shí),會(huì)自動(dòng)提升為int類(lèi)型計(jì)算。
// 如果轉(zhuǎn)換成想要的小范圍數(shù)據(jù)類(lèi)型,需要進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換
byte byteValue = 30;
short shortValue = 50;
char charValue = 30;
// 錯(cuò)誤寫(xiě)法:
// byte byteValue1 = byteValue + shortValue;
// 正確寫(xiě)法: 將計(jì)算的結(jié)果轉(zhuǎn)換成小范圍數(shù)據(jù)類(lèi)型。注意:強(qiáng)制類(lèi)型轉(zhuǎn)換時(shí)需要考慮到數(shù)據(jù)溢出的問(wèn)題。
byte byteValue1 = (byte) (byteValue + shortValue);
short shortValue1 = (short) (shortValue + charValue);
char charValue1 = (char) (byteValue + charValue); // 得到的結(jié)果是Unicode字符表中對(duì)應(yīng)的字符
System.out.println("byteValue1 = " + byteValue1);
System.out.println("shortValue1 = " + shortValue1);
System.out.println("charValue1 = " + charValue1);
System.out.println("----------分割線----------");
// 浮點(diǎn)數(shù)參與計(jì)算:整數(shù)會(huì)自動(dòng)提升為浮點(diǎn)類(lèi)型
double doubleValue1 = 0.1;
double doubleValue2 = 0.2;
int intValue3 = 30;
System.out.println("doubleValue1 + intValue3 = " + (doubleValue1 + intValue3));
System.out.println("doubleValue1 + doubleValue2 = " + (doubleValue1 + doubleValue2));
}
}
運(yùn)行結(jié)果:
浮點(diǎn)數(shù)計(jì)算為什么不準(zhǔn)確?
從上述結(jié)果我們發(fā)現(xiàn)一個(gè)問(wèn)題,double
類(lèi)型的值0.1
和0.2
相加得到的結(jié)果并不是0.3
,而是0.30000000000000004
,為什么?
假設(shè)有兩個(gè)浮點(diǎn)數(shù)0.1
和0.2
,如果兩個(gè)值賦值給float
類(lèi)型和double
類(lèi)型,相加計(jì)算是不是0.3?
我們使用Java代碼來(lái)測(cè)試一下:
/**
* 浮點(diǎn)數(shù)0.1和0.2分別使用float類(lèi)型和double類(lèi)型計(jì)算
*
* @author iCode504
* @date 2023-10-06 17:00:21
*/
public class DecimalCalculation1 {
public static void main(String[] args) {
// float類(lèi)型相加計(jì)算
float floatValue1 = 0.1f;
float floatValue2 = 0.2f;
System.out.println("floatValue1 + floatValue2 = " + (floatValue1 + floatValue2));
// double類(lèi)型相加計(jì)算
double doubleValue1 = 0.1;
double doubleValue2 = 0.2;
System.out.println("doubleValue1 + doubleValue2 = " + (doubleValue1 + doubleValue2));
double doubleValue3 = 0.5;
double doubleValue4 = 0.8;
System.out.println("doubleValue3 + doubleValue4 = " + (doubleValue3 + doubleValue4));
}
}
運(yùn)行結(jié)果:
此時(shí)發(fā)現(xiàn)一個(gè)問(wèn)題:doubleValue1 + doubleValue2 = 0.30000000000000004
并沒(méi)有得到我們預(yù)期的結(jié)果,為什么?
事實(shí)上,0.1 + 0.2
的結(jié)果在大多數(shù)編程語(yǔ)言中進(jìn)行運(yùn)算時(shí)也會(huì)得到上述結(jié)果,點(diǎn)我查看
眾所周知,計(jì)算機(jī)在底層計(jì)算使用的是二進(jìn)制。無(wú)論是整數(shù)還是浮點(diǎn)數(shù)都會(huì)轉(zhuǎn)換成二進(jìn)制數(shù)進(jìn)行運(yùn)算。以下是小數(shù)轉(zhuǎn)為二進(jìn)制數(shù)運(yùn)算的基本流程
flowchart LR 十進(jìn)制數(shù) --> 二進(jìn)制數(shù) --> 科學(xué)計(jì)數(shù)法形式表示二進(jìn)制數(shù) --> 指數(shù)補(bǔ)齊 --> 二進(jìn)制數(shù)相加 --> 還原成十進(jìn)制數(shù)十進(jìn)制小數(shù)轉(zhuǎn)為二進(jìn)制小數(shù)
小數(shù)轉(zhuǎn)為二進(jìn)制數(shù)的規(guī)則是:將小數(shù)乘以2,然后取整數(shù)部分作為二進(jìn)制數(shù)的一部分,然后再將小數(shù)部分繼續(xù)乘以2,再取整數(shù)部分,以此類(lèi)推,直到小數(shù)部分為0所達(dá)到的精度。
將0.2轉(zhuǎn)換成二進(jìn)制:
\[0.2 \times 2 = 0.4 \to 取整數(shù)部分0 \] \[0.4 \times 2 = 0.8 \to 取整數(shù)部分0 \] \[0.8 \times 2 = 1.6 \to 取整數(shù)部分1 \] \[0.6 \times 2 = 1.2\to取整數(shù)部分1 \] \[0.2 \times 2 = 0.4\to整數(shù)部分為0 \]此時(shí)我們發(fā)現(xiàn),我們對(duì)得到的小數(shù)怎么乘以2,小數(shù)位永遠(yuǎn)都不是0。因此,使用計(jì)算器計(jì)算0.2得到的二進(jìn)制數(shù)字為
\[0.00110011...(無(wú)限循環(huán)0011) \]同理,0.1轉(zhuǎn)換成二進(jìn)制數(shù)是:
\[0.000110011...(無(wú)限循環(huán)0011) \]二進(jìn)制小數(shù)轉(zhuǎn)為科學(xué)計(jì)數(shù)法表示
當(dāng)然,計(jì)算機(jī)不能存儲(chǔ)無(wú)限循環(huán)小數(shù)。Java的double
是雙精度浮點(diǎn)類(lèi)型,64位,因此在存儲(chǔ)時(shí)使用64位存儲(chǔ)double
浮點(diǎn)數(shù)。要想表示盡可能大的數(shù)據(jù),就需要使用到科學(xué)計(jì)數(shù)法來(lái)表示數(shù)據(jù)。
十進(jìn)制和二進(jìn)制數(shù)都可以轉(zhuǎn)換成相應(yīng)的科學(xué)計(jì)數(shù)法來(lái)表示。
十進(jìn)制的科學(xué)計(jì)數(shù)法的表示方式是整數(shù)只留個(gè)位數(shù),且個(gè)位數(shù)主要是1到9,通過(guò)乘以10的指數(shù)來(lái)表示。例如:89999用科學(xué)計(jì)數(shù)法表示為\(8.9999\times10^4\),0.08586用十進(jìn)制科學(xué)計(jì)數(shù)法表示為\(8.586\times10^{-2}\)。
二進(jìn)制的科學(xué)計(jì)數(shù)法的表示方式和十進(jìn)制的類(lèi)似。它的個(gè)位數(shù)使用1來(lái)表示,通過(guò)乘以2的指數(shù)來(lái)表示。
例如,0.1的二進(jìn)制數(shù)轉(zhuǎn)換成科學(xué)計(jì)數(shù)法表示,小數(shù)點(diǎn)需要向右移動(dòng)4位得到整數(shù)部分1;同理,0.2需要向右移動(dòng)3位。因此0.1和0.2的二進(jìn)制用科學(xué)計(jì)數(shù)法表示如下:
\[1.10011...\times2^{-4}(0011無(wú)限循環(huán)) \] \[1.10011...\times2^{-3}(0011無(wú)限循環(huán)) \]科學(xué)計(jì)數(shù)法的數(shù)據(jù)轉(zhuǎn)成二進(jìn)制表示
Java的double類(lèi)型是雙精度浮點(diǎn)數(shù),IEEE 754標(biāo)準(zhǔn)對(duì)64位浮點(diǎn)數(shù)做出了如下的規(guī)定:
- 最高1位是符號(hào)位,0表示正號(hào),1表示負(fù)號(hào)。
- 其后面的11位用來(lái)存儲(chǔ)科學(xué)計(jì)數(shù)法中指數(shù)的二進(jìn)制。以上述二進(jìn)制科學(xué)計(jì)數(shù)法為例,這11位數(shù)字存儲(chǔ)的就是-4的二進(jìn)制。
- 剩下的52位存儲(chǔ)二進(jìn)制科學(xué)計(jì)數(shù)法中小數(shù)點(diǎn)的后52位。以上述二進(jìn)制科學(xué)計(jì)數(shù)法為例,存儲(chǔ)的就是
10011...
之后的52位數(shù)字。
既然內(nèi)存已經(jīng)給出了11位用于表示指數(shù)。那么轉(zhuǎn)換成十進(jìn)制數(shù)默認(rèn)范圍就是\([0, 2^{11}]\),即\([0,2048]\)。但此時(shí)還有一個(gè)問(wèn)題,以上述的二進(jìn)制科學(xué)計(jì)數(shù)法為例,它的指數(shù)是-4,是負(fù)數(shù),如何表示負(fù)數(shù)?需要在11位的頭部在單獨(dú)拿出一位來(lái)表示嗎?
并不是,IEEE 754標(biāo)準(zhǔn)將指數(shù)為0的基數(shù)定為1023(1是1024,相當(dāng)于存儲(chǔ)\([-1023,1024]\)范圍的數(shù)),指數(shù)-4會(huì)轉(zhuǎn)換成1023 - 4 = 1019
,再將1019轉(zhuǎn)換成二進(jìn)制:1111111011,前面我們說(shuō)過(guò),指數(shù)為11位,需要在前面補(bǔ)零,得到的結(jié)果為:01111111011。
剩下的52位也需要處理,但是二進(jìn)制科學(xué)計(jì)數(shù)法的小數(shù)部分也是一個(gè)無(wú)限循環(huán)小數(shù)。此時(shí)就需要進(jìn)行舍入計(jì)算,0舍1入(類(lèi)似四舍五入),舍入計(jì)算會(huì)讓數(shù)據(jù)丟失精度。
此時(shí)得到的0.1的二進(jìn)制:
\[0\ 01111111011\ 1001100110011001100110011001100110011001100110011010 \]0.2的二進(jìn)制如下:
\[0\ 01111111100\ 1001100110011001100110011001100110011001100110011010 \]此時(shí)需要對(duì)二進(jìn)制科學(xué)計(jì)數(shù)法提取公因數(shù),為了減少精度損失,遵循小指數(shù)轉(zhuǎn)換成大指數(shù)的原則。這里較大的指數(shù)是-3,因此需要將0.1的二進(jìn)制科學(xué)計(jì)數(shù)法再乘以2,得到結(jié)果如下:
\[0\ 01111111011\ (0.)100110011001100110011001100110011001100110011001101 \]0.1原有的最后一位需要舍去,讓給小數(shù)點(diǎn)前的0。此時(shí)0.1和0.2的二進(jìn)制的指數(shù)均為-3、
此時(shí)0.1+0.2的小數(shù)部分得到的結(jié)果是:
\[10.0110011001100110011001100110011001100110011001100111 \]指數(shù)補(bǔ)齊
根據(jù)上述結(jié)果,我們會(huì)發(fā)現(xiàn)兩個(gè)問(wèn)題:
- 整數(shù)部分不符合科學(xué)計(jì)數(shù)法的規(guī)則。
- 二進(jìn)制數(shù)整體得到的結(jié)果超過(guò)52位。
首先需要將將結(jié)果轉(zhuǎn)換成二進(jìn)制科學(xué)計(jì)數(shù)法,小數(shù)點(diǎn)向左移動(dòng)一位(相當(dāng)于乘以2):
\[1.00110011001100110011001100110011001100110011001100111 \]指數(shù)部分也需要加1,因?yàn)橹笖?shù)由-3(1020)變?yōu)?2(1021)
\[01111111101 \]根據(jù)0舍1入的原則,將超出52位的小數(shù)部分做舍入計(jì)算,得到的結(jié)果為:
\[0\ 01111111101\ (1.)0011001100110011001100110011001100110011001100110100 \]還原成十進(jìn)制數(shù)
將二進(jìn)制科學(xué)計(jì)數(shù)法轉(zhuǎn)換成正常的二進(jìn)制數(shù),原有的指數(shù)是-2,還原時(shí)小數(shù)點(diǎn)需向左移動(dòng)兩位:
\[0.010011001100110011001100110011001100110011001100110100 \]再轉(zhuǎn)換為十進(jìn)制為:
\[0.30000000000000004 \]經(jīng)過(guò)上述的復(fù)雜推導(dǎo),我們可以總結(jié)出一個(gè)結(jié)論:使用基本數(shù)據(jù)類(lèi)型的浮點(diǎn)數(shù)進(jìn)行運(yùn)算并不準(zhǔn)確(尤其是在金融貨幣領(lǐng)域?qū)π?shù)點(diǎn)精度要求比較高的不能使用)。那么,有什么辦法可以解決浮點(diǎn)數(shù)計(jì)算不準(zhǔn)確的問(wèn)題?
方法一(現(xiàn)階段推薦):轉(zhuǎn)換成整數(shù)計(jì)算,得到結(jié)果再除以10的n次方。
還是以0.1 + 0.2為例,我們可以轉(zhuǎn)換成整數(shù)計(jì)算,整數(shù)計(jì)算的結(jié)果再除以10,示例代碼如下:
/**
* 浮點(diǎn)數(shù)計(jì)算: 計(jì)算0.1 + 0.2的精確結(jié)果
*
* @author ZhaoCong
* @date 2023-10-09 18:13:35
*/
public class DecimalCalculation2 {
public static void main(String[] args) {
double doubleValue1 = 0.1;
double doubleValue2 = 0.2;
// 將doubleValue1和doubleValue2轉(zhuǎn)換成整數(shù)
int tempValue1 = (int) (doubleValue1 * 10);
int tempValue2 = (int) (doubleValue2 * 10);
int tempResult = tempValue1 + tempValue2;
double result = (double) tempResult / 10;
System.out.println("result = " + result);
}
}
運(yùn)行結(jié)果:
此時(shí)能得到精確的結(jié)果。
方法二:使用BigDecimal
類(lèi)(這個(gè)類(lèi)后續(xù)會(huì)講到,小白可以直接跳過(guò))精確運(yùn)算
import java.math.BigDecimal;
/**
* 使用BigDecimal類(lèi)精確計(jì)算浮點(diǎn)數(shù)
*
* @author iCode504
* @date 2023-10-09 22:26
*/
public class DecimalCalculation3 {
public static void main(String[] args) {
double doubleValue1 = 0.1;
double doubleValue2 = 0.2;
// 將double類(lèi)型的值轉(zhuǎn)換成字符串
String doubleValueString1 = String.valueOf(doubleValue1);
String doubleValueString2 = String.valueOf(doubleValue2);
// 使用BigDecimal類(lèi)進(jìn)行運(yùn)算
BigDecimal decimal1 = new BigDecimal(doubleValueString1);
BigDecimal decimal2 = new BigDecimal(doubleValueString2);
BigDecimal resultDecimal = decimal1.add(decimal2);
double result = resultDecimal.doubleValue();
System.out.println("result = " + result);
}
}
運(yùn)行結(jié)果:
負(fù)數(shù)的除法和取余規(guī)則
負(fù)數(shù)的除法規(guī)則:兩個(gè)負(fù)數(shù)相除得到的結(jié)果是正數(shù),正數(shù)除以負(fù)數(shù)或者負(fù)數(shù)除以整數(shù)結(jié)果是負(fù)數(shù)。
/**
* 負(fù)數(shù)的除法運(yùn)算
*
* @author iCode504
* @date 2023-10-07 19:57
*/
public class DivideOperators {
public static void main(String[] args) {
int intValue1 = 20;
int intValue2 = -10;
int intValue3 = 5;
int intValue4 = -5;
// 情況一:被除數(shù)為正數(shù),除數(shù)為負(fù)數(shù),得到的結(jié)果是負(fù)數(shù)
int result1 = intValue1 / intValue2;
System.out.println("result1 = " + result1);
// 情況二:被除數(shù)為負(fù)數(shù),除數(shù)為正數(shù),得到的結(jié)果是負(fù)數(shù)
int result2 = intValue2 / intValue3;
System.out.println("result2 = " + result2);
// 情況三:被除數(shù)和除數(shù)都是負(fù)數(shù),得到的結(jié)果是正數(shù)
int result3 = intValue2 / intValue4;
System.out.println("result3 = " + result3);
}
}
運(yùn)行結(jié)果:
負(fù)數(shù)的取余規(guī)則:被除數(shù)如果是正數(shù),求余的結(jié)果就是正數(shù);反之,結(jié)果為負(fù)數(shù)。
/**
* 負(fù)數(shù)的取余運(yùn)算
*
* @author iCode504
* @date 2023-10-07 22:12
*/
public class ModOperators {
public static void main(String[] args) {
int intValue1 = 20;
int intValue2 = -13;
int intValue3 = 7;
int intValue4 = -3;
// 情況一:被除數(shù)為正數(shù),除數(shù)為負(fù)數(shù),得到的結(jié)果是正數(shù)
int result1 = intValue1 % intValue2;
System.out.println("result1 = " + result1);
// 情況二:被除數(shù)為負(fù)數(shù),除數(shù)為正數(shù),得到的結(jié)果是負(fù)數(shù)
int result2 = intValue2 % intValue3;
System.out.println("result2 = " + result2);
// 情況三:被除數(shù)和除數(shù)都是負(fù)數(shù),得到的結(jié)果是負(fù)數(shù)
int result3 = intValue2 % intValue4;
System.out.println("result3 = " + result3);
}
}
運(yùn)行結(jié)果:
賦值運(yùn)算符
賦值運(yùn)算符=
我們知道,創(chuàng)建Java變量的一般語(yǔ)法是:數(shù)據(jù)類(lèi)型 變量名 = 變量值。其中=
是賦值運(yùn)算符,它的作用是將右側(cè)的值賦值給左邊的變量。
- 變量值一般是:常量、已經(jīng)賦值的變量名或者是可以計(jì)算出新數(shù)值的表達(dá)式。
- 賦值運(yùn)算符
=
左側(cè)的變量名唯一。
基本數(shù)據(jù)類(lèi)型的變量可以直接賦值,因?yàn)榛緮?shù)據(jù)類(lèi)型保存的是實(shí)際值。
/**
* 賦值運(yùn)算符 = 的基本使用
*
* @author iCode504
* @date 2023-10-06 6:40
*/
public class AssignmentOperator1 {
public static void main(String[] args) {
// 將20賦值給number1
int number1 = 20;
System.out.println("number1 = " + number1);
// 將已經(jīng)賦值的變量名number1賦值給number2
int number2 = number1;
System.out.println("number2 = " + number2);
// 可以計(jì)算出新數(shù)值的表達(dá)式賦值給新變量
int number3 = 30 + 40;
System.out.println("number3 = " + number3);
int number4 = number1 + number2;
System.out.println("number4 = " + number4);
}
}
運(yùn)算結(jié)果:
由number1
和number2
的輸出結(jié)果可知:變量number1
存儲(chǔ)的值20賦值給了number2
,此時(shí)number2
的值也是20。
變量number3
和number4
右側(cè)是可以計(jì)算的表達(dá)式,即30 + 40
能夠直接計(jì)算出結(jié)果,前面已經(jīng)賦值的number1 + number2
也能計(jì)算出結(jié)果。
引用數(shù)據(jù)類(lèi)型存儲(chǔ)的是一個(gè)地址值引用。例如:Object
和String
是類(lèi),屬于引用數(shù)據(jù)類(lèi)型。此時(shí)我們創(chuàng)建這兩個(gè)類(lèi)型的對(duì)象并賦值給變量,然后直接輸出變量。
/**
* 賦值運(yùn)算符--引用數(shù)據(jù)類(lèi)型變量賦值并輸出
*
* @author iCode504
* @date 2023-10-06 23:50
*/
public class AssignmentOperator2 {
public static void main(String[] args) {
// 第一組:創(chuàng)建兩個(gè)Object對(duì)象分別賦值給object1和object2
Object object1 = new Object();
Object object2 = new Object();
// 輸出兩個(gè)地址值
System.out.println("object1 = " + object1);
System.out.println("object2 = " + object2);
System.out.println("--------------------");
// 第二組:讓object1指向object2
object2 = object1;
System.out.println("object1 = " + object1);
System.out.println("object2 = " + object2);
System.out.println("--------------------");
// 第三組:創(chuàng)建兩個(gè)String對(duì)象分別賦值給string1和string2
String string1 = new String();
String string2 = new String();
System.out.println("string1 = " + string1);
System.out.println("string2 = " + string2);
}
}
運(yùn)行結(jié)果:
前兩組輸出結(jié)果的格式我們發(fā)現(xiàn),它們是以java.lang.Object
、@
和變量在物理內(nèi)存中的地址(十六進(jìn)制數(shù))。
- 其中
java.lang.Object
叫做全限定類(lèi)名。全限定類(lèi)名是指當(dāng)前類(lèi)所屬的包名(包名會(huì)在后續(xù)文章中講到)和類(lèi)名組成。Object
是類(lèi)名,java.lang
是Object
類(lèi)所在的包名。 -
@
后面的就是變量在內(nèi)存中的存儲(chǔ)地址。如果你使用上述命令將代碼輸出,那么得到的地址值和上述的內(nèi)容不同,因?yàn)樽兞康牡刂分凳莾?nèi)存隨機(jī)分配的。
第一組的object1
和object2
分別創(chuàng)建了Object對(duì)象,相當(dāng)于在棧內(nèi)存和堆內(nèi)存中分別開(kāi)辟了兩塊不同的空間,棧內(nèi)存中存儲(chǔ)的變量地址和堆內(nèi)存中開(kāi)辟的內(nèi)存地址一一對(duì)應(yīng),因此object1
和object2
的地址值不同。第一組的object1
和object2
在內(nèi)存的表現(xiàn)形式如下:
第二組,我們發(fā)現(xiàn)object1
賦值給了object2
,在棧內(nèi)存中的表現(xiàn)形式是當(dāng)前變量object2
的地址值賦值給object1
。原來(lái)object2
在堆內(nèi)存中創(chuàng)建的對(duì)象不再被引用,虛擬機(jī)后續(xù)會(huì)對(duì)此對(duì)象進(jìn)行回收。
我們發(fā)現(xiàn)第三組兩個(gè)String
對(duì)象的輸出結(jié)果什么都看不到,它們也是引用數(shù)據(jù)類(lèi)型,難道不輸出地址值嗎?事實(shí)上,在源碼層面,String
做了進(jìn)一步處理。
我們使用new String()
創(chuàng)建對(duì)象時(shí),會(huì)調(diào)用String
的構(gòu)造器(構(gòu)造器,也叫做構(gòu)造方法,后續(xù)會(huì)講到),打開(kāi)源碼觀察這個(gè)構(gòu)造器:
在調(diào)用空參構(gòu)造器時(shí)就已經(jīng)初始化一個(gè)空字符串值了,因此我們?cè)谳敵?code>String對(duì)象時(shí)輸出的是空字符串,此時(shí)我們看不到任何內(nèi)容就顯得比較合理了。
其他賦值運(yùn)算符
假設(shè)有一個(gè)int
類(lèi)型變量intValue
的值是20,此時(shí)我在此基礎(chǔ)上再加上20再賦值給intValue
,得到的表達(dá)式如下:
int intValue = 20;
intValue = intValue + 20; // 此時(shí)intValue的結(jié)果為40
Java給我們提供了+=
運(yùn)算符可以簡(jiǎn)化當(dāng)前的代碼intValue = intValue + 20;
,使用+=
可以簡(jiǎn)化成如下形式:
int intValue = 20;
intValue += 20; // 得到的結(jié)果也是40,相當(dāng)于intValue = intValue + 20;
除了+=
以外,-=
、*=
、/=
和%=
的作用機(jī)制和+=
完全相同。
賦值運(yùn)算符 | 說(shuō)明 | 使用 |
---|---|---|
+= |
加并賦值運(yùn)算符:先相加,得到的結(jié)果再賦值 |
i = i + 20 可以簡(jiǎn)寫(xiě)成i += 20
|
-= |
減并賦值運(yùn)算符:先相減,得到的結(jié)果再賦值 |
i = i - 20 可以簡(jiǎn)寫(xiě)成i -= 20
|
*= |
乘并賦值運(yùn)算符:先相乘,得到的結(jié)果再賦值 |
i = i * 20 可以簡(jiǎn)寫(xiě)成i *= 20
|
/= |
除并賦值運(yùn)算符:先相除,得到的結(jié)果再賦值 |
i = i / 20 可以簡(jiǎn)寫(xiě)成i /= 20
|
%= |
取余并賦值運(yùn)算符:先取余,得到的結(jié)果再賦值 |
i = i % 20 可以簡(jiǎn)寫(xiě)成i %= 20
|
以下是5個(gè)運(yùn)算符在代碼中的應(yīng)用:
/**
* 其他賦值運(yùn)算符+=、-=、*=、/=和%=的使用
*
* @author iCode504
* @date 2023-10-07 20:14
*/
public class AssignmentOperator3 {
public static void main(String[] args) {
int intValue1 = 20;
int intValue2 = 30;
int intValue3 = 40;
int intValue4 = 50;
int intValue5 = 60;
intValue1 += 30;
intValue2 -= 40;
intValue3 *= 50;
intValue4 /= 10;
intValue5 %= 7;
System.out.println("intValue1 = " + intValue1);
System.out.println("intValue2 = " + intValue2);
System.out.println("intValue3 = " + intValue3);
System.out.println("intValue4 = " + intValue4);
System.out.println("intValue5 = " + intValue5);
}
}
運(yùn)行結(jié)果:
byte
、short
、char
三者使用上述賦值運(yùn)算符時(shí),不需要進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換:
/**
* byte、short、char使用賦值運(yùn)算符
*
* @author iCode504
* @date 2023-10-07 20:34
*/
public class AssignmentOperator4 {
public static void main(String[] args) {
byte byteValue1 = 30;
byte byteValue2 = 40;
short shortValue = 10;
char charValue = 'a';
byteValue1 += byteValue2;
System.out.println("byteValue1 = " + byteValue1);
byteValue1 += 10;
System.out.println("byteValue2 = " + byteValue2);
charValue += byteValue1;
shortValue += charValue;
byteValue2 += shortValue;
System.out.println("charValue = " + charValue);
System.out.println("shortValue = " + shortValue);
System.out.println("byteValue2 = " + byteValue2);
}
}
運(yùn)行結(jié)果:
使用賦值運(yùn)算符的優(yōu)勢(shì)包括:
1. 簡(jiǎn)潔性:使用+=
可以在一行內(nèi)同時(shí)完成加法計(jì)算和賦值操作,讓代碼更加簡(jiǎn)潔。例如:i += 20
就是i = i + 20
的簡(jiǎn)化寫(xiě)法(其他賦值運(yùn)算符亦同理)。
2. 性能優(yōu)勢(shì):在某些情況下,賦值運(yùn)算符要比單獨(dú)的加法和賦值操作更快。
總的來(lái)說(shuō),使用賦值運(yùn)算符可以增加代碼的簡(jiǎn)潔性,提高性能,并使代碼更易于閱讀和理解。
參考資料:
0.1 + 0.2為什么不等于0.3?
0.1+0.2為什么不等于0.3,以及怎么等于0.3
0.1 + 0.2 為什么不等于 0.3???