目標讀者
本指南特別適合有Python基礎的同學學習Java入門,對於沒有任何程式設計經驗的同學可能會存在困難。
為什麼測試人員要學Java
選擇Java,應該不錯。TesterHome測試論壇知名大佬基本都是以Java技術棧為主,少部分是Golang和Python。我公司2021年校招的兩個同濟大學研究生,測試開發,也是以Java為主。有一個測開同事跳槽去了美團,拿了高薪,只會Java。有一個測開同事跳槽去了創業公司做了測試架構師,只會Java。招聘網站搜尋測試開發20K以上職位,基本都要求會Java。我接觸到的開發,Java程式設計師佔80%以上。
測試人員用Java能幹嘛
如果你的公司是以Java技術棧為主,那麼你可以用Java做所有事情,而且有些事情只能用Java來做。這個問題挺關鍵的,學習一門語言肯定是要能夠學以致用。在自動化測試,Java會顯得稍微有點笨重,而Python會適合一點。你可以用Python來寫介面自動化指令碼,在小範圍內使用,但是當團隊變大以後,指令碼如何規範如何維護,就成了一個很大的問題,而Java由於靜態語言特性和麵向物件程式設計,正好可以用來解決這個問題。在測試平臺和效能測試,Java有很成熟的Web開發框架和配套的生態。在測試工具開發,公司封裝好的Java庫可以拿來即用,碰到問題也可以找開發幫忙。白盒測試,基本上都是要靠Java來做的,看程式碼,用JaCoCo統計程式碼覆蓋率。其他專項比如流量錄製回放、全鏈路壓測、Dubbo介面測試,都只能使用Java來做。
測試人員怎麼學Java
我推薦刷完一遍基礎語法後,在LeetCode上面刷演算法題來加強練習。Java還是有一定的學習門檻的,初學者可能學起來會有些吃力,可以先從Python入手,瞭解程式語言的底層邏輯,等對程式設計有些許感知以後,再學習Java。基礎語法可以快速瀏覽一遍,一遍並不會就能記住了,需要在編碼中持續加強記憶。光學語法也不行,學習Java和其他程式語言一樣,需要多敲多練,刷演算法題,既能熟悉Java語法,也能熟悉演算法,一舉兩得,題做不來就先把答案背一遍再做。另外,可以在工作中主動找研發開通下程式碼許可權,嘗試Review開發程式碼,看多了,有些技巧也會知道了。有機會,可以用Java寫點工具或者平臺,實踐出真知。
搭建環境
安裝Java
Java的安裝包是個.exe
檔案,特殊地方在於檔名不是java-xxx.exe
而是jdk-xxx.exe
,比如jdk-8u281-windows-x64.exe
,jdk
是Java Development Kit
的縮寫,指Java開發工具包,包括以下內容:
JDK的最新版本為15,但是國內大多數公司仍然使用的是JDK8,這是因為JDK8是各方面都很成熟穩定的版本,並且基於JDK8開發的業務系統已經具有一定規模,新版本JDK並不能完全無感知的遷移,需要做程式碼修改和測試,會是一筆巨大開銷,為了降低成本和規避相容問題風險,JDK8沿用到了至今。JDK8的下載地址如下:
https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
選擇相應的版本下載:
比如我的電腦是Windows 64位的系統,就選擇了Windows x64
這個版本,會下載到一個jdk-8u281-windows-x64.exe
檔案。Java已經被Oracle收購了,需要登入Oracle賬號後才能下載,沒有賬號註冊一個也很方便:
下載後可以開始安裝了:
安裝到預設位置即可,直接下一步。中途會讓選擇JRE(Java Runtime Environment,Java執行環境)的目標資料夾:
依然保持預設即可。安裝結束後就能看到兩個新資料夾了:
以前,還需要配置系統環境變數,設定JAVA_HOME
和CLASSPATH
才能使用Java(具體方法百度有很多)。現在,安裝完成即可用,省去了不少麻煩,速度加快。開啟cmd
輸入java -version
,命令能執行成功就表示Java已經安裝好了:
安裝IntelliJ IDEA
JetBrains全家桶中也有專門用來寫Java的,叫做IntelliJ IDEA
,一般只說後面一個單詞“哎迪兒”就知道是這個東西了。下載地址為:
https://www.jetbrains.com/idea/download/#section=windows
個人建議選擇旗艦版,看著齊全。下載後雙擊ideaIU-2020.3.2.exe
安裝,先別忙著開啟。
Maven倉庫
Maven是用來管理Java第三方包的主流倉庫工具,通過pom.xml
檔案來配置安裝即可,在mvnrepository網站上能檢索到所需配置資訊:
官方倉庫有時候下載速度很慢,本文用國內映象替代,提高首次開啟時同步倉庫速度。我們先把Maven中央倉庫從Apache替換成阿里雲。開啟本地目錄D:\Program Files\JetBrains\IntelliJ IDEA 2020.3.2\plugins\maven\lib\maven3\conf
:
編輯settings.xml
檔案,找到<mirrors>
標籤,新增程式碼:
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里雲公共倉庫</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
這是新版寫法,官網https://maven.aliyun.com/mvn/guide有說明。
接著可以開啟IDEA了,歡迎介面映入眼簾:
新建專案
選擇新建Maven專案:
填寫專案名和存放位置:
在pom.xml
檔案中新增倉庫配置:
<repositories>
<repository>
<id>public</id>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<url>https://maven.aliyun.com/repository/public</url>
</pluginRepository>
</pluginRepositories>
記得點選右上角的Load Maven Changes
按鈕,此時前面切換倉庫的作用就體現出來了,右下角同步速度比預設明顯增快。至此,以阿里云為Maven中央倉庫的專案就建立好了。
其他設定
UTF-8
網路自動代理
基礎語法
Java雖然學習門檻有點高,但是如果熟悉Python以後,再看Java基礎語法,其實是非常簡單的。
4個概念
- 物件:Java是純物件導向程式語言,物件的概念有點抽象,具體來說可以是一條狗,也可以是某個人。
- 類:類是物件的模板,有點像克隆的母體。
- 屬性:屬性就是狀態,相當於變數。
- 方法:方法就是行為,跟函式類似,完成某個特定功能。
Hello World
Java的Hello World經常拿來和其他語言比較,嫌它囉嗦,然而囉嗦的背後是嚴謹:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
Java把每個語法都顯式的表達了出來,閱讀程式碼就能知道是什麼意思,不會產生額外的意想不到的結果。
基本語法
public static void main(String[] args)
,是所有Java程式的執行入口。- 原始檔字尾是
.java
,原始檔名稱必須和類名一致。 - 原始檔編譯後的檔案字尾是
.class
。 - Java是大小寫敏感的,類名首字母應該大寫,方法名首字母小寫,也就是駝峰命名法。
識別符號
類名、屬性名和方法名都被稱為識別符號,Java識別符號規則如下:
- 識別符號是大小寫敏感的
- 所有的識別符號都應該以字母(
A-Z
或者a-z
)、美元符($
)、或者下劃線(_
)開始 - 首字元之後可以是字母(
A-Z
或者a-z
),美元符($
)、下劃線(_
)或數字的任何字元組合 - 關鍵字不能用作識別符號
比如合法的識別符號:
age、$salary、_value、__1_value
非法的識別符號:
123abc、-salary
修飾符
- 訪問控制修飾符 : default, public, protected, private
- 非訪問控制修飾符 : final, abstract, static, synchronized
Java的修飾符極大的提高了程式碼可閱讀性。
變數
因為Java的程式碼都必須寫到類裡面,所以就只有以下三種變數:
- 類變數(靜態變數),相當於全域性變數
- 成員變數(非靜態變數)
- 區域性變數
註釋
public class HelloWorld {
/* 這是第一個Java程式
* 它將輸出 Hello World
* 這是一個多行註釋的示例
*/
public static void main(String[] args){
// 這是單行註釋的示例
/* 這個也是單行註釋的示例 */
System.out.println("Hello World");
}
}
八種基本型別
boolean 布林型 1個位元組 8bit(8位)
byte 位元組型別 1個位元組
char 字元型別 2個位元組
short 短整型 2個位元組
int 整型 4個位元組
long 長整型 8個位元組
double 雙精度型別 8個位元組
float 浮點型(單精度)4個位元組
預設的整數型別是int,如果要定義為long ,則要在數值後加上L
或者l
。
預設的浮點型是double,如果要定義float,則要在數值後面加上F
或者f
。
物件和類
我們都知道Java是純物件導向程式語言,這個物件是什麼,類是什麼,它們的關係是怎樣呢?
類和物件的關係
先看一張圖:
類是girl和boy,物件是每個具體的女孩(Lucy、Rose)和男孩(David、Jack)。
這完美解釋了類和物件的關係,即:類是物件的模板。
狀態和行為
物件有兩個特徵,一個是狀態(又叫做屬性),一個是行為(又叫做方法),我們拿狗來舉例,狗的狀態有品種、大小、顏色、年齡;行為有吃、跑、睡覺。如圖所示:
圖的左邊是3個狗物件,右邊是1個狗類。類定義了物件應該有哪些屬性和方法,物件根據類定義好的模板,建立了個性化的例項。
程式碼實現如下:
public class Dog {
// 屬性
String breed;
int size;
String colour;
int age;
// 方法
void eat() {
}
void run() {
}
void sleep(){
}
}
構造方法
在通過類建立物件時,構造方法提供瞭如何建立物件的細節。Java會給類一個預設的構造方法,你也可以自定義一個或多個構造方法,構造方法命名必須和類名相同,比如:
public class Dog{
public Dog(String breed){
}
}
程式碼中定義了2個構造方法,根據引數不同,在構造時會呼叫相應的構造方法。
建立物件
如果沒有物件,那麼就new一個。Java是通過new關鍵字來建立物件的。比如使用預設構造方法建立物件:
Dog myDog = new Dog();
或者使用自定義構造方法建立物件:
Dog myDog = new Dog("Bulldog");
訪問物件屬性和方法
Java和大多數語言一樣,採用.
運算子訪問物件屬性和方法,比如:
public class Dog {
int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public static void main(String[] args) {
// 建立物件
Dog myDog = new Dog();
// 通過方法來設定age
myDog.setAge(2);
// 呼叫另一個方法獲取age
System.out.println(myDog.getAge());
// 也可以像下面這樣訪問成員變數
System.out.println(myDog.age);
}
}
類存放規則
Java原始檔是用類來組織的,存放在原始檔中的類遵循下面幾項規則:
- 一個原始檔只能有一個public類,可以有多個非public類。
- 原始檔名必須與public類名一致。
- package語句在首行,其次是import語句,最後是類。
八大基本資料型別
Java內建了8個基本資料型別,它們分別是byte、short、int、long、float、double、boolean、char。
每種基本資料型別都有相應的包裝類:Byte、Short、Integer、Long、Float、Double、Character。包裝類提供了物件導向的實現,比如二進位制位數(
Integer.SIZE
)、最小值(Integer.MIN_VALUE
)、最大值(Integer.MAX_VALUE
)等。
byte
8位整數,預設值是0
,byte型別主要用在大型陣列中節約空間,因為它佔用的空間只有int型別的四分之一。
short
16位整數,預設值是0
。跟byte型別用法類似,佔用空間是int型別的二分之一。
int
32位整數,預設值是0
。最常用的整數型別。
long
64位整數,預設值是0L
。超出int範圍的整數需要使用long型別。
float
32位浮點數,預設值是 0.0f
。float型別用來表示小數。
double
64位浮點數,預設值是0.0d
。浮點數的預設類似是double型別。
boolean
1位真假值(true/false),預設值是false
。
char
16位Unicode字元,預設值是u0000
。用來儲存任何單一字元。
第九種基本資料型別void
實際上,Java還有第九種基本資料型別void,我們經常在方法返回值那裡見到它,它的包裝類是java.lang.Void
。
三大變數型別
Java中的一個類可以包含3種型別的變數:區域性變數、成員變數、類變數。它們的定義位置如下圖所示:
區域性變數
區域性變數是在方法、構造方法或者語句塊中定義的變數。變數宣告和初始化都是在方法中,方法結束後,變數就會自動銷燬。
成員變數
成員變數是在類中,方法體之外定義的變數。變數在建立物件的時候例項化,可以被類中方法、構造方法和特定的語句塊訪問。
類變數
類變數跟成員變數定義的位置相同,只不過必須宣告為static型別。
成員變數和類變數在使用上有個明顯的區別是:類變數可以直接通過類名.變數
形式進行訪問,成員變數則不能。比如:
public class B {
static int classVar = 1; // 類變數
int memberVar = 2; // 成員變數
}
成員變數在寫程式碼時IDEA就已經報錯了。
修飾符
Java修飾符是讓Java變得囉嗦的罪魁禍首之一。其他很多語言並沒有這麼多修飾符,取而代之的是語法規則,比如Python下劃線開頭的變數是私有變數,Golang小寫字母開頭的變數是私有變數。但是,正因為Java有著明確的修飾符,所以Java程式碼看起來是最直白的表述。
修飾符概覽
Java修飾符有兩大類,它們分別如下:
訪問控制修飾符
- default(什麼都不寫)
- private
- public
- protected
非訪問控制修飾符
- static
- final
- abstract
- synchronized
- transient
- volatile
修飾符通常是放在一行程式碼最前面的,起到修飾作用,比如:
public class ClassName {
// ...
}
private boolean myFlag;
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
// 方法體
}
訪問控制修飾符
訪問控制,指的是對Java類、介面、變數、方法的訪問許可權的控制。我們知道Java每個檔案是一個類(Class),每個資料夾是一個包(Package),它們彼此之間能不能相互訪問,就是通過修飾符決定的。
訪問控制修飾符一覽表,從上往下,訪問許可權越來越小:
default
什麼都不寫,不使用任何修飾符,預設為包訪問許可權,即同一個包內都是可以訪問的。
Java有個很棒的設計:同一個包裡面的類不需要import就能直接使用。
示例:
String version = "1.5.1";
boolean processOrder() {
return true;
}
private
意思就像它的名字一樣,私有的,只有當前類的內部才可以訪問。private用來保護類的隱私,如果外部類想訪問private的變數,那麼只能通過public的getter方法暴露出去。需要注意的是,private可以用到變數、方法上,但是不能用到類和介面上(這麼做沒有意義,類總是要被外部呼叫的,介面總是要被外部實現的)。
示例:
public class Logger {
private String format;
public String getFormat() {
return this.format;
}
public void setFormat(String format) {
this.format = format;
}
}
public
公開的,所有都能訪問,沒有任何限制。
示例:
public static void main(String[] arguments) {
// ...
}
protected
當前類可以訪問,子類有可能可以訪問。子類有兩種情況:
- 子類與父類在同一個包中:子類可以訪問父類的protected。
- 子類與父類在不同的包中:子類可以訪問,非子類內部的子類例項不能訪問。
示例:
package test1;
public class Base {
int defaultInt;
protected int protectedInt;
}
// 不同的包
package test2;
// 子類
public class Test extends Base {
public void test(){
Test t = new Test();
//t.defaultInt = 2; 不可見
t.protectedInt = 3;
}
}
// 非子類
class TestNotSub{
public void test(){
Test t = new Test();
//t.defaultInt = 2; 不可見
//t.protectedInt = 3; 不可見
}
}
需要注意的是,protected可以用到變數、方法上,但是不能用到類(內部類除外)和介面上。
非訪問控制修飾符
static
static用來修飾變數和方法。修飾的變數叫做靜態變數/類變數,修飾的方法叫做靜態方法或/類方法。
靜態的含義是,無論例項化多少個物件,靜態變數或靜態方法只有一份。作為類變數或類方法,static的用法是可以直接通過ClassName.varName
訪問類變數,或直接通過ClassName.methodName()
訪問類方法,無需例項化物件。
需要注意的是,靜態方法裡面不能使用類的非靜態變數。
我以Python舉例可以更好說明這一點,Python的類方法第一個入參是cls,如果想訪問非類變數,那麼入參必須是self。
final
- final修飾變數:通常和static一起用來宣告常量,比如
static final String TITLE = "Manager";
- final修飾方法:父類的final方法可以被子類繼承,但是不能被重寫,防止該方法的內容被篡改。
- final修飾類:final類不能被繼承。
abstract
- abstract修飾類:抽象類。
- abstract修飾方法:抽象方法。
抽象意味著它們只定義了一個形式,沒有具體內容,一定會由其他的類或方法進行具體實現。如果類中有抽象方法,那麼這個類必須要定義為抽象類,否則會編譯報錯。
synchronized
用於修飾方法,這個方法同一時間只能被一個執行緒訪問。
transient
修飾變數,用的很少,我也看不懂。
volatile
修飾變數,變數每次被執行緒訪問時,都強制從共享記憶體中重新讀取值,當變數發生變化時,會強制執行緒將變化值寫入共享記憶體。這樣兩個執行緒在任何時候都能看到變數的同一個值。
運算子
Java一共有以下幾類運算子:
- 算術運算子
- 關係運算子
- 位運算子
- 邏輯運算子
- 賦值運算子
- 其他運算子
總的來說,Java運算子跟其他程式語言的運算子大同小異,可以快速瀏覽一下。
算術運算子
假設整數變數A的值為10,整數變數B的值為20:
特別的是,字首自增自減法(++a
--a
)和字尾自增自減法(a++
a--
):
字首自增自減法(++a
--a
):先進行自增自減,再進行表示式運算。
字尾自增自減法(a++
a--
):先進行表示式運算,再進行自增自減。
示例:
public class Test {
public static void main(String[] args) {
int d = 25;
// 檢視 d++ 與 ++d 的不同
System.out.println("d++ = " + (d++) );
System.out.println("++d = " + (++d) );
}
}
結果為:
d++ = 25
++d = 27
關係運算子
假設整數變數A的值為10,整數變數B的值為20:
位運算子
假設整數變數A的值為60,整數變數B的值為13:
邏輯運算子
假設布林變數A為真,布林變數B為假:
需要注意的是,如果第一個運算元已經能判斷結果了,那麼就不會執行下一個運算元,比如:
public class Test {
public static void main(String[] args) {
boolean a = false;
boolean b = true;
boolean c = a && b; // a已經能判斷結果為false,不再執行b
boolean d = b || a; // b已經能判斷結果為true,不再執行a
}
}
賦值運算子
其他運算子
條件運算子
variable x = (expression) ? value if true : value if false
示例:
public class Test {
public static void main(String[] args){
int a , b;
a = 10;
// 如果 a 等於 1 成立,則設定 b 為 20,否則為 30
b = (a == 1) ? 20 : 30;
System.out.println( "Value of b is : " + b ); // 30
// 如果 a 等於 10 成立,則設定 b 為 20,否則為 30
b = (a == 10) ? 20 : 30;
System.out.println( "Value of b is : " + b ); // 20
}
}
條件運算子也叫做三元運算子,三元場景可以多用這個運算子簡寫程式碼。
instanceof 運算子
( Object reference variable ) instanceof (class/interface type)
用來判斷物件是否為類的例項。比如:
String name = "James";
boolean result = name instanceof String; // 由於 name 是 String 型別,所以返回真
Java運算子優先順序
在編寫程式碼的時候,多用小括號把優先計算的表示式框起來,才不容易出錯。
迴圈結構
迴圈結構
while
while( 布林表示式 ) {
// 迴圈體
}
只要布林表示式為True,就會一直反覆執行迴圈體。
示例:
public class Test {
public static void main(String args[]) {
int x = 10;
while( x < 20 ) {
System.out.print("value of x : " + x );
x++;
System.out.print("\n");
}
}
}
do while
do {
// 迴圈體
}while( 布林表示式 );
無論表示式是否為True,都先執行一次迴圈體,然後就跟while一樣先判斷布林表示式,如果為True再繼續執行迴圈,為False就退出迴圈。
示例:
public class Test {
public static void main(String args[]){
int x = 10;
do{
System.out.print("value of x : " + x );
x++;
System.out.print("\n");
}while( x < 20 );
}
}
for
for(初始化; 布林表示式; 更新) {
// 迴圈體
}
- 初始化:定義一個或多個迴圈控制變數,也可以為空語句。
- 布林表示式:根據True或False決定是否繼續執行迴圈。
- 更新:更新迴圈控制變數。
示例:
public class Test {
public static void main(String args[]) {
for(int x = 10; x < 20; x = x+1) {
System.out.print("value of x : " + x );
System.out.print("\n");
}
}
}
Java也有更方便從陣列遍歷元素的for迴圈:
for(宣告語句 : 表示式)
{
// 迴圈體
}
- 宣告語句:跟陣列元素型別匹配的區域性變數。
- 表示式:陣列或返回陣列的方法。
示例:
public class Test {
public static void main(String args[]){
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ){
System.out.print( x );
System.out.print(",");
}
System.out.print("\n");
String [] names ={"James", "Larry", "Tom", "Lacy"};
for( String name : names ) {
System.out.print( name );
System.out.print(",");
}
}
}
break
跳出整個迴圈。
示例:
public class Test {
public static void main(String args[]) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
if( x == 30 ) {
break; // x等於30時跳出迴圈,後面都不列印了
}
System.out.print( x );
System.out.print("\n");
}
}
}
continue
跳過當前這次迴圈,執行下一次迴圈。
示例:
public class Test {
public static void main(String args[]) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
if( x == 30 ) {
continue; // 不會列印30,但是會繼續列印後面元素
}
System.out.print( x );
System.out.print("\n");
}
}
}
break和continue可以從字面意思來區分,break中斷迴圈,continue繼續下次迴圈。
條件語句
if
if(布林表示式)
{
//如果布林表示式為true將執行的語句
}
示例:
public class Test {
public static void main(String args[]){
int x = 10;
if( x < 20 ){
System.out.print("這是 if 語句");
}
}
}
if else
if(布林表示式){
//如果布林表示式的值為true
}else{
//如果布林表示式的值為false
}
示例:
public class Test {
public static void main(String args[]){
int x = 30;
if( x < 20 ){
System.out.print("這是 if 語句");
}else{
System.out.print("這是 else 語句");
}
}
}
也可以跟多個if else:
if(布林表示式 1){
//如果布林表示式 1的值為true執行程式碼
}else if(布林表示式 2){
//如果布林表示式 2的值為true執行程式碼
}else if(布林表示式 3){
//如果布林表示式 3的值為true執行程式碼
}else {
//如果以上布林表示式都不為true執行程式碼
}
示例:
public class Test {
public static void main(String args[]){
int x = 30;
if( x == 10 ){
System.out.print("Value of X is 10");
}else if( x == 20 ){
System.out.print("Value of X is 20");
}else if( x == 30 ){
System.out.print("Value of X is 30");
}else{
System.out.print("這是 else 語句");
}
}
}
巢狀的if else
if(布林表示式 1){
////如果布林表示式 1的值為true執行程式碼
if(布林表示式 2){
////如果布林表示式 2的值為true執行程式碼
}
}
示例:
public class Test {
public static void main(String args[]){
int x = 30;
int y = 10;
if( x == 30 ){
if( y == 10 ){
System.out.print("X = 30 and Y = 10");
}
}
}
}
switch case
switch(expression){
case value :
//語句
break; //可選
case value :
//語句
break; //可選
//你可以有任意數量的case語句
default : //可選
//語句
}
- expression:變數或返回變數的方法,變數型別可以是byte、short、int或char,以及String型別。
- value:字串常量或字面量,且與表示式的變數型別相同。
- break:可選,有break時會中斷後續匹配跳出switch語句,沒有break時會繼續執行後面的case。
- default:當所有case都沒有匹配到時,會執行default語句,一般放在最後的位置。
示例:
public class Test {
public static void main(String args[]){
//char grade = args[0].charAt(0);
char grade = 'C';
switch(grade)
{
case 'A' :
System.out.println("優秀");
break;
case 'B' :
case 'C' :
System.out.println("良好");
break;
case 'D' :
System.out.println("及格");
break;
case 'F' :
System.out.println("你需要再努力努力");
break;
default :
System.out.println("未知等級");
}
System.out.println("你的等級是 " + grade);
}
}
Number類
Java是純物件導向程式語言,為了以物件的方式使用內建資料型別,比如byte、int、long、double等,Java對它們進行了封裝,封裝後的類稱為包裝類。這裡的封裝一般也叫做裝箱,反之叫做拆箱。
所有的數字包裝類,都是抽象基類Number的子類,包括Byte、Short、Integer、Long、Float、Double。
示例:
public class Test{
public static void main(String[] args){
Integer x = 5; // 裝箱
x = x + 10; // 拆箱
System.out.println(x);
}
}
Math類
為了支援數學運算,Java提供了Math類,可以進行指數、對數、平方根等數學運算。
示例:
public class Test {
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的餘弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
對於四捨五入,Math提供了round、floor、ceil三個方法:
- round:四捨五入
- floor:向下取整
- ceil:向上取整(返回double型別)
示例:
基本型別與包裝類區別
- 基本型別不是物件,不需要new關鍵字建立,包裝類需要使用new關鍵字建立物件。
- 儲存方式不同,基本型別的值存在堆疊中,包裝類的例項存在堆中。
- 初始值不同,包裝類的初始值為null,基本型別視具體型別而定,比如int初始值為0,boolean初始值為false。
- 有些場景下只能使用包裝類,比如與集合類互動,使用泛型和反射呼叫函式,某個欄位允許null值,就只能使用包裝類。
Character類
Character用於對單個字元進行操作。
我們知道Java內建了資料型別char,但物件導向的Java在實際處理過程中需要的是物件,於是包裝類Character就被設計了出來。
建立物件程式碼如下:
Character ch = new Character('a');
也可以利用裝箱簡寫程式碼:
Character ch = 'a';
Character類具有以下方法:
String類
字串在任何程式語言都是應用非常多的,Java提供了String類來對字串進行操作。
建立字串有兩種方式:
簡單方式
String str = "Runoob";
new關鍵字
String str2=new String("Runoob");
它們的區別在於,前者建立的字串存放在公共池中,後者存放在堆上:
// 簡單方式 公共池
String s1 = "Runoob";
String s2 = "Runoob";
String s3 = s1;
// new關鍵字 堆
String s4 = new String("Runoob");
String s5 = new String("Runoob");
如下圖所示:
String有3個常用方法:
獲取長度
String site = "www.runoob.com";
int len = site.length();
連線字串
// 呼叫方法
"我的名字是 ".concat("Runoob");
// “+”操作符
"Hello," + " runoob" + "!"
建立格式化字串
String fs;
fs = String.format("浮點型變數的值為 " +
"%f, 整型變數的值為 " +
" %d, 字串變數的值為 " +
" %s", floatVar, intVar, stringVar);
StringBuilder類
String建立的字串物件是不能修改的,如果想修改,那麼需要用到StringBuffer和StringBuilder類。
StringBuilder相對於StringBuffer來說有速度優秀,所以大多數時候使用StringBuilder即可。如果想要保證執行緒安全,那麼只能使用StringBuffer。
StringBuilder示例:
public class RunoobTest{
public static void main(String args[]){
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(8, "Java");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
}
StringBuffer類
示例:
public class Test{
public static void main(String args[]){
StringBuffer sBuffer = new StringBuffer("菜鳥教程官網:");
sBuffer.append("www");
sBuffer.append(".runoob");
sBuffer.append(".com");
System.out.println(sBuffer);
}
}
陣列
Java中的陣列是用來儲存固定大小的同型別元素。
宣告方式:
dataType[] arrayRefVar;
建立陣列:
arrayRefVar = new dataType[arraySize];
宣告和建立可以一行程式碼搞定:
dataType[] arrayRefVar = new dataType[arraySize];
在建立時同時初始化值:
dataType[] arrayRefVar = {value0, value1, ..., valuek};
或者建立匿名陣列:
System.out.println(Arrays.toString(new int[]{3, 1, 2, 6, 4, 2}));
陣列是通過索引來訪問元素的,索引值從0到arrayRefVar.length-1。
可以使用for迴圈來遍歷陣列,比如:
public class TestArray {
public static void main(String[] args) {
double[] myArray = {1.9, 2.9, 3.4, 3.5};
// 列印所有陣列元素
for (int i = 0; i < myArray.length; i++) {
System.out.println(myArray[i] + " ");
}
// 計算所有元素的總和
double total = 0;
for (int i = 0; i < myArray.length; i++) {
total += myArray[i];
}
System.out.println("Total is " + total);
// 查詢最大元素
double max = myArray[0];
for (int i = 1; i < myArray.length; i++) {
if (myArray[i] > max) max = myArray[i];
}
System.out.println("Max is " + max);
}
}
也能使用for each在不使用下標的情況下遍歷陣列:
for(type element: array)
{
System.out.println(element);
}
比如:
public class TestArray {
public static void main(String[] args) {
double[] myArray = {1.9, 2.9, 3.4, 3.5};
// 列印所有陣列元素
for (double element: myArray) {
System.out.println(element);
}
}
}
前面介紹的都是一維陣列,除了一維陣列,還有多維陣列,比如:
String[][] str = new String[3][4];
int[][] a = new int[2][3];
java.util.Arrays類提供了很多方法來運算元組,這些方法都是靜態的。比如:
- toString:轉換為字串。
- fill:給陣列賦值。
- sort:對陣列排序。
- equals:比較陣列。
- binarySearch:對排序好的陣列進行二分查詢。
方法
Java中沒有函式的概念,只有方法這一說法。但實際上他們的作用是一模一樣的,都是把一段程式碼進行封裝後呼叫。
方法的命名規則
Java中的方法採用駝峰命名法,第一個單詞首字母小寫,後面每個單詞首字母均大寫,比如addPerson。
方法定義
main方法
public static void main(String[] args) {
int i = 5;
int j = 2;
int k = max(i, j);
System.out.println( i + " 和 " + j + " 比較,最大值是:" + k);
}
main方法的頭部是不變的,帶修飾符public和static,返回void型別值,方法名字是main,此外帶一個String[]型別引數args。
void
void是Java基本資料型別之一,表明方法沒有返回值。
值傳遞
Java方法的引數傳遞都是值傳遞。如果引數是基本型別,傳遞的值是基本型別字面量的拷貝。如果引數是物件,傳遞的值是物件引用的拷貝。
構造方法
構造方法和類名一模一樣,是一種特殊的方法,沒有返回值,在物件初始化時呼叫。一個類可以有多個構造方法,Java會根據引數進行匹配。比如:
// 一個簡單的建構函式
class MyClass {
int x;
// 建構函式
MyClass() {
x = 10;
}
// 建構函式
MyClass(int i) {
x = i;
}
}
構造方法可以不用顯式定義,Java會預設定義一個,一旦你定義了自己的構造方法,預設構造方法就會失效。預設構造方法的訪問修飾符和類的訪問修飾符相同,類為public構造方法也是public,類為protected構造方法也是protected。
finalize()
finalize()方式是建構函式的逆向,在物件銷燬時呼叫,比如:
public class FinalizationDemo {
public static void main(String[] args) {
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc(); //呼叫Java垃圾收集器
}
}
class Cake extends Object {
private int id;
public Cake(int id) {
this.id = id;
System.out.println("Cake Object " + id + "is created");
}
protected void finalize() throws java.lang.Throwable {
super.finalize();
System.out.println("Cake Object " + id + "is disposed");
}
}
可變引數
typeName... parameterName
一個方法中只能有一個可變引數,並且必須放在最後。比如:
public class VarargsDemo {
public static void main(String args[]) {
// 呼叫可變引數的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
// 可變引數
public static void printMax( double... numbers) {
if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
for (int i = 1; i < numbers.length; i++){
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result);
}
}
異常處理
Java的異常檢測格外的嚴格,如果沒有合適的處理異常,有可能程式碼都無法編譯。Java異常類如下圖所示:
Throwable類有兩個類Error和Exception,圖中也列舉了幾個常見的子類,比如OutOfMemoryError記憶體溢位、NullPointerException空指標異常等。
捕獲異常
try
{
// 程式程式碼
}catch(ExceptionName e1)
{
//Catch 塊
}
示例:
// 檔名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
多重捕獲
一個try後面可以跟多個catch:
try{
// 程式程式碼
}catch(異常型別1 異常的變數名1){
// 程式程式碼
}catch(異常型別2 異常的變數名2){
// 程式程式碼
}catch(異常型別3 異常的變數名3){
// 程式程式碼
}
示例:
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
f.printStackTrace();
return -1;
} catch(IOException i) {
i.printStackTrace();
return -1;
}
throws/throw
throws放在方法尾部用來丟擲異常,throw放在方法中用來丟擲異常。
import java.io.*;
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一個方法可以丟擲多個異常:
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
finally
無論是否發生異常,finally程式碼塊中的程式碼總會被執行。finally程式碼塊不是必須而是可選的。
try{
// 程式程式碼
}catch(異常型別1 異常的變數名1){
// 程式程式碼
}catch(異常型別2 異常的變數名2){
// 程式程式碼
}finally{
// 程式程式碼
}
示例:
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
自定義異常
繼承Exception或RuntimeException類可以自定義異常,比如:
// 檔名InsufficientFundsException.java
import java.io.*;
//自定義異常類,繼承Exception類
public class InsufficientFundsException extends Exception
{
//此處的amount用來儲存當出現異常(取出錢多於餘額時)所缺乏的錢
private double amount;
public InsufficientFundsException(double amount)
{
this.amount = amount;
}
public double getAmount()
{
return amount;
}
}
定義好以後就可以throw new InsufficientFundsException(needs);
丟擲異常,然後再try{} catch(InsufficientFundsException e){}
捕獲異常。
參考資料:
JDK維基百科 https://zh.wikipedia.org/zh-hans/JDK
Java菜鳥教程 https://www.runoob.com/java/java-tutorial.html
Java 到底是值傳遞還是引用傳遞?https://www.zhihu.com/question/31203609