public void eat(){
System.out.println("吃饭");
}
}
public class PersonEnhance{
private Person p; //把需要增强 的类传进去初始化
public PersonEnhance(Person p){ this.p=p;
} public void enhanceEat(){ System.out.println("开胃酒");
p.eat();
System.out.println("甜点");
}
}
装饰模式就是在原有类的基础上把某个方法增强功能
但是这让我想到了java 的动态代理,他也是在某个方法的基础上增加额外的功能,那么她们有什么区别呢?
装饰类和被装饰的类是应该继承或实现相同的接口,而java的动态代理不是, 还有一个不同点就是动态代理可以横切多个面,也就是同时对多个方法进行增强. 通过装饰模式和继承的区别发现了程序设计之美,虽然继承也可以增强某个方法,但是它使得类的体系很臃肿,并且可扩展性不好 因为装饰模式中,我们可以把被装饰类的父类当作参数传进装饰类的构造方法内,那么你这一个装饰类就可以应用于这个体系的了,这也是java多态性的好处. 相比较之下使用装饰模式降低了类之间的关系. 装饰类是因为增强了已有的对象,具有的功能和已有的是相同的,是不过提供了更强的功能,所以装饰类和被装饰类通常属于一个体系中的. 在API中可以看到BufferedReader类还有一个子类LineNumberReader 通过API对得知,这是一个字符缓冲输出流,该类保持对行号的跟踪,可以通过该类的
setLineNumber(int)
andgetLineNumber()
方法分别设置获取行号
例如程序:
publicstaticvoid main(String[] args)throws IOException{FileReader fr =new FileReader("test.txt");LineNumberReader lnr =new LineNumberReader(fr);String num =null;while((num=lnr.readLine())!=null){System.out.println(lnr.getLineNumber()+":"+num);}}
控制台输出:
但是我们也可以改变行号的开始值
publicstaticvoid main(String[] args)throws IOException{
FileReader fr =new FileReader("test.txt");
LineNumberReader lnr =new LineNumberReader(fr);
String num =null;
//设置行号的开始值为100
lnr.setLineNumber(100);
while((num=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+":"+num);
}
}
输出结果为:
LineNumberReader
EnhanceLineNumberReaderpublic String readLine() throws IOException {lineNumber++;StringBuilder buffer =new StringBuilder();int i = 0;while ((i =reader.read()) != -1) {if ((char) i =='\r') {continue;}if ((char) i =='\n') {return buffer.toString();}else {buffer.append((char) i);}}if (buffer.length() != 0) {return buffer.toString();}returnnull;}
书出结果是一样的
下面开始学习字节流
通过API文档字节流的*类为InputStream和OutputStream
首先来看一下FileOutputStream和FileInputStream
publicstaticvoid writeData()throws Exception{
OutputStream out =new FileOutputStream("D:\\test2.txt");
out.write("hello inputStream!".getBytes());
}
执行上面代码后,发现在D盘创建了test2.txt文件并且内容是hello inputStream!
从上面可以看出这和字符流是有区别的,因为当我们在使用字符流的时候,如果没有刷新并且没有关闭那么文件内容是空的,而这里刚好相反.
但是最好我们还是调用close方法,关闭资源.提高性能.
下面实现读取操作
public static void readData() throws Exception {InputStream is = new FileInputStream("D:\\test2.txt");
int num = 0;
while ((num = is.read()) != -1) {
System.out.println((char) num);
}
} 但是这样效率比较低,因为读取一次写一次,我们可以使用缓冲 publicstaticvoid readData2()throws Exception { InputStream is =new FileInputStream("D:\\test2.txt"); int num = 0; byte[] buffer =newbyte[1024]; //把读取到的数据放进字节数组里面 while ((num = is.read(buffer)) != -1) { System.out.println(new String(buffer, 0, num)); }} 在InputStream类中有这样一个方法available()返回int 他的作用是返回文件内容的长度 那么我们就可以这样读取数据,而不用while循环了 publicstaticvoid readData3()throws Exception { InputStream is =new FileInputStream("D:\\test2.txt"); //返回文件的长度 int num = is.available(); 把字节数组的长度定义成文件长度,那么这个数组就刚好装下这个文件了 byte[] buffer =newbyte[num]; is.read(buffer); System.out.println(new String(buffer));} 但是这样有一个缺陷,如果一个文件非常大,那么这就会出现内存溢出了.所以这是用操作小型 的文件. 练习,复制一份图片:代码片段: InputStream is = new FileInputStream("D:\\imagetest\\desk.jpg");
OutputStream os = new FileOutputStream("E:\\desk1.jpg");
byte[] buffer = new byte[1024];
int readNum = 0;
int a=0;
while((readNum=is.read(buffer))!=-1){
System.out.println(a++);
os.write(buffer, 0, readNum);
} 使用java缓冲输出流 BufferedOutputStream buffOs =new BufferedOutputStream(new FileOutputStream("F:\\KuGou\\baby2 - baby one more time.mp3"));BufferedInputStream buffIs =new BufferedInputStream(new FileInputStream("F:\\KuGou\\baby - baby one more time.mp3"));int len = 0;while((len=buffIs.read())!=-1){buffOs.write(len);}buffOs.close();buffIs.close(); 获取键盘录入: System.out对应的是标准的输出设备一般指控制台 System.in对应的是标准输入设备:键盘 下面模拟一个键盘录入的功能: publicstaticvoid main(String[] args)throws IOException {InputStream is = System.in;StringBuilder buffer =new StringBuilder();int i = 0;while (true) {i = is.read();if ('\r' == i)continue;if ('\n' == i) {String value = buffer.toString();//如果录入的是over那么则退出if ("over".equals(buffer.toString()))break;System.out.println(value);//清空缓冲区 以免下次录入时不会和前面录入的汇合buffer.delete(0, buffer.length());}else {buffer.append((char)i);}}} 注意在输入流在读取数据的时候连回车也会读取的.在windows中\r\n代表换行 例如下面简单的程序 InputStream is = System.in;System.out.println(is.read());System.out.println(is.read()); 控制台输出: 13 10 对于键盘录入功能我们可以使用更加简单的方式:因为他这个功能实际上就是读取一行 的操作: 那么就可以考虑使用readLine方法,然后该方法是字符六BufferedReader的方法 然而InputStream又是字节流.那么怎么办呢? 我们可以使用InputStreamReader类,这个类是字节流到字符流的桥梁, publicstaticvoid main(String[] args)throws IOException {InputStream is = System.in;InputStreamReader isr =new InputStreamReader(is);BufferedReader br =new BufferedReader(isr);String line =null;while((line=br.readLine())!=null){if(line.equals("over")){break;}System.out.println(line.toUpperCase());}} 对应的OutputStreamWriter是字符流向字节流转换的桥梁 也就是读进来的是字符,写进去的是字节,在上面的基础上我们可以这样改写: publicstaticvoid main(String[] args)throws IOException {InputStream is = System.in;InputStreamReader isr =new InputStreamReader(is);BufferedReader br =new BufferedReader(isr);OutputStreamWriter osw =new OutputStreamWriter(System.out);BufferedWriter bw =new BufferedWriter(osw);String line =null;while((line=br.readLine())!=null){if(line.equals("over")){break;}bw.write(line);//注意使用字符流要注意flushbw.flush();//System.out.println(line.toUpperCase());}} 但是控制台输出为: 发现输出的数据没有换行 当然我们可以在line后面加上\r\n 但是这是不跨品台的 我们可以这样解决: 我们可以使用 BufferedWriter 的newLine方法 在bw.write(line);后面加上bw.newLine(); 即可 总结: 下面总结一下IO的操作规律: 1,明确源和目的: 源 :输入流,InputStream Reader 目的: 输入流 OutpuStream Writer 3当明确体系后,在明确使用哪个具体的对象 通过设备来进行区分: 源设备: 存 硬盘 键盘 目的设备: 内存 硬盘 控制台 转载请注明 出处: http://blog.csdn.net/johnny901114/article/details/8710403