以《Java核心技術 卷1》第10版為主,結合自身實踐進行截圖及細節描述。
Java的基本程式設計結構
- 一、一個簡單的Java應用程式
- 二、注釋
- 三、資料類型
-
- 1. Java整型
- 2. 浮點類型
- 3.char類型
- 4. boolean類型
- 四、變量
-
- 1. 聲明變量
- 2. 變量初始化
- 3. 常量
- 五、運算符
-
- 1. 算術運算符
- 2. 數學函數與常量
- 3. 數值類型之間的轉換
- 4. 結合指派運算符
- 5. 自增與自減運算符
- 6. 關系和boolean運算符
- 7. 位運算符
- 8. 括号與運算符級别
- 9. 枚舉類型
- 六、字元串
-
- 1. 子串與拼接
- 2. 不可變字元串
- 3. 檢測字元串是否相等
- 4. 空串和Null串
- 5. 碼點與代碼單元
- 6. 建構字元串
- 七、輸入輸出
-
- 1. 讀取輸入
- 2. 格式化輸出
- 3. 檔案輸入輸出
- 八、控制流程
-
- 1. 塊作用域
- 2. 條件語句
- 3. 循環語句
- 4. 中斷控制流程語句
- 九、大數值
- 十、數組
-
- 1. 數組簡介及聲明
- 2. 數組初始化及匿名數組
- 3. 數組拷貝
- 5. Arrays類常用API
- 6. 多元數組
- 7. 不規則數組
一、一個簡單的Java應用程式
import java.util.Arrays; //導入數組類,友善數組輸出
public class Welcome {
public static void main(String[] args){
//System.out.println("We Will not use 'Hello,World!'");
System.out.println(Arrays.toString(args));
}
}
說明:
- Java語言區分大小寫
- 關鍵字import 導入其他包中的類。【public,class,import目前先不看,後續章節會詳細介紹】
- 關鍵字public稱為通路修飾符(access modifier)
- 關鍵字class表明Java程式中的全部内容都必須包含在類中
- Java中定義類名規則:必須字母開頭,後面可以跟字母和數字的任意組合,長度上沒有限制,但不可使用Java保留字(保留字不許要刻意去記)。标準命名規範:類名是以大寫字母開頭的名詞,後每個單詞的第一個字母大寫(駱駝命名法,如:FirstSample)
- 源代碼的檔案名必須與公共類(即public class修飾的類名)的名字相同,并用.java作為擴充名。即檔案名稱為:FirstSample.java
- 在運作已編譯的程式時,Java虛拟機将從指定類中的main方法開始執行,是以,在類的源檔案中必須包含一個main方法。
- main方法必須聲明為public
- 用大括号{ } 劃分程式的各個部分(通常稱為塊)
- Java使用的通用文法是:object.method(parameters)
- String[] args:是用來接受指令行參數的,程式中import(導入)Arrays類,都是為了這步的展示,平常并不需要。具體使用如下:(可先看看十、數組知識)
二、注釋
注釋不會出現在可執行程式中,是以可在源程式中添加任意多的注釋,而不必擔心可執行代碼膨脹。
-- // 單行注釋:注釋内容從開始到本行結尾
-- /* */多行注釋:以/* 開始 以 */ 結尾
-- /**
* 文檔注釋,可用來自動地生成文檔。在其他章節會詳細介紹文檔注釋的使用
*/
三、資料類型
1. Java整型
類型 | 存儲需求 | 取值範圍 |
---|---|---|
byte | 1位元組 | -128~127 |
short | 2位元組 | -32768~32767 |
int | 4位元組 | -2147483648~ 2147483647(約±2.1*109) |
long | 8位元組 | -9223327036854755808~9223327036854755807(約±9.2*1018) |
- Java中資料類型的取值範圍與運作Java代碼的機器無關(Java的移植性)
- Java中整數預設類型為int
- 長整型(long型)數值需有一字尾L或l進行标注(例:40000000L)
- 字首0x或0X:表示十六進制,字首0表示八進制,字首0b或0B表示二進制,還可為數字字面量加下劃線(如1_000_000),Java編譯器會去除這些下劃線。【從java7開始才有這些特性】
- Java中沒有無符号(unsigned)形式的int、short、long或byte類型,C++中有
2. 浮點類型
類型 | 存儲需求 | 取值範圍 |
---|---|---|
float | 4位元組 | 約 ± 3.40282347E+38F(有效位數為6~7位) |
double | 8位元組 | 約 ± 1.79769313486231570E+308(有效位數為15位) |
- Java中浮點數預設類型為double,float類型需在數值後加字尾F或f
- 可以用十六進制表示浮點數值,例如0.125 = 2-3 可以表示成0x1.0p-3(p表示指數。注意,尾數采用十六進制,指數采用十進制。指數的基數是2,而不是10)
- 所有浮點數值計算都遵循IEEE 754規範。(簡單來說就是用科學技術法來表示一個浮點數,然後統一規定浮點數在單精度,雙精度中符号位的位置,尾數,指數所占位數及其位置)
- 表示溢出和出錯情況的三個特殊的浮點數值:正無窮大,負無窮大,NaN(不是一個數字)。Double/Float.POSITIVE_INFINITY、NEGATIVE_INFINITY、NaN 分别表示這三個數值,實際中很少用到。
- 所有“非數值”的值都認為是不相同的,是以不可用x == Double.NaN來檢測一個特定值是否等于Double.NaN。但可以Double.isNaN(x) ,來檢測x是否是非數值。
- 在金融計算中,就不可使用浮點數值了,其存在誤差。得用BigDecimal類表示。(請檢視九、大數值)
3.char類型
char類型原本用于表示單個字元,如今,有些Unicode字元用一個char值描述,有些Unicode字元用兩個char表示。(Unicode字元表所描述的字元數量遠大于占2個位元組的char類型取值範圍)
char類型的字面量值要用單引号括起來。char類型的值可以表示為十六進制值,其範圍\u0000到\uffff。除\u外,還有其他轉義字元
轉義字元
轉義序列 | 名稱 | Unicode值 |
---|---|---|
\b | 倒退 | \u0008 |
\t | 制表 | \u0009 |
\n | 換行 | \u000a |
\r | 回車 | \u000d |
" | 雙引号 | \u0022 |
’ | 單引号 | \u0027 |
\ | 反斜杠 | \u005c |
特别地:注釋中遇到 \u 也會進行解析,如:// \u00A0 is a newline 會産生一個文法錯誤,因為\u00A0 表示換行。又如:// Look inside c:\users,也會産生一個文法錯誤,因為\u 後并不是4個數字。
Unicode 與 char類型
設計Unicode編碼是為了解決各國編碼方案不一緻的問題。剛開始Java采用16位的Unicode字元集,但很快Unicode字元超過了65536個,其主要原因是增加了大量的漢語、日語和韓語的表意文字。
為解決Unicode與char之間的問題,引入了碼點(code point)。碼點是指一個編碼表中某個字元對應的代碼值。在Unicode标準中,碼點采用十六進制書寫,并加上字首U+。
Unicode的碼點分成17個代碼級别(code plane)。第一個代碼級别稱為基本的多語言級别(常用),碼點從U+0000到U+FFFF;其餘的16個級别代碼從U+10000到U+10FFFF,其中包括一些輔助字元。
UTF-16編碼采用不同長度的編碼表示所有Unicode碼點。在基本的多語言級别中,每個字元用16位表示,被稱為代碼單元。此時就産生一個問題,要擴充位元組來容納其他級别字元嗎?不行,人們常用的字元大多是基本多語言級别中的字元,為了不常用的字元,去打破之前的相關設計不值得。那怎麼辦呢?其他級别字元(也常稱作輔助字元)采用一對連續的代碼單元進行編碼。輔助字元區間是U+10000~U+10FFFF(其個數總共是1024*1024個,二進制位需占用20位)。是以規定如下:其他級别字元用兩個代碼單元表示(二進制位共32位),即每個代碼單元,有10位表示具體數字的,剩餘6位做标記,所作标記要保證不管機器怎麼讀,不會存在歧義的情況。那規定前六位為1101 10(十進制54)的表示第一個代碼單元(1101 10xx xxxx xxxx);前六位為1101 11(十進制55)表示第二個代碼單元(1101 11xx xxxx xxxx)。即U+D800 ~ U+DBFF為輔助字元第一部分,U+DC00 ~ U+DFFF為輔助字元第一部分。為了UTF-16編碼方法的正确,Unicode将U+D800~U+DFFF作為保留區,不在這塊配置設定字元。(懂進制轉換的話,這塊比較容易了解)
在Java中,char類型描述了UTF-16編碼中的一個代碼單元,是以強烈建議不要在程式中使用char類型。(推薦使用字元串,字元串中對碼點和代碼單元也有相關介紹,見 六,5 碼點與代碼單元)
常見編碼:
- 數字:[0x30,0x39](或十進制[48, 57])
- 大寫字母:[0x41,0x5a](或十進制[65, 90])
- 小寫字母:[0x61,0x7a](或十進制[97, 122])
也可前往位址Unicode字元集,檢視所有的Unicode字元。
4. boolean類型
boolean(布爾)類型有兩個值:false和true,用來判定邏輯條件。整型值和布爾值之間不能進行互相轉換。(C++中0表示false)
四、變量
1. 聲明變量
格式:[類型] [變量名] [;]
- 類型可以是資料類型和類,接口等對象
- 變量名必須是一個以字母開頭并由字母和數字構成的序列。Java中字母或數字是在所有語言中表示字母或數字的Unicode字元,比如德國‘ä’,希臘‘π’。并不僅僅是A ~ Z,a ~ z,0~9。聲明的變量名應是有意義的,且大小寫敏感,長度上無限制。【推薦:變量名命名規範:首字母小寫,後面單詞首字母大寫(小駝峰)】
- 每個聲明以分号結束
- 盡管$屬于一個合法的Java字元,但不要使用,它隻用在Java編譯器或其他工具生成的名字中(編譯内部類時,編譯器是用$來作為中間符号定義内部類名的)。不能使用Java保留字作為變量名。
- 可以在一行中聲明多個變量,但不提倡。逐一聲明變量,可讀性加強。
2. 變量初始化
聲明一個變量之後,必須用指派語句對變量進行顯式初始化。
// 對一個已經聲明過的變量進行指派
int vacationDays;
vacationDays =12;
// 将變量的聲明和初始化放在同一行
int vacationDays = 12;
變量的聲明盡可能地靠近第一次使用的地方,這是一種良好的程式編寫風格。
3. 常量
關鍵字final 訓示常量
// 常量
final double CM_PER_INCH =2.54;
// 類常量
static final double CM_PER_INCH =2.54;
- 關鍵詞final 表示這個變量隻能被指派一次,一旦被指派之後,就不能再修改了
- 習慣上,常量名使用全大寫方式
- 類常量:可在一個類中多個方法中使用,定義在main方法外部
五、運算符
1. 算術運算符
+ - * / % (加,減,乘,除,求餘)
- 當參與 / (除)運算的兩個操作數是整數時,表示整法除法,即結果隻保留整數;否則浮點除法。舉例:15/2 結果是7;15.0/2=7.5
- 整數被0除會産生一個異常,浮點數被0除會得到無窮大或NaN結果
- 可移植性是Java語言的設計目标之一,無論在那個虛拟機上運作,同一運算應得到同一的結果。但對于浮點數的運算,這是很困難的。舉例說明:double類型使用64位存儲一個值,而有些處理器使用80位寄存器,得到的結果會比64位寄存器更加精确。此時Java虛拟機初期規定:所有的中間計算結果都必須進行截斷。但這種方法遭到反對,因截斷操作需消耗時間。後Java給予改進,預設情況下,Java虛拟機允許對中間計算結果采用擴充的精度,但是strictfp标記的方法或類内部必須使用嚴格的浮點計算。(嚴格在哪?嚴格在不同的機器上的浮點計算結果一緻)。
2. 數學函數與常量
在Math類中,包含了各種各樣的數學函數
常見函數
傳回類型 | 方法和參數 |
---|---|
static double | sqrt(double a):傳回正平方根 |
static double | pow(double a,double b):傳回a^b結果 |
static int | floorMod(int x,int y):傳回x%y的值。最初在設計%求餘操作時,忽略了一個準則:餘數總是>=0 。而 -3 % 2 = -1,這顯然不符合數學規範。是以引入了這個方法,保證餘數始終>=0 |
static long | round(double a):傳回a四舍五入後的long值 |
Math中還有一些三角函數,指數函數,對數函數,具體檢視jdk-api-1.8幫助文檔中文版(我有上傳資源) | |
常量 | Math中有兩個常量:Math.PI(π) Math.E (自然對數的基數) |
- 關于函數調用,因為Math類中的方法都是靜态方法(static标注),是以直接[ 類名. 方法(參數) ] 調用即可。也可靜态導入:import static java.lang.Math.*; 那麼調用時就可把類名去掉:[ 方法(參數) ] 調用。
- 在Math類中,為了達到最快的性能,所有的方法都使用計算機浮點單元中的例程。如果想得到嚴格的計算結果【即在所有平台上得到相同的結果】應使用StrictMath類。
3. 數值類型之間的轉換
①自動類型轉換
- 實線表示無資訊丢失的轉換,虛線表示有精度損失的轉換(說明:檢視上面3.1 和3.2 整形和浮點型可表示數值的範圍,發現float表示的數值範圍要大于long型,是以int/long可以自動轉化為float型,更别說double型了。int型可實線轉換為double型,是因為double的精度約15位,而int型共10位【正負20億左右】是以可無損轉換。)
- 當兩種不同類型的數值進行計算時
②強制類型轉換
不符合自動轉換圖形的,都是強制類型轉換。
文法格式:(要轉換的類型) 變量
double x =9.97;
int nx = (int)x;
- 預設的強制類型轉換是通過截斷方式進行的。如浮點型轉整形,截斷小數部分。但如果在強制類型轉換過程中,超出了目标類型的表示範圍(比如:300轉byte)會截斷成一個完全不同的數值。
- 若想要進行舍入運算,則需要Math.round 方法。其API見上表
4. 結合指派運算符
- 同類别的還有 /= -= *= %=等
- x +=3.5; 若得到值與 x 類型不同,就會發生強制類型轉換(自動行為)
5. 自增與自減運算符
n++ / n--:将變量n的目前值加一或減一 (字尾)
++n / --n:将變量n的目前值加一或減一 (字首)
- 字尾和字首兩種形式單獨存在沒有差別,但放到表達式中就有差別了,運算符在前面,先自增/自減,再算表達式,否則,反之。
int m =7;
int n =7;
int a =2* ++m; //a是16,m是8
int b =2* n++; //b是14,n是8
6. 關系和boolean運算符
運算符 | 類别 |
---|---|
關系運算符 | ==,!=,<,>,<=,>= |
邏輯運算符 | &&(短路與),|| (短路或),!(非),&(與),|(非) |
三元運算符 | ?: 用法:條件判斷?true執行片段:false執行片段 |
- 短路與(&&)說明:條件判斷A && 條件判斷B ,若A錯誤,B就不執行了,因為結果已經注定了。短路或也是一樣的道理。隻要通過A就能确定整個表達式結果,B就不執行了。
7. 位運算符
&(與),|(或),^(異或),~(非),>>(右移),<<(左移),>>>(無符号右移):是按二進制位來計算的。也不經常用,畢竟不直覺。
8. 括号與運算符級别
括号級别最高,注意:! && || 優先級逐降低
運算符優先級(從高到低)
運算符 | 結合性 |
---|---|
[ ] . ( ) 【方法調用】 | 從左到右 |
! ~ ++ -- +【一進制運算符】 -【一進制運算符】()【強制類型轉換】 new | 從右到左 |
* / % | 從左到右 |
+ - | 從左到右 |
<< >> >>> | 從左到右 |
< <= > >= instanceof | 從左到右 |
== != | 從左到右 |
& | 從左到右 |
^ | 從左到右 |
| | 從左到右 |
&& | 從左到右 |
|| | 從左到右 |
?: | 從右到左 |
= += -= *= /= %= &= |= ^= <<= >>= >>>= | 從右到左 |
- +/- 一進制運算符用于數值的符号(正/負),當用于非數值時,會解析為數字。
- 優先級順序不需要特别去記,當存在多個運算符時,加括号是個不錯的程式設計習慣
9. 枚舉類型
有時,變量的取值隻在一個有限的集合内,例如披薩大小。當然可以分别編号,但是存在隐患,有可能存儲一個錯誤的數值。是以引入了枚舉類型。
enum Size {SMALL,MEDIUM,LARGE,EXTRA_LARGE}; //自定義枚舉類型
Size s= Size.MEDIUM; //聲明
Size類型的變量隻能存儲這個類型聲明中給定的某個枚舉值或null值。
六、字元串
1. 子串與拼接
Java字元串就是Unicode字元序列,Java中沒有内置的字元串類型,而是在标準Java類庫中提供了一個預定義類。每個用雙括号括起來的字元串都是String類的一個執行個體。
常用方法
傳回類型 | 方法名和參數 | 說明 |
---|---|---|
String | subString(int beginIndex) subString(int beginIndex,int endIndex) | (子串)傳回一個從beginIndex到串尾的所有代碼單元 |
String | subString(int beginIndex,int endIndex) | (子串)傳回一個從beginIndex到endIndex-1的所有代碼單元 |
static String | join(CharSequence delimiter, CharSequence… elements) | (拼接) 傳回一個新的字元串,用給定的定界符連接配接所有元素 |
- 舉例說明:String.join("/",“S”,“M”,“L”,“XL”); //結果是S/M/L/XL
- CharSequence是String繼承的一個接口
- Java允許使用+号拼接兩個字元串;當一個字元串與另一個非字元串的值進行拼接時,後者會轉換為字元串
2. 不可變字元串
String類沒有提供用于修改字元串的方法,是以将String類對象稱為不可變字元串。我們修改字元串,并不是修改字元串本身,而是建立一個字元串,将原來的字元串變量引用該建立的字元串。
進一步了解:編譯器讓字元串共享。即 将各種字元串存放在公共的存儲池中,字元串變量指向存儲池中相應的位置。但這同樣存在一個問題:共享存儲池中使用後不再使用的字元串會越來越多,會導緻記憶體洩漏。但幸運的是有垃圾回收機制,如果一塊記憶體不再使用,系統會将其回收。
Java的設計者認為共享帶來的高效率遠遠勝過提取、拼接字元串所帶來的低效率。
3. 檢測字元串是否相等
傳回類型 | 方法名和參數 | 說明 |
---|---|---|
boolean | equals(Object anObject) | 将此字元串與指定對象進行比較。相等傳回true,否則false |
boolean | equalsIgnoreCase(String anotherString) | 不區分大小寫比較是否相等 |
- 不要使用“==”運算符檢測兩個字元串是否相等!這個運算符隻能确定兩個字元串是否在同一個位置上。
- 不對呀!不是字元串共享嗎,同一個字元串應該在同一個位置上啊!但其實是字元串常量是共享的,而+或subString等操作産生的結果并不是共享的。
4. 空串和Null串
空串是長度為0的字元串,是一個Java對象,有自己的串長度(0)和内容(空)。
String變量可以存儲一個特殊值:null,表示目前沒有任何對象與該變量關聯。
// 檢查一個字元串是否為空
if (str.length()==0) 或者 if (str.equals(""))
// 檢查一個字元串是否為null
if (str == null)
// 檢查一個字元串既不是null也不為空串
if (str != null && str.length() !=0)
// 必須首先檢查str不為null,才可再檢查是否為空串。因為null是不可以調用的
5. 碼點與代碼單元
碼點 = 1或2 個代碼單元。具體緣由,請檢視 三,3 char類型中的描述。String字元串中索引從0開始
傳回類型 | 方法名和參數 | 說明 |
---|---|---|
int | length() | 傳回字元串代碼單元的數量 |
int | codePointCount(int beginIndex, int endIndex) | 傳回beginIndex到endIndex-1的碼點數量,參數是代碼單元的位置值。 |
char | charAt(int index) | 傳回位置為index的代碼單元 |
int | offsetByCodePoints(int index,int codePointOffset) | 傳回從index代碼點開始,位移codePointOffse個碼點後的代碼單元索引 |
int | codePointAt(int index) | 傳回從給定位置開始的碼點 |
IntStream | codePoints() | 從CharSequence接口繼承的方法,傳回一個int值流,每個int值對應一個碼點,可以将其轉化為一個數組。 |
// 得到第i的碼點;因為預設索引是按照代碼單元編号的,是以要先得到對應的代碼單元索引,再擷取值。
int index = str.offsetByCodePoints(0,i); //index >= i
int cp = str.codePointAt(index);
為了了解得更清晰,看下面代碼
public class Welcome {
public static void main (String[] args){
//𝕆 占兩個代碼單元,String索引從0開始
String str = "Welcome𝕆java";
System.out.println("代碼單元數量:"+str.length()); //13
System.out.println("碼點數量:"+str.codePointCount(0,str.length()));//12
System.out.println("占一半碼點數量:"+str.codePointCount(0,8)); //8
System.out.println("測試上一句:"+str.codePointCount(0,9)); //8
int index = str.offsetByCodePoints(0,8);
System.out.println("第8個碼點的代碼單元值:"+index); //9
System.out.println("代碼單元索引為9的碼點值"+str.codePointAt(index)); //j ox6A 106
}
}
6. 建構字元串
有時需要将許多較短的字元串建構成一個字元串,例如按鍵或來自檔案中的單詞。采用字元串連接配接的方式效率低。是以使用StringBuilder類。
具體操作:
- 建構一個空的字元串建構器:StringBuilder builder = new StringBuilder();
- 當需要添加字元或字元串時,調用append方法
- 調用toString方法,可傳回String對象
補充:
- JDK5.0中引入了StringBuilder類,這個類的前身是StringBuffer,StringBuffer效率低,但允許采用多線程的方式執行添加或删除字元的操作。如果所有字元串在一個單線程中編輯,則應該用StringBuilder替代它。這兩類的API是相同的。
StringBuilder常見方法
傳回類型 | 方法名和參數 | 說明 |
---|---|---|
int | length() | 傳回代碼單元數量 |
StringBuilder | append(String str) | 追加一個字元串并傳回this |
StringBuilder | append(char c) | 追加一個代碼單元并傳回this |
StringBuilder | appendCodePoint(int codePoint) | 追加一個代碼點并傳回this |
void | setCharAt(int index,char ch) | 将第i個代碼單元設定為c |
StringBuilder | insert(int offset, String str) | 在offset位置插入一個字元串并傳回this |
StringBuilder | delete(int start, int end) | 删除從start到end-1的代碼單元并傳回this |
String | toString() | 傳回字元串 |
七、輸入輸出
本部分主要講輸入輸出到控制台,現代的程式都使用GUI收集使用者的輸入。
1. 讀取輸入
- 構造Scanner對象:Scanner in =new Scanner(String.in)
-
讀取一行:String name = in.nextLine(); //輸入行中可能包含空格
讀取一個單詞:String name = in.next(); //以空格進行分割
讀取一個整數:String age = in.nextInt(); // 還有其他方法,讀取浮點型等
需要注意:
- Scanner類定義在java.util包中,當使用的類不是定義在基本java.lang包中時,一定要使用import訓示字元将相應的包加載進來。比如Scanner 應在在檔案開頭:import java.util.Scanner;
- 因為輸入是可見的,是以Scanner類并不适用從控制台讀取密碼。JavaSE6特别引入了Console實作這個目的。但該類隻能在控制台(cmd)中執行,不能在eclipse中運作。而且現在都是通過GUI(界面)進行輸入的,是以Console類也不需要了解。
2. 格式化輸出
System.out.print(x); 輸出x,但是會将x對應的資料類型所允許的最大非0數字位數列印輸出。舉例:10000.0/3.0 會輸出 3333.3333333333335。
慶幸的是,Java5.0 沿用了C語言函數中的printf方法。調用語句是System.out.printf("%8.2f",x); %8.2f 就是格式說明符,當然不會這麼簡單,完整格式如下:
格式說明符
用于printf的标志
标志 | 目的 | 舉例 |
---|---|---|
+ | 列印正數和負數的符号 | +3333.33 |
空格 | 在正數之前添加空格 | | 3333.33| |
數字前面補0 | 003333.33 | |
- | 左對齊 | |3333.33 | |
( | 将負數括在括号内 | 原值:-3333.33 現:(3333.33) |
, | 添加分組分隔符 | 3,333.33 |
#(對于f格式) | 包含小數點 | 3,333. |
#(對于x或0格式) | 添加字首0x或0 | 0xcafe |
$ | 給定被格式化的參數索引 | %1$d 以十進制格式列印第一個參數 |
< | 格式化前面說明的數值 | %d%<x 以十進制,十六進制列印同一數值 |
用于printf的轉換符
轉換符 | 類型 | 舉例 |
---|---|---|
d | 十進制整數 | 159 |
x | 十六進制整數 | 9f |
o | 八進制整數 | 237 |
f | 定點浮點數 | 15.9 |
e | 指數浮點數 | 1.59e+01 |
g | 通用浮點數 | – |
a | 十六進制浮點數 | 0x1.fccdp3 |
s | 字元串 | Hello |
c | 字元 | H |
b | 布爾 | True |
h | 散列碼 | 42628b2 |
tx或Tx | 日期時間 | 已淘汰,應使用java.time包 |
% | 百分号 | % |
n | 與平台有關的行分隔符 | – |
舉了一些例子,說明值被格式化的位置問題
public class Welcome {
public static void main (String[] args){
//預設情況下,值的位置與格式說明符的位置一一對應
System.out.printf("測試:%08.2f,%(e \n",3333.33,-4444.44);
//也可通過$,< 進行位置指定
System.out.printf("測試:%2$08.2f,%1$(e , %<8.2f \n",3333.33,-4444.44);
}
}
- 标志是為了讓輸出項更加美觀
- 可以使用s轉換符格式化任意的對象,該對象若實作了Formattable接口,則調用formatTo方法,否則調用toString方法
- 關于時間/日期的轉換符,以t/T開頭,以相應其他字元結尾,比如%tD,會顯示美國格式的日期。這裡并沒有列出,是因為很多,且推薦使用java.time包中類與方法。
- 參數索引值從1開始
3. 檔案輸入輸出
檔案輸入: Scanner in =new Scanner(Path.get(“myfile.txt”),“UTF-8”);
- 如果檔案名中包含反斜杠符号,就要在每個反斜杠之前再加一個額外的反斜杠:“c:\\mydirectory\\myfile.txt”
- 這裡指定了UTF-8字元編碼,常見但不普遍。是以在讀取一個檔案時,要知道它的字元編碼。如果沒有指定,則會使用運作這個Java程式的機器的“預設編碼”,這不合适,因為部署其他機器上時可能會出現亂碼。
- 可使用前面介紹的任何一個Scanner方法對檔案進行讀取
- Scanner構造器中有一個Scanner(String source)的方法,其會将字元串解釋為資料,而不是檔案名。
輸出檔案: PrintWriter out = new PrintWriter(“myfile.txt”,“UTF-8”);
- 該方式輸出檔案,若檔案不存在,會建立該檔案,而且可使用print、println、printf 指令
- 當指定一個相對檔案名時,檔案位于Java虛拟機啟動路徑的相對位置;如果在指令行啟動程式,啟動路徑是指令解釋器的目前路徑;如果使用內建開發環境,啟動路徑有IDE控制。是以推薦使用絕對路徑
上面是Scanner類與PrintWriter類的簡單用法,其他用法請檢視jdk1.8API(我有上傳資源)
八、控制流程
1. 塊作用域
塊(即複合句)是指由一對大括号括起來的若幹條簡單的Java語句,塊決定了變量的作用域。
- 塊可以嵌套:一個塊可以嵌套在另一塊中
- 不能在嵌套的兩個塊中聲明同名的變量
- 在控制流程中(條件語句或循環語句)若statement(語句)隻有一句,可以不加塊(一對大括号),但加上最好,提高閱讀體驗。
public static void main (String[] args){
int n;
{ //塊可以嵌套
int k;
int n; //不可聲明同名變量,因為變量的作用域在其所屬塊及其嵌套塊中。
}
}
2. 條件語句
-- if 條件語句 --
1. if (condition) statement; //condition為TRUE,執行statement
2. if (condition) {statements;} //condition為TRUE,執行多條statement
3. if (condition) {Astatements;} else{Bstatements;} //condition為TRUE,執行Astatements,為FALSE,執行Bstatements。else部分可選
4. if (conditionA) {Astatements;} else if (conditionB){Bstatements} else{Cstatements} //conditionA 為TRUE,執行Astatements,為FALSE,再判斷conditionB,為TRUE,執行Bstatements,為FAlSE,執行Cstatements
5. 以上else部分皆可選
-- switch 多重選擇 --
//在處理多個單值選項時,if/else結構顯得有些笨拙。例如:結果是A怎麼樣,是B怎麼樣,是C怎麼樣...
switch(choice){
case label1: ... break;
case label2: ... break;
case label3: ... break;
....
default: ... break;
}
- switch語句将從與選項值相比對的case标簽處開始執行直到遇到break語句,或者執行到switch語句的結束處為止。如果沒有相比對的case标簽,而有default子句,就執行這個子句。
- 如果case分支語句的末尾沒有break語句,那麼就會接着執行下一個case分支語句。
- choice值的類型可以是char、byte、short或int的常量表達式;可以是枚舉變量;可以是字元串字面量(java7開始)
3. 循環語句
-- while循環 --
1. while(condition) statement; //condition為TRUE,執行一條statement,也可選擇{statements;}
2. do{statements;} while(condition); //與1的差别是:1循環體statement可能一次都不執行,而2先執行一次循環體,再判斷條件。注意:結尾分号不可少
-- for 循環 --
for (int i=0;i<10;i++) {System.out.println(i);..循環體..} //第一部分int i=0,對計數器進行初始化;第二部分i<10,再每次新一輪循環執行前要檢測的條件;第三部分i++ 訓示如何更新計數器。三個部分都可省略,相當于while(true){...},會一直循環下去。
-- for each循環 --
for(variable: collection) statement;
例:for(int element: a) System.out.println(element); //a為一個int數組
- for循環第一部分聲明一個變量後,這個變量的作用域為for循環的整個循環體。
- for循環中聲明變量時,不要用double類型,一般為int,因為浮點型在更新計數器時可能存在數值誤差。
- 如果想在for循環體之外使用計數器的值,就要将計數器i定義在循環體之外
- 可以在各自獨立(不嵌套)不同的for循環中可定義同名的變量。
- for循環語句隻不過是While循環的一種簡化形式。是以兩者在一定條件下是可以互相轉換的
- for循環的三個部分,定義部分(i=0),判斷部分(i<10)是先執行的,更新計數器部分(i++)是在循環體執行之後才執行的。
- for each循環用來依次處理集合中每一個元素,而不必為下标值分心。
- for each循環variable用于暫存集合中每一個元素,并執行相應的語句或語句塊。collection必須是一個數組或實作了Iterable接口的類對象。
- for each循環中不會改變集合元素,因為variable隻是集合中元素的一個副本
4. 中斷控制流程語句
不帶标簽的break語句
與用于退出switch語句的break語句一樣,在你想退出控制流程時,直接break就好。隻能退出一層循環。
帶标簽的break語句
主要用于退出多重嵌套的循環語句。具體用法如下:
label_declaration: //标簽聲明,标簽必須放在希望跳出的最外層循環之前
while(...){
for(...){
if(...)
break label_declaration; //跳出兩層循環,到标簽前
}
}
- 可以将标簽應用到任何語句中,甚至可以應用到if語句或塊語句中。
- 隻能跳出語句塊,不能跳入語句塊。
continue語句
與break語句一樣,将中斷正常的流程控制。具體效果:跳過剩餘的循環體部分,從新一輪循環開始執行。特别地,針對for循環,continue之後,先執行一次更新計數器的操作,再從新一輪循環開始。當然也有帶标簽的continue。
九、大數值
如果基本的整數和浮點數精度不能滿足需求,那麼可以使用java.math包中的兩個類:BigInteger和BigDecimal。這兩個類可以處理包含任意長度數字序列的數值。BigInterger類實作了任意精度的整數運算,BigDecimal實作了任意精度的浮點數運算。下面給出了一些方法供參考:
BigInteger
傳回值 | 方法名及參數名 | 解釋 |
---|---|---|
BigInteger | add(BigInteger other) | 傳回該大整數和另一個大整數other的和 |
BigInteger | subtract(BigInteger other) | 傳回該大整數和另一個大整數other的差 |
BigInteger | multiply(BigInteger other) | 傳回該大整數和另一個大整數other的積 |
BigInteger | divide(BigInteger other) | 傳回該大整數和另一個大整數other的商 |
BigInteger | mod(BigInteger other) | 傳回該大整數和另一個大整數other的餘數 |
int | compareTo(BigInteger other) | 比較兩個大整數,相等傳回0,<other傳回負數,>other傳回正數 |
static BigInteger | valueOf(long x) | 傳回 值等于x的大整數 |
BigDecimal
傳回值 | 方法名及參數名 | 解釋 |
---|---|---|
BigDecimal | add(BigDecimal other) | 傳回該大實數與另一個大實數的和 |
BigDecimal | subtract(BigDecimal other) | 傳回該大實數與另一個大實數的差 |
BigDecimal | multiply(BigDecimal other) | 傳回該大實數與另一個大實數的積 |
BigDecimal | divide(BigDecimal other, RoundingMode roundingMode) | 傳回該大實數與另一個大實數的商,RoundingMode 用來規定商的舍入方式 |
int | compare(BigDecimal other) | 比較兩個大實數,相等傳回0,<other傳回負數,>other傳回正數 |
static BigDecimal | valueOf(long x) | 傳回 值等于x的大實數 |
static BigDecimal | valueOf(long x, int scale) | 傳回 值等于x * 10scale 的大實數 |
十、數組
1. 數組簡介及聲明
數組是一種資料結構,是用來存儲同一類型值的集合,通過一個整型下标可以通路數組中的每一個值。
int[] a; //聲明數組a
int[] a = new int[100]; //聲明并建立數組(也被稱作初始化,因為數組會被預設指派)
- 可以使用兩種方式int[] a; int a[]; 聲明數組,但推薦使用int[] a; 需要注意的是:僅聲明數組是不能使用該數組的,必須建立new或者初始化才能使用。
- new int[100]:建立一個可以存儲100個整數的數組,數組長度100不要求是常量,還可以是變量。
- 數組的下标從0開始。建立一個數字數組時所有元素初始化為0;boolean數組初始化為false;對象數組的元素初始化為特殊值null,這表示這些元素還未存放任何對象
- 一旦建立了數組,就不能改變它的大小,若想更靈活的擴充數組,見ArrayList
- Arrays類中的toString() 方法,可将數組列印成字元串。API見十,5
2. 數組初始化及匿名數組
① int[] smallPrimes = {2,3,4,5,6,7}; //建立數組對象并同時賦予初始值
② new int[] {5,6,7,8,9,10}; //初始化一個匿名數組
③ smallPrimes = new int[] {5,6,7,8,9,10}; //不建立新變量的情況下重新初始化一個數組
- 在初始化中,數組的大小就是初始值的個數
- 允許數組長度為0
3. 數組拷貝
Java中允許将一個數組變量拷貝給另一個數組變量
int[] smallPrimes = new int[6];
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] =12 //現在smallPrimes[5] 也是12了
其邏輯如下:兩個數組變量指向同一塊空間
但也可以通過Arrays的copyOf方法,拷貝整個數組,這個方法也常用來增加或減少數組的大小
//拷貝數組
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers,luckyNumbers.length);
//增加數組大小,多餘的元素預設初始化;也可減少數組大小,那就隻拷貝最前面的數組元素
luckyNumbers = Arrays.copyOf(luckyNumbers,2*luckyNumbers.length);
其邏輯如下:
5. Arrays類常用API
type借指8種資料類型:byte,short,int,long,boolean,char,float,double。下面的方法都是靜态(static 修飾)的,即通過類名直接調用
傳回值 | 方法名與參數 | 解釋 |
---|---|---|
Static String | toString(type[ ] a) | 傳回a中資料元素的字元串,形如格式:[1,2,3,4], |
static type | copyOf(type[] a,int length ) | 傳回與a類型相同的一個數組,長度為length,數組元素為a的值 |
static type | copyOf(type[] a,int start,int end) | 傳回與a類型相同的一個數組,長度為end-start,數組元素為a的值。包括start,不包括end |
static void | sort(type[] a) | 采用優化的快速排序算法對數組進行排序 |
static int | binarySearch(type[] a,type v) | 采用二分搜尋算法查找值v,查找成功,傳回下标值,否則傳回一個負數 |
static int | binarySearch(type[] a,int start,int endtype v) | 采用二分搜尋算法在[start,end) 區間内查找值v,查找成功,傳回下标值,否則傳回一個負數 |
static void | fill(type[] a,type v) | 将數組中所有資料元素值設定為v |
static boolean | equals(type[] a,type[] b) | 若兩個數組大小相同,且下标相同的元素都對應相等,傳回true,否則,傳回false |
static String | deepToString(Object[] a) | 用于将多元數組轉換為字元串,其格式:[[…],[…],[…]] |
6. 多元數組
多元數組将使用多個下标通路資料元素,适用于表示表格或更加複雜的排列方式。
//聲明數組
double[][] balances;
//建立數組/初始化 (三行三列)
balances = new double[3][3];
//若知道數組元素,就可以不調用new/簡化的書寫形式進行初始化
int[][] magicSquare={{16,3,2},{5,10,11},{9,6,7}};
//一旦數組被初始化,可使用兩個括号通路數組元素
magicSquare[1][2] 值為:11 //數組索引從0開始計數
- for each循環語句不能自動處理二維數組的每一個元素。若想使用,需要兩個嵌套的循環
- 列印二維數組:使用Arrays的deepToString方法
①for(double[] row: magicSquare)
for(double value:row)
...do something with value...
② System.out.println(Arrays.deepToString(magicSquare));
7. 不規則數組
Java中實際沒有多元數組,隻有一維數組,多元數組被解釋為“數組的數組”。是以可以建立不同行有不同列的情況
int[][] balances = new int[3][]; //也可new int[3][4];表示3行4列
balances[0] = new int[4];
balances[1] = new int[3];
balances[2] = new int[1];
其邏輯如下:
- new int[3][];可以,但new int[][3];不可以,即在建立數組時,可隻規定行數,列數後續建立。但不可以隻規定列數,行數空缺。