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)

| ByteArrayInputStream | ByteArrayOutputStream |
|---|---|
| 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的繼承結構和構造方法:
| 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 out | 標準輸出 |
|---|---|
| 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類的繼承結構,構造方法,操作方法:
| 繼承結構: | java.lang.Object java.io.Reader java.io.BuffereedReader |
|---|---|
| 構造方法: | 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);
else
System.out.println("輸入資料有誤!");
}
}
6、Scanner
這個類是作為了一個工具類出現的,在Scanner之中定義兩個如下的一些方法:
| public Scanner(InputStream sourse); | 構造方法 |
|---|---|
| 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,而這兩個類的繼承結構,構造方法,操作方法定義如下:
| 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;
}
@Override
public 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;
}
@Override
public 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,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295156.html
標籤:java
