成鹏致远 | lcw.cnblog.com |2014-02-01
JAVA常用类库
1.StringBuffer
- StringBuffer是使用缓冲区的,本身也是操作字符串的,但是与String类不同,String类的内容一旦声明之后则不可改变,改变的只是其内存地址的指向,而StringBuffer中的内容是可以改变的
- 对于StringBuffer而言,本身是一个具体的操作类,所以不能你String那样采用直接赋值的方式进行对象的实例化,必须通过构造方法完成
- 当一个字符串的内容需要被经常改变时就要使用StringBuffer
- StringBuffer的内容是可以修改的,通过引用传递的方式完成
- StringBuffer常用方法
- 字符串连接操作:append()
- 在任意位置处为StringBuffer添加内容:insert(int offset, boolean b)
- 字符串反转操作:reverse()
- 替换指定范围的内容:replace(int start, int end, String str)
- 字符串截取:substring(int start, int end)
- 字符串截取:delete(int start, int end)
- 查找指定的内容是否存在:indexOf()
- 以上的常用方法,实际上对于String类中也是存在的,所以使用的时候直接根据DOC文档查看即可
- 小结
- 凡是需要频繁修改字符串内容的时候,都要使用StringBuffer类完成
- StringBuffer类中也提供了一些方法是String类中所没有的,包括:delete()、insert()等等,这些方法需要的时候直接通过DOC文档进行查找
2.Runtime类
- Runtime:运行时,是一个封装了 JVM进程的类。每一个JAVA程序实际上都是启动了一个 JVM进程,那么每一个JVM进程都是对应这一个Runtime实例,此实例是由 JVM为其实例化的
- Runtime类的定义中根本就没有构造方法,本类的构造方法被私有化了,通过 getRuntime()静态方法就可以取得Runtime类的实例
- 得到 JVM信息:每一个Runtime对象都是由 JVM进行实例化,所以,可以直接通过此类取得一些信息
- 可以直接使用 Runtime类运行本机的可执行程序:public Process exec(String command) throws IOException
- exec()方法的加值值是 Process,表示一个进程的操作类,可以通过 destroy()方法销毁掉一个进程
- 小结
- Runtime类本身就是单态设计的一种应用,因为在整个 JVM中只存在一个Runtime类的对象
- 可以使用Runtime类取得 JVM的系统处,或者使用 gc()方法释放掉垃圾空间
- 还可以使用此类运行本机的程序
3.国际化程序
- 国际化:程序根据不同的语言环境找到不同的资源文件,之后从资源文件中取出内容,资源文件中的内容都是以 key ->value的形式保存的,所以在读取的时候通过其 key找到对应的 value即可
- 如果要想实现 Java程序的国际化操作必须通过以下的三个类完成
- java.util.Locale:用于表示一个国家语言类
- java.util.ResourceBundle:用于访问资源文件
- java.text.MessageFormat:格式化资源文件的占位字符串
- Locale类
- Locale表示的是本地,实际上使用的是一个 ISO编码的封装类。
- 对于各个国家来说都存在一个唯一的编码,那么这种编码就称为 ISO编码,使用Locale可以指定好一个具体的国家编码
- 中国编码:zh-CN
- 英语-美国的编码:eh-US
- 法语的编码:fr-FR
- ResourceBundle
- 此类是专门完成属性文件读取操作的,读取的时候直接指定文件名称即可(此文件名称一般不需要指定后缀,后缀统一为 *.properties)
- 可以根据Locale所指定的区域码来自动选择所需要的资源文件
- public static final ResourceBundle getBundle(String baseName),此方法就是指定要操作的资源文件,此方法找到的是默认的操作系统的语言Locale对象
- public final String getString(String key)根据 key取得对应的 value
- 资源文件命名的时候最好采用单词首字母大写的方式完成
- 【注意】对于中文的资源文件虽然可以直接通中文读取,但是这样做是不合理的,应该将其进行 Unicode编码,转换为Java认识的16进制,这样可以避免一些系统所带来的乱码问题,此工具为 JDK自动提供:native2ascii.exe,只要是中文,就必须进行转码操作
- 处理动态文本:就必须在资源文件中进行一些动态文本的配置,设置点位符,则必须使用 MessageForm类,此类是在 java.text包中定义的
- 在 Format类中还存在数字格式化的 Format(NumberFormat)、日期格式化的 Format(DateFormat)
- JAVA新特性:可变参数:在 JDK1.5之后增加了新特性的操作,可以向方法中传递可变的参数
- 小结
- 国际化程序实现的思路:程序与显示相分离,根据不同的 Locale指定的区域找到不同的资源文件并根据其 key取得对应的 value
- 使用资源文件的方式保存所有的信息内容,其基本原理就是依靠了 ResourceBundle类取得资源文件中的内容
- MessageForm是 Format类的子类,以后还会有 Format其它子类的讲解
4.System类
- System类是一些与系统相关的属性和方法的集合在 System类中所有的属性都是静态的,要想引用这些属性和方法,直接使用System类调用即可
- System类可以通过方法取得一个操作的计算时间:System.currentTimeMillis()
- 还可以列出本机的全部系统属性:getProperties()
- 一个对象如果不使用,则要等待进行垃圾收集,垃圾收集可以自动调用也可以手工调用,手工调用的时候就是调用 System.gc()或者 Runtime.getRuntiom().gc()。但是,如果一个对象在回收之前需要做一些收尾的工作,则就必须覆写 Object类中的:protected void finalize() throws Throwable,在对象被回收之前进行调用,以处理对象回收前的若干操作,例如释放资源等等
- 只有强制性调用 gc()的时候才可以发现对象被回收,当然,如果不调用,则系统也会在一定时间内自动进行回收
- 对象生命周期:初始化->对象实例化->垃圾收集->对象终结->卸载
- 小结
- System类本身提供的静态属性都是与 IO操作有关的,在 IO操作中还将进一步涉及 System类的使用,可以使用 System类取得计算的时间,以及通过 gc()方法进行垃圾收集,此方法就是包装了 Runtime类中的 gc()方法
5.日期操作类
- Date类是一个较为常用的类,但是其操作的日期格式会有一些不符合于个人的要求,而如果要想进一步取得一些自己需要的时间,则可以使用Calendar类
- 在java.util包中定义了 Date类,Data类本身使用非常简单,直接输出其实例化对象即可
- 如果希望可以按照自己需要的格式显示时间,可以使用 Calendar类,此类可以直接将日期精确到毫秒
- Calendar类是一个抽象类,既然是一个抽象类则肯定无法直接使用,此时就要利用对象多态性的概念,通过向上转型关系实例化本类对象
- 使用 Calendar类可以非常轻松取得一个完整的日期,但是在取得月份的时候要特别注意,需要增加1
- 最好的做法是将 Date进行一些相关的格式化操作
- 小结
- Date类虽然直接取出的时间格式并不是十分理想,但是其作用依然很大
- 通过 Calendar类可以完整的取得时间
6.DateFormat、SimpleDateFormat
- DateFormat类是一个抽象类,其类本身的内部提供了可以直接为其实例化的操作
- 得到日期的 DateFormat对象:public static final DateFormat getDateInstance()
- 得到日期时间的 DateFormat对象:public static final DateFormat getDateTimeInstance()
- 直接使用 DateFormat类完成Date类的转换:public final String Format(Date date)
- 通过DateFormat类可以直接将 date类的显示进行合理的格式化操作,此时采用的是默认的格式化操作,也可以通过 Locale对象指定要显示的区域
- SimpleDateFormat类:功能是完成日期的显示格式化的
- 要想实现转换,则必须首先准备好一个模板,通过此模板进行日期数据的提取工作
- 在SimpleDateFormat类使用的时候,必须注意的是构造对象时要传入匹配的模板
- 构造方法:public SimpleDateFormat(String pattern)
- 转换:public Date parse(String source) throws ParseException:此时取得的是全部的时间数
- 格式化:public final String format(Date date):将时间重新格式化成字符串显示
- 小结
- DateFormat可以直接使用,但其本身是一个抽象类,可以根据 Locale指定的区域不同得到不同的日期时间显示效果
- SimpleDateFormat类是 DateFormat类的子类,一般情况下来说 DateFormat类很少会直接使用,而都使用 SimpleDateFormat类完成
- 直接使用 SimpleDateFormat类取得时间会比使用 Calendar类更加方便,而且不用去增加补零的操作,所以在开发中如果需要取得一个日期的话,则基本上都使用 SimpleDateFormat类进行操作
7.Math与Random
- Math类,表示数学操作,Math类中的方法都是静态方法,直接使用“类.方法名称()”的形式调用即可
- Math.round求四舍五入的时候实际上是将小数点之后的内容全部忽略掉了,如果此时需要进行准确倍数的四舍五入,则需要使用其它的类完成:BigDecimal
- Random类的主要功能是产生随机数,可以产生一个指定范围的随机数,Random类是定义在 java.util包中的类
- 小结
- Math类中的 round()方法要特别注意
- Random类的主要功能
8.NumberFormat
- 可以使用 NumberFormat类进行本地化的数字显示
- 可以使用 DecimalFormat指定格式化模板
- NumberFormat表示数字的格式化类,即:可以按照本地的风格习惯进行数字的显示
- MessageForm、DateFormat、NumberFormat是 Format三个常用的子类,如果要想进一步完成一个好的国际化程序,则肯定需要同时使用这样三个类完成,根据不同的国家显示日期,或者显示货币的形式
- DecimalFormat是 NumberFormat类的子类,可以直接指定其显示的模板
- DecimalFormat主要的作用是用来格式化数字使用,当然,在格式化数字的时候要比直接使用 NumberFormat更加方便,因为可以直接指定按用户自定义的方式进行格式化操作,与之前讲解的 SimpleDateFormat类似,如果要想进行自定义格式化操作,则必须指定格式化操作的模板
- 小结
- NumberFormat完成的功能只是根据区域不同固定的数字显示格式
- DecimalFormat是可以由用户自己指定其显示的形式,所以比较好用
9.大数操作
- 在java中有两个大数的操作类
- 操作整型:BigInteger
- 操作小数:BigDecimal
- 如果在操作的时候一个整型数据已经超过了整数的最大类型长度long的话,则此数据就无法装入,所以,此时要使用BigInteger类进行操作
- BigDecimal:使用此类可以完成大的小数操作,而且也可以使用此类进行精确的四舍五入,这一点在开发中经常使用
- 对于不需要任何准确计算精度的程序可以直接使用float或double完成,但是如果需要精确计算的结果,则必须使用BigDecimal类
- 小结
- 使用BigDecimal可以指定好四舍五入的精确位置
10.对象克隆技术
- 对象克隆:对象的复制,完整的复制一个对象
- 如果要想完成对象克隆的话,则肯定依靠 Object类:方法:protected Object clone() throws CloneNotSupportedExcetion
- 以上的方法就是对象克隆的方法,如果现在一个类的对象被克隆,则就必须在此类中明确的覆写此方法,但是此方法不能直接调用
- Cloneable是一个接口,但是在此接口中并没有规定任何的操作方法,所以此接口实际上属性标识接口,表示一种能力
- 对象克隆支持:在java中支持对象的克隆操作,直接使用 Object类中的clone()方法即可
- 对象所有的类必须实现 Cloneable接口才可以完成对象的克隆操作
- 小结
- 在以后的JAVA类库中会经常看到 Cloneable接口的出现
- 只有实现了 Cloneable接口的对象才可以被克隆,否则无法克隆
11.比较器(Comparable、Comparator)
- Array类中存在 sort()方法,此方法可以直接对对象进行排序
- 可以直接使用 java.util.Arrays类进行数组的排序操作,但对象所在的类必须实现 Comparable接口,用于指定排序接口
- 比较器的排序原理:实际上比较器的操作,就是经常听到的二叉树的排序算法
- 排序的基本原理:使用第一个元素作为根节点,之后如果后面的内容比根节点要小,则放在左子树,如果内容比根节点的内容要大,则放在右子树
- 另一种比较器:如果一个类已经开发完成,但是此类建立的初期并不实现 Comparable接口,此时肯定是无法进行对象排序操作的,所以为了解决这样的问题,java又定义了另一个比较器的操作接口:Comparator
- 小结
- 在使用中尽可能还是使用 Comparable在需要排序的类上实现好此接口,而 Comparator需要单独建立一个排序的类,这样如果有很多的话,则排序的规则类就会非常的多,操作起来比较麻烦
- 掌握一点:只要是对象排序,则在java中永远是以 Comparable接口为准
12.观察者模式
- 如果要想实现观察者模式,则必须依靠java.util包中提供的 Observable类和 Observer接口
- 在 Observer接口中的 update方法里面有两个参数
- o:表示 Observable类的对象
- arg:需要被观察的内容
- 小结
- 此模式是一种Java本身的机制,不使用 Observer和 Observable也是可以实现的,只是比较复杂
13.正则表达式
- 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证,拆分、替换功能
- Pattern、Matcher两个类为正则的核心操作类,两个类都定义在 java.util.regex包中
- Pattern类的主要作用是进行正则规范(如“[0-9]”就属于正则规范)的编写
- Matcher类主要是执行规范,验证一个字符串是否符合其规范
- 正则表达式
- \d:表示数字,[0-9]
- \D:表示非数字,[^0-9]
- \w:表示字母、数字、下划线,[a-zA-Z0-9]
- \W:表示非字母、数字、下划线,[^a-zA-Z0-9]
- 要想驱动正则表达式,必须依靠Pattern类和Matcher类
- Pattern类中没有明确的构造方法可以供用户使用,那么则肯定此类的构造方法被私有化了,则可以直接从Pattern类中取得本类的实例
- 指定好操作的正则:public static Pattern compile(String regex)
- 可以为 matcher类实例化:public Matcher matcher(CharSequence input)
- 拆分:public String[] spilt(Charsequence input)
- 如果要验证一个字符串是否符合规范,则可以使用Matcher类
- 进行字符串的验证:public boolean matcher()
- 字符串替换:public String replaceAll(String replacement)
- 只要使用正则的验证的规则,那么就可以匹配各种复杂的字符串
- String类对正则的支持:在 JDK1.4之后,Java对正则进行了一些扩充,在 String中开始直接支持正则的操作
- 字符串匹配:public boolean matchers(String regex)
- 字符串替换:public String replaceAll(String regex, String replacement)
- 字符串拆分:public String[] split(String regex)
- 【注意】如果有时候发现一个字符串无法按照指定的字符拆分的话,则需要使用“\”转义,转义的时候两个“\”表示一个“\”
- 小结
- 使用正则可以方便的完成字符串的验证、拆分、替换等复杂功能
- 在开发中一般都会直接使用 String类中提供好的正则支持,而往往很少直接使用 Pattern类或者Matcher类
- 在一些正则应用的时候,对于一些敏感的字符要进行转义操作
14.定时调度
- 定时调度:每当一段时间,程序会自动执行,称为定时调度
- 如果要使用定时调度,则必须保证程序始终运行着才可以,也就是说是相当于定时调度是在程序之外又启动了一个新的线程
- Timer和 TimerTask两个类完成定时调度
- Timer类
- Timer类是一种线程设施,可以用来实现在某一时间或某一段时间后,安排某一个任务执行一次,或定期重复执行
- 该功能要与 TimerTask配合使用。
- TimerTask类用来实现由 Timer安排的一次或重复执行的某一个任务
- 每一个 Timer对象对应的是一个线程,因此计时器所执行的任务应该迅速完成,否则可能会延迟后续任务的执行,而这些后续的任务就有可能堆在一起,等到该任务完成后才能快速连续执行
- schedule()与scheduleAtFixedRate()方法的区别
- 两者的区别在与重复执行任务时,对于时间间隔出现延迟的情况处理
- schedule()方法的执行时间间隔永远是固定的,如果之前出现了延迟的情况,之后也会继续按照设定好的间隔时间来执行
- scheduleAtFixedRate()方法可以根据出现的延迟时间自动调整下一次间隔的执行时间
- TimerTask类
- 要想执行具体的任务,则必须使用TimerTask类,TimerTask类是一个抽象类,如果要使用该类,需要自己建立一个类来继承此类,并实现其中的抽象方法
- 如果现在一个 Timer类要想调度程序的话,则需要使用 TimerTask的子类
- 完成一个具体的任务操作类,以后定时调度的是此类的操作,方法的主体就是 run()方法
- 小结
- 一般在 web的开发中此内容比较有用,因为要维护一个窗口不关闭才可以一直定时操作下去
JAVA IO
1.File类
- 所有的 io操作都保存在 java.io包中
- 在整个 io包中,唯一表示与文件本身有关的类就是 File类
- 使用 File类可以进行创建或删除文件等常用操作
- 构造方法:public File(String pathname) ->实例化 File类的时候,必须设置好路径,直接根据路径找到文件
- File类常用方法
- 创建文件:public boolean createNewFile() throws IOException
- 分隔符:File.separator
- 删除一个文件:public boolean delete()
- 判断文件是否存在:public boolean exists()
- 所有的 JAVA IO操作并不会立刻执行,因为 JAVA是通过 JVM与底层进行交互的,所以所有的操作需要经过 JVM完成,那么就有可能产生延迟
- 创建文件夹:public boolean mkdir()
- 列出指定目录的全部文件
- 以字符串数组的形式返回:public String[] list() ->只是列出全部的名字,包括文件夹名字和文件名字
- 以 File数组的形式返回:pulic File[] listFiles() ->列出一个完整的路径,这样对于程序本身来说是很容易操作的
- 判断一个给定的路径是否是目录:public boolean isDirectory()
- 小结
- File类是在 java.io包中唯一与文件本身有关的
- 可以使用 File类创建、删除等常见的文件操作
- 在使用 File类指定路径的时候一定要注意操作系统间的差异,尽量使用 separator进行分割
2.RandomAccessFile
- RandomAccessFile类的主要功能是完成随机读取功能,可以读取指定位置的内容
- RandomAccessFile写数据的时候可以将一个字符串写入,读的时候需要一个个的以字节的形式读取出来
- 如果要想操作文件内容的话,可以使用 RandomAccessFile完成
- 小结
- RandomAccessFile类的作用
- RandomAccessFile类操作起来比较麻烦,所以在 IO中会提供专门的输入、输出操作
3.字节流与字符流
- 流:在程序中所有的数据都是流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将数据保存起来的时候,就要使用输出流完成
- 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件
- 在 java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作
- 在字节流中输出数据主要是使用 OutputStream完成,输入使的是 InputStream
- 在字符流中输出数据主要是使用 Writer类完成,输入主要是使用 Reader类完成
- 实际上四个操作类都是抽象类
- 在 JAVA中 IO操作也是有相应步骤的,以文件操作为例,主要的操作流程如下:
- 使用 File类打开一个文件
- 通过字节流或字符流的子类,指定输出的位置
- 进行读/写操作
- 关闭输入/输出
- 使用 File类操作的时候一定要有路径的问题,注意分隔符
- IO操作属于资源操作,对于资源操作,操作的最后都必须关闭,否则就有可能出现未知的错误
- 字节流
- 字节流主要是操作 byte类型数据,以 byte数组为准,主要操作类就是 OutputStream、InputStream
- Byte是字节,肯定是字节流操作,所有的数据基本上都可以直接使用 byte数组表示出来
- OutputStream
- OutputStream是整个 IO包中字节输出流的最大父类
- OutputStream是一个抽象类,如果要想使用此类的话,则首先必须子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类,通过向上转型之后,可以为 OutputStream实例化
- Closeable:表示可以关闭的操作,因为程序运行到最后肯定要关闭
- Flushable:表示刷新,清空内存中的数据
- InputStream
- 通过 InputStream可以从文件中把内容读取进来
- InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,子类肯定是 FileInputStream
- 知道文件大小:直接使用 File类即可:public long length()
- 字符流
- 在程序中一个字符等于2个字节,JAVA提供了Reader、Writer两个专门操作字符流的类
- Writer
- Writer本身也是一个抽象类,如果要想使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,所以应该使用 FileWriter的子类
- 字符流的操作比字节流操作好在一点:就是可以直接输出字符串了,不用再像之前那样进行转换操作了
- Reader
- Reader是使用字符的方式从文件之中取出数据
- Reader本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用 FileReader子类
- 字节流与字符流的区别
- 字节流和字符流使用是非常相似的
- 字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的
- 字符流在操作的时候是使用到缓冲区的
- 【问题】开发中使用字节流好还是字符流好:在所有的硬盘上保存文件或是进行传输的时候都是以字节的方式进行的。包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的
- 小结
- 掌握流的概念
- 掌握字节流和字符流操作文件的基本步骤
- 本章是以文件为例,实际以后的所有操作都可以通过此段代码完成,只是替换子类而已
- 字节流和字符流的区别
- 字节流:没有使用缓冲区
- 字符流:使用了缓冲区
- 边读边写的方式在开发中非常有用处
4.字节-字符转换流
- 在整个 IO包中,实际上就是分为字节流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换
- OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变为字节流的输出对象
- InputStreamReader:是Reader的子类,将输入的字节流变为字符流:即:将一个字节流的输入对象变为字符流的输入对象
- 如果以文件操作为例
- 则在内存中的字符数据需要通过 OutputStreamWriter变为字节流才能保存在文件之中,读取的时候需要将读入的字节流通过 InputStreamReader变为字符流
- 虽然只是以文件操作为例,因为 OutputStreamWriter中接收的类型是 OutputStream,只要是字节输出流都可以使用字符的形式操作
- 而InputStreamReader()中接收的类型是 InputStream,只要是字节的输入流都可以使用字符的输入流操作
- FileWriter和FileReader的说明
- 从 JDK文档中可以知道 FileOutputStream是 OutputStream的直接子类,FileOutputStream也是 InputStream的直接子类
- 但是在字符流文件的两个操作类却有一些特殊
- FileWriter并不直接是Writer的子类,而是 OutputStreamWriter的子类,而 FileReader也是直接是 Reader的子类,是 InputStreamReader的子类
- 那么从这两个类的继承关系就可清楚的发现,不管是使用字节流还是字符流实际上最终都是以字节的形式操作输入输出流的
- 也就是说:最后不管如何,虽然是以字符的输出流形式操作了字节的输出流,但是实际上还是以字节的形式输出,而字符的输入流,虽然以字符的形式操作,但是实际还是使用的字节流
- 也就是说:传输或者是从文件读取数据的时候,文件里真正保存的数据永远是字节
- 小结
- 一定要掌握两个转换类的作用
- 一定要明白,操作的终端点实际上都是以字节的形式进行的
- FileWriter和FileReader两个子类的定义,中间使用了转换类
5.内存操作流
- 之前的输入和输出都是从文件中来的,当然,也可以将输出的位置设置在内存之上
- 此时就要使用 ByteArrayInputStream、ByteArrayOutputStream来完成输入、输出功能了
- ByteArrayInputStream:主要完成将内容写入到内存之中
- ByteArrayOutputStream:主要将内存中的数据输出
- 此时操作的时候应该以内存为操作点
- 如果要想把一个字符变为小写,则可以通过包装类:Character
- 小结
- 内存操作流的操作对象一定是以内存为准,不要以程序为准
- 实际上此时可以通过向上转型的关系为 OutputStream或 InputStream实例化
- 这样的操作可以很好的体现对象的多态性,通过实例化其子类的不同,完成的功能也不同,也就相当于输出位置也就不同,如果是文件,则使用 FileXxx,如果是内存,则使用 ByteArrayXxx
- 内存输出流是 JAVA开发中也经常要使用到,要重点掌握
6.管道流
- 管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream)、管道输入流(PipedInputStream)
- 如果要想进行管道输出,则必须把输出流连在输入流之上,在PipedOutputStream类上有一个方法用于连接管道:public void connect(PipedInputStream snk) throws IOException
- 要想实现管道流,则可以使用 PipedInputStream和 PipedOutputStream
- 小结
- 在 JAVA开发中很少直接去开发多线程程序
7.打印流
- 在整个 IO包中,打印流是输出信息最方便的类,主要包含字节打印流(PrintStream)和字符打印流(PrintWriter)
- 在打印流类中定义了很多的 print()或 println()方法,System.out.println(),此方法可以打印任何数据类型
- 构造方法:public PrintStream(OutputStream out) ->参数指定输出位置
- 在 JDK1.5之后,JAVA又对 PrintStream类进行了扩充,增加了格式化的输出方式,直接使用 printf()方法就可以完成操作
- 小结
- PrintStream可以方便的完成输出的功能
- 在以后的输出中基本上都使用 PrintStream完成,因为比较方便一些
- PrintStream属于装饰设计模式
8.System类对 IO类的支持
- System.out和 System.err的区别
- System.out和 System.err都是 PrintStream的实例化对象,而且两者都可以输出错误信息,但是一般来讲 System.out是将信息显示给用户看,是正常的信息显示,而 System.err的信息正好相反是不希望用户看到的,会直接在后台打印,是专门显示错误的
- System.in实际上是一个键盘的输入流,其本身是 InputStream类型的对象,那么,此时就可以利用此方式完成从键盘读取数据的功能
- 指定了输入数据的长度,如果现在输入的数据超过了长度范围,则只能输入部分数据
- 指定的 byte数组长度是奇数的话,则还有可能出现中文乱码的问题
- 最好的输入方式
- 最好的输入方式是将全部输入的数据暂放到一块内存之中,之后一次性的从内存中读取出数据,这样所有数据只读了一次,则不会造成乱码,而且也不会受长度的限制
- 如果要想实现以上的功能,则只能通过 BufferReader类完成
- 重定向
- 为 System.out输出重定向:使用 setOut()方法完成
- 为 System.err输出重定向:使用 setErr()方法完成
- 为 System.in输出重定向:使用 setIn()方法完成
- 对于重定向操作,基本上都在 System.out上使用,以把信息展现给用户观看
- 小结
- 三个常量的使用
- System.out:是希望用户可以看见的信息,用 IDE(Eclipse)的话错误信息是用黑颜色显示的
- System.err:是不希望用户可以看见的信息,用 IDE(Eclipse)的话错误信息是用红颜色显示的
- System.in:对应键盘输
- 以上三个常量的输入、输出都可以重定向,但是一般只建议修改 setOut的重定向
- System.in 读取的时候会出现中文乱码问题,则可以通过 BufferReader完成读取功能
9.BufferedReader类
- 如果想接收任意长度的数据,而且避免乱码产生,就可以使用 BufferedReader
- public class BufferedReader extends Reader ->因为输入的有可能出现中文,所以,此处使用字符流完成
- BufferedReader是从缓冲区中读取内容,所有的输入的字节数据都将放在缓冲区之中
- System.in本身表示的是 InputSteam(字节流),现在要求接收的是一个字符流,则需要将字节流变为字符流才可以,InputStreamReader
- 小结
- 掌握 BufferedReader类的作用
- 可以使用 BufferedReader接收输入的数据
10.Scanner类
- 在 JDK1.5之后 JAVA提供了专门的输入数据类,此类可以完成 BufferReader类的功能,也可以方便的对输入数据进行验证,此类放在 java.util包中,此类是个工具类
- 如果要想输入空格的话,则就必须修改分隔符,将分隔符变成“\n”
- Scanner这个类虽然可以接收各种类型,但是对于日期型的数据却无法接收
- 如果要想接收 Date类型的数据,则只能通过字符串转型,但是在接收的时候依然可以使用 Scanner类中提供的方法进行验证
- 进行验证:public String next(Pattern pattern)
- 进行接收:public String next(String pattern)
- 还可以直接从文件中读取信息
- 在使用 Scanner读文件的时候,要考虑到换行的功能
- 小结
- 掌握 Scanner类的作用:方便的读取数据
- 在读取操作的时候一定要注意分隔符的影响
11.数据操作流
- 在 IO包中,提供了两个与平台无关的数据操作流
- 数据输出流:DataOutputStream
- 数据输入流:DataInputStream
- 通常数据输出流会按照一定的格式将数据输出,再通过数据输入流按照一定的格式将数据读入
- 如果要想使用数据操作流,则肯定要由用户自己指定数据的保存格式,必须按指定好的格式保存数据,才可以使用数据输入流将数据读取出来
- DataOutputStream继承自 FilterOutputStream类(FilterOutputStream是 OutputStream的子类)同时实现了 DataOutput接口,在 DataOutput接口定义了一系列的写入各种数据的方法
- DataOutputStream接口定义了一系列的 writeXxx()的操作,可以写入各种数据类型的数据
- 要想使用 DataOutputStream写入数据的话,则必须指定好数据的输出格式
- 小结
- 随机读取访问很相似
- 两个接口:DataOutput接口、DataInput接口,这两个接口的操作彼此对应,而且以后还要使用
12.合并流
- 合并流:从概念上讲就是内容合并在一起了
- 合并流的主要功能就是将两个文件的内容合并成一个文件
- 主要操作的是内容
- SequenceInputStream类直接继承自 InputStream
13.压缩流
- ZIP是一种常见的压缩形式,在 Java中要想实现 ZIP的压缩需要导入 java.util.zip包,可以使用此包中的 ZipFile、ZipOutputStream、ZipInputStream、ZipEntry几个类完成操作
- 在 JAVA IO中不仅可以实现 ZIP压缩格式的输入、输出,也可以实现 JAR及 GZIP文件格式的压缩
- ZipEntry:在每一个压缩文件中都会存在多个子文件,那么这每一个的子文件在 JAVA中就使用 ZipEntry表示
- 在实例化 ZipEntry的时候,要设置名称,此名称实际上就是压缩文件中每一个元素的名称
- 如果要想完成一个文件或文件夹的压缩,要使用 ZipOutputStream类完成,ZipOutputStream是 OutputStream的子类,就是一个字节的输出流,此类的功能就是 ZIP格式输出的
- 在压缩文件中,每一个压缩的内容都可以用一个 ZipEntry表示,所以在进行压缩之前必须通过 puNextEntry设置一个 ZipEntry即可
- ZipFile:是一个专门表示压缩文件的类
- 在 Java中,每一个压缩文件都可以使用 ZipFile表示,还可以使用 ZipFile根据压缩后的文件名称找到每一个压缩文件中的 ZipEntry并将其进行解压缩操作
- ZipFile在实例化的时候必须接收 File类的实例,此 File类的实例是指向一个压缩的 *.zip文件
- ZipEntry对象,可以找到每一个 ZipEntry的输入流,但是 ZipInputStream并不能得到每一个输入流,所以需要使用 ZipFile,但是 ZipInputStream在取得每一个 ZipEntry的时候,不需要每一个 ZipEntry的名称
- 小结
- 压缩文件中每一个压缩实体都使用 ZipEntry保存,一个压缩文件中可能包含一个或多个的 ZipEntry对象
- 在 JAVA中可以进行zip/jar/gz三种格式的压缩支持,操作流程基本是一样的
- ZipOutputStream可以进行压缩的输出,但是输出的位置不一定是文件
- ZipFile表示每一个压缩文件,可以得到每一个压缩实体的输入流
14.回退流
- 回退:给了用户第二次读的机会
- 在 JAVA IO中所有的数据都是采用顺序的读取方式,即,对于一个输入流来讲都是采用从头到尾顺序读取的,如果在输入流中某个不需要的内容被读取进来,则只能通过程序将这些不需要的内容处理掉,为了解决这样的读取问题,在 Java中提供了一种回退输入流(PusbackInputStream、PushbackReader)可以把读取进来的某些数据重新退回到输入流的缓冲区中
- 使用 InputStream要使用 read()方法不断读取,是采用顺序的读取方式
- 回退操作同样分为字节和字符流
- 对于回退操作来说,提供了三个 unread()的操作方法,这三个操作方法与 InputStream类中的 read()方法是一一对应的
15.字符编码
- 在计算机世界里,任何的文字都是以指定的 编码方式存在的,在 JAVA程序的开发中最常见的是以下的几种:、GBK/GB2312、unicode、UTF
- ISO8859-1:编码属于单字节编码,最多只能表示 0~255的字符范围,主要在英文上应用
- GBK/GB2312:中文的国标编码,专门用来表示汉字,是双字节编码,GBK包括中文繁体,字库更大
- unicode:java中就是使用此编码式,也是最标准的一种编码,是使用16进制表示的编码,但此编码不兼容ISO8859-1编码
- UTF:由于 nnicode不支持 ISO8859-1编码,而且容易占用更多的空间,而且对于英文字母也需要使用两个字节编码,这样使用 unicode不便于传输和存储,因此产生了 utf编码,utf编码兼容了 ISO8859-1编码,同时也可以用来表示所有的语言字符,不过 utf编码是不定长编码,每一个字符的长度从 1~6个字节不等,一般在中文网页中使用此编码,因为这样可以节省空间
- 如果没有处理好编码的事情,则肯定在程序中出现乱码
- 乱码产生的根本原因就是字符编码不统一造成的
- 小结
- 了解几种常用的编码特点
- 理解乱码是如何产生的
16.对象序列化
- 什么叫对象序列化:一个对象产生之后实际上是在内存中为其开辟了一个存储空间,方便存储信息
- 对象序列化:就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便的实现对象的传输或存储
- 如果一个类的对象想被序列化,则对象所在的类必须实现 java.io.Serializable接口
- Serializable接口中没有一个方法,此接口属于一个标识接口,表示具备了某种能力
- 被序列化了的对象,变为二进制 byte流
- 对象的序列化和反序列化
- 要想完成的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)
- 使用对象输出流输出序列化对象的步骤,有时也称为序列化,而使用对象输入读入对象的过程,有时也称为反序列化
- 对象序列化依靠:ObjectOutputStream,对象反序列化依靠:ObjectInputStream
- ObjectOutputStream类的使用形式与 PrintStream非常的相似,在实例化时也需要传入一个 OutputStream的子类对象,之后根据传和的 OutputStream子类的对象不同,输出的位置也不同(装饰模式)
- SerialVersionUID:在对象进行序列化或反序列化操作的时候,要考虑 JDK版本的问题,如果序列化的 JDK版本和反序列化的 JDK版本不统一则就有可能造成异常,所以在序列化操作中引入了一个 SerialVersionUID的常量,可以通过此常量来验证版本的一致性,在进行反序列化时,JVM会把传来的字节流中的 SerialVersionUID与本地相应实体(类)的 SerialVersionUID进行比较,如果相同就认为是一致的,要以进行反序列化,否则就会出现序列化版本不一致的异常
- 【问题】对象序列化到底序列化了哪些东西:所有的对象拥有各自的属性值,但是所有的方法都是公共的,所以序列化对象的时候实际上序列化的就是属性
- Externalizable接口
- 使用Serializable接口可以方便的序列化一个对象,但是在序列化操作中也提供了另外一种序列化机制:Externalizable接口
- 被 Serializable接口声明的类其对象的内容都将被序列化,如果现在用户希望可以自己指定序列化的内容,则可以让一个类实现 Externalizable接口
- 写入方法:void writeExternal(ObjectOutput put) throws IOException
- 读取方法:void readExternal(ObjectInput in) throws IOExcetion,ClassNotFoundExceteption
- 在使用 Externalizable接口的时候需要在被序列化的类中定义一个无参构造函数,因为此接口在进行反序列化的时候,会先用类中的无参构造方法为其进行实例化,之后再将内容分别设置到属性之中
- transient关键字:当使用 Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化的话,则可以使用 transient关键字进行声明
- transient + Serializable接口完成可以取代 Externalizable接口的功能
- 序列化一组对象
- 对象输出时只提供了一个对象的输出操作(writeObject(Object obj)),并没有提供多个对象的输出,所以如果现在要同时序列化多个对象的时候就可以使用对象数组进行操作,因为数组属于引用数据类型,所以可以直接使用 Object类型进行接收
- 如果要保存多个对象,则最好使用对象数组的形式完成
- 数组保存的数据有限,所以为了解决这样的问题,Java中引入了类集框架解决数组的存储限制问题
- 小结
- 对象序列化的作用:对象序列化并不一定都向文件中保存,也有可能面向于其它的输入或输出
- 被序列化的类必须实现 Serializable接口,如果某个属性不希望被保存下来,则可以使用 transient关键字声明
- ObjectOutputStream序列化对象,ObjectInputStream反序列化对象
- Externalizable接口的作用:开发人员手工实现序列化的操作
- 使用序列化保存一组对象的时候要使用对象数组的形式操作