JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片


一.装饰设计模式

其实我们自定义readLine就是一种装饰模式

  • 当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,并且提供加强功能,那么自定义的该类就称为装饰类
package com.lgl.hellojava;

public class HelloJJAVA {
    public static void main(String[] args) {

        Person p = new Person();
        p.eat();
        // 开始进行增强
        superPerson p1 = new superPerson(p);
        p1.superEat();
    }
}

class Person {
    public void eat() {
        System.out.println("吃饭");
    }
}

class superPerson {

    private Person p;

    public superPerson(Person p) {
        this.p = p;
    }

    public void superEat() {
        System.out.println("小菜+吃饭");
    }
}

这里的逻辑就是当我们吃饭这个功能需要增强的时候,我们应该装饰他

  • 装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能提供更强的功能

二.继承和装饰的区别

你现在知道了装饰模式,那你一定会疑问,和继承的道理类似,对吧,我们现在来说下他们的区别

这里我们就不写代码了,我们看注释

package com.lgl.hellojava;

public class HelloJJAVA {
    public static void main(String[] args) {
        /**
         * MyReader:专门用于读取数据的类
         * MyTextReader:专门读取文本 两个向上抽取,形成继承体系
         */

        /**
         * 想实现更多的功能
         * MyBufferReader
         * myBufferTestReader
         */

        /**
         *谁需要加强就传谁进来
         * class MyBufferReader{
         * }
         */

    }
}

这个逻辑大概是这样的,我们有两个功能,一个读取文件,一个读取文本,他们其实是有共性的,你就把他们共性部分抽取出来,可是我现在在读取文本的时候我顺便想读取图片呢?其实,我们就是这样才产生的装饰者模式

  • 装饰者模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系
  • 装饰类因为增强已有对象,具备功能和已有的想相同,只不过提供了更强的功能,所以装饰类和被装饰类通常属于一个体系中的

三.LineNumberReader

这也是一个子类

他也是一个包装类,我们看例子

package com.lgl.hellojava;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class HelloJJAVA {
    public static void main(String[] args) {
        FileReader fr;
        try {
            fr = new FileReader("test.txt");
            LineNumberReader lnr = new LineNumberReader(fr);
            String line = null;
            while((line = lnr.readLine()) != null){
                System.out.println(lnr.getLineNumber()+":"+line);
            }
            lnr.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

他输出的结果

他可以获取和设置行号

四.自定义LineNumberReader

我们可以根据他的原理自己也来实现一个,仔细看注释

package com.lgl.hellojava;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class HelloJJAVA {
    public static void main(String[] args) {
        try {
            FileReader fr = new FileReader("test.txt");
            MyLineNumberReader my = new MyLineNumberReader(fr);
            String line = null;
            while ((line = my.MyReadLine()) != null) {
                System.out.println(my.getLineReader() + ":" + line);
            }
            my.MyClose();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class MyLineNumberReader {
    // 读取
    private Reader r;
    // 行号
    private int lineReader;

    // 构造方法
    public MyLineNumberReader(Reader r) {
        this.r = r;
    }

    // 提供对外方法
    public String MyReadLine() {
        // 行号自增
        lineReader++;
        StringBuilder sb = new StringBuilder();
        int ch = 0;
        try {
            while ((ch = r.read()) != -1) {
                if (ch == '\r')
                    continue;
                if (ch == '\n')
                    return sb.toString();
                else
                    sb.append((char) ch);
            }
            if (sb.length() != 0)
                return sb.toString();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public int getLineReader() {
        return lineReader;
    }

    public void setLineReader(int lineReader) {
        this.lineReader = lineReader;
    }

    public void MyClose() {
        try {
            r.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

这个思路是不是很清晰,实际上和LineNumberReader是类似的

五.字节流读取操作

字符流我们讲的差不多了,我们接着说字节,其实他们类似的,知识他操作的是字节而已

  • inputStream:读
  • outputStream:写

我们还是从例子开始

package com.lgl.hellojava;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class HelloJJAVA {
    public static void main(String[] args) {
        writeFile();

    }

    // 写文件
    public static void writeFile() {
        try {
            FileOutputStream fo = new FileOutputStream("demo.txt");
            fo.write("test".getBytes());
            fo.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

这里我们可以看到,他写入数据不需要刷新,现在还没有涉及到缓存区,我们继续看,写已经写好了,现在我们开始读,对于读取数据,我们开头用到的两种方法

// 字符读数据
    public static void readFile() {
        try {
            FileInputStream fs = new FileInputStream("demo.txt");
            int ch = 0;
            while ((ch = fs.read()) != -1) {
                System.out.println((char) ch);
            }
            fs.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 字节读取
    public static void readFile1() {
        try {
            FileInputStream fs = new FileInputStream("demo.txt");
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = fs.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
            }
            fs.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

现在我们有了专门处理的字节流,我们可以这样做

public static void readFile2() {
        try {
            FileInputStream fs = new FileInputStream("demo.txt");
            int num = fs.available();
            System.out.println(num);
            fs.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

我们发现直接用available就可以拿到字节了,原理其实是这段代码

public static void readFile2() {
        try {
            FileInputStream fs = new FileInputStream("demo.txt");
            byte[] buf = new byte[fs.available()];
            fs.read(buf);
            System.out.println(new String(buf));
            fs.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

六.I/O复制图片

ok,这里算是一个小练习,复制一张图片,我们理顺下思路

  • 1.用字节读取流和图片关联
  • 2.用字节流写入流对象创建一个图片文件,存储数据
  • 3.通过循环读写,完成数据存储
  • 4.关闭流

OK,我们用代码说话

package com.lgl.hellojava;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class HelloJJAVA {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        FileInputStream fis = null;

        try {
            // 复制
            fos = new FileOutputStream("copy_img.png");
            // 原图
            fis = new FileInputStream("img.png");

            byte[] buf = new byte[1024];

            int len = 0;

            while ((len = fis.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }

            fis.close();
            fos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

这样。我们图片就拷贝过来了

好的,知识点今天就到这里

有兴趣的可以加群:555974449,咱们一起学习,一起进步!

JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片的更多相关文章

  1. JAVA之旅(十六)——String类,String常用方法,获取,判断,转换,替换,切割,子串,大小写转换,去除空格,比较

    JAVA之旅(十六)--String类,String常用方法,获取,判断,转换,替换,切割,子串,大小写转换,去除空格,比较 过节耽误了几天,我们继续JAVA之旅 一.String概述 String时 ...

  2. Java进阶专题(二十六) 将近2万字的Dubbo原理解析,彻底搞懂dubbo

    前言 ​ 前面我们研究了RPC的原理,市面上有很多基于RPC思想实现的框架,比如有Dubbo.今天就从Dubbo的SPI机制.服务注册与发现源码及网络通信过程去深入剖析下Dubbo. Dubbo架构 ...

  3. Java开发学习(二十六)----SpringMVC返回响应结果

    SpringMVC接收到请求和数据后,进行了一些处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户. 比如:根据用户ID查 ...

  4. Java从零开始学二十六(包装类)

    一.包装类 包装类是将基本类型封装到一个类中.也就是将基本数据类型包装成一个类类型. java程序设计为每一种基本类型都提供了一个包装类.这些包装类就在java.lang包中.有8个包装类 二.包装类 ...

  5. Java基础(二十六)Java IO(3)字节流(Byte Stream)

    字节流是以字节为单位来处理数据的,由于字节流不会对数据进行任何转换,因此用来处理二进制的数据. 一.InputStream类与OutputStream类 1.InputStream类是所有字节输入流的 ...

  6. Java之集合(二十六)ConcurrentSkipListMap

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7542578.html 1.前言 一个可伸缩的并发实现,这个map实现了排序功能,默认使用的是对象自身的compa ...

  7. Java学习笔记二十六:Java多态中的引用类型转换

    Java多态中的引用类型转换 引用类型转换: 1.向上类型转换(隐式/自动类型转换),是小类型到大类型的转换: 2.向下类型转换(强制类型转换),是大类型到小类型的转换: 3.instanceof运算 ...

  8. Python学习日记(二十六) 封装和几个装饰器函数

    封装 广义上的封装,它其实是一种面向对象的思想,它能够保护代码;狭义上的封装是面向对象三大特性之一,能把属性和方法都藏起来不让人看见 私有属性 私有属性表示方式即在一个属性名前加上两个双下划线 cla ...

  9. java 面向对象(二十六):枚举类的使用

    1. 枚举类的说明:* 1.枚举类的理解:类的对象只有有限个,确定的.我们称此类为枚举类* 2.当需要定义一组常量时,强烈建议使用枚举类* 3.如果枚举类中只一个对象,则可以作为单例模式的实现方式. ...

  10. Java进阶专题(二十六) 数据库原理研究与优化

    前言 在一个大数据量的系统中,这些数据的存储.处理.搜索是一个非常棘手的问题. 比如存储问题:单台服务器的存储能力及数据处理能力都是有限的, 因此需要增加服务器, 搭建集群来存储海量数据. 读写性能问 ...

随机推荐

  1. 背景重复样式background-repeat

    一.background-repeat属性 在CSS中,使用background-repeat属性可以设置背景图像是否平铺,并且可以设置如何平铺. 语法: background-repeat:取值; ...

  2. java底层学习

    额,马上就要面试了,Java的底层肯定是需要了解的.网上找了找java的底层文章,做个记号.java底层主要是类的加载.连接和初始化. 本文主要分为四个方面: (1)java底层概述 (2)new和n ...

  3. js操作符+和()

    ECMA-262 描述了一组用于操作数据值的操作符,包括一元操作符.算数操作符逻辑操作符.关系操作符.赋值操作符.字符串操作符.对象操作符等.ECMAScript 操作符的与众不同之处在于,它们能够适 ...

  4. java中的构造,封装

    今天给大家讲一下面向对象中的构造,封装: 构造:构造方法有以下几个特点:1.方法名和类名一致.2.无返回类型.接下来的几种构造样式,直接上代码吧: //这是一个宠物类 有一个属性:名字(name) p ...

  5. python while条件和if判断的总练习

    输出123456 89的数字 num =1 while num < 11: if num == 7: pass else: print(num) num = num + 1 输出1-100的奇数 ...

  6. MongoDB Java

    MongoDB Java 环境配置 在Java程序中如果要使用MongoDB,你需要确保已经安装了Java环境及MongoDB JDBC 驱动. 你可以参考本站的Java教程来安装Java程序.现在让 ...

  7. Dockerfile的指令

    指令的一般格式为 INSTRUCTION arguments,指令包括 FROM.MAINTAINER.RUN 等. FROM 格式为 FROM <image>或FROM <imag ...

  8. jboss规则引擎KIE Drools 6.3.0 Final 教程(1)

    前言 目前世面上中文的KIE DROOLS Workbench(JBOSS BRMS)的教程几乎没有,有的也只有灵灵碎碎的使用机器来翻译的(翻的不知所云)或者是基于老版本的JBOSS Guvnor即5 ...

  9. 实例演示如何在spring4.2.2中集成hibernate5.0.2并创建sessionFactory

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/49388209 文章作者:苏生米沿 本文目的:使用spring4.2.2集成hibern ...

  10. Shell脚本了解

    一.什么是Shell Shell 是一个用C语言编写的程序,它是用户使用Linux的桥梁.Shell既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这个应用程序提供了一个界面, ...