Java
JDK(Java Development Kit)稱為Java開發(fā)包或Java開發(fā)工具,是一個(gè)編寫Java的Applet小程序和應(yīng)用程序的程序開發(fā)環(huán)境。JDK是整個(gè)Java的核心,包括了Java運(yùn)行環(huán)境(Java Runtime Envirnment),一些Java工具和Java的核心類庫(kù)(Java API)。不論什么Java應(yīng)用服務(wù)器實(shí)質(zhì)都是內(nèi)置了某個(gè)版本的JDK。主流的JDK是Sun公司發(fā)布的JDK,除了Sun之外,還有很多公司和組織都開發(fā)了自己的JDK,例如,IBM公司開發(fā)的JDK,BEA公司的Jrocket,還有GNU組織開發(fā)的JDK。
另外,可以把Java API類庫(kù)中的Java SE API子集和Java虛擬機(jī)這兩部分統(tǒng)稱為JRE(JAVA Runtime Environment),JRE是支持Java程序運(yùn)行的標(biāo)準(zhǔn)環(huán)境。
JRE是個(gè)運(yùn)行環(huán)境,JDK是個(gè)開發(fā)環(huán)境。因此寫Java程序的時(shí)候需要JDK,而運(yùn)行Java程序的時(shí)候就需要JRE。而JDK里面已經(jīng)包含了JRE,因此只要安裝了JDK,就可以編輯Java程序,也可以正常運(yùn)行Java程序。但由于JDK包含了許多與運(yùn)行無(wú)關(guān)的內(nèi)容,占用的空間較大,因此運(yùn)行普通的Java程序無(wú)須安裝JDK,而只需要安裝JRE即可[15] 。
編程工具
Eclipse:一個(gè)開放源代碼的、基于Java的可擴(kuò)展開發(fā)平臺(tái)。
NetBeans:開放源碼的Java集成開發(fā)環(huán)境,適用于各種客戶機(jī)和Web應(yīng)用。
IntelliJ IDEA:在代碼自動(dòng)提示、代碼分析等方面的具有很好的功能。
MyEclipse:由Genuitec公司開發(fā)的一款商業(yè)化軟件,是應(yīng)用比較廣泛的Java應(yīng)用程序集成開發(fā)環(huán)境。
EditPlus:如果正確配置Java的編譯器“Javac”以及解釋器“Java”后,可直接使用EditPlus編譯執(zhí)行Java程序
理解Java中字符流與字節(jié)流的區(qū)別
1. 什么是流
Java中的流是對(duì)字節(jié)序列的抽象,我們可以想象有一個(gè)水管,只不過(guò)現(xiàn)在流動(dòng)在水管中的不再是水,而是字節(jié)序列。和水流一樣,Java中的流也具有一個(gè)“流動(dòng)的方向”,通常可以從中讀入一個(gè)字節(jié)序列的對(duì)象被稱為輸入流;能夠向其寫入一個(gè)字節(jié)序列的對(duì)象被稱為輸出流。
2. 字節(jié)流
Java中的字節(jié)流處理的最基本單位為單個(gè)字節(jié),它通常用來(lái)處理二進(jìn)制數(shù)據(jù)。Java中最基本的兩個(gè)字節(jié)流類是InputStream和OutputStream,它們分別代表了組基本的輸入字節(jié)流和輸出字節(jié)流。InputStream類與OutputStream類均為抽象類,我們?cè)趯?shí)際使用中通常使用Java類庫(kù)中提供的它們的一系列子類。下面我們以InputStream類為例,來(lái)介紹下Java中的字節(jié)流。
InputStream類中定義了一個(gè)基本的用于從字節(jié)流中讀取字節(jié)的方法read,這個(gè)方法的定義如下:
public abstract int read() throws IOException;
這是一個(gè)抽象方法,也就是說(shuō)任何派生自InputStream的輸入字節(jié)流類都需要實(shí)現(xiàn)這一方法,這一方法的功能是從字節(jié)流中讀取一個(gè)字節(jié),若到了末尾則返回-1,否則返回讀入的字節(jié)。關(guān)于這個(gè)方法我們需要注意的是,它會(huì)一直阻塞知道返回一個(gè)讀取到的字節(jié)或是-1。另外,字節(jié)流在默認(rèn)情況下是不支持緩存的,這意味著每調(diào)用一次read方法都會(huì)請(qǐng)求操作系統(tǒng)來(lái)讀取一個(gè)字節(jié),這往往會(huì)伴隨著一次磁盤IO,因此效率會(huì)比較低。有的小伙伴可能認(rèn)為InputStream類中read的以字節(jié)數(shù)組為參數(shù)的重載方法,能夠一次讀入多個(gè)字節(jié)而不用頻繁的進(jìn)行磁盤IO。那么究竟是不是這樣呢?我們來(lái)看一下這個(gè)方法的源碼:
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
它調(diào)用了另一個(gè)版本的read重載方法,那我們就接著往下追:
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off 《 0 || len 《 0 || len 》 b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i 《 len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
從以上的代碼我們可以看到,實(shí)際上read(byte[])方法內(nèi)部也是通過(guò)循環(huán)調(diào)用read()方法來(lái)實(shí)現(xiàn)“一次”讀入一個(gè)字節(jié)數(shù)組的,因此本質(zhì)來(lái)說(shuō)這個(gè)方法也未使用內(nèi)存緩沖區(qū)。要使用內(nèi)存緩沖區(qū)以提高讀取的效率,我們應(yīng)該使用BufferedInputStream。
3. 字符流
Java中的字符流處理的最基本的單元是Unicode碼元(大小2字節(jié)),它通常用來(lái)處理文本數(shù)據(jù)。所謂Unicode碼元,也就是一個(gè)Unicode代碼單元,范圍是0x0000~0xFFFF。在以上范圍內(nèi)的每個(gè)數(shù)字都與一個(gè)字符相對(duì)應(yīng),Java中的String類型默認(rèn)就把字符以Unicode規(guī)則編碼而后存儲(chǔ)在內(nèi)存中。然而與存儲(chǔ)在內(nèi)存中不同,存儲(chǔ)在磁盤上的數(shù)據(jù)通常有著各種各樣的編碼方式。使用不同的編碼方式,相同的字符會(huì)有不同的二進(jìn)制表示。實(shí)際上字符流是這樣工作的:
輸出字符流:把要寫入文件的字符序列(實(shí)際上是Unicode碼元序列)轉(zhuǎn)為指定編碼方式下的字節(jié)序列,然后再寫入到文件中;
輸入字符流:把要讀取的字節(jié)序列按指定編碼方式解碼為相應(yīng)字符序列(實(shí)際上是Unicode碼元序列從)從而可以存在內(nèi)存中。
我們通過(guò)一個(gè)demo來(lái)加深對(duì)這一過(guò)程的理解,示例代碼如下:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fileWriter = null;
try {
try {
fileWriter = new FileWriter(“demo.txt”);
fileWriter.write(“demo”);
} finally {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上代碼中,我們使用FileWriter向demo.txt中寫入了“demo”這四個(gè)字符,我們用十六進(jìn)制編輯器WinHex查看下demo.txt的內(nèi)容:
從上圖可以看出,我們寫入的“demo”被編碼為了“64 65 6D 6F”,但是我們并沒有在上面的代碼中顯式指定編碼方式,實(shí)際上,在我們沒有指定時(shí)使用的是操作系統(tǒng)的默認(rèn)字符編碼方式來(lái)對(duì)我們要寫入的字符進(jìn)行編碼。
由于字符流在輸出前實(shí)際上是要完成Unicode碼元序列到相應(yīng)編碼方式的字節(jié)序列的轉(zhuǎn)換,所以它會(huì)使用內(nèi)存緩沖區(qū)來(lái)存放轉(zhuǎn)換后得到的字節(jié)序列,等待都轉(zhuǎn)換完畢再一同寫入磁盤文件中。
4. 字符流與字節(jié)流的區(qū)別
經(jīng)過(guò)以上的描述,我們可以知道字節(jié)流與字符流之間主要的區(qū)別體現(xiàn)在以下幾個(gè)方面:
字節(jié)流操作的基本單元為字節(jié);字符流操作的基本單元為Unicode碼元。
字節(jié)流默認(rèn)不使用緩沖區(qū);字符流使用緩沖區(qū)。
字節(jié)流通常用于處理二進(jìn)制數(shù)據(jù),實(shí)際上它可以處理任意類型的數(shù)據(jù),但它不支持直接寫入或讀取Unicode碼元;字符流通常處理文本數(shù)據(jù),它支持寫入及讀取Unicode碼元。
以上是我對(duì)Java中字符流與字節(jié)流的一些認(rèn)識(shí),如有敘述不清晰或是不準(zhǔn)確的地方希望大家可以指正,謝謝大家:)
5.字節(jié)流與和字符流的使用非常相似,兩者除了操作代碼上的不同之外,是否還有其他的不同呢?實(shí)際上字節(jié)流在操作時(shí)本身不會(huì)用到緩沖區(qū)(內(nèi)存),是文件本身直接操作的,而字符流在操作時(shí)使用了緩沖區(qū),通過(guò)緩沖區(qū)再操作文件,如圖12-6所示。
下面以兩個(gè)寫文件的操作為主進(jìn)行比較,但是在操作時(shí)字節(jié)流和字符流的操作完成之后都不關(guān)閉輸出流。
范例:使用字節(jié)流不關(guān)閉執(zhí)行
Java代碼 package org.lxh.demo12.byteiodemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamDemo05 {
public static void main(String[] args) throws Exception { // 異常拋出, 不處理
// 第1步:使用File類找到一個(gè)文件
File f = new File(“d:” + File.separator + “test.txt”); // 聲明File 對(duì)象
// 第2步:通過(guò)子類實(shí)例化父類對(duì)象
OutputStream out = null;
// 準(zhǔn)備好一個(gè)輸出的對(duì)象
out = new FileOutputStream(f);
// 通過(guò)對(duì)象多態(tài)性進(jìn)行實(shí)例化
// 第3步:進(jìn)行寫操作
String str = “Hello World!??!”;
// 準(zhǔn)備一個(gè)字符串
byte b[] = str.getBytes();
// 字符串轉(zhuǎn)byte數(shù)組
out.write(b);
// 將內(nèi)容輸出
// 第4步:關(guān)閉輸出流
// out.close();
// 此時(shí)沒有關(guān)閉
}
}
程序運(yùn)行結(jié)果:
此時(shí)沒有關(guān)閉字節(jié)流操作,但是文件中也依然存在了輸出的內(nèi)容,證明字節(jié)流是直接操作文件本身的。而下面繼續(xù)使用字符流完成,再觀察效果。
范例:使用字符流不關(guān)閉執(zhí)行
Java代碼 package org.lxh.demo12.chariodemo;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriterDemo03 {
public static void main(String[] args) throws Exception { // 異常拋出, 不處理
// 第1步:使用File類找到一個(gè)文件
File f = new File(“d:” + File.separator + “test.txt”);// 聲明File 對(duì)象
// 第2步:通過(guò)子類實(shí)例化父類對(duì)象
Writer out = null;
// 準(zhǔn)備好一個(gè)輸出的對(duì)象
out = new FileWriter(f);
// 通過(guò)對(duì)象多態(tài)性進(jìn)行實(shí)例化
// 第3步:進(jìn)行寫操作
String str = “Hello World!??!”;
// 準(zhǔn)備一個(gè)字符串
out.write(str);
// 將內(nèi)容輸出
// 第4步:關(guān)閉輸出流
// out.close();
// 此時(shí)沒有關(guān)閉
}
}
程序運(yùn)行結(jié)果:
程序運(yùn)行后會(huì)發(fā)現(xiàn)文件中沒有任何內(nèi)容,這是因?yàn)樽址鞑僮鲿r(shí)使用了緩沖區(qū),而 在關(guān)閉字符流時(shí)會(huì)強(qiáng)制性地將緩沖區(qū)中的內(nèi)容進(jìn)行輸出,但是如果程序沒有關(guān)閉,則緩沖區(qū)中的內(nèi)容是無(wú)法輸出的,所以得出結(jié)論:字符流使用了緩沖區(qū),而字節(jié)流沒有使用緩沖區(qū)。
提問:什么叫緩沖區(qū)?
在很多地方都碰到緩沖區(qū)這個(gè)名詞,那么到底什么是緩沖區(qū)?又有什么作用呢?
回答:緩沖區(qū)可以簡(jiǎn)單地理解為一段內(nèi)存區(qū)域。
可以簡(jiǎn)單地把緩沖區(qū)理解為一段特殊的內(nèi)存。
某些情況下,如果一個(gè)程序頻繁地操作一個(gè)資源(如文件或數(shù)據(jù)庫(kù)),則性能會(huì)很低,此時(shí)為了提升性能,就可以將一部分?jǐn)?shù)據(jù)暫時(shí)讀入到內(nèi)存的一塊區(qū)域之中,以后直接從此區(qū)域中讀取數(shù)據(jù)即可,因?yàn)樽x取內(nèi)存速度會(huì)比較快,這樣可以提升程序的性能。
在字符流的操作中,所有的字符都是在內(nèi)存中形成的,在輸出前會(huì)將所有的內(nèi)容暫時(shí)保存在內(nèi)存之中,所以使用了緩沖區(qū)暫存數(shù)據(jù)。
如果想在不關(guān)閉時(shí)也可以將字符流的內(nèi)容全部輸出,則可以使用Writer類中的flush()方法完成。
范例:強(qiáng)制性清空緩沖區(qū)
Java代碼 package org.lxh.demo12.chariodemo;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriterDemo04 {
public static void main(String[] args) throws Exception { // 異常拋出不處理
// 第1步:使用File類找到一個(gè)文件
File f = new File(“d:” + File.separator + “test.txt”);// 聲明File
對(duì)象
// 第2步:通過(guò)子類實(shí)例化父類對(duì)象
Writer out = null;
// 準(zhǔn)備好一個(gè)輸出的對(duì)象
out = new FileWriter(f);
// 通過(guò)對(duì)象多態(tài)性進(jìn)行實(shí)例化
// 第3步:進(jìn)行寫操作
String str = “Hello World!??!”;
// 準(zhǔn)備一個(gè)字符串
out.write(str);
// 將內(nèi)容輸出
out.flush();
// 強(qiáng)制性清空緩沖區(qū)中的內(nèi)容
// 第4步:關(guān)閉輸出流
// out.close();
// 此時(shí)沒有關(guān)閉
}
}
程序運(yùn)行結(jié)果:
此時(shí),文件中已經(jīng)存在了內(nèi)容,更進(jìn)一步證明內(nèi)容是保存在緩沖區(qū)的。這一點(diǎn)在讀者日后的開發(fā)中要特別引起注意。
提問:使用字節(jié)流好還是字符流好?
學(xué)習(xí)完字節(jié)流和字符流的基本操作后,已經(jīng)大概地明白了操作流程的各個(gè)區(qū)別,那么在開發(fā)中是使用字節(jié)流好還是字符流好呢?
回答:使用字節(jié)流更好。
在回答之前,先為讀者講解這樣的一個(gè)概念,所有的文件在硬盤或在傳輸時(shí)都是以字節(jié)的方式進(jìn)行的,包括圖片等都是按字節(jié)的方式存儲(chǔ)的,而字符是只有在內(nèi)存中才會(huì)形成,所以在開發(fā)中,字節(jié)流使用較為廣泛。
字節(jié)流與字符流主要的區(qū)別是他們的的處理方式
流分類:
1.Java的字節(jié)流
InputStream是所有字節(jié)輸入流的祖先,而OutputStream是所有字節(jié)輸出流的祖先。
2.Java的字符流
Reader是所有讀取字符串輸入流的祖先,而writer是所有輸出字符串的祖先。
InputStream,OutputStream,Reader,writer都是抽象類。所以不能直接new
字節(jié)流是最基本的,所有的InputStream和OutputStream的子類都是,主要用在處理二進(jìn)制數(shù)據(jù),它是按字節(jié)來(lái)處理的
但實(shí)際中很多的數(shù)據(jù)是文本,又提出了字符流的概念,它是按虛擬機(jī)的encode來(lái)處理,也就是要進(jìn)行字符集的轉(zhuǎn)化
這兩個(gè)之間通過(guò) InputStreamReader,OutputStreamWriter來(lái)關(guān)聯(lián),實(shí)際上是通過(guò)byte[]和String來(lái)關(guān)聯(lián)
在實(shí)際開發(fā)中出現(xiàn)的漢字問題實(shí)際上都是在字符流和字節(jié)流之間轉(zhuǎn)化不統(tǒng)一而造成的
在從字節(jié)流轉(zhuǎn)化為字符流時(shí),實(shí)際上就是byte[]轉(zhuǎn)化為String時(shí),
public String(byte bytes[], String charsetName)
有一個(gè)關(guān)鍵的參數(shù)字符集編碼,通常我們都省略了,那系統(tǒng)就用操作系統(tǒng)的lang
而在字符流轉(zhuǎn)化為字節(jié)流時(shí),實(shí)際上是String轉(zhuǎn)化為byte[]時(shí),
byte[] String.getBytes(String charsetName)
也是一樣的道理
至于java.io中還出現(xiàn)了許多其他的流,按主要是為了提高性能和使用方便,
如BufferedInputStream,PipedInputStream等
評(píng)論
查看更多