系列連載文章,大家可以從我的專欄學習Java入門基礎知識,後續也會有更高級的Java特性、企業級開發框架,也有平常工作中的技術總結和分享,歡迎關注我的CDSN博客。同時可關注微信公衆號“Java開發之旅”,獲得更多技術資料!
目錄
閒言碎語
在上一節中,我們認識了Java中的基本數據類型(四類八種),並且定義了這些類型的變量,那麼在這一節當中,我們對數據類型和變量進行更深一步的學習。
數據類型轉換
上節課當中,當我們聲明變量時,敢於嘗試的朋友會發現以下代碼也可以正常運行:
public class Hello {
public static void main(String[] args) {
//左邊聲明的是double雙精度浮點,右邊賦的值卻是整數
double test = 1;
//打印是沒問題的
System.out.println(test);
}
}
what???double類型不是雙精度浮點的小數嗎?怎麼會可以存儲整數呢?
是的你沒有看錯,確實是可以的,只不過會自動升級爲小數,這就是Java當中的數據類型轉換在發揮作用。
在Java當中,有些數據類型之間是可以互相兼容、互相轉換的,這個機制叫做數據類型轉換,就是將等號右邊的數據類型轉換爲左邊的數據類型。
一般的,大的類型可以向下兼容小的類型,此時等號右邊的小類型會自動提升爲左邊的大類型,叫做自動轉換。拿所有的數值類型來說(boolean不存在自動轉換和強轉,char稍後結合String講解),在不超過各自的取值範圍的情況下,自動轉換關係如下圖所示:
上圖中的每一個數據類型,都可以兼容它右邊的所有數據類型,也就是說double可以兼容所有的數據類型,float可以兼容long、int、short、byte,以此類推。
所以以下代碼都是合法的(注意看註釋):
public class Hello {
public static void main(String[] args) {
//聲明一個byte類型變量
byte a = 1;
//將byte類型賦值給short類型,合法
short b = a;
//將short類型賦值給int類型,合法
int c = b;
//將int類型賦值給long類型,合法
long d = c;
//將long類型賦值給float類型,合法
float e = d;
//將float類型賦值給double類型,合法
double f = e;
//由於自動轉換時,會提升數據類型,所以變量e的值已經不是1了,而是1.0,所以此處輸出1.0
System.out.println(e);
//雖然變量f是雙精度浮點,但是因爲它的值是由變量e而來,所以這裏其實f的值是1.00,
//只不過我們沒有指定格式,Java爲我們省略了最後的一個0,所以這裏也輸出1.0
System.out.println(f);
/*
* 以上賦值鏈說明,數據類型可以向下兼容,而且可以跨層級兼容
* 比如double兼容float,而float又兼容long,long又兼容int……
* 以此類推,所以double兼容所有的數值類型,其他的向下兼容同理。
* */
}
}
上面是向下兼容,如果我們要向上兼容呢?比如將一個int類型的變量賦值給short類型的變量,這就需要short兼容int,屬於向上兼容。
這就需要我們手動轉型,也叫做強制轉換。我們只需要在值的前面用英文的小括號說明我們要轉換的類型,就可以實現強制轉換:
public class Hello {
public static void main(String[] args) {
int a = 1;
//使用語法進行強制轉換:(轉換的類型)
short b = (short) a;
System.out.println(b);
}
}
如果要將float或者double轉換爲整型的int、long等,會丟掉小數點後的精度:
public class Hello {
public static void main(String[] args) {
double a = 5.3;
//將浮點型轉爲整型
int b = (int) a;
// 輸出5。
// 注意這裏不是四捨五入,只是簡單的丟掉小數點之後的部分,
// 就算a的值是5.9,也會輸出5
System.out.println(b);
}
}
另外,前面我們說過,大類型兼容小類型會自動轉換,當然我們也可以自己強制轉換,只不過編輯器會提醒你不必這麼做:
至於其他的強轉,大家可以自由的去編寫,都是一樣的道理,有問題給我發私信或者在下方評論~~~
算術運算符
Java中的算術運算符主要有:
這裏順便說一句,也有人覺得+=、-=、*=、/=、%=這幾個也是算術運算符,我覺得它們不能列到上面的表格中,畢竟它們只是一種簡潔的變身寫法,只是上面幾種的變形,在下文中也會給大家介紹。
先介紹簡單的加減乘除、取餘:
public class Hello {
public static void main(String[] args) {
int num1 = 1;
int num2 = 2;
//加,輸出3
System.out.println(num1 + num2);
//減,輸出-1
System.out.println(num1 - num2);
//乘,輸出2
System.out.println(num1 * num2);
//除,取商,輸出0
System.out.println(num1 / num2);
//取餘,輸出1
System.out.println(num1 % num2);
}
}
有趣的是,算術表達式的結果,會向表達式中更高級的數據類型轉型,什麼意思呢?看一段代碼:
什麼?short類型不就是整型嗎?整型進行+1操作,有毛病嗎?
原因是,Java當中所有的整數,默認是int類型,就像浮點數默認是double一樣。語句a = a + 1中的1,是一個整數,整數默認是int類型,雖然a是short類型,但整體的a + 1這個算術表達式的運算結果就被提升爲了int。雖然結果都是整數2,但它是一個int類型的2而不是short類型的2,等號右邊是int,左邊是short,顯然要進行強轉,我這麼說大家懂了嗎?
所以改成以下代碼即是正確的,用括號將表達式括起來,提高優先級,再強轉:
再舉一個例子,以下代碼是正確的:
雖然表達式a = a + 1中的1是int型,但是這裏的a是long類型的,最後的結果會向類型更大的轉換,也就是說會自動提升爲long類型,所以是可行的。
同理,以下代碼就是不可行的,就像我們上面說的那樣,右邊的運算結果提升爲了long類型,左邊卻是int,顯然是不行的:
基於上面所說的數據類型提升,顯然存在以下結論:
當算術表達式中存在浮點數時,會提升爲默認的浮點類型double,特別標註的除外。
什麼意思呢?看一段代碼:
整型提升爲浮點型,我覺得很容易理解吧,你加了一個小數,運算結果爲2.6,2.6當然是浮點型了!只不過Java中默認的浮點型是double,所以提升爲了double。
如果我們將小數特殊標註爲float,你就可以用float類型去接收運算結果:
乘、除、取餘都一個道理,不再舉例了。下面重點說說++、--,即自增和自減。
有趣的++、--
++和--是自增、自減運算符,值的變化幅度是1,即自增1、自減1:
public class Hello {
public static void main(String[] args) {
int a = 0;
//自增1,等價於a = a + 1
a++;
}
}
自增和自減運算符只能直接作用於變量的身上,不能寫在具體的數字身上,以下代碼是錯誤的:
有趣的是,++、--可以寫在變量的前面,也可以寫在變量的後面,不同的地方有不同的執行機制,大家思考一下,以下代碼的輸出結果:
public class Hello {
public static void main(String[] args) {
int a= 1;
//a++
System.out.println(a++);
//++a
System.out.println(++a);
System.out.println(a);
}
}
最後的輸出結果是:
爲什麼是1、3、3呢?這是因爲,自增或自減寫在變量之後,程序會先使用變量的值,再重新計算賦值;自增或自減寫在變量之前,程序先重新計算賦值,再進行使用。區別就是先使用、還是先計算,++或--寫在前面是先計算、再使用,寫在後面是先使用、再計算。
所以上述代碼,在第6行先使用變量a的值進行打印,此時的變量值是1,所以打印出了1,緊接着將變量a的值自增1,變成了2;在第8行,由於++寫在了變量之前,要先進行計算、再使用,先將a的值自增1,變成了3,然後再進行打印,所以打印出了3;最後的打印語句沒有自增或自減,所以也打印3。
再來一個例子:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = ++a;
int c = a++;
System.out.println(b);
System.out.println(c);
System.out.println(a);
}
}
上述代碼的打印結果是2、2、3,在第5行先將a的值+1變成2,再賦值給b,所以b的值是2;然後在第6行,先使用a的值2賦給變量c,再將a的值+1變成3,所以此時c的值是2,a的值是3,故而我們的打印結果是2、2、3,大家明白了嗎?
而且,自增、自減運算符有隱式的數據類型轉換,以下代碼正確:
自減運算符--也是一個道理,這裏我就不再舉例了。
“特殊”的算術運算符
接下來就介紹幾個特殊的算術運算符:+=、-=、*=、/=、%=。
它們是基本算術運算符的變形,我們就拿+=舉例:
public class Hello {
public static void main(String[] args) {
int a= 1;
//意思是在a的基礎上,+2
a += 2;
//輸出3
System.out.println(a);
}
}
以上代碼中的算術表達式a += 2,等價於a = a + 2,是一種簡寫而已。那麼同理,a -= 2等價於a = a - 2,a *= 2等價於a = a * 2……不再舉例。
需要注意的是,同自增、自減運算符一樣,此類運算符也有隱式的類型轉換,所以以下代碼是可行的:
“+”在字符串中的應用
“+”在數值類型的計算中表示加法,它還有一種用法,就是在String類型的字符串中表示拼接:
public class Hello {
public static void main(String[] args) {
String str = "你好,";
//使用+進行拼接
str = str + "Java開發之旅";
//輸出 你好,Java開發之旅
System.out.println(str);
}
}
同樣的,既然“+”可以用,“+=”也可以用:
public class Hello {
public static void main(String[] args) {
String str = "你好,";
//等價於 str = str + "Java開發之旅";
str += "Java開發之旅";
//輸出 你好,Java開發之旅
System.out.println(str);
}
}
而且,String類型是更大的數據類型,它可以使用“+”兼容所有的8種基本類型,表達式的結果會被提升爲String字符串,注意只能是“+”進行字符串的拼接,其餘的乘除減法等等都是不成立的:
public class Hello {
public static void main(String[] args) {
//輸出 a的值是:1
int a = 1;
String str = "a的值是:" + a;
System.out.println(str);
//輸出 b的值是:5.6
double b = 5.6;
str = "b的值是:" + b;
System.out.println(str);
//由於這裏的1是字符串的“1”,所以雖然用了+=2,但只是字符串的拼接,輸出字符串的“12”
str = "1";
str += 2;
System.out.println(str);
}
}
在後面我們講到面向對象的時候,會專門用一篇文章來講解String類,因爲現在大家對類、方法、常量還沒有概念,我們會逐漸深入。
算術運算符的優先級
Java當中的運算符有3種,算術運算符、關係運算符、邏輯運算符,在講完這三種運算符之後會給大家彙總一個表。
基本的算術運算符,和我們在數學裏的習慣是一樣的:()、*、/、%、+、-,括號最大,往右遞減之。
那+=、-=、*=……這些特殊的運算符,和基本的運算符結合起來是怎樣的優先級呢?這裏就留給大家思考的空間,大家下去自己嘗試一下、總結一下,想想下面的執行結果:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += 6 * 2 - 1;
System.out.println(b);
}
}
當然了,這裏只是讓大家總結,真正的開發中如果寫成這樣,會被同事罵死的,我們要用括號來提高優先級,這樣代碼的可讀性也更高:
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += 6 * (2 - 1);
System.out.println(b);
}
}
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = (a += 6) * 2 - 1;
System.out.println(b);
}
}
public class Hello {
public static void main(String[] args) {
int a = 1;
int b = a += (6 * 2) - 1;
System.out.println(b);
}
}
小結
以上就是第5節課的內容,你懂了嗎?