1, 基本數據類型
Java是強類型語言, 對於每一種數據都定義了類型,基本數據類型分為數值型,字符型,布爾型。數值型又分為了整型和浮點型。
整型又分為byte, int, short long.
浮點型又分為了float 和double.
字符型是char 類型, 一般不用。
布爾型是boolean, 取值為 true 和 false.
2, 變量
由於強類型,java在聲明變量的時候,必須指定數據類型。Type variable, 比如int num; 給這個變量進行賦值的時候,也必須是相同的數據類型, 必須變為num 賦組一個int 型,如num = 5; 變量的使用一定要注意數據類型。
3, 常量
常量也有類型,但是我寫了個123,沒有給它定義數據類型啊,它是什么數據類型? 對於常量來說,它采用的是默認數據類型。對於整數來說,默認類型為int, 小數的默認類型則是double. 字符類型為char等。但對於采取默認類型來說,整型和浮點型又有所不同。
當我們寫一個整數字面量的時候,這個字面量默認是int 類型,但是,它也可以賦值給byte 和short 類型,只要不超過byte 類型和short 類型取值范圍。當然,這個整型字面量也可以賦值給long. 以下三種寫法都不會報錯。
byte b = 2; short s = 5; long l = 10;
但對於浮點數就有所不同,寫一個浮點數,默認是double , 它就不能賦值float.
float f = 3.14;
它會報錯,報錯的原因是,我們正在把一個double類型的值賦值給一個float類型,而float類型的精度比double類型小,所以報錯了,損失精度了。所謂的精度,就是小數點后有幾位小數,對於float類型來說,它小數點后面有6-7位小數,而對於double類型來說,它小數點后面有15位小數,所以double類型比float類型精度高。又由於15是 7的兩倍多,所以float稱為單精度浮點型, double稱之為雙精度浮點型。那怎么辦,就不能把常量賦值給float 類型了?也不是,不過要對這個常量進行標識,給它加個后綴f,表示它是一個float類型。像下面這樣就沒有問題了。
float f = 3.14f;
這又讓我想到了整數long型, 我們都知道long類型的取值范圍比int 類型大,如果是一個特別大的整數,我們就把它賦值給long. 但是你會發現報錯了。
long l = 100000000000;
超出了整型int 的最大取值范圍, 數值字面量默認是int 類型,太大就超出了。那怎么才能賦給long,也要在后面加一個標識 L ,
long l = 100000000000L;
對於這種很大的數值,JDK7 還提供了一種便利,可以在各個數字間添加_ , 這樣我們一看就可以知道這個數值多少了。
long l = 100_000_000_000L;
4,類型轉換
類型轉換分為自動類型轉換和強制類型轉換。自動類型轉換必須滿足兩個條件:1, 兩種類型必須是兼容的(compatible); 2, 目標類型的取值范圍必須大於來源類型(The destination type is larger than source type). 通過這兩個條件,可以發現,自動類型轉換是發生在數值類型之間,因為類型是兼容的,可以把 byte 類型的值賦值給int 類型,也可以把int 類型賦值給double 類型。
int a = 10; long l = a;
自動類型轉換絕對不會出現到 數值類型轉化到char 類型或 布爾類型, 同樣布爾類型和char 類型也不能互相轉換, 因為他們類型不兼容,是不同的數據類型, 所以,如果你把一個布爾類型賦值給char 類型或數值類型,它就會出錯, 同樣的一個數值類型也不可能賦值給布爾類型或char 類型。
int a = 10; char c; c = a; // 報錯了,不能把int 轉換為char
但你會發現,當使用數值字面量進行變量初始化的時候,它也發生了自動類型轉換,並且沒有滿足上面的兩條,因為你可以int 類型的字面量賦值為char 類型或 byte 類型
byte b = 10; char c = 20;
強制類型轉換,也是在滿足第一個條件的情況下進行的(char 類型除外),當第二個條件不滿足的時候,對類型進行強制轉換, 比如把int 類型轉化成 byte 類型。語法是 (目標類型) 值 ,把要轉換的數據前面加上它要轉換成的類型
int a = 4; byte b = (byte) a;
但是強制類型轉換最大的問題是丟失數據,因為它的工作原理是舍棄高位,這里的位是二進制位。int 類型的數據在內存中占32位,如 int 4 在內存中的表示是 00000000 00000000 00000000 00000100,而byte 類型在內存中只占8個字節, 把int 類型轉換成byte 類型,就要把前面24個字節全部舍棄, 00000000 00000000 00000000 00000100 變成 00000100, 如果前面24個二進制位有數據,那就舍棄了,肯定丟失數據了。
當把double 等浮點類型的數據轉換為int 的時候,它會舍棄小數點,也會損失精度
double d = 10.2; int intD = (int) d; // 10 去掉了小數點0.2
所以在真正的程序中很少用到強制類型轉換。
最后看一下特殊的char 類型 和數值類型的轉換。
int a = 10; char c = (char) a ;
char 類型之所以和數值類型進行轉換,是因為char 類型在存儲的時候,要轉換成數字進行存儲,這涉及到了Unicode 編碼了,就不細說了。
數值類型和char 類型是不可能和布爾類型進行轉換的, 因為類型不同。
Java 是強類型語言,只有在兩種類型兼容的情況下,才可能進行類型轉換,比如整數型內部類型的變量轉換, 不同類型是不可能進行類型轉換的。
5,運算中的類型轉換
首先要記住一點,對於java 的強類型來說,運算兩端一定要數據類型相同,如果數據類型不同,是無法進行計算的。一個數值類型,是無法和一個布爾類型進行計算。但數值類型自己除外,因為它會自動類型的提升,就是把小類型轉化成大類型,大小主要指的是類型的取值范圍,byte 就是小類型,int 就是大類型。byte 類型 + int類型,結果就會轉化為int 類型。這個法則應用到字面量默認類型時,容易引發錯誤
byte b = 4; b = b+3;
就會報錯。計算時,先計算右邊b+3; b 是一個byte類型,3是int 類型(默認類型), 那就是byte 類型 + int類型,就把byte類型轉化成int類型然后再進行計算,計算結果是int 類型的數字7,最后進行賦值運算,把int類型賦值給byte 類型,肯定報錯了。這時如果必須要這么做,讓計算成立,那要用到強制類型轉換, 把int 型轉化成byte.
byte b = (byte) b+3; 就沒有問題了
除了類型之外,還要注意除法, 當一個整數去除以0的時候,它會報錯,但一個浮點數去除以0 時,它確不會報錯,而是返回NaN.
最后是計算越界的問題,當計算結果超出一個類型的取值范圍后,它就會報錯。但對於int 默認類型來說,它不會。如果計算結果超出int 的取值范圍,它會把計算結果的高位舍棄掉(這里的高位是二進制的位,計算結果用二進制表示),得到的結果還是int 類型, 在int 類型的取值范圍內。對於浮點類型它也不會,如果上溢,它返回負無窮或正無窮,如果下溢,則返回0.
布爾類型:它也不會進行類型轉化,也就是說,只有數值類型才能進行大小判斷,使用> < 等。其他的同類型只能進行相等性判斷。還有在if 條件語句的時候要注意。if 中的條件表達式,一定要顯示的返回的true or false. 如果習慣了js, 我們會直接寫一個變量如 if (done) ,但在java 中不行, 要寫 if (done == 0)
字符串String
在java 中,字符串不是基本數據類型,而是String 類的對象,當我們創建一個字符串的時候,真的是要使用new 來調用String 構造函數
String str = new String();
但是如果僅僅想創建一個字符串對象的話,完全可以使用字面量的方法,字面量還是使用雙引號
String str = “abc”;
這里要注意的一點是,在Java中字符串字面量是共享的。當我們使用字面量的方式創建字符串對象的時,java在內存中會開辟一個字符串緩沖區,也可以理解為字符串常量池。當我們真正創建字符串對象時,如這里的”abc” ,它就會到字符串常量池中查找這個對象有沒有存在,如果沒有,它就會新建這個對象, 然后把這個對象的地址引用賦值給我們聲明的變量str。這時我們再聲明一個變量,
String anotherString = “abc” ;
它又會到字符串常量池中尋找“abc”,這時候發現”abc” 這個對象已經存在,那它直接把常量池中存在的對象的地址賦值給聲明的變量anotherString. 這就是字符串共享。
字符串的共享也僅僅適用於字符串字面量,如果使用加號,或其它方法進行拼接形成的字符串,那就不一定在字符串常量池中了。如
String c = “Hello”;
Stirng st = c + “word”;
那st 應該在堆內存中了。
但
String str = ‘Hello’ + ‘world’;
str 確是在字符串常量值中。這是為什么呢?因為java 都是先編譯,然后再運行,編譯器在編譯的時候會對代碼進行優化。‘Hello’ + ‘ world’ 都是確定好的,不會再發生改變,編譯時,str 就會拼接成‘Hello world’, 所以當程序運行時,它是一個字符串常量,要在字符串常量池中進行查找。但 c + “word” 就不一樣了,因為c是一個對象引用,在編譯的時候,不會進行任何優化, 所以在運行的時候,它會在堆內存中生成一個對象,雖然內容都相同,但是地址不同。這也引出了一個判斷兩個字符串變量相等性的問題,如果使用==進行判斷,那么判斷的是這兩個變量所引用的對象的地址,而不是這兩個字符串變量所持有的內容,
str == st; // false 地址不同
一般情況下,這不是我們想要的。大多數情況下,只想判斷兩個字符串持有的內空是否相同,那要使用字符串中的方法,equals(), 如果內容相同,返回true, 如果內容不同,返回false
str.equals(st); // true
在java 中,雖然字符串是作為對象存在的,但是一旦創建之后,這個字符串對象就不會再發生變化,字符串的任何操作都會生成一個新的對象。對於頻繁進行字符串操作來說,要生成好多個對象,不利於性能, 所以java 就有了一個類,StringBuilder, 專門用來操作大量變化的字符串。
StringBuilder 類的操作步驟如下:
1, 首先通過StringBuilder類生成一個空的字符串對象 builder
StringBuilder builder = new StringBuilder();
2, 調用方法去操作這個空字符對象builder, 如append()方法,是向里面填加字符串,setCharAt修改某個位置上的字符等。
//調用append方法添加字符。 builder.append("hello"); // 修改某個位置上的字符 builder.setCharAt(2,'c'); // 在某個位置插入字符 builder.insert(3, "wordl"); // 刪除字符 builder.delete(0, 2); // 還有一個length方法,一共有多少個字符System.out.println(builder.length());
3, 調用toString() 方法,把SringBuilder對象轉化成字符串對象
// 調用toString 方法,轉化成字符串 String completeString = builder.toString(); System.out.println(completeString);
整 個代碼如下,輸出 cwordllo
public class FirstSimple { public static void main(String[] args) { StringBuilder builder = new StringBuilder(); builder.append("hello"); builder.setCharAt(2,'c'); builder.insert(3, "wordl"); builder.delete(0, 2); String completeString = builder.toString(); System.out.println(completeString); } }
數組
java是強類型語言,對於數組來說,這就意味着一個數組中只能保存相同的數據類型的內容,所以數組聲明時,要指定其要保存的數據類型,同時還要指定保存的最大數量,保存的最大數量一旦聲明就不會再改變。那數組怎么進行聲明呢?我們都知道,聲明一個變量,使用的是數據類型加變量名,如 int num, 就聲明了一個int 類型的num變量,但它只能保存一個數據。如果在int 類型的后面加一個[] 呢,就表示可以存多個數據了,就是數組了。
int[] numbers = new int[10];
int[] 就是一個類型,聲明數組的專用類型,想要聲明其它類型的數組,就把前面的類型改為其它類型就好了,String[] str = new String[10], 保存字符串的數組。數組的使用,基本都是一樣的,都是基於索引
numbers[0] = 10; // 賦值
當然聲明數組變量的時候,還可以初始化。它這里用的是{} 進行的初始化
int[] numbers = {2,5};
這里還要注意java數組元素的默認值,在java中,只要聲明了數組,數組中元素都會有默認值。對於數值型數組,它的默認值是0;對於Boolean型數組,它的默認值是false. 對於對象型數組,它的默認值是null, 這里指的是數組中的每個元素的默認值。在 java中字符串是對象,所以一個字符串對象數組,它里面中的所有元素的默認值為null。