场景 思考一下:克隆技术是怎样的过程?克隆羊多莉大家还记得吗? javascrip语言中,继承怎么实现?那里面也有prototype,大家还记得吗? 原型模式 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式 就是java中的克隆技术,以某个对象为原型,复制出新的对象.显然, 优势有:效率高(直接克隆,避免了重新执行构造过程步骤) 克隆类似于new,但是不同于new.new创建新的对象属性采用的是默认值.克隆出的对象的属性值完全和原型对象相同.并且克隆出的新对象改变不会影响原型对象.然后再修改克隆对象的值 原型模式实现 Cloneable接口可clone方法 Protype模式中实现起来最困难的地方就是内存复制操作,所幸Java中提供了clone()方法替我们做了绝大部分事情 import java.util.Date; //1997年英国克隆羊多莉 public class Sheep implements Cloneable{ private String name; private Date brithday; public Sheep() { // TODO Auto-generated constructor stub } public Sheep(String name, Date brithday) { super(); this.name = name; this.brithday = brithday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBrithday() { return brithday; } public void setBrithday(Date brithday) { this.brithday = brithday; } //重写Object的clone方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } import java.util.Date; public class Client { @SuppressWarnings("deprecation") public static void main(String[] args) throws CloneNotSupportedException { //浅克隆 Date d = new Date(183964743); Sheep s1 = new Sheep("莉莉",d); System.out.println(s1); System.out.println(s1.getName()); System.out.println(d.getTime()); d.setDate(183974743); System.out.println(d.getTime()); Sheep s2 = (Sheep) s1.clone(); System.out.println(s2); System.out.println(s2.getName()); s2.setName("多莉"); System.out.println(s2.getName()); System.out.println(d.getTime()); } } import java.util.Date; //1997年英国克隆羊多莉 public class Sheep implements Cloneable{ private String name; private Date brithday; public Sheep() { // TODO Auto-generated constructor stub } public Sheep(String name, Date brithday) { super(); this.name = name; this.brithday = brithday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBrithday() { return brithday; } public void setBrithday(Date brithday) { this.brithday = brithday; } //重写Object的clone方法 @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone(); //添加如下代码实现深复制 Sheep s = (Sheep)obj; //把属性也进行克隆 s.brithday = (Date)this.brithday.clone(); return obj; } } import java.util.Date; /** * 深复制 * @author Matrix42 * */ public class Client2 { public static void main(String[] args) throws CloneNotSupportedException { Date d = new Date(183964743); Sheep s1 = new Sheep("莉莉",d); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBrithday()); Sheep s2 = (Sheep) s1.clone(); d.setTime(2222222222222L); System.out.println(s1.getBrithday()); System.out.println(s2.getBrithday()); } } 利用序列化和反序列化技术实现深克隆 短时间大量修改对象时,原型模式和普通new方式效率测试 创建对象比较耗时时大约提高1000倍左右 开发中的应用场景 原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者 spring中的bean的创建市级就是两种:单例模式和原型模式(原型模式需要和工厂模式搭配起来) Sheep实现Serializable接口 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Date; /** * 使用序列化和反序列化实现深克隆 * @author Matrix42 * */ public class Client3 { public static void main(String[] args) throws IOException, ClassNotFoundException { Date d = new Date(183964743); Sheep s1 = new Sheep("莉莉",d); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBrithday()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(s1); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); Sheep s2 = (Sheep) ois.readObject(); System.out.println(s2.getName()); } }
场景 我们要建造一个复杂的产品.比如:神州飞船,iphone.这个复杂的产品的创建.有这样一个问题需要处理 装配这些子组件是不是有个步骤问题? 实际开发中,我们所需要的对象构建时,也非常复杂,有很多步骤需要处理时 建造模式的本质 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)，从而可以构造出复杂的对象,这个模式适用于:某个对象的构建过程复杂的情况 由于实现了构建和装配的解耦,不同的构建器,相同的装配,也可以做出不同的对象相同的构建器,不同的装配顺序也可以做出不同的对象,也就是实现了构建算法、装配算法的解耦,实现了更好的复用 public class AirShip { private OrbitalModule orbitalModule; //轨道舱 private Engine engine; //发动机 private EscapeTower escapeTower; //逃逸塔 public OrbitalModule getOrbitalModule() { return orbitalModule; } public void Launch(){ System.out.println("发射!"); } public void setOrbitalModule(OrbitalModule orbitalModule) { this.orbitalModule = orbitalModule; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } } class OrbitalModule{ private String name; public OrbitalModule() { } public OrbitalModule(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine{ private String name; public Engine() { } public Engine(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower{ private String name; public EscapeTower() { super(); } public EscapeTower(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public interface AirShipBuilder { Engine buildEngine(); OrbitalModule buildOrbitalModule(); EscapeTower buildEscapeTower(); } public class LorindaArishipBuilder implements AirShipBuilder{ @Override public Engine buildEngine() { System.out.println("构建发动机!"); return new Engine("Lorinda发动机"); } @Override public OrbitalModule buildOrbitalModule() { System.out.println("构建轨道舱!"); return new OrbitalModule("Lorinda轨道舱"); } @Override public EscapeTower buildEscapeTower() { System.out.println("构建逃逸塔!"); return new EscapeTower("Lorinda逃逸塔"); } } public interface AirShipDirector { AirShip createAirShip(); } public class LorindaAirShipDirector implements AirShipDirector{ private AirShipBuilder builder; public LorindaAirShipDirector(AirShipBuilder builder) { super(); this.builder = builder; } @Override public AirShip createAirShip() { Engine engine = builder.buildEngine(); OrbitalModule module = builder.buildOrbitalModule(); EscapeTower tower = builder.buildEscapeTower(); AirShip ship = new AirShip(); ship.setEngine(engine); ship.setEscapeTower(tower); ship.setOrbitalModule(module); return ship; } } public class Client { public static void main(String[] args) { AirShipDirector director = new LorindaAirShipDirector(new LorindaArishipBuilder()); AirShip ship = director.createAirShip(); System.out.println(ship.getEngine().getName()); ship.Launch(); } } 开发中的应用场景 StringBuilder类的append方法 SQL中的PreparedStatement JDOM中,DOMBuilder,SAXBuilder
工厂模式 实现了创建者和调用者的分离 简单工厂模式 用来产生同一等级结构中的任意产品(对于新增的产品,需要修改已有代码) 工厂方法模式 用来生产同一等级结构中的固定产品(支持增加任意产品) 抽象工厂模式 用来生产不同产品族的全部产品(对于增加新的产品,无能为力;支持增加产品族) 面向对象设计的基本原则 OPC(开闭原则,Open-Close Principle):一个软件的实体应对对扩展开发,对修改关闭 DIP(依赖倒转原则,Dependence Inversion Principle):要针对接口编程,不要针对实现编程 LOD(迪米特法则,Low of Demeter):只与你直接的朋友通信,而避免和陌生人通信 核心本质 实例化对象,用工厂方法代替new操作 将选择实现类,创建对象同一管理和控制.从而将调用者跟我们的实现类解耦 简单工厂模式(使用的比较多) 简单工厂模式也叫静态工厂模式,就是工厂类一般是使用静态方法,通过接收不同的参数来返回不同的对象实例 对于增加的新产品无能为力!不修改代码的话是无法扩展的 Car接口: public interface Car { void run(); } Car的两个子类: public class Audi implements Car{ @Override public void run() { System.out.println("奥迪在跑!"); } } public class Byd implements Car{ @Override public void run() { System.out.println("比亚迪在跑!"); } } 工厂1: public class CarFactory { public static Car CreatCar(String type){ if("奥迪".equals(type)){ return new Audi(); }else if("比亚迪".equals(type)){ return new Byd(); }else { return null; } } } 工厂2: public class CarFactory2 { public static Car getAudi(){ return new Audi(); } public static Car getByd(){ return new Byd(); } } Client: /** * 测试在没有工厂模式的情况下 * @author Matrix42 * */ public class Client01 { public static void main(String[] args) { Car c1 = new Audi(); Car c2 = new Byd(); c1.run(); c2.run(); } } public class Client02 { public static void main(String[] args) { Car c1 = CarFactory.CreatCar("奥迪"); Car c2 = CarFactory.CreatCar("比亚迪"); c1.run(); c2.run(); } } 工厂方法模式 为了避免工厂模式的缺点,不完全满足OCP 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式由一组实现了相同接口的工厂类 虽然工厂方法模式符号OCP但是会建很多类,实际用的比较多的还是简单工厂模式 Car接口: public interface Car { void run(); } Car的两个子类: public class Audi implements Car{ @Override public void run() { System.out.println("奥迪在跑!"); } } public class Byd implements Car{ @Override public void run() { System.out.println("比亚迪在跑!"); } } 两个工厂: public class AudiFactory implements CarFactory{ @Override public Car creatCar() { return new Audi(); } } public class BydFactory implements CarFactory{ @Override public Car creatCar() { return new Byd(); } } Client: public class Client { public static void main(String[] args) { Car c1 = new AudiFactory().creatCar(); Car c2 = new BydFactory().creatCar(); c1.run(); c2.run(); } } 新增类: public class Benz implements Car{ @Override public void run(){ System.out.println("奔驰在跑!"); } } 新增工厂类: public class BenzFactory implements CarFactory{ @Override public Car creatCar() { return new Benz(); } } 简单工厂模式和工厂方法模式的对比 结构复杂度 从这个角度比较，显然简单工厂模式要占优。简单工厂模式只需一个工厂类，而工厂方法模式的工厂类随着产品类个数增加而增加，这无疑会使类的个数越来越多，从而增加了结构的复杂程度 代码复杂度 代码复杂度和结构复杂度是一对矛盾，既然简单工厂模式在结构方面相对简洁，郡么它在代码方圆肯定是比工厂方法模式复杂.简单工厂模式的工厂类随着产品类的增加需要增加很多方法(或代码),而工厂方法模式每个具体工厂类只完成单一任务,代码简洁 客户端编程难度 工厂方法模式虽然在工厂类结构中引入了接口从而满足了OCP，但是在客户端编码中需要对工厂类进行实例化。而简单工厂模式的工厂类是一个静态类,在客户端无需实例化,这无疑是个吸引人的优点 管理上的难度 这是个关键的问题,我们先谈扩展,众所周知，工厂方法模式完全满足OCP,即它有非常良好的扩展性,那是否就说明了简单工厂模式就没有扩展性呢?答案是否定的.简单工厂模式同样具有良好的扩展性----扩展的时候仅需要修改少量趵代码(修改工厂类的代码)就可以满足扩展性的要求了,尽管这没有完全满足OCP,但我们不需要太拘泥于设计理论,要知道，sun提供的Java官方工具包中也有很多没有满足OCP的例子啊 然后我们从维护性的角度分析下,假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类,当同时需要修改多个产品类的时候,対工厂类的修改发会变得相当麻烦(对号入座已经是个问题了)反而简单工厂没有这些麻烦,当多个产品类需要修改时,简单工厂模式仍然仅仅需要修改唯一的工厂类(无论怎样都能改到满足要求吧?大不了把这个类重写) 抽象工厂模式 用来生产不同产品族的全部产品(对于增加新的产品无能为力,支持增加产品族) 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种,业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式 public interface Engine { void run(); void start(); } class LuxuryEngine implements Engine{ @Override public void run() { System.out.println("转得快!"); } @Override public void start() { System.out.println("启动快!可以自动启停!"); } } class LowEngine implements Engine{ @Override public void run() { System.out.println("转的慢!"); } @Override public void start() { System.out.println("启动慢!"); } } public interface Seat { void massage(); } class LuxurySeat implements Seat{ @Override public void massage() { System.out.println("可以自动按摩!"); } } class LowSeat implements Seat{ @Override public void massage() { System.out.println("不能自动按摩!"); } } public interface Tyre { void revolve(); } class LuxuryTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损慢!"); } } class LowTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损快!"); } } public interface CarFactory { Engine createEngine(); Seat createSeat(); Tyre createTyre(); } public class LuxuryCarFactory implements CarFactory{ @Override public Engine createEngine() { return new LuxuryEngine(); } @Override public Seat createSeat() { return new LuxurySeat(); } @Override public Tyre createTyre() { return new LuxuryTyre(); } } public class LowCarFactory implements CarFactory{ @Override public Engine createEngine() { return new LowEngine(); } @Override public Seat createSeat() { return new LowSeat(); } @Override public Tyre createTyre() { return new LowTyre(); } } public class Client { public static void main(String[] args) { CarFactory factory = new LuxuryCarFactory(); Engine engine = factory.createEngine(); Seat seat = factory.createSeat(); Tyre tyre = factory.createTyre(); } } 工厂模式要点 简单工厂模式(静态工厂模式) 虽然某种程度不符合设计模式,但实际使用最多 工厂方法模式 不修改已有类的前提下,通过增加新的工厂类实现扩展 抽象工厂模式 不可以增加产品,可以增加产品族 应用场景 JDK中Calendar的getInstance方法 JDBC中Connection对象的获取 Hibernate中SessionFactory创建Session Spring中IOC容器创建管理bean对象 XML解析时的DocumentBuilderFactory创建解析器对象 反射中Class对象的newInstance()
软件版本 之前安装的zookeeper apache-storm-1.0.1 安装Storm 解压安装包 将bin目录加入到环境变量 配置storm.yaml storm.zookeeper.servers: - "192.168.112.139" - "192.168.112.140" - "192.168.112.142" storm.local.dir: "/home/matrix42/storm/apache-storm-1.0.1/data" storm.zookeeper.port: 2181 nimbus.seeds: ["master"] 注：每一个配置点前面需要加一个空格,否则启动时会报配置文件相关异常 拷贝文件到其余工作节点 scp -r storm 用户名@IP:地址 启动Storm 启动主控节点 storm nimbus 启动工作节点 storm supervisor 启动管理页面 在主控节点上运行storm ui 管理界面将运行在启动它的服务器的8080端口，日志文件在程序目录中logs文件夹下 后台运行的方法 nohup storm nimbus & 可以使用jps命令查看进程
环境 Centos 6.5 64位 jdk 1.8 u 101 python 2.7.12 zookeeper 3.4.8 https://www.python.org/ftp/python/2.7.12/下载tgz文件 修改服务器信息 更改master的hostname为master vim /etc/sysconfig/network更改hostname 重启后生效,用hostname命令检查是否生效 更改hosts文件 对应master和slave的ip vim /etc/hosts 配置免密码登录 使用```ssh-keygen命令生成密钥对 cp id_rsa.pub authorized_keys 把其他机器的公钥也复制到authorized_keys文件中 使用scp命令将hosts文件和authorized_keys文件传输到其他机器 spc 文件名 用户名@IP:地址 如果是文件夹加上`-r``` 使用ssh 主机名 尝试是否能连接到主机 安装jdk tar -zxvf 包名 把bin的路径添加到~/.bashrc文件中: PATH=$PATH:路径 export PATH 编译安装python 解压压缩包 进入目录 ./configure make 转到root,make install,再转回来 安装ZooKeeper 解压ZooKeeper 将zk的bin目录加入到环境变量中 复制conf中的zoo_sample.cfg为zoo.cfg 添加如下配置 dataDir=/home/matrix42/storm/zookeeper/data dataLogDir=/home/matrix42/storm/zookeeper/datalog clientPort=2181 server.1=master:2888:3888 server.2=slave1:2888:3888 server.3=slave2:2888:3888 新建data,datalog目录 在data目录下新建myid文件,按服务器写入1,2,3.... 配置说明 initLimit：多少个心跳时间内，允许其他server连接并初始化数据,如果ZooKeeper管理的数据较大,则应相应增大这个值 clientPort：服务的监听端口 dataDir：用于存放内存数据库快照的文件夹，同时用于集群的myid文件也存在这个文件夹里(注意：一个配置文件只能包含一个dataDir字样，即使它被注释掉了) dataLogDir：用于单独设置transaction log的目录,transaction log分离可以避免和普通log还有快照的竞争 syncLimit：多少个tickTime内,允许follower同步,如果follower落后太多，则会被丢弃 启动ZK集群 zkServer.sh start 如遇到Error contacting service. It is probably not running.错误可以把zk的端口号加入到iptables或关闭防火墙 可能需要安装nc包yum install nc zkServer.sh status检查ZK状态 zkServer.sh stop 停止ZK服务 zkServer.sh restart 重启ZK服务 Zookeeper常用命令
Maven能解决的问题 管理和构建项目 解决jar冲突的问题 解决依赖问题 Maven介绍及环境搭建 Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具 下载地址:http://maven.apache.org/download.cgi 解压并配置环境变量 目录说明 bin:包含mvn的运行脚本 boot:包含一个类加载器的框架,maven使用它加载自己的类库 conf:配置文件目录,settings.xml lib:maven运行时用到的类库和第三方依赖类库 mvn -v 可以查看到maven的版本号,java版本,系统版本 maven项目的目录结构 src-->main-->java-->package src--test-->java-->package src--resources pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>test01</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>test01</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project> 常用构建命令 编译项目:mvn compile 运行测试用例:mvn test 打包项目:mvn package 删除target文件夹(字节码文件和测试报告):mvn clean 将jar包安装到本地仓库:mvn install 自动创建目录骨架 archetype插件用于创建符合maven规定的目录骨架 创建目录骨架:mvn archety:generate 另一种方式:mvn archety:generate -DgroupId=com.lorinda.demo -DartifactId= mavenDemo -Dversion=1.0.0SNAPSHOT -Dpackage:com.lorinda.cc groupId一般为组织名,公司网址的反写+项目名 artifactId一般为项目名-模块名 version为版本号 代码所在包名 maven中的坐标和仓库 坐标:任何一个依赖,插件项目构件的输出,所有构件通过坐标作为其唯一标识 标识: <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> 仓库:用来管理依赖,如果在本地找不到依赖则到maven的全球的中央仓库找,并下载到本地 阿里云镜像仓库:http://maven.aliyun.com/nexus/content/groups/public 在maven的settings.xml 文件里配置mirrors的子节点,添加如下mirror: <mirror> <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> http://maven.aliyun.com/nexus/#view-repositories;public~browsestorage 更改仓库默认位置 在settings.xml中加入:<localRepository>地址</localRepository> 在eclipse中安装maven插件以及创建maven项目 eclipse插件地址:http://download.eclipse.org/technology/m2e/releases 按照默认方式创建项目后,在pom.xml文件上右键,选择run as,Maven Build,在Goals中输入compile maven的生命周期和插件 完整的项目构建过程包括:清理,编译,测试,打包,集成测试,验证,部署 maven生命周期(相互独立的,后面的依赖前面的) clean 清理项目 pre-clean 执行清理钱的工作 clean 清理上一次构建生成的所有文件 post-clean 执行清理后的工作 default 构建项目(最核心) compile test package install site 生成项目站点 pre-site 在生成项目站点前要完成的工作 site 生成项目站点的文档 post-site 在生成项目站点后要完成的工作 site-deploy 发布生成的站点到服务器上 在package是打包源码,用的source插件 在pom.xml中 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.4</version> <executions> <execution> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> </plugins> </build> pom.xml常用元素介绍 modelVersion指定当前pom版本 groupId,artifactId,version,packaging共同组成坐标标识,packaging默认是jar,它还可以打包成war,zip,pom等 name:项目描述 url:项目的地址 description:项目的描述 developers:开发人员 licenses:许可信息 organization:组织信息 dependencies:依赖 <dependencies> <dependency> <groupId></groupId> <artifactId></artifactId> <version></version> <type></type> <scope>依赖的范围</scope> <optional>设置依赖是否可选true和false(默认)</optional> <exclusions>依赖排除 <exclusion></exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement>依赖列表,不会被运行,定义在父模块中被子模块继承 <dependencies> <dependency> </dependency> </dependencies> </dependencyManagement> <build>为构建提供支持 <plugins>插件列表 <plugin> 坐标 </plugin> </plugins> </build> <parent></parent> <modules></modules>编译多个模块 依赖范围(scope) 六种classpath compile(默认) provided 在编译和测试时有效 runtime 在测试和运行时有效 test 只在测试时有效 system 在编译和测试时有效,可移植性差 import 导入的范围,它只使用在dependencyManagement中,表示从其他的pom中导入dependency的配置 依赖传递 使用dependency和坐标指定依赖即可,使用前需要将依赖install 可以exclusions排除依赖 可以自settings.xml中指定jdk版本 依赖冲突 如果有A和B依赖不同版本的相同的构件,对于依赖A和B的C来说,它到底依赖A和B哪个版本的构件?两个原则 短路优先 先声明的优先(xml中的先后顺序) 聚合和继承 新建maven项目(同级),在pom.xml中:packaging更改为pom,添加: <modules> <module>../项目名</module> <module>../项目名</module> <module>../项目名</module> </modules> install就可以一起构建了 新建项目,packaging改为pom,在dependencyManagement中加入 <dependencyManagement> <dependencies> <dependency> 坐标 </dependency> </dependencies> </dependencyManagement> 在其他项目中使用patent标签加父类的坐标就可以继承父类了
核心作用 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 常见应用场景 Windows的Task Manager(任务管理器)就是很典型的单例模式 Windows的Recycle Bin(回收站)也是典型的单例应用.在整个系统运行过程中,回收站一直维护着仅有的一个实例 项目中,读取配置文件的类,一般也只有一个对象.没有必要每次使用配置文件数据都new一个对象去读取 网站的计数器,一般也是采用单例模式实现,否则难以同步 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统 Application也是单例的典犁府用(Servlet中会涉及到) 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理 在Servlet编程中,每个Servlet也是单例 在spring MVC架构/struts1框架中,控制器对象也是单例 单例模式的优点 由于单例模式只生产一个实例,减少了系统性能开销,当一个对象的生产需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存来解决 单例模式可以在系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例,负责所有数据表的映射处理 常见的五种单例模式实现方式 主要 饿汉式(线程安全,调用效率高,但是不能延时加载) 懒汉式(线程安全,调用效率不高,但是可以延时加载) 其他 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用) 静态内部类式(线程安全,调用效率高,可以延时加载) 枚举单例(线程安全,调用效率高,不能延时加载) 如何选用 单例对象 占用资源少 不需要延时加载 枚举式 好于 饿汉式 单例对象 占用资源多 需要延时加载 静态内部类 好于 懒汉式 饿汉式实现(单例对象立即加载) /** * 饿汉式 * @author Matrix42 * */ public class SingletonDemo01 { //类初始化时立即加载 private static SingletonDemo01 instance = new SingletonDemo01(); private SingletonDemo01(){ } //方法没有同步,调用效率高 public static SingletonDemo01 getInstance(){ return instance; } } 饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题.虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题.因此,可以省略synchronized关键字 问题:如果只加载本类,而不调用getInstance(),甚至永远没有调用,则会造成资源浪费! 懒汉式实现(单例对象延迟加载) public class LazayLoad { private static LazayLoad instance; private LazayLoad(){ } public static synchronized LazayLoad getInstance(){ if (instance==null) { instance = new LazayLoad(); } return instance; } } 问题:资源利用率高了,但是每次调用getInstance()方法都要同步,并发效率低了 双重检测锁实现 这个模式将同步内容放到if内部,提高了执行的效率,不比每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了 由于JVM底层内部模型原因,偶尔会出现问题,不建议使用 public class SingletonDemo3 { private static SingletonDemo3 instance = null; public static SingletonDemo3 getInstance() { if (instance == null) { SingletonDemo3 sc; synchronized (SingletonDemo3.class) { sc = instance; if (sc == null) { synchronized (SingletonDemo3.class) { if(sc == null) { sc = new SingletonDemo3(); } } instance = sc; } } } return instance; } private SingletonDemo3() { } } 静态内部类实现方式(也是一种懒加载方式) 外部类没有static属性,不会像饿汉式那样立即加载对象 只有真正调用getInstance(),才会加载静态内部类.加载时是线程安全的.instance是static final类型,保证了内存中只有一个实例存在,而且只能被赋值一次,从而保证了线程安全性 兼备了并发高效调用和延迟加载的优势 public class SingletonDemo04 { private static class SingketonClassInstance{ private static final SingletonDemo04 instance = new SingletonDemo04(); } public static SingletonDemo04 getInstance(){ return SingketonClassInstance.instance; } private SingletonDemo04(){ } } 使用枚举实现单例模式 优点 实现简单 枚举本身就是单例模式.由JVM从根本上提供保障!避免通过反射和反序列化的漏洞! 缺点 无延迟加载 public enum SingletonDemo05 { //这个枚举元素本身就是单例对象 INSTANCE; //添加自己需要的操作 public void singtonOperation(){ } } 问题 反射可以破解上面几种(不包含枚举)实现方式!(可以在构造方法中手动抛出异常来控制) 反序列化也可以破解上面几种(不包含枚举)实现方式,可以通过定义readResolve()防止获得不同对象 反序列化时,如果对象所在类定义了readResolve()(实际是一种回调)定义返回哪个对象 import java.io.Serializable; /** * 测试懒汉式单例模式(如何防止反射和反序列化漏洞) * @author Matrix42 * */ public class Demo06 implements Serializable{ private static final Demo06 instance = new Demo06(); public static Demo06 getInstance(){ return instance; } //更严密,一般不用考虑这么多 private Demo06(){ if(instance!=null){ throw new RuntimeException(); } } //反序列化时,如果定义了readResolve()则直接返回此方法指定的对象.而不需要创建新对象 private Object readResolve(){ return instance; } } import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; public class Client { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { Demo06 s1 = Demo06.getInstance(); Demo06 s2 = Demo06.getInstance(); System.out.println(s1); System.out.println(s2); //通过反射方式调用私有构造器 // Class<Demo06> clazz = (Class<Demo06>) Class.forName("design.sington.Demo06"); // // Constructor<Demo06> constructor = clazz.getDeclaredConstructor(null); // // constructor.setAccessible(true); // // Demo06 s3 = constructor.newInstance(); // // System.out.println(s3); //通过反序列化破解 FileOutputStream fos = new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/a.txt"))); Demo06 s3 = (Demo06) ois.readObject(); System.out.println(s3); } } 常见的五种单例模式在多线程环境下的效率测试 只关注相对值即可,在不同环境下不同的程序测得值会不一样 CountDownLatch 同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待 countDown()当前线程调用此方法,则计数减一(建议放在finally里执行) await()调用此方法会一直阻塞当前线程,直到计数器的值为0 import java.util.concurrent.CountDownLatch; /** * 测试五种创建单例模式的效率 * @author Matrix42 * */ public class Client02 { public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); int threadNum = 10; CountDownLatch countDownLatch = new CountDownLatch(threadNum); for(int i=0;i<10;i++){ new Thread(new Runnable() { @Override public void run() { for(int i=0;i<1000000;i++){ Object object = SingletonDemo01.getInstance(); } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("总耗时: "+(end-start)); } }
将设计者的思维融入学习和工作中 设计模式分类 创建型模式 单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式 关注对象的创建过程 结构模型 设配器模式 桥接模式 装饰模式 组合模式 外观模式 亨元模式 代理模式 关注对象和类的组织 行为模式 模板方法模式 命令模式 迭代器模式 观察者模式 中介模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 访问模者式 关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和写作,进一步明确对象的职责
基本概念 什么是计算机网络 把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大,功能强的网络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件,软件,数据信息等资源 计算机网络的主要功能 资源共享 信息传递与集中处理 均衡负荷与分布处理 综合信息服务(www/综合业务数字网络ISDN) 什么是网络通信协议 计算机网络中实现通信必须有一些约定即通信协议,对速率,传输代码,代码结构,传输控制步骤,出错控制等制定标准 网络通信接口 为了使两个节点之间能进行对话,必须在他们之间建立通信工具(即接口),彼此之间能进行信息交换.接口包括两部分: 硬件装置:实现节点之间的信息传送 软件装置:规定双方进行通信的约定协议 网络分层 原因 由于节点之间联系很复杂,在制定协议时,把复杂成分分解成一些简单的成分,再将它们复合起来.最常用的复合方式是层次方式,即同层间可以通信,上一层可以调用下一次,而与再下一层不发生关系 通信协议的分层 OSI参考模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 TCP/IP参考模型 应用层 传输层(TCP/UDP) 网络层(IP) 物理+数据链路层 传输协议 TCP(transfer control prottocol) 一种面向连接(连接导向)的,可靠的,基于字节流的运输层(Transport layer)通信协议 特点 面向连接 点到点的通信 高可靠性 TCP三次握手(Three-way Handshake) UDP(User Datagram Protocol) 一种无连接的传输层协议,提供面向事物的简单不可靠信息传送服务 特点 非面向连接 传输不可靠 数据可能丢失 数据封装拆分 网络编程值地址及端口 1.InetAddress :封装 IP 及DNS 方法: getHostAddress() 返回ip地址 getHostName() 返回域名|本机为计算机名 InetAddress.getLocalHost(); InetAddress.getByName("ip地址|域名"); 2.InetSocketAddress:封装端口 1)创建对象: InetSocketAddress(String hostname, int port) InetSocketAddress(InetAddress addr, int port) 2)方法： getAddress() getHostName() getPort() public class InetDemo01 { /** * @param args * @throws UnknownHostException * @throws MalformedURLException */ public static void main(String[] args) throws UnknownHostException{ //使用getLocalHost方法创建InetAddress对象 InetAddress addr = InetAddress.getLocalHost(); System.out.println(addr.getHostAddress()); //返回：192.168.1.100 System.out.println(addr.getHostName()); //输出计算机名 //根据域名得到InetAddress对象 addr = InetAddress.getByName("www.163.com"); System.out.println(addr.getHostAddress()); //返回 163服务器的ip:61.135.253.15 System.out.println(addr.getHostName()); //输出：www.163.com //根据ip得到InetAddress对象 addr = InetAddress.getByName("61.135.253.15"); System.out.println(addr.getHostAddress()); //返回 163服务器的ip:61.135.253.15 System.out.println(addr.getHostName()); //输出ip而不是域名。如果这个IP地 址不存在或DNS服务器不允许进行IP地址和域名的映射，getHostName方法就直接返回这个IP地址。 } } import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; /** * 封装端口:在InetAddress基础上+端口 * @author Administrator * */ public class InetSockeDemo01 { /** * @param args * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException { InetSocketAddress address = new InetSocketAddress("127.0.0.1",9999); address = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),9999); System.out.println(address.getHostName()); System.out.println(address.getPort()); InetAddress addr =address.getAddress(); System.out.println(addr.getHostAddress()); //返回：地址 System.out.println(addr.getHostName()); //输出计算机名 } } URL URI(Uniform resource identifier)统一资源标识符,用来唯一的标识一个资源。 URL（Uniform Resource Locator）统一资源定位器,它是一种具体的URI 四部分组成: 协议 存放资源的主机域名 端口 资源文件名(/) 一、创建 URL(String spec) :绝对路径构建 URL(URL context, String spec) :相对路径构建 二、方法 System.out.println("协议:"+url.getProtocol()); System.out.println("域名:"+url.getHost()); System.out.println("端口:"+url.getPort()); System.out.println("资源:"+url.getFile()); System.out.println("相对路径:"+url.getPath()); System.out.println("锚点:"+url.getRef()); //锚点 System.out.println("参数:"+url.getQuery());//?参数 :存在锚点 返回null ,不存在，返回正确 三、流 openStream() public class URLDemo01 { public static void main(String[] args) throws MalformedURLException { //绝对路径构建 URL url = new URL("http://www.baidu.com:80/index.html?uname=bjsxt"); System.out.println("协议:"+url.getProtocol()); System.out.println("域名:"+url.getHost()); System.out.println("端口:"+url.getPort()); System.out.println("资源:"+url.getFile()); System.out.println("相对路径:"+url.getPath()); System.out.println("锚点:"+url.getRef()); //锚点 System.out.println("参数:"+url.getQuery());//?参数 :存在锚点 返回null ,不存在，返回正确 url = new URL("http://www.baidu.com:80/a/"); url = new URL(url,"b.txt"); //相对路径 System.out.println(url.toString()); } } 网络爬虫原理 ** * 获取资源：源代码 */ public class URLDemo02 { public static void main(String[] args) throws IOException { URL url = new URL("http://www.baidu.com"); //主页 默认资源 //获取资源 网络流 /* InputStream is =url.openStream(); byte[] flush = new byte[1024]; int len =0; while(-1!=(len=is.read(flush))){ System.out.println(new String(flush,0,len)); } is.close(); */ BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(),"utf-8")); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("baidu2.html"),"utf-8")); String msg =null; while((msg=br.readLine())!=null){ //System.out.println(msg); bw.append(msg); bw.newLine(); } bw.flush(); bw.close(); br.close(); } } UDP编程 UDP:以数据为中心 非面向连接 不安全 数据可能丢失 效率高 一、类 DatagramSocket DatagramPacket 1、客户端： 1)、创建客户端 DatagramSocket 类 +指定端口 2)、准备数据 字节数组 3)、打包 DatagramPacket +服务器地址 及端口 4)、发送 5)、释放资源 2、服务器端： 1)、创建 服务端 DatagramSocket 类+指定端口 2)、准备接受容器 字节数组 封装 DatagramPacket 3)、包 接受数据 4)、分析 5)、释放资源 Server端 /** * 服务端 * 1、创建服务端 +端口 * 2、准备接受容器 * 3、封装成 包 * 4、接受数据 * 5、分析数据 * 6、释放 */ public class MyServer { public static void main(String[] args) throws IOException { //1、创建服务端 +端口 DatagramSocket server = new DatagramSocket(8888); //2、准备接受容器 byte[] container = new byte[1024]; //3、封装成 包 DatagramPacket(byte[] buf, int length) DatagramPacket packet =new DatagramPacket(container, container.length) ; //4、接受数据 server.receive(packet); //5、分析数据 byte[] data =packet.getData(); int len =packet.getLength(); System.out.println(new String(data,0,len)); //6、释放 server.close(); } } Client端 /** * 客户端 * 1、创建客户端 +端口 * 2、准备数据 * 3、打包（发送的地点 及端口） * 4、发送 * 5、释放 */ public class MyClient { public static void main(String[] args) throws IOException { //1、创建客户端 +端口 DatagramSocket client = new DatagramSocket(6666); //2、准备数据 String msg ="udp编程"; byte[] data =msg.getBytes(); //3、打包（发送的地点 及端口） DatagramPacket(byte[] buf, int length, InetAddress address, int port) DatagramPacket packet = new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888)); //4、发送 client.send(packet); //5、释放 client.close(); } } UDP编程进阶 Server端 /** * 服务端 * 1、创建服务端 +端口 * 2、准备接受容器 * 3、封装成 包 * 4、接受数据 * 5、分析数据 字节数组-->double * 6、释放 */ public class Server { public static void main(String[] args) throws IOException { //1、创建服务端 +端口 DatagramSocket server = new DatagramSocket(8888); //2、准备接受容器 byte[] container = new byte[1024]; //3、封装成 包 DatagramPacket(byte[] buf, int length) DatagramPacket packet =new DatagramPacket(container, container.length) ; //4、接受数据 server.receive(packet); //5、分析数据 double data =convert(packet.getData()); System.out.println(data); //6、释放 server.close(); } /** * 字节数组 +Data 输入流 * @param data * @return * @throws IOException */ public static double convert(byte[] data) throws IOException{ DataInputStream dis =new DataInputStream(new ByteArrayInputStream(data)); double num =dis.readDouble(); dis.close(); return num; } } Client端 /** * 客户端 * 1、创建客户端 +端口 * 2、准备数据 double -->字节数组 字节数组输出流 * 3、打包（发送的地点 及端口） * 4、发送 * 5、释放 */ public class Client { public static void main(String[] args) throws IOException { //1、创建客户端 +端口 DatagramSocket client = new DatagramSocket(6666); //2、准备数据 double num =89.12; byte[] data =convert(num); //3、打包（发送的地点 及端口） DatagramPacket(byte[] buf, int length, InetAddress address, int port) DatagramPacket packet = new DatagramPacket(data,data.length,new InetSocketAddress("localhost",8888)); //4、发送 client.send(packet); //5、释放 client.close(); } /** * 字节数组 数据源 +Data 输出流 */ public static byte[] convert(double num) throws IOException{ byte[] data =null; ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos =new DataOutputStream(bos); dos.writeDouble(num); dos.flush(); //获取数据 data = bos.toByteArray(); dos.close(); return data; } } Socket编程 TCP编程 一, 基于tcp:面向连接 安全 可靠 效率低 ,类似于打电话 一、面向连接:请求-相应 Request --Response 二、Socket编程 1、服务器:ServerSocket 2、客户端:Socket Server /** 必须先启动服务器 后连接 1、创建服务器 指定端口 ServerSocket(int port) 2、接收客户端连接 3、发送数据+接收数据 * */ public class Server { public static void main(String[] args) throws IOException { //1、创建服务器 指定端口 ServerSocket(int port) ServerSocket server = new ServerSocket(8888); //2、接收客户端连接 阻塞式 Socket socket =server.accept(); System.out.println("一个客户端建立连接"); //3、发送数据 String msg ="欢迎使用"; //输出流 /* BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())); bw.write(msg); bw.newLine(); bw.flush(); */ DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeUTF(msg); dos.flush(); } } Client /** 1、创建客户端 必须指定服务器+端口 此时就在连接 Socket(String host, int port) 2、接收数据 +发送数据 * */ public class Client { public static void main(String[] args) throws UnknownHostException, IOException { //1、创建客户端 必须指定服务器+端口 此时就在连接 Socket client = new Socket("localhost",8888); //2、接收数据 /* BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); String echo =br.readLine(); //阻塞式方法 System.out.println(echo); */ DataInputStream dis = new DataInputStream(client.getInputStream()); String echo = dis.readUTF(); System.out.println(echo); } }
节点流 字节数组节点流 输入流:ByteArrayInputStream read(byte[] b,int off,int len) close() 不用关闭 输出流:ByteArrayOutputStream write(byte[] b,int off,int len) toByteArray() import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public class Demo08 { public static void main(String[] args) throws IOException { read(write()); } public static void read(byte[] src) throws IOException { //选择流 InputStream is = new BufferedInputStream(new ByteArrayInputStream(src)); //操作 byte[] flush = new byte[1024]; int len = 0; while(-1!=(is.read(flush))){ System.out.println(new String(flush)); } } public static byte[] write(){ //目的地 byte[] dest; //选择流 ByteArrayOutputStream bos = new ByteArrayOutputStream(); //操作写出 String msg = "操作与文件输入流一致"; byte[] info = msg.getBytes(); bos.write(info,0,info.length); //获取数据 dest = bos.toByteArray(); return dest; } } import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** *1、文件 --程序->字节数组 *1)、文件输入流 * 字节数组输出流 * * * 2、字节数组 --程序->文件 * 1)、字节数组输入流 * 文件输出流 * @author Administrator * */ public class ByteArrayDemo02 { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { byte[] data =getBytesFromFile("e:/xp/test/1.jpg"); toFileFromByteArray(data,"e:/xp/test/arr.jpg"); } /** * 2、字节数组 --程序->文件 */ public static void toFileFromByteArray(byte[] src,String destPath) throws IOException{ //创建源 //目的地 File dest=new File(destPath); //选择流 //字节数组输入流 InputStream is =new BufferedInputStream(new ByteArrayInputStream(src)); //文件输出流 OutputStream os =new BufferedOutputStream(new FileOutputStream(dest)); //操作 不断读取字节数组 byte[] flush =new byte[1]; int len =0; while(-1!=(len =is.read(flush))){ //写出到文件中 os.write(flush, 0, len); } os.flush(); //释放资源 os.close(); is.close(); } /** * 1、文件 --程序->字节数组 * @return * @throws IOException */ public static byte[] getBytesFromFile(String srcPath) throws IOException{ //创建文件源 File src =new File(srcPath); //创建字节数组目的地 byte[] dest =null; //选择流 //文件输入流 InputStream is =new BufferedInputStream(new FileInputStream(src)); //字节数组输出流 不能使用多态 ByteArrayOutputStream bos =new ByteArrayOutputStream(); //操作 不断读取文件 写出到字节数组流中 byte[] flush =new byte[1024]; int len =0; while(-1!=(len =is.read(flush))){ //写出到字节数组流中 bos.write(flush, 0, len); } bos.flush(); //获取数据 dest =bos.toByteArray(); bos.close(); is.close(); return dest; } } 处理流 基本数据类型处理流 基本数据类型+String 保留数据+类型 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 1.输入流:DataInputStream * 2.输出流:DataOutputStream * java.io.EOFException :没有读取到相关的内容 * @author Matrix42 * */ public class Demo09 { public static void main(String[] args) throws IOException { write("F:/data.txt"); read("F:/data.txt"); } /** * 从文件读取数据+类型 * @throws IOException */ public static void read(String destPath) throws IOException{ //创建源 File src = new File(destPath); //选择流 DataInputStream dis = new DataInputStream( new BufferedInputStream( new FileInputStream(src))); //操作 读取顺序与写入顺序一致 必须存在才能读取 double point = dis.readDouble(); long num = dis.readLong(); String str = dis.readUTF(); dis.close(); System.out.println(point+" "+num+" "+str); } public static void write(String destPath) throws IOException { double point = 2.5; long num = 100L; String str = "数据类型"; //创建源 File dest = new File(destPath); //选择流 DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream(dest))); //操作 写出的顺序 为读取准备 dos.writeDouble(point); dos.writeLong(num); dos.writeUTF(str); dos.flush(); dos.close(); } } 引用数据类型处理流 反序列化:ObjectInputStream readObject() 序列化:ObjectOutputStream writeObject() 反序列化顺序必须和反序列化一致 不是所有的对象都可以系列化,需要实现java.io.Serializable 不是所有的属性都需要序列化,使用transient表示这个属性不需要序列化 /** * 空接口只是标识 */ public class Employee implements java.io.Serializable { //不需要序列化 private transient String name; private double salary; public Employee() { } public Employee(String name, double salary) { super(); this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } } import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Demo10 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { ser("F:ser.txt"); read("F:ser.txt"); } public static void read(String destPath) throws FileNotFoundException, IOException, ClassNotFoundException{ File dest = new File(destPath); ObjectInputStream dis = new ObjectInputStream( new BufferedInputStream( new FileInputStream(dest))); Object object = dis.readObject(); if (object instanceof Employee) { Employee employee = (Employee) object; System.out.println(employee.getName()); System.out.println(employee.getSalary()); } dis.close(); } public static void ser(String destPath) throws FileNotFoundException, IOException{ Employee emp = new Employee("me",10000); File dest = new File(destPath); ObjectOutputStream dos = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream(dest))); dos.writeObject(emp); dos.close(); } } 1.7新特性 try-with-resource try(代码){ 关闭流 }catch(){ } 打印流 重定向输出到文件 import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; public class Demo11 { public static void main(String[] args) throws FileNotFoundException { File src = new File("F:/out.txt"); PrintStream ps = new PrintStream(src); ps.print("123"); } } import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.util.Scanner; /** * 三个常量 * 1、System.in 输入流 键盘输入 * 2、System.out 输出流 控制台输出 * System.err * * ==>重定向 * setIn() * setOut() * setErr() * FileDescriptor.in * FileDescriptor.out * @author Administrator * */ public class SystemDemo01 { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { //test1(); //test2(); //重定向 System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("e:/xp/test/print.txt")),true)); System.out.println("a"); //控制台 -->文件 System.out.println("test"); //回控制台 System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true)); System.out.println("back...."); } public static void test2() throws FileNotFoundException{ InputStream is =System.in; //键盘输入 is = new BufferedInputStream(new FileInputStream("e:/xp/test/print.txt")); Scanner sc = new Scanner(is); //System.out.println("请输入:"); System.out.println(sc.nextLine()); } public static void test1(){ System.out.println("test"); System.err.println("err"); } } 装饰设计模式 处理流就是对节点流的包装 public class Voice { private int voice =10; public Voice() { } public int getVoice() { return voice; } public void setVoice(int voice) { this.voice = voice; } public void say(){ System.out.println(voice); } } /** * 扩音器 * 类与类之间的关系 * 1、依赖:形参|局部变量 * 2、关联:属性 * 聚合:属性 整体与部分 不一致的生命周期 人与手 * 组合:属性 整体与部分 一致的生命周期 人与大脑 * 3、继承:父子类关系 * 4、实现: 接口与实现类关系 */ public class Amplifier { private Voice voice; public Amplifier() { } public Amplifier(Voice voice) { super(); this.voice = voice; } public void say(){ System.out.println(voice.getVoice()*1000); } } 文件的分割与合并 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.SequenceInputStream; import java.util.ArrayList; import java.util.List; import java.util.Vector; import com.bjsxt.io.util.FileUtil; public class SplitFile { //文件的路径 private String filePath; //文件名 private String fileName; //文件大小 private long length; //块数 private int size; //每块的大小 private long blockSize; //分割后的存放目录 private String destBlockPath; //每块的名称 private List<String> blockPath; public SplitFile(){ blockPath = new ArrayList<String>(); } public SplitFile(String filePath,String destBlockPath){ this(filePath,destBlockPath,1024); } public SplitFile(String filePath,String destBlockPath,long blockSize){ this(); this.filePath= filePath; this.destBlockPath =destBlockPath; this.blockSize=blockSize; init(); } /** * 初始化操作 计算 块数、确定文件名 */ public void init(){ File src =null; //健壮性 if(null==filePath ||!(((src=new File(filePath)).exists()))){ return; } if(src.isDirectory()){ return ; } //文件名 this.fileName =src.getName(); //计算块数 实际大小 与每块大小 this.length = src.length(); //修正 每块大小 if(this.blockSize>length){ this.blockSize =length; } //确定块数 size= (int)(Math.ceil(length*1.0/this.blockSize)); //确定文件的路径 initPathName(); } private void initPathName(){ for(int i=0;i<size;i++){ this.blockPath.add(destBlockPath+"/"+this.fileName+".part"+i); } } /** * 文件的分割 * 0)、第几块 * 1、起始位置 * 2、实际大小 * @param destPath 分割文件存放目录 */ public void split(){ long beginPos =0; //起始点 long actualBlockSize =blockSize; //实际大小 //计算所有块的大小、位置、索引 for(int i=0;i<size;i++){ if(i==size-1){ //最后一块 actualBlockSize =this.length-beginPos; } spiltDetail(i,beginPos,actualBlockSize); beginPos+=actualBlockSize; //本次的终点，下一次的起点 } } /** * 文件的分割 输入 输出 * 文件拷贝 * @param idx 第几块 * @param beginPos 起始点 * @param actualBlockSize 实际大小 */ private void spiltDetail(int idx,long beginPos,long actualBlockSize){ //1、创建源 File src = new File(this.filePath); //源文件 File dest = new File(this.blockPath.get(idx)); //目标文件 //2、选择流 RandomAccessFile raf = null; //输入流 BufferedOutputStream bos=null; //输出流 try { raf=new RandomAccessFile(src,"r"); bos =new BufferedOutputStream(new FileOutputStream(dest)); //读取文件 raf.seek(beginPos); //缓冲区 byte[] flush = new byte[1024]; //接收长度 int len =0; while(-1!=(len=raf.read(flush))){ if(actualBlockSize-len>=0){ //查看是否足够 //写出 bos.write(flush, 0, len); actualBlockSize-=len; //剩余量 }else{ //写出最后一次的剩余量 bos.write(flush, 0, (int)actualBlockSize); break; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ FileUtil.close(bos,raf); } } /** * 文件的合并 */ public void merge(String destPath){ //创建源 File dest =new File(destPath); //选择流 BufferedOutputStream bos=null; //输出流 SequenceInputStream sis =null ;//输入流 //创建一个容器 Vector<InputStream> vi = new Vector<InputStream>(); try { for (int i = 0; i < this.blockPath.size(); i++) { vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i))))); } bos =new BufferedOutputStream(new FileOutputStream(dest,true)); //追加 sis=new SequenceInputStream(vi.elements()); //缓冲区 byte[] flush = new byte[1024]; //接收长度 int len =0; while(-1!=(len=sis.read(flush))){ bos.write(flush, 0, len); } bos.flush(); FileUtil.close(sis); } catch (Exception e) { }finally{ FileUtil.close(bos); } } /** * 文件的合并 */ public void merge1(String destPath){ //创建源 File dest =new File(destPath); //选择流 BufferedOutputStream bos=null; //输出流 try { bos =new BufferedOutputStream(new FileOutputStream(dest,true)); //追加 BufferedInputStream bis = null; for (int i = 0; i < this.blockPath.size(); i++) { bis = new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))); //缓冲区 byte[] flush = new byte[1024]; //接收长度 int len =0; while(-1!=(len=bis.read(flush))){ bos.write(flush, 0, len); } bos.flush(); FileUtil.close(bis); } } catch (Exception e) { }finally{ FileUtil.close(bos); } } public static void main(String[] args) { SplitFile split = new SplitFile("E:/xp/20130502/test/学员设置(20130502).xls","E:/xp/20130502",51); //System.out.println(split.size); //split.split(); split.merge("E:/xp/20130502/test1.xls"); } }