【Java】day21--裝飾者設計模式、序列流對象、對象輸入輸出流、Properties配置文件部分知識點總結

(一)繼承增強一個類的功能

BufferedReader    對FileReader拓展了一個功能,readLine.
需求1:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有行號。
需求2:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有分號。//semicolon分號
需求3:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有雙引號。
需求4:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有行號和分號。
需求5:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有雙引號和行號。
需求6:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有雙引號和分號。
需求7:編寫一個類對BufferedReader的功能進行增強,增強其readLine方法,返回數據帶有雙引號和號。

解決方案:使用繼承,通過子類增強其功能。

增強一個類的功能:
    通過繼承增強一個類的功能的優點:代碼結構清晰簡單。
    缺點:代碼不靈活,會導致繼承體系過於龐大。

//帶行號的緩衝類
class BufferedLineNum extends BufferedReader{
	int count=0;
	public BufferedLineNum(Reader in) {
		super(in);//此句話只是爲了讓編譯器編譯不報錯
	}
	@Override
	public String readLine() throws IOException {
		String line=super.readLine();//調用其父類的readLine()方法
		if(line==null)
			return null;
		line=count+":"+line;
		count++;
		return line;//不可能爲null
	}
}
//帶有分號的緩衝類
class BufferedSemi extends BufferedReader{
	public BufferedSemi(Reader in) {//構造函數
		super(in);
	}
	@Override
	public String readLine() throws IOException {
		String line=super.readLine();
		if(line==null)
			return null;
		line=line+";";
		return line;
	}
}
//帶雙引號的緩衝類
class BufferedDoubleQuo extends BufferedReader{
	public BufferedDoubleQuo(Reader in) {
		super(in);
	}
	@Override
	public String readLine() throws IOException {
		String line=super.readLine();
		if(line==null)
			return null;
		line="\""+line+"\"";//兩側添加雙引號
		return line;
	}
}
public class demo1 {

	public static void main(String[] args) throws IOException {
		File file =new File("C:\\Users\\lenovo\\eclipse-workspace\\day19\\src\\output\\copy_picture.java");
		FileReader fileReader=new FileReader(file);
		/*
		BufferedLineNum bufferedLineNum =new BufferedLineNum(fileReader);
		String line=null;
		while((line=bufferedLineNum.readLine())!=null) {
			System.out.println(line);
		}
		*/
		/*
		BufferedSemi bufferedSemi=new BufferedSemi(fileReader);
		String line=null;
		while((line=bufferedSemi.readLine())!=null) {
			System.out.println(line);
		}
		*/
		BufferedDoubleQuo BufferedDoubleQuo=new BufferedDoubleQuo(fileReader);
		String line=null;
		while((line=BufferedDoubleQuo.readLine())!=null) {
			System.out.println(line);
		}
	}
}

(二)裝飾者設計模式增強功能

裝飾者設計模式:增強一個類的功能 。
步驟:
    1.在增強類的內部維護一個被增強類的引用。
    2.讓增強與被增強類有一個共同父類或父接口。
    
好處:利用了多態達到了類與類之間可以互相裝飾,比較靈活。
缺點:代碼結構不清晰,難以理解。

讓這些裝飾類有一個共同父類(父接口)的目的是爲了讓這些裝飾類可以互相裝飾,構成一條裝飾鏈。
 

//帶行號
class BufferedLineNum2 extends BufferedReader{
	BufferedReader bufferedReader;//在內部維護一個被增強類的引用對象
	int count=1;
	//構造函數
	public BufferedLineNum2(BufferedReader bufferedReader) {//BufferedReader bufferedReader=new BufferedSemi2(); 
		super(bufferedReader);
		this.bufferedReader=bufferedReader;
	}
	public String readLine() throws IOException {
		String line=bufferedReader.readLine();//如果這裏的readLine方法調用的是BufferedSemi2的readLine方法,可以保證又有行號又有分號
		if(line==null)
			return null;
		line=count+":"+line;
		count++;
		return line;
	}
}
//帶分號
class BufferedSemi2 extends BufferedReader{//繼承是爲了讓該類的對象可以傳遞給BufferedLineNum2
	BufferedReader bufferedReader;//在內部維護一個被增強類的引用對象
	//構造函數
	public BufferedSemi2(BufferedReader bufferedReader) {
		super(bufferedReader);//該語句沒有任何作用,只是爲了編譯不報錯,因爲父類沒有無參的構造函數。
		this.bufferedReader=bufferedReader;
	}
	public String readLine() throws IOException {
		String line=bufferedReader.readLine();
		if(line==null)
			return null;
		line=line+";";
		return line;
	}
}
//帶雙引號
class BufferedDoubleQuo2 extends BufferedReader{
	BufferedReader bufferedReader;//在內部維護一個被增強類的引用對象
	//構造函數
	public BufferedDoubleQuo2(BufferedReader bufferedReader) {
		super(bufferedReader);
		this.bufferedReader=bufferedReader;
	}
	public String readLine() throws IOException {
		String line=bufferedReader.readLine();
		if(line==null)
			return null;
		line="\""+line+"\"";
		return line;
	}
}
public class demo2 {

	public static void main(String[] args) throws IOException {
		File file =new File("C:\\Users\\lenovo\\eclipse-workspace\\day19\\src\\output\\copy_picture.java");
		//建立輸入字符流對象
		FileReader fileReader=new FileReader(file);
		//建立一個緩衝輸入字符流對象
		BufferedReader bufferedReader=new BufferedReader(fileReader);
		//建立一個帶行號的緩衝輸入字符流對象
		BufferedSemi2 bufferedSemi2=new BufferedSemi2(bufferedReader);
		BufferedLineNum2 bufferedLineNum2=new BufferedLineNum2(bufferedSemi2);
		BufferedDoubleQuo2 bufferedDoubleQuo2=new BufferedDoubleQuo2(bufferedLineNum2);//行號+雙引號+分號

				
		//BufferedDoubleQuo2 bufferedDoubleQuo2=new BufferedDoubleQuo2(bufferedSemi2);//雙引號+分號
		
		//BufferedLineNum2 bufferedLineNum2=new BufferedLineNum2(bufferedDoubleQuo2);//行號+雙引號
		//BufferedLineNum2 bufferedLineNum2=new BufferedLineNum2(bufferedSemi2);//行號+分號

		String line=null;
		while((line=bufferedDoubleQuo2.readLine())!=null) {
			System.out.println(line);
		}
	}
}

(三)序列流對象

序列流:SequenceInputStream(序列流):可以把多個輸入流串聯起來讀取,先從第一個開始讀取,再讀下一個。。

兩個源文件:

	public static void merge2() throws IOException{
		//找到目標文件
		File file1=new File("E:\\aa.txt");
		File file2=new File("E:\\bb.txt");
		File file3=new File("E:\\cc.txt");
		//建立數據輸入輸出通道
		FileInputStream fileInputStream1=new FileInputStream(file1);
		FileInputStream fileInputStream2=new FileInputStream(file2);
		FileOutputStream fileOutputStream=new FileOutputStream(file3);
		//創建序列流對象
		SequenceInputStream sequenceInputStream=new SequenceInputStream(fileInputStream1,fileInputStream2);
		//邊讀邊寫
		byte[] buf=new byte[1024];
		int length=0;
		while((length=sequenceInputStream.read(buf))!=-1) {
			fileOutputStream.write(buf,0,length);
			//fileOutputStream.flush();
		}
		//關閉資源
		sequenceInputStream.close();//關閉的是傳入的兩個輸入流
		fileOutputStream.close();
	}
}

三個源文件:

public static void merge3() throws IOException{
		//找到目標文件
		File file1=new File("E:\\aa.txt");
		File file2=new File("E:\\bb.txt");
		File file3=new File("E:\\cc.txt");
		File file4=new File("E:\\dd.txt");

		//建立數據輸入輸出通道
		FileInputStream fileInputStream1=new FileInputStream(file1);
		FileInputStream fileInputStream2=new FileInputStream(file2);
		FileInputStream fileInputStream3=new FileInputStream(file3);
		FileOutputStream fileOutputStream=new FileOutputStream(file4);
		
		Vector<FileInputStream> v=new Vector<FileInputStream>();
		v.add(fileInputStream1);
		v.add(fileInputStream2);
		v.add(fileInputStream3);
		//迭代器的接口
		Enumeration<FileInputStream> e=v.elements();//通過vector得到一個迭代器
		//創建一個序列流對象
		SequenceInputStream sequenceInputStream =new SequenceInputStream(e);
		byte[] buf=new byte[1024];
		int length=0;
		while((length=sequenceInputStream.read(buf))!=-1) {
			fileOutputStream.write(buf,0,length);
		}
		sequenceInputStream.close();
		fileOutputStream.close();
	}
}

練習:把一首mp3分成n份,每份1m,然後合併起來。

public class demo5 {

	public static void main(String[] args) throws IOException {
		//cutFile();
		mergeMp3();
	}
	//將一個mp3文件拆成多個文件,每個大小1M
	public static void cutFile() throws IOException {
		File file=new File("F:\\KwDownload\\song\\王一博-因爲我們在一起.mp3");
		FileInputStream fileInputStream=new FileInputStream(file);
		byte[] buf=new byte[1024*1024];//1M
		int length=0;
		int count=1;
		while((length=fileInputStream.read(buf))!=-1) {
			System.out.println("lll");
			//每讀取一次,生成一個文件
			FileOutputStream fileOutputStream=new FileOutputStream("E:\\music1\\part"+count+".mp3");
			fileOutputStream.write(buf,0,length);
			count++;
			fileOutputStream.close();
		}
		fileInputStream.close();
	} 
	//合併多個mp3文件爲一個 
	public static void mergeMp3() throws IOException {
		File dir=new File("E:\\music1");
		File destFile=new File("F:\\因爲我們在一起.mp3");
		File[] files=dir.listFiles();//獲取文件夾中所有子文件
		//創建一個Vector對象,存儲FileInputStream對象
		Vector<FileInputStream> vector=new Vector<FileInputStream>();
		//遍歷數組
		for(File file1:files) {
			if(file1.getName().endsWith(".mp3")) {
				vector.add(new FileInputStream(file1));
			}
		}
		//創建一個序列流對象
		SequenceInputStream sequenceInputStream =new SequenceInputStream(vector.elements());
		//創建一個輸出流對象
		FileOutputStream fileOutputStream=new FileOutputStream(destFile);
		//邊讀邊寫
		byte[] buf=new byte[1024];
		int length=0;
		while((length=sequenceInputStream.read(buf))!=-1) {
			fileOutputStream.write(buf,0,length);
		}
		fileOutputStream.close();
		sequenceInputStream.close();
	}
}

(四)對象輸入輸出流

ObjectOutputStream(對象的輸出流):主要用於將數據寫到文件上。(硬盤)
ObjectInputStream(對象的輸入流):把硬盤中的數據讀取回來。
ObjectOutputStream要注意的事項:
    1.使用ObjectOutputStream的write方法時,只能寫出實現了Serializable接口的對象。
    Serializable接口沒有任何方法,這種接口稱爲標識接口。
    2.對象反序列化時創建對象是不會調用構造方法的。
    3.把對象寫到文件上的時候。文件除了記錄對象的一些信息以外,還記錄了class的版本號,版本號是通過一個類的
    類名、包名、工程名、成員一起算出來的一個id號。
    4.在反序列化的時候,jvm會使用本地class文件算出一個id號與文件記錄的id號相比較,若不相等,則反序列化失敗。
    5.如果一個類的成員後期可能會發生改動,那麼可以在序列化之前就指定一個serialVersionUID,如果一個類一旦制定了一個
    serialVersionUID,那麼jvm就不會再計算該class文件的serialVersionUID。
    6.如果一個類的某些成員不想報序列化到硬盤上,可以用關鍵字transient修飾。
    7.如果一個類的內部維護了另外一個類的對象,那麼另外一個類也必須要實現Serializable接口。


    構造方法調用了一定會創建對象,創建對象不一定會調用構造方法。(對象反序列化)

class Address implements Serializable{
	String country;
	String city;
	public Address(String country, String city) {
		super();
		this.country = country;
		this.city = city;
	}
}
class User implements Serializable{//對象要寫入硬盤就必須實現該接口
	public static final long serialVersionUID=1;
	Address address=new Address("中國","北京");
	String userName;
	String password;
	transient int age;//透明化,不會被序列化
	public User(String userName, String password,int age) {
		super();
		this.userName = userName;
		this.password = password;
		this.age=age;
	}
	@Override
	public String toString() {
		return "{用戶名:"+this.userName+" 密碼:"+this.password+" 年齡:"+this.age+"}";
	}
}
public class demo1 {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		writeObj();
		//readObj();
	}
	//對象的反序列化---->讀取硬盤中的對象到內存中。
	//把對象寫到(文件)硬盤上--->對象的序列化
	public static void writeObj() throws IOException {
		User user=new User("admin","123",18);
		//找到目標
		File file=new File("E:\\Obj.txt");
		//建立數據的輸出通道
		FileOutputStream fileOutputStream=new FileOutputStream(file); 
		//建立對象的輸出流對象
		ObjectOutputStream objectOutputStream=new ObjectOutputStream(fileOutputStream);
		//把對象寫出到輸出流中
		objectOutputStream.writeObject(user);
		//關閉資源
		objectOutputStream.close();
	}
	public static void readObj() throws IOException, ClassNotFoundException {
		//找到目標
		File file=new File("E:\\Obj.txt");
		//建立數據的輸入通道
		FileInputStream fileInputStream=new FileInputStream(file);
		//建立對象的輸入流
		ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
		//讀取對象數據
		User user=(User)objectInputStream.readObject();//反序列化的過程中創建了對象
		//反序列化時需要創建對象,創建對象時需要依賴class文件
		System.out.println("對象的信息是:"+user);
	}
}

(五)Properties配置文件

Properties--配置文件類   屬於Map集合體系。
作用:
    1.生成配置文件。
    2.讀取配置文件。

Properties要注意的事項:
    1.往Properties添加數據時,不要添加非字符串類型數據,如果添加了非字符串類型數據,那麼Properties的處理方式就是進行強制類型轉換,強轉報錯。
    2.如果Properties的數據出現了中文字符,那麼使用store方法時千萬不要使用字節流,如果使用了字節流,那麼默認使用iso8859-1碼錶進行保存,
          中文數據建議使用字符流。
    3.如果修改了Properties裏面的數據,一定要重新生成一個配置文件。

public class demo1 {

	public static void main(String[] args) throws IOException {
		readProperties();
		//createProperties();
	}
	//讀取配置文件---加載配置文件到Properties使用load方法。
	public static void readProperties() throws IOException {
		Properties properties =new Properties();
		//創建輸入字符流對象
		FileReader fileReader=new FileReader("E:\\users.properties.txt");
		//加載配置文件的數據到Properties
		properties.load(fileReader);
		//遍歷元素
		Set<Entry<Object,Object>> set=properties.entrySet();
		for(Entry<Object,Object> entry:set) {
			System.out.println("鍵:"+entry.getKey()+" 值:"+entry.getValue());
		}
		properties.setProperty("hongmi", "110");
		//重新生成一個配置文件
		properties.store(new FileWriter("E:\\users.properties.txt"), "heihei");//第一個參數是一個輸出流對象的匿名對象
	}
	//創建一個配置文件
	public static void createProperties() throws IOException {
		//創建一個Properties對象
		Properties properties =new Properties();
		properties.setProperty("xiaomi", "123");
		properties.setProperty("大米", "456");
		properties.put("hongmi", "147");
		properties.setProperty("heimi", "789");
		/*
		//遍歷
		Set<Entry<Object,Object>> set=properties.entrySet();
		for(Entry<Object,Object> entry:set) {
			System.out.println("鍵:"+entry.getKey()+" 值:"+entry.getValue());
		}
		*/
		
		/*
		FileOutputStream fileOutputStream=new FileOutputStream("E:\\users.properties.txt");
		//利用Properties生成一個配置文件。
		properties.store(fileOutputStream, "haha");//第二個參數是使用一段文字對對象進行描述
		*/
		FileWriter fileWriter=new FileWriter("E:\\users.properties.txt");
		properties.store(fileWriter, "haha");//第二個參數是使用一段文字對對象進行描述

	}
}

 

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