# Day15-Java基础
Day15-Java
文章目錄
- Day15-Java
- 1、字符編碼
- 1.1 常用字符編碼
- 1.2 亂碼產生分析
- 2、內存流基本操作
- 3、打印流
- 3.1 格式化文本信息
- 4、 System類
- 4.1 系統輸出
- 4.2 系統輸出
- 4.3 系統輸入
- 5、BufferedReader類
- 6、Scanner
- 7、對象序列化
- 7.1 對象序列化的概念
- 7.2 實現序列化和反序列化
- 7.3 transient關鍵字(了解)
1、字符編碼
1.1 常用字符編碼
在計算機的世界之中,所有的顯示文字都是按照其指定的數字編碼進行保存的,如果沒有正確的解碼,那么就坑你產生亂碼,如果要想清楚解決亂碼問題,就要了解經常見到一些常見的編碼:
GBK/GBK2312:表示國標中文編碼,其中GBK是包含簡體中文和繁體中文,而GB2312只有簡體;
ISO 8859-1:是一種國際通用編碼,可以表示任何文字,但是對于中國文字需要進行轉碼;
UNICODE:使用十六進制完成的編碼,可以準確的表示出任何的語言文字;
UTF-8:部分編碼使用UNICODE,而一些編碼繼續使用像ISO 8859-1,類型的編碼,適合于網絡傳輸,在以后的所有的項目開發之中,都必須采用此編碼。可是考慮到日后學習的方便,幾乎都會使用命令行進行操作,所以命令行只支持GBK編碼,UTF不支持,一旦程序設置了UTF編碼,那么通過命令行查看就是亂碼。
在開發之中經常會遇見亂碼的問題,所謂的亂碼的核心在于編碼和解碼不統一。如果要想正確的避免項目之中出現的亂碼,那么首先就應該知道環境之中所支持的編碼是什么。
1.2 亂碼產生分析
讀取Java運行屬性
package com.day15.demo;public class ListDemo {public static void main(String[] args) {System.getProperties().list(System.out);} }這個時候顯示出來的信息是很多的,這里面有專門的編碼選項“file.encoding=GBK”,也就是說如果沒有任何的意外,所有的文字編碼都是GBK。
改變編碼
package com.day15.demo;import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream;public class ListDemo {public static void main(String[] args) throws Exception{OutputStream out = new FileOutputStream(new File("f:" + File.separator + "test" + File.separator + "hello.txt"),true);out.write("世界和平".getBytes());out.close();} }2、內存流基本操作
在講解之前首先來思考一個問題:就是如果現在某個操作必須發生IO,但有不希望有一些臨時文件產生的話,那么現在肯定無法使用之前的文件操作流,所以為了解決這樣的問題,提供了內存操作流,即:以內存進行操作的終端,以發生IO操作關系。
對于內存操作流也分為兩組:
**字節內存操作流:**內存輸入流(ByteArrayInputStream)內存輸出流(ByteArrayOutputStream)
**字符內存操作流:**內存輸入流(CharArrayReader)內存輸出流(CharArrayWriter)
| java.lang.Object java.io.InputStream java.io.ByteArrayInputStream | java.lang.Object java.io.OutputStream java.io.ByteArrayOutputStream |
| public ByteArrayInputStream(byte[] buf) | public ByteArrayOutputStream() |
輸出流
輸入流
通過內存實現大小寫轉換的操作
package com.day15.demo;import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream;import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;public class MemoryDemo {public static void main(String[] args) throws Exception{String str = "Hello,World!";InputStream in = new ByteArrayInputStream(str.getBytes());OutputStream out = new ByteOutputStream();int temp = 0;while((temp = in.read())!=-1){out.write(Character.toUpperCase(temp));}in.close();out.close();System.out.println(out.toString());} }此過程我們發現沒有文件的產生,而此過程只不過是產生了臨時文件。
3、打印流
如果說想在要想輸出數據,肯定使用OuputStream或者是Writer,那么請問,這兩個操作類在執行輸出的時候你認為它好用嗎?
打印流主要解決的就是OutputStream缺陷,屬于OutputStream加強版,如果現在操作不是二進制的數據,只是通過程序向終端目標輸出信息。OutputStream并不方便。
缺點一:所有的數據必須變為字節數組
缺點二:只支持String類型,輸出int、double就不方便
如果現在要想輸出字符串,使用Writer可以直接輸出,而使用OutputStream還需要將字符串變為字節數組,那么如果現在要想輸出數字(int型或double型),還需要將這些數據先變為字符串,之后再變為字節數組輸出,多以,如果用戶直接調用OutputStream或Writer輸出的時候本身并不方便,所以在這個時候可以想辦法將OutputStream或Writer變得加強一些,定義一個專門的工具類:PrintUtil.java。
編寫一個輸出功能類PrintUtil類
package com.day15.demo;import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream;class PrintUtil{OutputStream out;public PrintUtil(OutputStream out){this.out=out;}public void print(String str) throws Exception{this.out.write(str.getBytes());}public void println(String str) throws Exception{this.print(str.concat("\r\n"));}public void print(int num) throws Exception{this.print(String.valueOf(num));}public void println(int num) throws Exception{this.println(String.valueOf(num));} } public class PintUtilDemo {public static void main(String[] args) throws Exception {PrintUtil printUtil = new PrintUtil(new FileOutputStream(new File("f:" + File.separator + "test" + File.separator + "test.txt")));printUtil.println("姓名:" + "張麻子");printUtil.print("年齡");printUtil.print(19);} }以后使用PrintWriter的使用率挺高,但是這兩者的使用形式相同的。首先觀察這兩個類的繼承結構和構造方法:
首先來觀察一下PrintStream,PrintWriter的繼承結構和構造方法:
| java.lang.Object java.io.OutputStream java.io.FilterOutputStream java.io.PrintStream | java.lang.Object java.io.Writer java.io.PrintWriter |
| public PrintStream(OuputStream out) | public PrintWriter(Writer out) |
看見以上的結構,可能第一反應就屬于代理設計模式,但它并不是代理,代理設計模式的特點:以接口為使用原則,用戶調用代理主題方法的時候依然是接口之中定義的方法。而此時PrintStream類調用的絕對不是OutputStream類之中定義的一系列write()方法。雖然PrintStream在外表操作上產生了變化,但實際上依然執行的是OutputStream累哦所定義的操作,所以本質沒有發生變化,只是提供了一些更加方便的功能支持,多以這種設計模式上講稱為裝飾設計模式。
3.1 格式化文本信息
在JDK1.5之后,打印流也進行了更新,增加了一個新的方法,格式化輸出:
格式化輸出:public PrintStream printf(String format,Object… args)
當看到此方法名稱的時候首先想到的是C語言中的輸出,而現在Java也具備了同樣的功能,而輸出的時候可以使用一些標記表示要輸出的內容,例如:字符串(%s),數字(%d)小數(%m.nf),字符(%c)等。
觀察格式化輸出
package com.day15.demo;import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter;public class PrintWriterDemo {public static void main(String[] args) throws Exception{PrintWriter pu = new PrintWriter(new FileOutputStream(new File("f:" + File.separator + "test" + File.separator + "test.txt")),true);String name = "張麻子";int age=23;double score=8123219.127456;pu.printf("姓名:%s 年齡:%d 成績:%7.2f",name,age,score);} }而在JDK1.5之后增加字符串格式化操作類不光有PrintStream,還有String類,String類也提供了一個格式化字符串的操作方法:public static String format(String format,Object… args)
格式化字符串
package com.day15.demo;import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter;public class PrintWriterDemo {public static void main(String[] args) throws Exception{PrintWriter pu = new PrintWriter(new FileOutputStream(new File("f:" + File.separator + "test" + File.separator + "test.txt")),true);String name = "張麻子";int age=23;double score=8123219.127456;String str = String.format("姓名:%s 年齡:%d 成績:%7.2f",name,age,score);System.out.println(str);} }雖然格式化字符串可以執行準確的四舍五入操作,但是這種處理完的數據都是String型,而實際工作中,如果要四舍五入,肯定還是要編寫BigDecimal類完成。
以后只要是程序輸出數據的操作,都使用PrintStream類。
4、 System類
在我們學習完了PrintWriter、PrintStream之后我們會發現里面的方法都很熟悉,例如print()、println()輸出就利用我們的IO流模式完成的。在System類中實際上定義有三個操作的常量。
| public static final PrintStream err | 錯誤輸出 |
| public static final InputStream in | 標準輸出 |
4.1 系統輸出
系統輸出我們發現一共有兩個常量:out、err,而且這兩個常量所表示的都是PrintSream的對象。從
Java設計的本質上來講這樣的輸出有以下設計的目的。out是希望輸出的用戶可以看見的內容
,err是希望輸出用戶不能夠看見的內容。
package com.day15.demo;public class PrintDemo {public static void main(String[] args) throws Exception{try{Integer.valueOf("abc");}catch(Exception e){System.err.println(e);System.out.println(e);}} }/* java.lang.NumberFormatException: For input string: "abc" java.lang.NumberFormatException: For input string: "abc" */4.2 系統輸出
系統輸出是將所有的信息輸出到指定的輸出設備上——顯示器。而System.out本身是屬于PrintStream對象,而PrintStream是OutputStream子類,所以現在實際上可以利用System.out為OutputStream類執行實例化操作。
package com.day15.demo;import java.io.OutputStream; public class PrintDemo {public static void main(String[] args) throws Exception {String str ="hello,world";OutputStream output = System.out;//System.out為OutputStream實例化output.write(str.getBytes());} }本程序沒有任何的意義,而講解的主要目的就希望可以理解:OutputStream會根據實例化它的子類或對象的不同,輸出的位置也不同。
4.3 系統輸入
系統輸入針對于標準的輸入設備——鍵盤,也就是俗稱的鍵盤輸入數據,但是System.in返回的是InputStream型的數據,所以下面編寫一個操作由鍵盤輸入數據。
package com.day15.demo;import java.io.IOException; import java.io.InputStream;public class inDemo {public static void main(String[] args) throws Exception {InputStream input = System.in;System.out.println("請輸入!");byte data[] = new byte[1024];int len = input.read(data);System.out.println(new String(data,0,len));} }除了實例化InputStream類的對象不同之外,其他的地方和之前文件輸入數據沒有任何區別,但是這個程序本身有問題,已經開辟的空間大小是1024,如果輸入的數據超過1024呢?發現只會接收滿足指定長度的數據,程序有bug,那么最好的解決方法是不設置長度,輸入一個讀取一個,一直到用戶不輸入為止。
package com.day15.demo;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;public class inDemo {public static void main(String[] args) throws Exception {InputStream input = System.in;//為父類實例化ByteArrayOutputStream bos = new ByteArrayOutputStream();byte data[] = new byte[10];//開辟一個空間System.out.println("請輸入!");int temp = 0;while((temp = input.read(data))!=-1){//數據讀取到字節數//這里面要用戶自己來處理換行問題bos.write(data,0,temp);//保存在內存輸出流if(temp < data.length){break;}}System.out.println(new String(bos.toByteArray()));} }簡化操作,但是中文無法識別
package com.day15.demo;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;public class inDemo {public static void main(String[] args) throws Exception {InputStream input = System.in;//為父類實例化StringBuffer buf = new StringBuffer();System.out.println("請輸入!");int temp = 0;while((temp = input.read())!=-1){//數據讀取到字節數//這里面要用戶自己來處理換行問題if(temp == '\n'){break;}buf.append((char)temp);}System.out.println(buf);} }通過以上比較可以感受到System.in的支持度原本不高,對于英文的操作是支持,但是對于中文是不太友好的,對于中文的輸出還必須借助內存流來實現的。
5、BufferedReader類
BufferedReader屬于一個緩沖的輸入流,而且是一個字符流的操作對象。但是必須清楚一點就是對于我們的緩存流定義有兩類:字節緩沖流( BufferedInputStream )、字節緩沖流( BufferedReader )。
如果說想在把所有的輸入數據放在一起了,一次性讀取出來,那么這個時候肯定就能夠避免中文問題了,而這一操作就必須依靠緩沖區操作流完成。對于緩沖區的讀取在IO包中定義了兩種類:BufferedInputStream,BufferedReader,但是考慮到本次操作有中文的問題,肯定使用BufferedReader類完成操作。下面就需要觀察一下BufferedReader類的繼承結構,構造方法,操作方法:
| 構造方法: | public BuffereedReader(Reader in) |
| 讀取操作: | public String readLine() throws IOException |
之所以選擇BufferReader類操作提供的readLine()方法,這個方法可以讀取一行數據以回車為準。
使用BufferedReader進行數據讀取
package com.day15.demo;import java.io.BufferedReader; import java.io.InputStreamReader;public class BufferReaderDemo {public static void main(String[] args) throws Exception{BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));System.out.println("請輸入");//默認的換行模式是BufferReader最大的缺點String str = bufr.readLine();//接受輸入信息,默認使用回車換行System.out.println(str);} }對輸入的數據進行驗證,判斷是否是數字
package com.day15.demo;import java.io.BufferedReader; import java.io.InputStreamReader;public class BufferReaderDemo {public static void main(String[] args) throws Exception{BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));System.out.println("請輸入年齡");//默認的換行模式是BufferReader最大的缺點String str = bufr.readLine();//接受輸入信息,默認使用回車換行if(str.matches("\\d{1,3}"))System.out.println(str);elseSystem.out.println("輸入數據有誤!");} }6、Scanner
這個類是作為了一個工具類出現的,在Scanner之中定義兩個如下的一些方法:
| public Boolean hasNextXxx(); | 判斷是否有數據 |
| public 數據類型 nextXxx(); | 取得數據 |
| public Scanner useDelimiter(String partern); | 定義分隔符 |
以后調用的時候在執行nextXxx()之前一定要首先使用hasNextXxx()判斷是否有指定格式的數據出現。
通過Scanner類進行數據的輸入
package com.day15.demo;import java.util.Scanner;public class ScannerDemo {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("請輸入數據:");if(sc.hasNext()){//現在有輸入的內容,不能判斷空字符串System.out.println(sc.next());}sc.close();} }使用Scanner類判斷輸入數據是否是int型數據
package com.day15.demo;import java.util.Scanner;public class ScannerDemo {public static void main(String[] args) {System.out.println("請輸入數據:");Scanner sca=new Scanner(System.in);if(sca.hasNextInt()){int date=sca.nextInt();System.out.println("輸入的數據是:"+date);}else{System.out.println("輸入的不是數字");}} }在Scaner類之中,useDelimiter()方法的輸入針對于字符串,但是其他的數據類型并不方便使用。
使用Scanner類判斷用戶輸入的是不是生日
package com.day15.demo;import java.util.Scanner;public class ScannerDemo {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("請輸入生日:");if(sc.hasNext("\\d{4}-\\d{2}-\\d{2}")){//現在有輸入的內容,不能判斷空字符串String bir = sc.next("\\d{4}-\\d{2}-\\d{2}");System.out.println(bir);}sc.close();} }Scanner讀取文件內容
package com.day15.demo;import java.io.File; import java.io.FileInputStream; import java.util.Scanner;public class ScannerDemo {public static void main(String[] args) throws Exception{Scanner sc = new Scanner(new FileInputStream(new File("f:" + File.separator + "test" + File.separator + "hello.txt")));sc.useDelimiter("\n");if(sc.hasNext()){//現在有輸入的內容,不能判斷空字符串System.out.println(sc.next());}sc.close();} }除了二進制文件拷貝處理之外,只要針對于程序的信息輸出都使用打印流,對于信息的輸入都是Scanner。
7、對象序列化
所有的項目都一定有序列化的概念。
7.1 對象序列化的概念
所謂的對象序列化是指在內存中保存的對象變為二進制流的形式進行傳輸,或者將其保存在文本中。但是我們并不意味著所有對象都可以被序列化,嚴格來講,我們需要被實例化的類對象往往需要傳輸使用,同時這個類 必須實現java.io.Serializable接口。但是這個接口沒有任何方法定義,所以只是一個標識。
package com.day15.demo;import java.io.Serializable;class Person implements Serializable{private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;} } public class SerializableDemo {}序列化對象是所需要保存的就是對象中的屬性所以默認情況下對象的屬性將被轉為二進制數據流存儲。
7.2 實現序列化和反序列化
如果要想進行對象的序列化和反序列話的手工操作,在java之中提提供了兩個操作類:ObjectOutputStream,ObjectInputStream,而這兩個類的繼承結構,構造方法,操作方法定義如下:
| java.lang.Object java.io.OutputStream java.io.ObjectOutputStream | java.lang.Object java.io.InputStream java.io.ObjectInputStream |
| public ObjectOutputStream(OutputStream out) throws IOException | public ObjectInputStream(InputStream in) throws IOException |
| public final void writeObject(Object obj) throws IOException | public final Object readObject() throws IOException,ClassNotFoundException |
實現對象的序列化操作
package com.day15.demo;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays;class Person implements Serializable{private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";} } public class SerializableDemo{public static final File FILE = new File("F:" + File.separator + "test" + File.separator + "person.txt");public static void ser(Object o) throws Exception {ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(FILE));outputStream.writeObject(o);outputStream.close();}public static void dser() throws Exception {ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(FILE));System.out.println(inputStream.readObject());inputStream.close();}public static void main(String[] args) throws Exception{//序列化//ser(new Person("張麻子",20));//反序列化dser();} }如果出現com.day15.demo.Person@6d311334這個情況的主要原因是因為實體類沒有進行toString()方法的重寫。
7.3 transient關鍵字(了解)
實際上序列化的處理在Java.io有兩類,Serializable是使用最多的序列化接口,這種操作采用自動化的模式完成,默認情況下所有的屬性都會進行序列化。有一個Externalizable接口需要用戶手動序列化處理。
由于默認情況Serializable會將對象中的所有屬性進行保存,但是如果現在有某些屬性不希望被保存了,那么可以使用transient關鍵字。
使用transient
package com.day15.demo;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays;class Person implements Serializable{private transient String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";} } public class SerializableDemo{public static final File FILE = new File("F:" + File.separator + "test" + File.separator + "person.txt");public static void ser(Object o) throws Exception {ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(FILE));outputStream.writeObject(o);outputStream.close();}public static void dser() throws Exception {ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(FILE));System.out.println(inputStream.readObject());inputStream.close();}public static void main(String[] args) throws Exception{ser(new Person("張麻子",20));dser();} } /* Person [name=null, age=20] */發現此處name沒有進行序列化操作。使用序列化往往在簡單java類上使用,其他類上使用序列化的使用很少,但是在簡單java類中基本上不去使用transient。
總結
以上是生活随笔為你收集整理的# Day15-Java基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言中整形常量表达形式,C语言中整型常
- 下一篇: Java之非对称加密