装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于以后的功能,并提供加强功能,那么自定义的这个类就称为装饰类。
装饰类通常会通过构造方法,来接收被装饰的对象,并且基于被装饰的对象的功能,提供更强的功能。
例如:
1: import java.io.*;
2:3: /*
4: 使用装饰设计模式,比较灵活,降低了类与类之间的关系5: */6: class Person
7: {8: public void chifan()9: {10: System.out.println("吃饭");
11: }12: }13:14: class SuperPerson
15: {16: private Person p;
17:18: //将Person类的对象通过SuperPerson的构造函数传进来,这样就可以在
19: //SuperPerson类中使用Person对象的方法,并且可以对Person对象的功能进行增强
20: SuperPerson(Person p)21: {22: this.p=p;
23: }24:25: public void superChifan()26: {27: System.out.println("开胃酒");
28: p.chifan();29: System.out.println("甜点");
30: }31:32: }33:34: class PersonDemo
35: {36: public static void main(String[] args)37: {38: Person p=new Person();
39: SuperPerson sp=new SuperPerson(p);
40:41: sp.superChifan();42: }43: }44:45:46:47:
MyReader 专门用来读取数据的类
|MyBufferedTextReader
|MyBufferedMediaReader
MyReader有很多子类,例如MyTextReader和MyMediaReader,但是单个读取的效率太低,因此又出现了使用缓冲区的子类,加强形式,但是这样MyReader每增加一个子类,就需要增加一个加强形式。这样扩展性太差。
如果想Buffer功能单独写成一个类呢,那么有
class MyBufferReader
{
MyBufferedReader(MyTextReader mytext) { }
MyBufferedReader(MyMediaReader mymedia) { }
………….
}
这样的话,MyReader每增加一个子类,MyBufferReader就要增加一个构造方法,扩展性也很差。那么找其参数的共同类型,改写成多态的形式,这样就提高了扩展性。
class MyBufferedReader extends MyReader
{
MyBufferReader(MyReader r) { }
}
装饰类因为增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强的功能。所以装饰类和被装饰类通常都是属于一个体系中。
MyReader 专门用来读取数据的类
|MyMediaReader
|---MyBufferedReader
LineNumberReader:(BufferedReader的子类)
跟踪行号的缓冲字符输入流,此类定义了方法setLineNumber和getLineNumber,用于设置和获取当前行号。
1: import java.io.*;
2:3: class MyLineNumberReader
4: {5: private FileReader r;
6: private int num=0;7: MyLineNumberReader(FileReader r)8: {9: this.r=r;
10: }11:12: public String myReadLine()throws IOException13: {14: num++;15: StringBuilder sb=new StringBuilder();
16: int ch=0;
17: while((ch=r.read())!=-1)
18: {19: if(ch==‘\r‘)
20: continue;
21: if(ch==‘\n‘)
22: return sb.toString();
23: else sb.append((char)ch);24: }25:26: if(sb.length()!=0)
27: return sb.toString();
28:29: return null;30:31: }32:33: //设置行号
34: public void mySetLineNumber(int num)35: {36: this.num=num;
37: }38:39: //获取行号
40: public int myGetLineNumber()41: {42: return num;
43: }44:45: public void myClose()throws IOException46: {47: r.close();48: }49:50:51: }52:53:54:55:56: class MyLineNumberReaderDemo
57: {58: public static void main(String[] args) throws IOException59: {60: FileReader fr=new FileReader("MyBufferedReaderDemo.java");61: MyLineNumberReader mylnr=new MyLineNumberReader(fr);
62:63: String line=null;
64: while((line=mylnr.myReadLine())!=null)65: {66: System.out.println(mylnr.myGetLineNumber()+":"+line);
67: }68: mylnr.myClose();69:70:71: }72: }73:
字节流:
需求,如果想要操作图片数据,这是需要使用到字节流。InputStream和OutputStream
1: import java.io.*;
2:3:4: class FileStream
5: {6: public static void writeFile()throws IOException7: {8: FileOutputStream fos=new FileOutputStream("fos.txt");9:10:11: //字节流只可以写入字节或者字节数组,abcde为字符串,需要进行转换,getBytes()
12: //getBytes()方法,将String编码为byte序列,并将结果存在一个新的byte数组中
13: fos.write("abcde".getBytes());
14:15: //如果没有使用到指定的缓冲区,是不需要缓冲的,但是需要关闭资源
16: fos.close();17: }18:19: //单个字节读取
20: public static void readFile_1()throws IOException21: {22: FileInputStream fis=new FileInputStream("fos.txt");23:24: int ch=0;
25: while((ch=fis.read())!=-1)
26: {27: System.out.println((char)ch);
28: }29: fis.close();30: }31:32: //按字节数组来进行读取
33: public static void readFile_2()throws IOException34: {35: FileInputStream fis=new FileInputStream("fos.txt");36:37: byte[] buf=new byte[1024];38: int len=0;
39:40: while((len=fis.read(buf))!=-1)
41: {42: System.out.println(new String(buf));
43: }44:45: fis.close();46: }47:48: public static void readFile_3()throws IOException49: {50: FileInputStream fis=new FileInputStream("fos.txt");51:52: //available()方法,返回值为文件中的字节数,包括换行符,这样可以定义一个刚好的缓冲区,不需要循环
53:54: byte[] buf=new byte[fis.available()];55:56: fis.read(buf);57:58: System.out.println(new String(buf));
59:60: fis.close();61: }62:63:64:65: public static void main(String[] args) throws IOException66: {67: readFile_3();68: }69: }70:
练习:复制一张图片
1: import java.io.*;
2:3: class PictureCopy
4: {5: public static void main(String[] args)6: {7: FileInputStream fis=null;
8: FileOutputStream fos=null;
9: try
10: {11: fis=new FileInputStream("IMG_0696.jpg");12: fos=new FileOutputStream("abc.jpg");13: byte[] buf=new byte[1024];14:15: int len=0;
16: while((len=fis.read(buf))!=-1)
17: {18: fos.write(buf);19: }20:21: }22: catch (IOException e)
23: {24: System.out.println("...");
25:26: }27: finally
28: {29: try
30: {31: fis.close();32: }33: catch (IOException e)
34: {35: System.out.println("关闭读取资源失败");
36:37: }38: try
39: {40: fos.close();41: }42: catch (IOException e)
43: {44: System.out.println("关闭写入资源失败");
45:46: }47: }48: }49: }50:
MP3的复制,通过缓冲区:
1: class CopyMP3
2: {3: public static void main(String[] args) throws IOException4: {5: //定义一个读取流对象,读取目标文件中的数据
6: BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("c:\\0.mp3"));7:8: //定义一个输出流对象,用来将读取到的数据写入到目的文件中去
9: BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));10:11: int by=0;
12: byte[] buf=new byte[1024];13: while((by=bufis.read(buf))!=-1)
14: {15: bufos.write(by);16: }17:18: bufis.close();19: bufos.close();20:21: }22: }23:
自定义字节流缓冲区:
1: class MyBufferedInputStream
2: {3: private InputStream in;
4: //定义一个byte型的数组,用于存储数据
5: private byte[] buf=new byte[1024];6: //count为计数器,pos为数组的指针
7: private int pos=0,count=0;8:9: MyBufferedInputStream(InputStream in)10: {11: this.in=in;
12: }13:14: //一次读取一字节,从
15: public int myRead() throws IOException16: {17: //通过in来读取硬盘上的数据,并且存储到buf中
18: if(count==0)
19: {20: count=in.read(buf);21: if(count<0)
22: return -1;
23: pos=0;24: byte b=buf[pos];
25: count--;26: pos++;27:28: return b&255;
29: }30: else if(count >0)31: {32: byte b=buf[pos];
33: count--;34: pos++;35:36: return b&255;
37: }38: return -1;
39: }40:41: public void myClose()throws IOException42: {43: in.close();44: }45:46: }47:48: /*
49: why b&255?50:51: 若数据文件的第一个数据恰好是1111 111152: 提升成了int类型以后,数据值为-153:54: 是-1的原因是因为在8个1前面补得为1,如果在前边补0,即可以保留原字节数据不变,又可以避免-1的出现55:56: 1111 1111 1111 1111 1111 1111 1111 111157: 0000 0000 0000 0000 0000 0000 1111 111158:59:60: 0000 0000 0000 0000 0000 0000 1111 111161: 提升为int型后,多占了内存,write方法写入时,将前面的舍弃,只保留后8位62:63: */
读取键盘录入:
需求:通过键盘录入数据,当录入一行数据,就将该行数据进行打印,如果录入的数据为over,那么停止录入
1: class InputStreamDemo
2: {3: public static void main(String[] args)4: {5: InputStream in=System.in;6: StringBuilder sb=new StringBuilder();
7: while(true)8: {9: int ch=in.read();
10: if(ch==‘\r‘)
11: continue;
12: if(ch==‘\n‘)
13: {14: String s=sb.toString();15: if("over".equals(s))16: break;
17: System.out.println(s.toUpperCase());18: //每次录入一行数据,就将该行数据进行打印以后,应该将存在StringBuilder里面的
19: //内容清空,下次录入时,才不会有下一次的数据
20:21: sb.delete(0,sb.length());22:23: }24: else sb.append((char)ch);25: }26: }27: }28:29: /*
30: 以上代码即为读一行数据的原理,即readLine()方法31: 那能不能直接用readLine方法来完成键盘录入的一行数据的读取呢?32:33: 但是readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法,是字节流InputStream的方法34: 那么能不能将字节流转换成字符流,而使用字符流缓冲区的readLine方法呢?35:36: 使用InputStreamReader类37:38: */
1: public void method()throws Exception2: {3: InputStream in=System.in;4:5: //将字节流对象转成字符流对象,使用转换流
6: InputStreamReader isr=new InputStreamReader(in);
7: //为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
8: BufferedReader bufr=new BufferedReader(isr);
9:10: String line=null;
11: while((line=bufr.readLine())!=null)12: {13: if("over".equals(line))14: break;
15: System.out.println(line.toUpperCase());16: }17:18: bufr.close();19: }
黑马程序员---IO流2(装饰设计模式,LineNumberReader,InputStream,OutputStream,InputStreamReader)