Java中內置類及其方法的使用通常翻閱對應的API文檔即可,但是對於常用的一些類和方法還是需要我們能夠熟練的使用。 一、System System.gc():手動啟動垃圾回收器,垃圾回收器通常是自動啟動的,某些時候Java可能覺得當下的情況並不需要啟動gc,但是你又想啟動的話,就可以調用這個方法手動 ...
Java中內置類及其方法的使用通常翻閱對應的API文檔即可,但是對於常用的一些類和方法還是需要我們能夠熟練的使用。
一、System
System.gc():手動啟動垃圾回收器,垃圾回收器通常是自動啟動的,某些時候Java可能覺得當下的情況並不需要啟動gc,但是你又想啟動的話,就可以調用這個方法手動啟動gc。
System.exit(0):終止並退出JVM,exit方法可以傳入一個程式結束的狀態碼,通常傳入0就可以了。
System.currentTimeMillis():獲取自1970年1月1日 00:00:00 000到當前時間的總毫秒數。
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length):從源數組src中拷貝若幹length連續的元素到目標數組dest當中,src為源數組,srcPos為源數組的起始下標,dest為目標數組,destPos為目標數組的起始下標,length為拷貝的元素個數或長度。
二、Object
protected Object clone():返回對象的克隆,註意這個方法的修飾符為protected,只有子類或同一個包下才能使用。
int hashCode():返回對象的哈希值。
boolean equals(Object obj):判斷兩個對象是否相等,預設使用“==”進行判斷。註意,“==”的判斷其實判斷的是變數的值,對於引用類型就是比較的是記憶體地址,但這通常不是我們想要的結果,因為對於兩個對象的比較,我們大多時候認為同一個類的對象,如果它們的屬性等對象的內容是相同的話,那麼這兩個對象也可以認為它們是相同的,而不是去判斷那它們的記憶體地址,所以這種時候就需要重寫這個方法了。也由此可以看出,平時判斷相等時,如果是基本數據類型則使用“==”進行判斷,如果是引用數據類型,如String等,則需要使用它自帶的equals方法。
String toString():將對象轉換成字元串形式,預設為“類名@對象的記憶體地址”。在列印某個對象時,也會自動調用對象的這個方法。但是因為這個方法預設的返回值很多時候並不是我們想要的,所以通常都是在需要使用的時候重寫它,而不是使用它的預設值。
三、String
方法區的字元串常量池:字元串雖然也是引用類型的實例對象,但是字元串字面值是存儲在方法區中的字元串常量池當中,無論是使用雙引號定義還是使用String定義,都會先在方法區記憶體中創建一個字元串對象,如果以後使用到了相同的字元串,則不會再創建一個字元串對象,而是會直接使用已經存在的字元串對象。
String類型引用:需要註意的是,直接使用雙引號定義的字元串對象會直接在方法區中直接創建一個字元串對象,但是因為使用new關鍵字都是會先在堆中創建對應的對象,所以對於使用new關鍵字創建String對象,如“String s = new String("hello");”,雖然創建的對象在堆中,但s的值(記憶體地址)其實還是指向的是在方法區的字元串常量池中“"hello"”這個字元串對象。
字元串垃圾回收:另外一點,垃圾回收器不會回收字元串常量池中的字元串常量對象。
常用的構造方法:
// 最常用的方法 String s1 = "hello"; // 不常用 String s = new String("hello"); // 傳入一個byte數組 byte[] bytes = {97, 98, 99}; // 97->a, 98->b, 99->c String s2 = new String(bytes); System.out.println(s2); // 輸出:abc String s3 = new String(bytes, 1, 2); System.out.println(s3); // 輸出:bc // 傳入一個char數組 char[] chars = {'h', 'e', 'l', 'l', 'o'}; String s4 = new String(chars); System.out.println(s4); // 輸出:hello String s5 = new String(chars, 2, 3); System.out.println(s5); // 輸出:llo
常用方法:
- char charAt(int index):返回指定索引處的char值。
- int compareTo(String anotherString):按字元順序比較兩個字元串大小,全部字元都相等則返回0,如果同一個索引位置的字元不相同,就不會再繼續比較下去了,並且比較這兩個字元,前者大於後者則返回1,前者小於後者則返回-1。
- boolean contains(CharSequence s):判讀一個字元串中是否包含另一個子串,如果包含則返回true,否則返回false。
- boolean startsWith(String prefix):判斷一個字元串是否以另一個子串開始,如果是則返回true,否則返回false。
- boolean endsWith(String suffix):判斷一個字元串是否以另一個子串結尾,如果是則返回true,否則返回false。
- boolean equals(Object anObject):判斷兩個字元串是否相等。註意,應該保持良好的編程習慣,比較兩個字元串的相等總應該使用equals方法,而不是使用“==”。
- boolean equalsIgnoreCase(String anotherString):比較兩個字元串是否相等,忽略大小寫。
- byte[] getBytes():將一個字元串轉換成位元組數組並返回。
- int indexOf(String str):返回子串在字元串中第一次出現的索引。
- int lastIndexOf(String str):返回子串在字元串中最後一次出現的索引。
- boolean isEmpty():判斷一個字元串是否為空。
- int length():返回字元串的長度。註意,判斷數組長度時,它的length是數組對象的一個屬性,而不是方法,字元串對象的length則是方法。
- String replace(char oldChar, char newChar):返回一個新的字元串,原字元串中所有的oldChar都將被替換為newChar。
- String replace(CharSequence target, CharSequence replacement):返回一個新的字元串,原字元串中的所有target都將被替換為replacement。註意String的父介面就是CharSequence,所以這裡就傳入String對象即可。
- String[] split(String regex):返回一個根據指定正則表達式(分隔符)切割後的字元串數組。
- String substring(int beginIndex):返回一個從指定索引位置往後截取的子串。
- String substring(int beginIndex, int endIndex):返回一個從指定開始索引到結束索引(endIndex-1)的子串,註意,返回的子串不包括endIndex處的字元。
- char[] toCharArray():返回一個將字元串轉換為字元的數組。
- String toLowerCase():返回一個將字元串全部字元都轉換為小寫的字元串。
- String toUpperCase():返回一個將字元串全部字元都轉換為大寫的字元串。
- String trim():返回一個去處字元串前後空白的字元串。
- String valueOf():將另一個不是String的對象轉換為字元串對象。註意這是一個靜態方法,即使用的時候應該這樣“String s = String.valueOf(111);”。
四、StringBuffer/StringBuilder
如果需要進行大量的字元串拼接操作,建議使用Java自帶的StringBuffer或StringBuilder,而不是使用加號+。
StringBuffer示例:
public class Test{ public static void main(String[] args){ // 預設會創建一個長度為16的byte[] // StringBuffer stringBuffer = new StringBuffer(); // 創建一個指定長度的StringBuffer StringBuffer stringBuffer = new StringBuffer(100); // 拼接字元串統一調append方法,當拼接的字元串長度超過了16或者指定的容量,這個byte[]數組會自動擴容 stringBuffer.append("abc"); stringBuffer.append(3.14); stringBuffer.append(true); } }
關於StringBuffer的優化:其中一個優化點是在初始化時預估一下需要的字元串長度,給一個大一點的長度(預設的數組只有16個byte),以減少後續數組擴容的次數,關鍵點在於這個長度不能太大也不能太小,太大也浪費空間,太小會增加擴容次數。
StringBuilder和StringBuffer的區別:兩者在示例的使用上都一樣的,都可以用於字元串的拼接,但區別在於StringBuffer是有synchronized關鍵字修飾的,表示在多線程的環境下是線程安全的,StringBuilder則沒有synchronized關鍵字修飾,表示不是線程安全的。
對比String:String的底層其實是一個final類型的byte[], StringBuffer底層同樣是一個byte[],但區別是沒有final修飾符,因為數組的長度一旦確定了就不能改變,這表示final修飾的String類型的變數(引用)指向的記憶體地址是不能改變的,即該字元串是不能改變的,但是如果沒有final修飾符,則這個數組滿了之後可以擴容,StringBuffer的變數就可以指向擴容後新的數組的記憶體地址。說到String的這個final,特別需要註意的是,對於如“String s = "hello";”而言,final修飾的是“"hello"”這個字元串對象本身,而不是變數s(引用),s是可以重新給它賦值的。
五、8中基本數據類型的包裝類
包裝類之所以存在,就是為了應對一種情況,一些方法的參數需要是Object類型,但是又需要傳入Java中的基本數據類型,基本數據類型因為類型不相容所以肯定是不能傳進去的,此時就需要使用基本數據類型經過包裝過後的的包裝類了,包裝類型都屬於引用數據類型,且它們的最終父類都是Object類,此時就可以傳入這些方法中進行使用了。
基本數據類型對應的包裝類:除了int和char類型對應的包裝類略有不同外,其他類型的包裝類都是其本身單詞的首字母大寫形式。
- byte:Byte
- short:Short
- int:Integer
- long:Long
- float:Float
- double:Double
- boolean:Boolean
- char:Character
public class Test{ public static void main(String[] args){ // 裝箱:將基本數據類型轉換為引用數據類型 Integer i = new Integer(100); // 拆箱:將包裝類對象轉換為基本數據類型 float f = i.floatValue(); // 拆箱:將包裝類對象轉換為基本數據類型 int iv = i.intValue(); } }
自動裝箱和自動拆箱:平時使用的時候都是使用的自動轉換,上面示例的方式一般不常用了。
public class Test{ public static void main(String[] args){ // 自動裝箱:自動將基本數據類型轉換為引用數據類型 Integer i = 100; // 自動拆箱:自動將包裝類對象轉換為基本數據類型 int iv = i; // 對於算術運算,會進行自動拆箱操作 System.out.println(i + 1); } }
整數型常量池:Java中為了提高程式的執行效率,將[-128, 127]之間的所有包裝對象提前創建好了,並放到了方法區中的整數型常量池中,以後只要用到這些對象就不會再去new對象了,就像字元串常量池一樣。
Integer常用方法:因為包裝類的用法大部分都相同,不同的部分也可以通過查閱幫助文檔來瞭解使用,所以這裡只展示Integer類的常用方法。
- java.lang.NumberFormatException異常:如“Integer a = new Integer("哈嘍");”,這個語句在編譯時不會報錯,因為Integer構造方法允許傳入一個字元串,但是“哈嘍”這個字元串明顯不是數字,執行時就會報數字格式化異常。
- static int parseInt(String s):這是一個靜態方法,將一個字元串轉換為一個int類型的數字,這個方法同樣不能傳入一個不是數字的字元串,其他包裝類也有比如parseDouble、parseFloat等轉換作用的方法。
- static String toBinaryString(int i):將十進位的整數轉換為二進位的字元串。
- static String toHexString(int i):將十進位的整數轉換為十六進位的字元串。
- static String toOctalString(int i):將十進位的整數轉換為八進位的字元串。
六、數組
// 靜態初始化語法,即定義的時候就初始化好了所有的元素 int[] array1 = {100, 55, 30}; // 動態初始化語法,初始化時只定義好數組中元素的個數,new int[5]表示創建一個 // 有5個int類型元素的數組,但是並沒有初始化數組中元素的值,只是賦予了預設值,即 // 基本數據類型的預設值和引用類型的預設值null。 int[] array2 = new int[5];
使用數組時,應註意以下幾點:
- 數組因為是引用類型,所以數組對象是存儲在堆記憶體當中的。
- 數組一旦創建,其長度是不可變的。
- 數組中的元素的數據類型是統一的,如int數組則表示此數組中的元素全部都是int類型的。
- 所有數組對象都有length屬性(註意不是length方法),用來獲取數組中元素的個數。
- 數組中在存儲時,數組中的元素的記憶體地址都是連續的。
數組的訪問和賦值:直接通過下標進行訪問和賦值即可,如“array1[0]=22;”。
數組的優點和缺點:
- 優點:根據下標去檢索元素時效率極高,因為數組中的元素在空間地址上是連續的,並且每個元素占用的記憶體空間是相同的,檢索某個元素時只需要根據數組記憶體地址的起始位置就可以算出這個元素的記憶體地址,所以檢索第100個元素和第100萬個元素的地址的時間都是一樣的。
- 缺點:一個是,為了保證數組中每個元素的記憶體地址連續性,所以在數組中間的某個位置刪除或增加元素時,會涉及到元素的向前或者向後位移的操作,此時的效率就會極低。另外一個是,數組不能存儲大數據量,因為很難在記憶體空間上找到一塊特別大的連續的記憶體空間。
數組擴容:Java中數組擴容的原理或者說方法是將小容量的數組使用“System.arraycopy”方法拷貝到大容量的數組當中,然後刪除小容量的數組,Java中數組的擴容效率是較低的,所以在數組的使用當中,應該儘量避免數組的拷貝和擴容。
二維數組:二維數組,包括三位數組等多位數組,其實就是數組中的元素又是一個數組,多少維其實由這個數組的元素“套了多少層”決定的,二維就是數組中的元素是一個一維數組,同理,三位數組中的元素是一個二維數組,然後以此類推即可。
// 靜態初始化語法 int[][] a = { {1, 2, 3}, {4, 5, 6}, {9} }; // 動態初始化語法 int[][] array = new int[3][4];
Arrays工具類:這個工具類最常用的就是sort和binarySearch這兩個方法,但是註意,二分查找方法的前提是數組已經排好序了。
import java.util.Arrays; public class ArrayToolsTest{ public static void main(String[] args){ int[] myArray = {3, 2, 6, 4}; // sort方法可以將一個數組排序,但是註意,sort方法並沒有返回值, // 即不是返回排好序的數組,而是直接排序傳入的數組 Arrays.sort(myArray); // 二分查找演算法的前提是需要數組已經排好序了 // 返回值為元素在數組中的下標,元素在數組中不存在則返回-1 // 但是這個方法多用來判斷數組中有沒有這個元素,因為如果數組中該元素 // 不只一個的話,那麼返回的下標不一定是第一個元素的下標 int indexd = Arrays.binarySearch(myArray, 6); } }
七、Date/SimpleDateFormat
對日期進行格式化則使用“java.text.SimpleDateFormat”類。
使用示例:
// 專門進行日期格式化的類 import java.text.SimpleDateFormat; // 日期操作的類 import java.util.Date; public class DateTest { public static void main(String[] args) throws Exception { // 直接調用無參構造方法,會預設使用當前系統日期時間來進行初始化,精確到毫秒 Date nowTime = new Date(); // 輸出當前日期時間 System.out.println(nowTime); // 按照指定格式創建日期格式化對象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); // 將日期對象格式化為指定格式的字元串 String nowTimeStr = sdf.format(nowTime); System.out.println(nowTimeStr); // 將時間字元串按格式轉換為Date對象,需要註意,指定的格式需要和字元串中的格式相同 String t = "2020-06-01 21:18:22 333"; SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); Date dateTime = sdf2.parse(t); // 獲取自1970年1月1日 00:00:00 000到當前日期的總毫秒數 long nowTimeMillis = System.currentTimeMillis(); System.out.println(nowTimeMillis); // 根據毫秒數創建一個Date對象 Date tt = new Date(nowTimeMillis); } }
日期時間格式化字元如下:
Letter | Date or Time Component | Presentation | Examples |
---|---|---|---|
G |
Era designator | Text | AD |
y |
Year | Year | 1996 ; 96 |
Y |
Week year | Year | 2009 ; 09 |
M |
Month in year (context sensitive) | Month | July ; Jul ; 07 |
L |
Month in year (standalone form) | Month | July ; Jul ; 07 |
w |
Week in year | Number | 27 |
W |
Week in month | Number | 2 |
D |
Day in year | Number | 189 |
d |
Day in month | Number | 10 |
F |
Day of week in month | Number | 2 |
E |
Day name in week | Text | Tuesday ; Tue |
u |
Day number of week (1 = Monday, ..., 7 = Sunday) | Number | 1 |
a |
Am/pm marker | Text | PM |
H |
Hour in day (0-23) | Number | 0 |
k |
Hour in day (1-24) | Number | 24 |
K |
Hour in am/pm (0-11) | Number | 0 |
h |
Hour in am/pm (1-12) | Number | 12 |
m |
Minute in hour | Number | 30 |
s |
Second in minute | Number | 55 |
S |
Millisecond | Number | 978 |
z |
Time zone | General time zone | Pacific Standard Time ; PST ; GMT-08:00 |
Z |
Time zone | RFC 822 time zone | -0800 |
X |
Time zone | ISO 8601 time zone | -08 ; -0800 ; -08:00 |
八、數字格式化
數字格式化應該使用“java.text.DecimalFormat”,如果處理大數據或者財務數據,應該使用“java.math.BigDecimal”,因為它的精度極高,具體使用可參閱API文檔。
部分格式化字元:
- #:井號表示任意字元。
- ,:逗號表示千分位。
- .:點號表示小數點。
- 0:0表示不足的位數用0補齊。
import java.text.DecimalFormat; public class DecimalFormatTest{ public static void main(String[] args){ DecimalFormat df = new DecimalFormat("###,###.##"); String s = df.format(1234.561); System.out.println(s); // 輸出:1,234.56 DecimalFormat df2 = new DecimalFormat("###,###.0000"); String s2 = df2.format(1234.56); System.out.println(s2); // 輸出:1,234.5600 } }
九、隨機數
想要生成一個隨機數,應該使用“java.util.Random”,詳細用法請參閱API文檔。
import java.util.Random; public class RandomTest{ public static void main(String[] args){ Random random = new Random(); // 生成一個隨機整數 int num1 = random.nextInt(); // 生成一個[0, 100]的隨機整數,註意,這裡不包括101 int num2 = random.nextInt(101); } }
十、枚舉
枚舉類型,關鍵字enum,也是一種引用數據類型,一個枚舉編譯後也會生成一個“.class”位元組碼文件。
枚舉中的每一個值可以看做是常量,且每個枚舉值只需要定義對應的名稱即可,不需要給它賦值。
public enum Result{ // 只需要定義每個枚舉項的名稱即可,不需要給它賦值。 // 如果只有兩個枚舉項,建議使用boolean類型即可,多餘兩個時才建議使用枚舉類型。 SUCCESS, FAIL }
public class Test{ public static void main(String[] args){ Result res = divide(3, 0); System.out.println(res); } public static Result divide(int a, int b){ try{ int c = a / b; return Result.SUCCESS; } catch (Exception e) { return Result.FAIL; } } }