00 06Java高級之Java基礎類庫

1 StringBuffer類

String類是在所有項目開發之中一定會使用到的一個功能類,並且這個類擁有如下的幾個特點:
(1)每一個字符串的常量都屬於一個String類的匿名對象,並且不可以更改;
(2)String有兩個常量池:靜態常量池和運行時常量池。
(3)String類對象實例化建議使用直接賦值的形式完成,這樣可以直接將對象保存在對象池之中以方便下次重用。

雖然String類很好用,但是如果認真去思考也會發現其最大的弊端:內容不允許修改,雖然大部分情況下都不會涉及到字符串內容的頻繁修改,但是依然可能會存在有這樣的情況,所以爲了解決此問題,專門提供了一個StringBuffer類,可以提供字符串內容的修改處理。

StringBuffer並不像String類那樣擁有兩種對象實例化的方式,StringBuffer必須像普通類對象那樣首先進行對象實例化,而後纔可以調用方法執行處理,而這個時候可以考慮使用StringBuffer類中的如下方法:
(1)構造方法:public StringBuffer()
(2)構造方法:public StringBuffer​(String str)
(3)數據追加:public java.lang.AbstractStringBuilder append​(數據類型 obj),相當於字符串中的"+"操作
範例:觀察String類對象引用傳遞與StringBuffer類對象引用傳遞對比

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		String str = "Hello ";
		StringBuffer sbf = new StringBuffer("Hello ");
		changeString(str);
		changeStringBuffer(sbf);
		System.out.println("String: " + str);
		System.out.println("StringBuffer: " + sbf);
	}
	
	public static void changeString(String temp) {
		temp += "World!";
	}
	
	public static void changeStringBuffer(StringBuffer sbf) {
		sbf.append("World!");
	}
}

/*
String: Hello 
StringBuffer: Hello World!
*/

實際上大部分情況下,很少會出現有字符串內容的改變,這種改變指的並不是針對靜態常量池的改變

範例:分析一個問題

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		String strA = "lks loves hhy";
		String strB = "lks " + "loves " + "hhy";
		System.out.println("strA == strB: " + (strA==strB));  //true
	}
	
}
/*
strA == strB: true
*/

這個時候的strB對象的內容並不算是改變,或者更加嚴格的意義上來講,對於現在的strB當程序編譯之後會變爲如下的形式。

StringBuffer strC = new StringBuffer("lks").append(" loves").append(" hhy");

所有的"+"再編譯之後都變爲了StringBuffer中的append()方法,並且來講在程序之中StringBuffer與String類的對象之間本來就可以直接互相轉換:
(1)String類對象變爲StringBuffer可以依靠StringBuffer類的構造方法或者使用append()方法。
(2)所有的類對象都可以通過toString()方法將其變爲Sting類型。

在StringBuffer類裏面除了可以支持有字符串內容的修改之外,實際上也提供有一些String類所不具有的方法:
(1)插入數據:public StringBuffer insert​(int offset, 數據類型 b)
(2)刪除指定範圍的數據:public StringBuffer delete​(int start, int end)
(3)字符串內容反轉:public StringBuffer reverse()

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		StringBuffer strC = new StringBuffer("lks").append(" loves").append(" hhy");
		System.out.println(strC.reverse());
	}
	
}
/*
yhh sevol skl
*/

實際上與StringBuffer類還有一個類似的功能類:StringBuilder類,這個類是在JDK 1.5的時候提供的,該類中提供的方法與StringBuffer功能相同,最大的區別在於StringBuffer類中的方法屬於線程安全的,全部使用了synchronized關鍵字進行了標註,而StringBuilder屬於非線程安全的。
面試題:請解釋String、StringBuffer和StringBuilder的區別?
(1)String類是字符串的首選類型,其最大的特點是內容不允許修改。
(2)StringBuffer與StringBuilder類的內容允許修改;
(3)StringBuffer是在JDK 1.0的時候提供的,屬於線程安全的操作,而StringBuilder是在JDK 1.5的之後提供的,屬於非線程安全的操作。

2 CharSequence接口

CharSequence是一個描述字符串結構的接口,在這個接口裏面一般可以發現有三種常見的子類:
(1)public final class StringBuffer extends Object implements Serializable, CharSequence
(2)public final class String extends Object implements Serializable, Comparable<String>, CharSequence
(3)public final class StringBuilder extends Object implements Serializable, CharSequence

現在只要有字符串就可以爲CharSequence接口實例化。

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		CharSequence chse = "love you";
		System.out.println(chse);
	}
	
}
/*
love you
*/

CharSequence本身是一個接口,在該接口之中也定義有如下操作方法:
(1)獲取指定索引字符:char charAt​(int index)
(2)獲取字符串長度:int length()
(3)截取部分字符串:CharSequence subSequence​(int start, int end)
範例:字符串的截取

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		CharSequence chse = "love you";
		System.out.println(chse.subSequence(5, 8));
	}
	
}
/*
you
*/

以後只要看見了CharSequence描述的就是一個字符串。

3 AutoCloseable接口

AutoCloseable主要是日後進行資源開發的處理,以實現資源的自動關閉(釋放資源),例如,在以後進行文件、網絡、以及數據庫開發的過程之中由於服務器的資源有限,所以使用之後一定要關閉資源,這樣纔可以被更多的使用者所使用。

下面爲了更好地說明資源的問題,將通過一個消息的發送處理來完成。
範例:手工實現資源處理

package cn.victor.demo;

interface IMessage{
	public abstract void send();
}

class Message implements IMessage{
	private String msg;
	
	public Message() {}
	
	public Message(String msg) {
		this.msg = msg;
	}
	
	public void send() {
		System.out.println(this.msg);
	}
	
	public void open() {
		System.out.println("[Message Send]: begin send");
	}
	
	public void close() {
		System.out.println("[Message Close]: close send");
	}
}

public class JavaAPIDemo {
	public static void main(String[] args) {
		Message msg = new Message("love you");
		msg.open();
		msg.send();
		msg.close();
	}
	
}

/*
[Message Send]: begin send
love you
[Message Close]: close send
*/

此時有位設計師說了,既然所有的資源完成處理之後都必須進行關閉操作,能否實現一種自動關閉的功能?在這種要求下,推出了AutoCloseable接口,這個接口是在JDK 1.7的時候提供的,並且該接口只提供了一個方法:
(1)關閉方法:void close() throws Exception

要想實現自動關閉處理,除了要使用AutoCloseable之外,還需要結合有異常處理語句纔可以正常調用。
範例:實現自動關閉處理

package cn.victor.demo;

interface IMessage extends AutoCloseable{
	public abstract void send();
}

class Message implements IMessage{
	private String msg;
	
	public Message() {}
	
	public Message(String msg) {
		this.msg = msg;
	}
	
	public void send() {
		System.out.println(this.msg);
	}
	
	public void open() {
		System.out.println("[Message Send]: begin send");
	}
	
	public void close() {
		System.out.println("[Message Close]: close send");
	}
}

public class JavaAPIDemo {
	public static void main(String[] args) {
		try(IMessage msg = new Message("love you")){
			((Message)msg).open();
			msg.send();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

4 Runtime類

Runtime描述的是運行時的狀態,也就是說在整個的JVM之中,Runtime是唯一一個與JVM運行狀態有關的類,並且都會默認提供有一個該類的實例化對象。

由於在每一個JVM進程只允許提供一個Runtime類的對象,所以這個類的構造方法被默認私有化了,那麼就證明該類使用的是單例設計模式,並且單例設計模式一定會提供有一個static方法獲取本類實例。

由於Runtime類屬於單例設計模式,如果要想獲取實例化對象,那麼就可以依靠類中的getRuntime()方法完成。

通過這個類中的public int availableProcessors()方法可以獲取本機的CPU內核數:public int availableProcessors()
(1)獲取實例化對象:
範例:獲取Runtime類對象

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		Runtime run = Runtime.getRuntime();
		System.out.println(run.availableProcessors());  //獲取可用進程數
	}
	
}

除了以上方法之外,在Runtime類裏面還提供有以下四個重要的操作方法:
(1)獲取最大可用內存空間:public long maxMemory(),默認的配置爲本機系統內存的4分之一。
(2)獲取可用內存空間:public long totalMemory(), 默認的配置爲本機系統內存的64分之一。
(3)獲取空閒內存空間:public long freeMemory()
(4)手工進行GC處理:public void gc()

範例:觀察內存狀態

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		Runtime run = Runtime.getRuntime();
		System.out.println(run.availableProcessors());
		System.out.println("[1]MaxMemory: " + run.maxMemory());
		System.out.println("[1]TotalMemory: " + run.totalMemory());
		System.out.println("[1]FreeMemory: " + run.freeMemory());
		String str = "lks";
		for(int i = 0; i < 50000; i++) {
			str += i;  //創建大量對象
		}
		System.out.println("**************************************");
		System.out.println("[2]MaxMemory: " + run.maxMemory());
		System.out.println("[2]TotalMemory: " + run.totalMemory());
		System.out.println("[2]FreeMemory: " + run.freeMemory());
		run.gc();   //手動回收對象
		System.out.println("**************************************");
		System.out.println("[3]MaxMemory: " + run.maxMemory());
		System.out.println("[3]TotalMemory: " + run.totalMemory());
		System.out.println("[3]FreeMemory: " + run.freeMemory());
	}
	
}

面試題:請問什麼是GC?如何處理?
(1)GC(Garbage Collector)垃圾收集器,是可以由系統自動調用的垃圾釋放功能,或者使用Runtime類中的gc()手工調用。

5 System類

System類是一直陪伴着我們學習的程序類,之前使用的系統輸出採用的就是System類中的方法,除了這些方法之外,在System類中也定義有其他方法:
(1)數組拷貝:public static void arraycopy​(Object src, int srcPos, Object dest, int destPos, int length)
(2)獲取當前的日期時間數值:public static long currentTimeMillis()
(3)進行垃圾回收:public static void gc()
範例:操作耗時的統計

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		String str = "lks";
		for(int i = 0; i < 50000; i++) {
			str += i;  //創建大量對象
		}
		long end = System.currentTimeMillis();
		System.out.println(end-start);
	}
	
}

在System類裏面會發現也提供有一個gc()方法,但是這個gc()方法並不是重新定義的新方法,而是繼續調用Runtime類中的gc()操作。

6 Cleaner類

Cleaner是在JDK 1.9之後提供的一個對象的清理操作,其主要的功能是進行finialize()方法的替代。在C++語言裏面有兩種特殊的函數:構造函數、析構函數(對象手工回收),在Java裏面所有的垃圾空間都是通過GC自動回收的,所以很多情況下是不需要使用這類析構函數的,也正是因爲如此,所以Java並沒有提供這方面的支持。

但是Java本身依然提供了給用戶收尾的操作,每一個實例化對象在回收之前至少給他一個喘息的機會,最初實現對象收尾處理的方法是Object類中提供的finialize()方法,這個方法的定義如下:

@Deprecated(since="9")
protected void finalize() throws Throwable

該替換指的是不建議繼續使用這個方法了,而是說子類可以繼續使用這個方法名稱。但是這個方法最大的特點是拋出了一個Throwable異常類型,而這個異常類型分爲兩個子類型:Error、Exception,平常所處理的都是Exception。
範例:觀察傳統回收

package cn.victor.demo;

class Member {
	
	public Member() {
		System.out.println("[Object create]");
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("[recycle]");
		throw new Throwable("[NO!!!]");
	}
	
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		Member mem = new Member();
		mem = null;   //成爲垃圾
		System.gc();  //手動執行垃圾回收器
		System.out.println("[Everything normal]");
	}
	
}

但是從JDK 1.9開始,這一操作已經不建議使用了,而對於對象的回收與釋放,從JDK 1.9開始建議開發者使用AutoCloseable或者使用Cleaner類進行回收處理。

package cn.victor.demo;

import java.lang.ref.Cleaner;
import java.lang.ref.Cleaner.Cleanable;

class Member implements Runnable{
	
	public Member() {
		System.out.println("[Object create]");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("[recycle]");
	}
}

class MemberCleaner implements AutoCloseable{

	private static final Cleaner cleaner = Cleaner.create();
	
	public Member member;
	public Cleaner.Cleanable cleanable;
	
	public MemberCleaner() {
		this.member = new Member();
		this.cleanable = cleaner.register(this, this.member);
	}
	
	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		this.cleanable.clean();
	}
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		try(MemberCleaner mem = new MemberCleaner()){
			//your code
			System.out.println("[Everything normal]");
		}catch(Exception e) {
			
		}
	}
	
}

在新一代的清除回收處理的過程之中,更多的情況下考慮的是多線程的使用,即,爲了防止有可能造成的延遲處理,所以許多對象回收前的處理都是單獨通過一個線程完成的。

7 對象克隆

所謂對象克隆指的就是對象的複製,而且屬於全新的複製。即使用已有對象內容創建一個新的對象,如果要想進行對象的克隆需要使用到Object類中提供的clone()方法。

所有的類都會繼承Object父類,所以所有的類一定會有clone()方法,但是並不是所有的類都希望被克隆。所以如果要想實現對象克隆,那麼對象所在的類需要實現一個接口Cloneable,此接口並沒有任何的方法提供,是因爲它描述的是一種能力。
範例:實現對象克隆

package cn.victor.demo;

class Member implements Cloneable{
	private String name;
	private int age;
	
	public Member() {}
	
	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String toString() {
		return "name: " + this.name + "; age: " + this.age;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
	
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		Member memA = new Member("lks", 23);
		Member memB = (Member)memA.clone(); //use clone
		Member memC = memA;  //don't use clone
		System.out.println(memA == memB);  //false
		System.out.println(memA == memC);  //true
	}
	
}

如果在開發之中不是非常特別的需求下,很少會出現有對象克隆的需求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章