1. 程式人生 > >Java基礎類庫

Java基礎類庫

一、StringBuffer類

在講解StringBuffer類之前先來回顧一下String類特點:

  • 一個字串常量就是String類的匿名物件;
  • String類物件有兩種例項化方式:

     |- 方式一:直接賦值,可以自動入池,只開闢一塊記憶體空間;

     |- 方式二:構造方法例項化,會開闢兩塊空間,其中一塊將成為垃圾,不會自動入池,可以使用intern()方法手工入池;

  • 字串內容一旦宣告則不可改變。

正是因為字串內容一旦宣告不可改變,所以如果在頻繁修改字串內容的程式上是不能夠使用String的,那麼為此在Java之中又提供有一個StringBuffer類,而String和StringBuffer類最大的特徵在於:String不可改變內容,而StringBuffer可以改變。在String類物件之中使用“+”可以實現字串連線操作,但是在StringBuffer類之中只能夠使用append()方法實現字串連線:public StringBuffer append(資料型別 b)。既然返回的是StringBuffer就可以一直使用append()連線。

範例:觀察程式

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuffer buf = new StringBuffer();
		buf.append("Hello ").append("World ").append("!!!");
		fun(buf);
		System.out.println(buf);
	}

	public static void fun(StringBuffer temp) {
		temp.append("\n").append("Hello MLDN .");
	}
}

此時在fun()方法之中對StringBuffer類物件所做的修改可以影響原始物件,所以就可以得出結論:StringBuffer的內容可以進行修改。

到此已經學習過了兩個表示字串的類:String、StringBuffer,那麼這兩個類有什麼聯絡呢?

String類定義:

StringBuffer類定義:

public final class String

extends Object

implements Serializable, Comparable, CharSequence

public

final class StringBuffer

extends Object

implements Serializable, CharSequence

 發現String和StringBuffer兩個類都是CharSequence介面的子類。那麼就表示,如果見到某些方法上的引數或返回值型別是CharSequence,就應該立刻想到是字串。

範例:利用CharSequence接收

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuffer buf = new StringBuffer();
		buf.append("Hello ").append("World ").append("!!!");
		CharSequence csA = buf; // StringBuffer實現CharSequence
		CharSequence csB = "HELLO"; // String實現了CharSequence
		System.out.println(csA);
		System.out.println(csB);
	}
}

但是雖然String和StringBuffer都是CharSequence介面的子類,可是這兩個類的物件並不可能直接進行轉型。但是在實際的工作之中畢竟直接使用String和StringBuffer這兩子類居多。那麼這兩個類物件之間也可以進行轉型。

1、將String變為StringBuffer;

·  利用StringBuffer類的構造方法:public StringBuffer(String str)。

利用StringBuffer類的append()方法:public StringBuffer append(String str)。

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuffer bufA = new StringBuffer("Hello"); // String變為StringBuffer
		StringBuffer bufB = new StringBuffer();
		bufB.append("World");
		System.out.println(bufA);
		System.out.println(bufB);
	}
}

2、將StringBuffer變為String

·  所有類物件都支援變為String方法:public String toString();

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuffer bufA = new StringBuffer("Hello"); // String變為StringBuffer
		String str = bufA.toString(); // StringBuffer變為String
		System.out.println(str);
	}
}

除了以上的基本特徵之外,在StringBuffer類裡面還提供有一些String類所沒有的方法。

範例:執行資料插入

  • 方法:public StringBuffer insert(int offset, 資料型別 l)。
public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuffer buf = new StringBuffer("Hello"); // String變為StringBuffer
		buf.insert(0, "你好 ");
		System.out.println(buf);
	}
}

範例:刪除部分資料

  • 方法:public StringBuffer delete(int start, int end);
    public class TestDemo {
    	public static void main(String[] args) throws Exception { // 方便處理
    		StringBuffer buf = new StringBuffer("Hello World");
    		buf.delete(5, 11);
    		System.out.println(buf);
    	}
    }
    

範例:字串反轉

  • 方法:public StringBuffer reverse()。
    public class TestDemo {
    	public static void main(String[] args) throws Exception { // 方便處理
    		StringBuffer buf = new StringBuffer("Hello World");
    		System.out.println(buf.reverse());
    	}
    }
    

擴充套件題目:請解釋String和StringBuffer的區別?

  • String和StringBuffer都是CharSequence介面的子類,其中String的內容不可以修改,而StringBuffer的內容可以修改;
  • StringBuffer類提供了與String類互補的操作方法,例如:append()、insert()、reverse()。

工作之中使用最多的一定是String類,只有在頻繁修改的時候才使用StringBuffer類。

在JDK 1.5之後Java增加了一個StringBuilder類,此類定義如下:

public final class StringBuilder
extends Object
implements Serializable, CharSequence

但是通過方法組成可以發現,StringBuilder和StringBuffer類的操作方法可以說是完全一樣的。

範例:使用StringBuilder

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		StringBuilder buf = new StringBuilder("Hello World");
		System.out.println(buf.reverse());
	}
}

範例:比較一下String、StringBuffer、StringBuilder的區別

public class TestDemo {
	public static void main(String[] args) throws Exception {
		testString();
		testStringBuffer();
		testStringBuilder();
	}

	public static void testString() { // 方便處理
		long start = System.currentTimeMillis();
		String str = "";
		for (int x = 0; x < 20000; x++) {
			str += x;
		}
		long end = System.currentTimeMillis();
		System.out.println("1、String花費:" + (end - start));
	}

	public static void testStringBuffer() { // 方便處理
		long start = System.currentTimeMillis();
		StringBuffer str = new StringBuffer();
		for (int x = 0; x < 200000; x++) {
			str.append(x);
		}
		long end = System.currentTimeMillis();
		System.out.println("2、StringBuffer花費:" + (end - start));
	}

	public static void testStringBuilder() { // 方便處理
		long start = System.currentTimeMillis();
		StringBuilder str = new StringBuilder();
		for (int x = 0; x < 200000; x++) {
			str.append(x);
		}
		long end = System.currentTimeMillis();
		System.out.println("2、StringBuffer花費:" + (end - start));
	}
}

可以發現,如果在頻繁修改的情況下,String的效能是明顯不足的,而StringBuffer和StringBuilder明顯是高效的,但是以上的程式碼是在單執行緒情況下,如果是多執行緒共同操作,那麼StringBuilder會更快,因為StringBuilder採用的是非同步處理,而StringBuffer採用的是同步處理的,但是StringBuffer資料安全。

擴充套件題目:請解釋String、StringBuffer、StringBuilder的區別?

  • String不適合於字串的頻繁修改,而StringBuffer和StringBuilder適合於頻繁修改,而且速度要遠遠高於String;
  • StringBuffer是在JDK 1.0的時候引入的,而StringBuilder是在JDK 1.5的時候引入的,而且StringBuffer和StringBuilder繼承結構相同,方法的組成也相同;
  • StringBuffer中的所有方法都使用synchronized進行標記,都是同步方法,效能相對較低,而StringBuilder採用的非同步處理,效能相對較高,但是StringBuffer在多執行緒操作時的資料安全性要高於StringBuilder。

二、Runtime類

在每一個JVM程序之中都會存在有一個Runtime類的例項化物件,此類物件將由JVM為使用者提供好。但是為了保持只有一個Runtime類的例項化物件,所以Runtime類所採用的是一個單例設計模式,構造方法被私有化了。

既然此處是單例設計模式,那麼一定會存在有一個static方法可以取得本類的例項化物件:

  • 取得Runtime類物件:public static Runtime getRuntime();

當取得了Runtime類物件之後就可以通過如下的三個方法取得一些記憶體資訊:

  • 最大可用記憶體量:public long maxMemory();
  • 可用記憶體量:public long totalMemory();
    • 空閒記憶體量:public long freeMemory()。
    • 清理垃圾空間:public void gc()。

範例:觀察記憶體資訊

public class TestDemo {
	public static void main(String[] args) {
		Runtime run = Runtime.getRuntime(); // 單例設計
		System.out.println("1、MAX = " + run.maxMemory());
		System.out.println("1、TOTAL = " + run.totalMemory());
		System.out.println("1、FREE = " + run.freeMemory());
		String str = "";
		for (int x = 0; x < 30000; x++) {
			str += x; // 垃圾產生
		}
		System.out.println("2、MAX = " + run.maxMemory());
		System.out.println("2、TOTAL = " + run.totalMemory());
		System.out.println("2、FREE = " + run.freeMemory());
		run.gc();
		System.out.println("3、MAX = " + run.maxMemory());
		System.out.println("3、TOTAL = " + run.totalMemory());
		System.out.println("3、FREE = " + run.freeMemory());
	}
}

擴充套件題目:請問什麼是GC?如何操作?

  • GC是垃圾收集器(Garbage Collector),是負責進行垃圾空間清理的執行緒;
  • 在Java之中可以由JVM自動呼叫GC,或者是由使用者呼叫Runtime類中的gc()方法手工清理垃圾。

三、System類

對於System類應該是很熟悉的,至少已經接觸過兩類方法:輸出、陣列排序,但是對於之前給出的陣列排序方法名稱並不標準:public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)。此方法基本上不用。

在System類裡面有一個方法是取得當前的日期時間:public static long currentTimeMillis()。此時取得的資料只是一個數值,並不是傳統意義的年、月、日。

範例:觀察currentTimeMillis()方法

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		long start = System.currentTimeMillis();
		String str = "";
		for (int x = 0; x < 30000; x++) {
			str += x; // 垃圾產生
		}
		long end = System.currentTimeMillis();
		System.out.println("本操作所花費的時間:" + (end - start));
	}
}

在System類之中存在如下的一個方法:public static void gc()。但是此操作並不是一個新的操作,通過System類呼叫gc()就等價於呼叫了Runtime類的gc()方法,這兩個gc()沒有任何的區別。

思考?所謂的垃圾指的就是沒有任何的棧記憶體所指向堆記憶體空間,但是在堆記憶體變為垃圾之前,一定會經歷建立、使用的兩個過程,最終的過程才成為垃圾。那麼現在的疑問:一個物件產生的時候發現可以通過構造方法做一些物件產生的處理,但是一旦物件沒用了,連個說最後一句話的機會都沒有。

那麼如果希望在物件被回收前可以進行一些處理操作,則可以覆寫Object類之中的finliaze()方法:

  • 方法:protected void finalize() throws Throwable;

雖然此時丟擲了異常資訊,但是不管丟擲什麼樣的資訊,最終都不會影響程式的執行。

class Person {
	public Person() {
		System.out.println("啊從出生了。");
	}

	@Override
	protected void finalize() throws Throwable {
		System.out.println("啊從因為得罪李老師,結果自殺了。");
		throw new Exception("老子死的好嗨皮啊!");
	}
}

public class TestDemo {
	public static void main(String[] args) throws Exception { // 方便處理
		Person per = new Person();
		per = null;
		System.gc();
	}
}

面試題:請解釋final、finally、finalize的區別?

  • final:關鍵字,可以定義不能被繼承的父類、定義不能被覆寫的方法、常量;
  • finally:關鍵字,異常處理的統一出口,不管是否有異常都執行;
  • finalize:方法(protected void finalize() throws Throwable),Object類方法,當物件被清理前執行的收尾操作。

四、物件克隆

克隆指的就是物件的複製操作,在Object類裡面提供有一個clone()方法:

  • clone()方法:protected Object clone() throws CloneNotSupportedException;

要被克隆的物件所在的類需要去實現一個Cloneable介面。但是此接口裡面沒有包含任何的方法,所以此介面屬於一個標識介面,表示一種能力。

class Person implements Cloneable {
	private String name;
	private int age;

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone(); // 呼叫父類的物件克隆方法
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "姓名:" + this.name + ",年齡:" + this.age;
	}
}

public class TestDemo {
	public static void main(String[] args) throws Exception {
		Person perA = new Person("張三", 20);
		Person perB = (Person) perA.clone(); // 克隆
		perB.setAge(90);
		System.out.println(perA);
		System.out.println(perB);
	}
}

一定要知道這使用的是一個標識介面,表示能力。