Java從入門到放棄(1)Java的基礎(chǔ)知識(shí)、標(biāo)識(shí)符、變量、運(yùn)算符

前言

做了這么久的Java開(kāi)發(fā),也非常喜歡這門語(yǔ)言,卻對(duì)它本身了解不多。而我又報(bào)名參加了2020年的藍(lán)橋杯Java組,并且打算參加軟件杯和C4,為了能把這些比賽打好,在下學(xué)期的Java程序設(shè)計(jì)課里拿個(gè)高分(雖然能不能選上這門課還不一定),也為了能對(duì)Java語(yǔ)言有一個(gè)更深入、系統(tǒng)的了解,不在以后的開(kāi)發(fā)中對(duì)語(yǔ)言本身感到困惑,所以打算寫這個(gè)系列,從零開(kāi)始重新學(xué)習(xí)Java基礎(chǔ)知識(shí),并對(duì)第一次學(xué)習(xí)掌握得不好的部分重新記錄。

參考資料

《Java核心技術(shù)》
Java300集及其資料

菜鳥(niǎo)教程

javac和java命令做了什么?

我們?cè)诎惭b好JDK之后開(kāi)始寫HelloWorld程序時(shí),都會(huì)用到javacjava兩條命令。那么這兩條命令為我們做了些什么呢?

javac命令啟動(dòng)了一個(gè)Java編譯器,它把后綴名為.java的Java源碼文件編譯成了后綴名為.class的字節(jié)碼文件。java命令則啟動(dòng)了JRE——Java運(yùn)行時(shí)環(huán)境(Java Runtime Environment)和JVM——Java虛擬機(jī)(Java Virtual Machine),裝載剛才編譯好的.class文件并以解釋的方式執(zhí)行其中的字節(jié)碼。

(圖片來(lái)自Java300集)

所以,我們可以很清楚地看出為什么Java是半編譯半解釋的語(yǔ)言——因?yàn)樵创a需要先編譯成字節(jié)碼,字節(jié)碼在JVM中又是解釋執(zhí)行的。

這里如果展開(kāi)了說(shuō)還會(huì)涉及到Java語(yǔ)言、JVM的底層原理,比如JVM是怎么加載這個(gè)類,怎么執(zhí)行其中的字節(jié)碼,還有JIT即時(shí)編譯、雙委派模型之類的,這里先不考慮這些細(xì)節(jié),在后面學(xué)習(xí)JVM基礎(chǔ)知識(shí)的部分再去詳細(xì)展開(kāi)。

JDK、JRE和JVM的關(guān)系

JRE并不等于JVM。

除了JVM之外,JRE其實(shí)還包含一些庫(kù)函數(shù)和必須的文件,所以JRE其實(shí)是包含JVM的。

JDK則在JRE的基礎(chǔ)上又增加了編譯器、調(diào)試器等開(kāi)發(fā)需要的東西。

JDK的目錄結(jié)構(gòu)

  • bin:二進(jìn)制文件,比如java、javac之類的,也就是我們用到的命令
  • db:存放一些數(shù)據(jù)
  • include:一些需要包含的頭文件
  • jre:就是JRE
  • lib:庫(kù)目錄,存放了一些jar包
  • src.zip:JDK源碼,不過(guò)為啥我macOS版的Java11沒(méi)這個(gè)呢?

標(biāo)識(shí)符

標(biāo)識(shí)符其實(shí)就是一個(gè)名字,用來(lái)給變量、包、類等命名。

標(biāo)識(shí)符有一定的規(guī)則——

  • 所有的標(biāo)識(shí)符都應(yīng)該以字母(A-Z 或者 a-z),美元符($)、或者下劃線(_)開(kāi)始
  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下劃線(_)或數(shù)字的任何字符組合
  • class等Java關(guān)鍵字不能用作標(biāo)識(shí)符

注意:Java使用的是Unicode標(biāo)準(zhǔn)字符集,所以可以用中文命名變量。

數(shù)據(jù)類型

在Java中,一共有8種基本類型(primitive type),其中有4種整型、2種浮點(diǎn)類型、1種用于表示Unicode 編碼的字符單元的字符類型char和1種用于表示真值的boolean類型。

除此之外,都是引用數(shù)據(jù)類型。它們占四個(gè)字節(jié),用來(lái)表示一個(gè)對(duì)象的地址(類似于C++的指針)。

注意:Java有一個(gè)能夠表示任意精度的算術(shù)包,通常被稱為大數(shù)值(BigDecimal),但它并不是一種新的Java類型,而是一個(gè)Java對(duì)象。

變量的類型、長(zhǎng)度與范圍

整數(shù)類型

類型 長(zhǎng)度 取值范圍
int 4字節(jié) -2147483648~2147483647
short 2字節(jié) -32768~32767
long 8字節(jié) -9223372036854775808~9223372036854775807(-264~264-1)
byte 1字節(jié) -128~127

注意:

長(zhǎng)整型數(shù)值有一個(gè)后綴 L 或 l (如 4000000000L) 十六進(jìn)制數(shù)值有一個(gè)前綴 0x 或 0X ( 如 0xCAFEL 八進(jìn)制有一個(gè)前綴0,例如,010 對(duì)應(yīng)八進(jìn)制中的 8。 很顯然, 八進(jìn)制表示法比較容易混淆, 所以建議最好不要使用八進(jìn)制常數(shù)。并且,由于l容易和數(shù)字1、大寫的I混淆,所以一般都使用大寫的L表示長(zhǎng)整型數(shù)。

從 Java 7 開(kāi)始, 加上前綴 0b 或 0B 就可以寫二進(jìn)制數(shù)。 例如, 0b1001就是 9。 另外, 同樣是 從Java7開(kāi)始,還可以為數(shù)字字面量加下劃線,如用1_000_000表示一百萬(wàn),不會(huì)影響到編譯結(jié)果。

關(guān)于boolean的長(zhǎng)度問(wèn)題

Java規(guī)范中并沒(méi)有明確地指出boolean類型的長(zhǎng)度。但是,并不能說(shuō)boolean的長(zhǎng)度就不確定了:

在《Java虛擬機(jī)規(guī)范》一書(shū)中的描述:“雖然定義了boolean這種數(shù)據(jù)類型,但是只對(duì)它提供了非常有限的支持。在Java虛擬機(jī)中沒(méi)有任何供boolean值專用的字節(jié)碼指令,Java語(yǔ)言表達(dá)式所操作的boolean值,在編譯之后都使用Java虛擬機(jī)中的int數(shù)據(jù)類型來(lái)代替,而boolean數(shù)組將會(huì)被編碼成Java虛擬機(jī)的byte數(shù)組,每個(gè)元素boolean元素占8位”。也就是說(shuō)JVM規(guī)范指出boolean當(dāng)做int處理,也就是4字節(jié),boolean數(shù)組當(dāng)做byte數(shù)組處理,這樣我們可以得出boolean類型占了單獨(dú)使用是4個(gè)字節(jié),在數(shù)組中是確定的1個(gè)字節(jié)。
from: https://blog.csdn.net/YuanMxy/article/details/74170745

雖說(shuō)單獨(dú)使用的boolean是跟int一樣占用四個(gè)字節(jié),但是booleanint不能相互轉(zhuǎn)換。

浮點(diǎn)類型

類型 長(zhǎng)度 取值范圍
float 4字節(jié) 大約 ± 3.402 823 47E+38F (有效位數(shù)為 6 ~ 7 位)
double 8字節(jié) 大約 ± 1.797 693 134 862 315 70E+308 (有效位數(shù)為 15 位)

浮點(diǎn)數(shù)不僅可以用小數(shù)點(diǎn)表示,也可以用科學(xué)計(jì)數(shù)法來(lái)表示,例如314e2、314E2。

注意:float類型的數(shù)值有一個(gè)后綴F或f (例如,3.14F) 沒(méi)有后綴F的浮點(diǎn)數(shù)值(如3.14) 默 認(rèn)為 double 類型。當(dāng)然, 也可以在浮點(diǎn)數(shù)值后面添加后綴 D 或 d ( 例如,3.14D)。

注意2:Java中有三個(gè)特殊的浮點(diǎn)數(shù)值,它們可以用一些特殊的常量來(lái)表示:

  • 正無(wú)窮大——Double.POSITIVE_INFINITY
  • 負(fù)無(wú)窮大——Double.NEGATIVE_INFINIT
  • NaN(不是一個(gè)數(shù)字)——Double.NaN

可以用Double.isXxx方法,例如Double.isNaN來(lái)檢測(cè)需要檢測(cè)的數(shù)是不是這三個(gè)常數(shù)。

注意3:與C/C++一樣,浮點(diǎn)數(shù)類型在計(jì)算時(shí)可能會(huì)產(chǎn)生誤差,因?yàn)楦↑c(diǎn)數(shù)并不是精確存儲(chǔ)的,可能產(chǎn)生舍入誤差,所以也最好不要比較兩個(gè)浮點(diǎn)數(shù)。如果業(yè)務(wù)要求不能產(chǎn)生誤差或者必須要比較兩個(gè)浮點(diǎn)數(shù),需要使用BigInteger(整數(shù))或者BigDecimal(浮點(diǎn)數(shù))類。

注意4:Java提供了PI與E的近似值常量——Math.PI、Math.E

字符類型

char類型可以表示的字符范圍為\u0000\uffff。

注意:Unicode轉(zhuǎn)義序列會(huì)在解析代碼之前被處理,所以必須小心注釋中的\u,它們可能會(huì)引起一些意想不到的錯(cuò)誤。

自動(dòng)類型轉(zhuǎn)換

下圖為Java不同數(shù)值類型之間的合法轉(zhuǎn)換(實(shí)線代表不會(huì)損失精度,虛線代表會(huì)損失精度。圖片來(lái)自《Java核心技術(shù)》):

強(qiáng)制類型轉(zhuǎn)換

Java的強(qiáng)制類型轉(zhuǎn)換與C/C++基本相同,但是在面向?qū)ο蟛糠郑行┣闆r下不可以使用強(qiáng)制類型轉(zhuǎn)換,這一點(diǎn)在后面復(fù)習(xí)面向?qū)ο髸r(shí)再詳細(xì)總結(jié)。

變量

變量的本質(zhì)

變量的本質(zhì)其實(shí)就是內(nèi)存中的一個(gè)可操作、固定長(zhǎng)度的存儲(chǔ)空間(不過(guò)據(jù)說(shuō)boolean的長(zhǎng)度是不確定的),在內(nèi)存中的地址是確定的,但是里面放置什么值是由程序運(yùn)行決定的。我們可通過(guò)變量名來(lái)訪問(wèn)對(duì)應(yīng)的存儲(chǔ)空間,從而操縱這個(gè)存儲(chǔ)空間里存儲(chǔ)的值。

Java是一種強(qiáng)類型語(yǔ)言,聲明變量必須在變量名前先聲明其類型,但是在Java11中,能自動(dòng)推斷出類型的可以不顯示指定類型而使用var關(guān)鍵字指定,非常方便。

變量在使用前必須聲明, 只有在變量聲明以后,才能為其分配相應(yīng)長(zhǎng)度的存儲(chǔ)空間,所以在使用變量之前必須聲明。

注意:使用沒(méi)有初始化局部的變量會(huì)報(bào)錯(cuò),但是聲明了變量不使用則不會(huì)報(bào)錯(cuò)(這跟Go語(yǔ)言不一樣)。

變量的分類

Java的變量與C++一樣,分為三種:

  • 局部變量
  • 靜態(tài)變量
  • 成員變量/實(shí)例變量

成員變量的初值

成員變量從屬于對(duì)象,生命周期伴隨對(duì)象始終。

成員變量如果沒(méi)有初始化,會(huì)有一個(gè)默認(rèn)值:

類型 默認(rèn)值
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
char '\u0000'
boolean false
String等引用類型 null

靜態(tài)變量

靜態(tài)變量(使用static聲明的變量)從屬于類,是生命周期最長(zhǎng)的,生命周期為從類的加載到類的卸載。

常量

與C/C++不同,常量使用final關(guān)鍵字聲明,一旦有值,其值就不能發(fā)生變化。

final關(guān)鍵字除了用于常量(不能修改的變量)之外,還有以下作用:

  1. 使用final修飾的類不能被繼承
  2. 使用final修飾的方法不能被重寫

這在后面復(fù)習(xí)面向?qū)ο蟮臅r(shí)候再詳細(xì)學(xué)習(xí)。

雖然Java不使用const修飾常量,但是const是Java的一個(gè)保留關(guān)鍵字,不能使用。

運(yùn)算符

Java中有以下運(yùn)算符(圖片來(lái)自Java300集):

算術(shù)運(yùn)算符

除了++--以外都屬于二元運(yùn)算符,二元運(yùn)算符運(yùn)算時(shí)遵守以下規(guī)則:

  1. 如果兩個(gè)操作數(shù)有一個(gè)為L(zhǎng)ong, 則結(jié)果也為long。
  2. 沒(méi)有l(wèi)ong時(shí),結(jié)果為int。即使操作數(shù)全為short,byte,結(jié)果也是int。
  3. 如果兩個(gè)操作數(shù)有一個(gè)為double,則結(jié)果為double。
  4. 只有兩個(gè)操作數(shù)都是float,則結(jié)果才為float。
  5. 取模操作其操作數(shù)可以為浮點(diǎn)數(shù),但是一般使用整數(shù)。結(jié)果是“余數(shù)”,“余數(shù)”符號(hào)和左邊操作數(shù)相同,如:7%3=1,-7%3=-1,7%-3=1。

++--的運(yùn)算規(guī)則與C/C++等語(yǔ)言相同。

賦值運(yùn)算與結(jié)合賦值運(yùn)算

Java一共有以下幾種結(jié)合賦值運(yùn)算符:

  • +=
  • -=
  • *=
  • \=
  • %=

用法與C/C++相同。

注意:如果整數(shù)除以0會(huì)拋出一個(gè)異常,而浮點(diǎn)數(shù)除以0則會(huì)得到無(wú)窮大或者是NaN。

關(guān)系運(yùn)算符

Java的關(guān)系運(yùn)算符一共有以下幾種:

  • ==
  • !=
  • >
  • <
  • >=
  • <=

用法同樣與C/C++相同。

邏輯運(yùn)算符

Java 沿用了 C++ 的做法,使用&&表示邏輯“與”運(yùn)算符,使用||表示邏輯“或”運(yùn)算符。從 != 運(yùn)算符可以想到,感嘆號(hào)!就是邏輯非運(yùn)算符。&&和||運(yùn)算符是按照“短路”方式來(lái)求值的: 如果第一個(gè)操作數(shù)已經(jīng)能夠確定表達(dá)式的值,第二個(gè)操作數(shù)就不必計(jì)算了。

位運(yùn)算符

Java中的位運(yùn)算符與C/C++的基本相同,個(gè)人感覺(jué)這些東西在實(shí)際開(kāi)發(fā)中很難用到,除非是在性能要求非常高的地方。

(圖片來(lái)自Java300集)

運(yùn)算符的優(yōu)先級(jí)

Java運(yùn)算符的優(yōu)先級(jí)也與C/C++基本相同。在實(shí)際使用中一般很少會(huì)遇到需要考慮優(yōu)先級(jí)的問(wèn)題,一般都使用小括號(hào)來(lái)解決運(yùn)算符的優(yōu)先級(jí)帶來(lái)的問(wèn)題,因?yàn)樾±ㄌ?hào)的優(yōu)先級(jí)最高。

(圖片來(lái)自Java300集)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容