Java 编程入门(中)

面向对象 | 类 | 异常处理 | IO

Posted by Paradise on April 12, 2021

教材链接:https://book.douban.com/subject/11534743/

示例代码:https://pan.baidu.com/s/1EQW8Ijyqvak0vxscaMfjtg | 提取码:k3q4

第七章 类和对象

7.1 面向对象概述

早期的程序开发使用结构化开发语言,但是随着软件的规模越来越大,已经不再适用。因此引入面向对象的开发思想,将所有要处理的问题抽象为对象。

  • 7.1.1 什么是对象
    • 通常将对象划分为动态部分和静态部分,即行为和属性。
  • 7.1.2 什么是类
    • 类是封装对象属性和行为的载体,具有相同属性和行为的一类实体称为类
  • 7.1.3 面向对象的特点
    • 封装:将对象的属性和行为封装起来,对用户隐藏起细节;
    • 继承:类与类之间有关联,如果超市类和售货员类;继承是关联的一种。当处理一个问题时,可以将有用的类保留下来,遇到类似的问题可以拿来复用,这就是继承。继承利用了同类对象之间的共有属性,减少开发工作。
    • 多态:将父类对象应用与子类的特征,就是多态。继承的过程中的实例化,即为多态。

7.2 类

  • 7.2.1 类的构造方法
    • 在类型中除了成员方法,还有一种特殊的方法,称为构造方法。对象的创建通过构造方法完成,每实例化一个对象,类会自动调用构造方法。
    • 构造方法必须与类同名,构造方法没有返回值,但是与一般方法不同,不需要关键void进行声明。定义构造方法的语法:
      • public classname(){}
    • 示例:构建AnyThting类。
  • 7.2.2 类的主方法
    • 主方法是类的入口,提供了程序的流程控制:
      • public static void main(String args[]){}
    • 主方法是静态的。要直接在程序中调用的其他方法,也必须是静态的;
    • 主方法没有返回值,主方法的形参为数组。
    • 示例:创建TestMain类。
  • 7.2.3 成员变量
    • 成员变量对应于对象的属性;
    • 使用private关键字声明成员变量,否则为局部变量;
    • 示例:创建Book类;
  • 7.2.4 成员方法
    • 成员方法对应于对象的行为;
    • 成员方法定义格式:
      • 极限修饰符 返回值类型 方法标识符(参数类型 参数
      • ` 标识符){`
      •         方法体(语句块);
      •         return 返回值;
      • }
    • 示例:参考上节的Book类;
  • 7.2.5 局部变量
    • 示例:参考上节的Book类;
  • 7.2.6 局部变量的有效范围
    • 局部变量的作用域从该变量的声明到该变量的结束为止(可理解为大括号中的范围);
    • 互不嵌套的作用域(大括号)可以声明两个同类型、同名称的局部变量;
  • 7.2.7 静态变量、常量和方法
    • 由static修饰的变量、常量和方法称为静态的;也称为静态成员;
    • 静态:在处理问题时,可能需要两个类共享一个数据。这是可以通过类名和’.’运算符调用;
    • 不能将方法体内的局部变量声明为静态;
    • 对类进行初始化,可以在类中划分静态区域:
      • public class example{
      •         static{
      •                 //初始化变量
      •         }
      • }
    • 示例:创建StaticTest类。
  • 7.2.8 极限修饰符
访问包位置 本类 本包其他类或子类 其他包的类或子类
private 可见 不可见 不可见
protected 可见 可见 不可见
public 可见 可见 可见
  • 7.2.9 this关键字 +成员变量可以与成员方法中的形参同名,为了区分,可以使用this.指定成员变量;
  • 7.2.10 范例:自定义图书类,创建Books类。
  • 7.2.11 范例:温度单位转换工具,创建CelsiusConverter类。

7.3 对象

  • 7.3.1 对象的创建
    • 格式:classname objectname = new classname(args[]);
  • 7.3.2 访问对象的行为和属性
    • 引用格式:obj.类成员
    • 示例:创建TransferProperty类。
  • 7.3.3 对象的引用
    • 对Book类的引用:Book book; //不一定要与一个新对象相关联
  • 7.3.4 对象的比较
    • 使用 == 运算符比较和使用equals方法比较;
    • 示例:创建Compare类。
  • 7.3.5 对象的销毁
    • 当对象的生命周期结束,占用的内存会被回收;
    • 被回收的情况:当对象引用超过其作用范围(该作用域执行结束),这个对象将视为垃圾;将对象赋值为null。
  • 7.3.6 范例:略。

7.4 经典范例

  • 汉诺塔问题求解,创建HanoiTower类。

第八章 接口、继承与多态

继承和多态可以使程序的架构更加有弹性,减少代码的冗余度。多态机制可以动态调整对象的调用,降低对象之间的依存关系。同时,为了优化继承和多态,一些类除了继承父类,还使用接口的形式。Java中的类可以同时实现多个接口,接口被用来建立类与类之间关联的标准。

8.1 接口的使用

Java只支持单重继承,不支持多继承,即一个类只能有一个父类。但是在实际 中需要使用多继承来解决问题,因此Java提供了接口来实现多继承功能。

  • 8.1.1 接口的定义
1
2
3
4
5
6
7
8
// 使用interface关键字定义一个接口
[修饰符] interface 接口名 [extends 父接口名列表]{
    //接口体:
    [public] [static] [final] 变量名;
    [public] [abstract] 方法;
}

// 示例:定义一个计算圆的周长和面积的接口:ICalculate.java
  • 8.1.2 接口的实现
    • 接口定义后,就可以在类中实现该接口,使用了implements关键字:
      • [修饰符] class <类名> [extends 父类名] [implements 接口列表]{}
    • 示例:创建Cire类,实现8.1.1的接口;
  • 8.1.3 范例:图片的不同格式储存
    • 首先编写ImageSaver接口,在该接口中定义save方法;
    • 然后在项目中创建GIFSaver类,实现ImageSaver接口;
  • 8.1.4 范例:为汽车增加GPS功能
    • 在项目中创建Car类,并定义car的属性和方法;
    • 在项目中编写GPS接口,定义getLocation方法;
    • 在项目中编写GPSCar类,继承Car类并实现GPS接口;

8.2 类的继承

  • 8.2.1 继承的实现
    • 使用extends关键字显式指定继承的父类:
      • [修饰符] class 子类名 extends 父类名{类体}
    • 示例:创建Bird类,并创建Pigeon类继承Bird类。
  • 8.2.2 继承中的重写
    • 重写也称覆盖,当子类继承父类中所有可能被子类访问的成员方法时,子类的成员方法如果与父类方法同名,则发生重写。重写允许同一方法在不同的子类变现不同行为。
    • 示例:创建Animal父类,创建Dog子类,重写父类的cry方法。
  • 8.2.3 使用super关键字
    • 子类可以继承父类的非私有(不是用private声明的)成员变量和成员方法。但是如果子类成员变量(或方法)与父类成员(或方法)同名,则父类成员变量被隐藏。
    • 如果要访问父类中被隐藏的成员方法或变量,可以使用super关键字。以下是super关键字的两种用法:
      • 在子类构造方法中用super关键字调用父类构造方法
        • super([参数列表]); //父类构造方法的参数列表
        • 示例:创建Beast类和Tiger类;
      • 操作被隐藏的成员变量或被重写的成员方法
        • super.成员变量名;
        • super.成员方法名([参数列表]);
        • 示例:在上一节例子中添加。
  • 8.2.4 范例:创建Employee、Manager和Test类。
  • 8.2.5 范例:重写父类的方法,见上一个范例。

8.3 多态

  • 8.3.1 什么是多态
    • 在Java语言中,通常使用方法的重载(Overloading)和重写(Overriding)实现类的多态性。
    • 重写实现多态性是因为子类方法与父类方法名称相同但功能不同;
    • 重载是指一个类中出现多个方法名相同,但参数个数或参数类型不同的方法。
    • 示例:创建Calculate类。
  • 8.3.2 范例:计算几何图形的面积 +创建抽象类Shape,然后创建Circle、Rectangle继承Shape,最后创建类testShape测试两个子类。
  • 8.3.3 范例:汽车销售市场
    • 创建抽象类Car,然后创建子类BMW、Benz,然后创建CarFactory类,根据指定车型创建对象,最后创建Customer类进行测试。

8.4 经典范例

  • 8.4.1 使用Comparable接口自定义排序
  • 8.4.2 动态设置类的私有域

第九章 类的高级特性

高级特性,如包、内部类等;包在管理繁杂的类文件,解决类的重名问题,控制访问权限,等方面有重要作用;Java的一个更有效的隐藏细节的技巧是使用内部类。将内部类中的方法设置为类最小范围的修饰极限,就可以隐藏内部类的细节。

9.1 抽象类

  • 抽象类只声明方法的存在,而不具体实现。抽象类不能被实例化,只能被继承。
  • 声明格式:
    • abstract class 类名{
    • 类体
    • }
  • 在抽象类中声明没有实际意义的,必须由子类重写的抽象方法:
    • abstract <返回值类型> 方法名(参数列表);
  • 注意:抽象方法不能使用private或static进行修饰;如果一个类中定义了抽象方法,那么该类只能定义为抽象类。
  • 示例:创建抽象类Fruit,创建子类Apple、Orange,并在Farm中测试。

9.2 内部类

即,在类中再定义一个类;可分为成员、局部以及匿名内部类。

  • 9.2.1 成员内部类
    • 格式:
      • public class OuterClass{
      •         private class InnerClass{
      •                 //...
      •         }
      • }
    • 在内部类中可以自由使用外部类的成员变量和成员方法,尽管这类成员被修饰为private。同时内部类的实例绑定在外部类的实例上,如果在外部类中初始化一个内部类对象,那么该内部类对象就会被绑定在外部类对象上。
    • 内部类初始化方式和其他类相同,都是使用new关键字。
    • 示例:创建OuterClass类。
    • 示例:在内部类中使用this关键字,创建TheSameName类。
  • 9.2.2 局部内部类
    • 局部内部类是指在类的方法中定义的类,作用域在方法体之内。
    • 示例:创建SellOutClass类,在其sell方法中创建局部内部类Apple。
  • 9.2.3 匿名内部类
    • 不给内部类取名,直接以对象名代替,简化代码增加可读性。
    • 基本格式:
      • return new A(){
      •         //类体
      • }
    • 匿名内部类编译后产生“外部类名$序号.class”文件。
    • 示例:创建OutString类。
  • 9.2.4 静态内部类
    • 在内部类前添加符static,则是静态内部类。一个静态内部类中可以声明 static 成员,而非静态内部类中不能声明静态成员。
    • 静态内部类的最大特点,就是不可以使用外部类的非静态成员,因此在程序开发中比较少用。
    • 可以认为普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象,但如果内部类被定义为static时,则具有更多的限制。静态内部类具有两个特点:
      • 创建静态内部类对象,不需要其外部类对象;
      • 不能从静态内部类的对象访问非静态外部类对象。
    • 示例:创建StaticInnerClass类。
  • 9.2.5 内部类的继承
    • 创建OutputInnerClass类,使其继承ClassA中的内部类ClassB:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
        public class OutputInnerClass extends ClassA.ClassB{
            public OutputInnerClass(ClassA a){
                a.super();
            }
        }
        class ClassA{
            class ClassB{
            }
        }
      
  • 9.2.6 范例:局部内部类设置闹钟,9_2_6.java;
  • 9.2.7 范例:静态内部类求极值,9_2_7.java。

9.3 Class类与Java反射

通过Java反射机制,可以访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。在java.lang.reflect包中提供了对该功能的支持。

Java的所有类默认继承了Object类,在Object类中定义了一个getClass方法,该方法返回一个类型为Class的对象,通过该对象可访问类的描述信息:Class textFieldC = textField.getClass(); 具体textField对象的组成和成员方法见文中表格。

  • 9.3.1 访问构造方法
    • 通过下列一组方法访问构造方法时,将返回Constructor类的对象或数组。
    • 每个Constructor对象代表一个构造方法,利用Constructor对象可操作对应的构造方法:
      • getConstructor()
      • getConstructor(Class<?>...parameterTypes)
      • getDeclaredConstructor()
      • getDeclaredConstructor(Class<?>...parameterTypes)
    • Constructor类提供的常用方法:略。
    • 示例:创建MoreConstructor类,在AccessConstructor中测试。
  • 9.3.2 访问成员变量
    • 在通过下列一组方法访问成员变量时,将返回Field类型对象或数组。每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。
      • getFields()
      • getField(String name) //访问指定的成员变量
      • getDeclaredFields()
      • getDeclaredField(String name) //访问指定的成员变量
    • Field类提供的方法:略。
    • 示例:创建MoreFields类,在其中声明不同访问权限的成员变量,在AccessFields类中测试。
  • 9.3.3 访问方法
    • 通过下列方法访问方法,返回Method类的对象:
      • getMethods()
      • getMethod(String name, Class<?>...parameterTypes)
      • getDeclaredMethods()
      • getDeclaredMethod(String name, Class<?>...parameterTypes)
    • Method类提供的方法:略。
    • 示例:略。
  • 9.3.4 范例:运用反射查看类的成员,创建ClassDeclarationViewer类。

9.4 经典范例

  • 利用反射重写toString方法,创建StringUtils类。

第十章 Java集合类

集合可以看作一个容器。Java提供不同的集合类,这些类具有不同的储存对象的方式,并提供相应的方法方便用户对集合进行遍历;通过本章:掌握集合类接口的常用方法,掌握集合类接口的实现类,掌握迭代器的创建和使用。

10.1 集合类概述

  • Java的java.util包中提供了一些集合类,这些集合类又称为容器。容器的概念与数组类似,与数组不同在于,集合的长度可变,而Java数组的长度不可变。
  • 数组用来存放基本类型的数据,集合用来存放对象的引用。
  • 常用的集合有List集合、Set集合、Map集合等,其中List和Set实现了Collection接口。各接口还提供了不同的实现类。
  • 上述集合类的继承关系:(向上继承)
    • java.lang.Object
      • Collection
        • Set
          • HashSet, TreeSet
        • List
          • ArrayList, LikedList
      • Map
        • HashMap, TreeMap

10.2 集合类接口的常用方法

Collection接口是层次结构中的根接口。构成Collection的单位称为元素。Collection接口通常不能直接使用,该接口提供添加和删除元素、管理数据的方法。这些方法对其子集合类Set和List是通用的。

  • 10.2.1 List接口的常用方法
    • add(int index, Object obj), void, 在指定位置添加对象;
    • addAll(int index, Collection coll), boolean, 添加集合类对象;
    • remove(int index), Object, 移除指定对象;
    • get(int index), Object, 获取指定对象;
    • indexOf(Object obj), int, 返回对象第一次出现的索引,不存在返回-1;
    • lastIndexOf(Object obj), int, 返回最后一次出现的索引或-1;
    • subList(int formIndex, int toIndex), List, 返回元素列表;
    • set(int index, E element), Object, 替换指定位置元素并返回原元素;
    • listIterator(), ListIterator, 返回列表迭代器;
    • 示例:set()与add()的区别,创建CollectionDemo类;
    • 示例:indexOf与lastIndexOf,在上例中添加。
  • 10.2.2 Set接口的常用方法
    • add(Object obj), boolean, 如果Set集合中不存在指定元素则添加;
    • addAll(Collection coll), boolean, 添加元素集合;
    • remove(Object obj), boolean, 将指定对象移出集合;
    • retainAll(Collection c), boolean, 保存Set集合与指定集合重复的内容
    • removeAll(Collection c), boolean, 移除Set集合与指定集合重复的内容
    • clear(), void, 清空集合;
    • iterator(), Iterator, 返回迭代器;
    • size(), int, 返回元素个数;
    • isEmpty(), boolean, 返回是否不包含元素;
    • 示例:创建SetDemo类。
  • 10.2.3 Map接口的常用方法
    • Map接口提供了将键映射到值的对象。一个映射不能包含重复的键,且每个键只能映射到唯一的值。
    • Map接口中的常用方法
      • put(key k, value v), Object, 向集合中添加键值对;
      • containskey(Object key), boolean, 返回是否含有某个键;
      • containsValue(Object value), boolean, 如果存在一个或多个键映射到指定值,则返回true;
      • get(Object key), Object, 返回某个指定键对应的值;
      • keySet(), Set, 返回所有键组成的Set集合;
      • values(), Collection, 返回所有值组成的Collection集合;
    • 示例:创建MapDemo类。
  • 10.2.4 范例:用List集合传递学生信息
  • 10.2.5 范例:Map集合二级联动

10.3 集合类接口的实现类

  • 10.3.1 List接口的实现类
    • 使用List集合,通常需要声明为List类型,然后通过List接口的实现类来对集合进行实例化。List接口的常用实现类有ArrayList和LinkedList。
    • ArrayList类,实现了可变数组,允许所有元素,包括null。可以根据索引位置对集合进行快速访问。缺点是向指定索引位置插入对象或删除对象的速度较慢。语法格式如下:
      • List<String> list = new ArrayList<String>();
    • LinkedList类,采用链表结构保存对象。优点是插入和删除对象的速度比ArrayList高。但是对于随机访问集合中的对象,效率较低。语法格式:
      • List<String> list = new LinkedList<String>();
    • 示例:创建Gather类。
  • 10.3.2 Set接口的实现类
    • 要使用Set集合,通常需要声明为Set类型,然后通过Set接口的实现类来实例化。Set接口的实现类常用有HashSet和TreeSet类。语法格式:
      • Set<String> set = new HashSet<String>();
      • Set<String> set = new TreeSet<String>();
    • Set集合中的对象是无序的,遍历Set集合的结果与插入Set集合的顺序不同
    • 示例:创建People类,并在testPeople类中测试。
  • 10.3.3 Map接口的实现类
    • Map接口常用的实现类有HashMap和TreeMap。通常建议使用HashMap实现Map集合,因为HashMap类实现对于添加和删除映射关系的效率更高。HashMap是基于哈希表的Map接口实现,HashMap通过哈希码对其内部的映射关系进行快速查找。虽然HashMap效率较高,但是集合对象没有对象,而TreeMap类实现的集合对象存在顺序。
    • HashMap类,基于哈希表的Map接口实现,该实现提供所有可选的映射操作,并允许使用null和null键,但必须保持键的唯一性。
    • TreeMap类,该类不仅实现Map接口,还实现了java.util.SortedMap接口,因此集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系上性能不如HashMap。由于TreeMap类实现的Map集合中的映射关系是根据对象按照一定顺序排列的,因此不允许键对象为null。
    • 示例:创建Emp类,在testEmp类中测试。
  • 10.3.4 范例:for循环遍历ArrayList,创建GeneralForDemo类。
  • 10.3.5 范例:用动态数组保存学生姓名,略。

10.4 迭代器

  • 10.4.1 迭代器的创建和使用
    • Iterator接口位于java.util包下。接口定义了三个方法:
      • hasNext() | next() | remove():从迭代器指向的collection中移除迭代器返回的最后一个元素。
    • 示例:创建ListIteratorDemo类。
  • 10.4.2 范例:Iterator遍历ArrayList,创建IteratorDemo类。
  • 10.4.3 范例:ListIterator遍历ArrayList,创建InverseIteration类。

第十一章 异常处理

11.1 异常概述

异常类的继承关系(不完全):

1
2
3
4
5
Throwable:
    Error:
        AWTError/ IOErroe/ other subclass...
    Exception:
        IOException/ RuntimeException/ SQLException/ other subclass...

其中Exception类可以捕获,Error类为不被捕获的严重问题。

11.2 异常的分类

  • 11.2.1 可控式异常
    • Java中把可以预知的错误,例如文件读取、数据库操作等,在编译时就对程序中可能存在的错误进行处理,并给出具体的错误信息。这类错误称为可控式异常。
    • 常用的可控式异常:
      • IOException; I/O异常
      • SQLException; 数据库访问异常
      • ClassNotFoundException; 类没有找到异常
      • NoSuchFieldException; 类不包含指定名称的字段时产生的异常
      • NoSuchMethodException; 无法找到某一特定的方法时产生的异常
    • 示例:创建Example_01类。
  • 11.2.2 运行时异常
    • 一些错误不能被编译器检测到,例如进行除法运算时除数为零,试图将不是由数字组成的字符串强制转换为整型,等。这些异常称为运行时异常。
    • 常用的运行时异常:
      • IndexOutOfBoundsException; 集合或数组索引超出范围
      • NullPointerException; 当程序在需要对象的地方使用null时发生的异常
      • ArithmeticException; 出现异常的运算条件时发生的异常
      • IllegalArgumentException; 向方法传递了不合法的参数时发生的异常
      • ClassCastException; 试图将对象强制转换为不是实例的子类时发生的异常
    • 示例:创建Example_02类。
  • 11.2.3 范例:算术异常,创建ExceptionTest类。
  • 11.2.4 范例:数组下标越界异常,创建ArrayExceptionTest类。

11.3 获取异常信息

  • Java中的java.lang.Throwable类是所有异常类的超类,该类提供了获得异常信息的方法:
    • String getLocalizedMessage(); 获得此Throwable的本地化描述
    • String getMessage(); 获得此Throwable的详细消息字符串
    • void printStackTrace(); 将此Throwable及其栈踪迹输出至标准错误流
    • String toString(); 获得此Throwable的简短描述
  • 示例:创建Example_03类。

11.4 处理异常

  • 11.4.1 使用try-catch处理异常
  • 11.4.2 使用try-catch-finally处理异常
    1
    2
    3
    4
    5
    6
    7
    8
    
      try{
          需要执行的语句
      }catch{
          对异常进行处理的语句
      }finally{
          一定会被执行的语句
      }
      // 示例:创建Example_04类。
    
  • 11.4.3 使用try-finally处理异常
    • 示例;创建Example_05类。

11.5 抛出异常

除了用try-catch-finally处理异常外,还可以用抛出异常。

  • 11.5.1 使用throws声明抛出异常
    • throws通常用于方法的声明,当方法中可能存在异常,而不想在方法中对异常进行处理时,可以用throws声明抛出异常,然后在其他方法中进行处理
    • 声明格式:
      • 极限修饰符 方法名(形参列表) throws 异常类1, 异常类2, ...,异常类n{方法体}
    • 异常类可以是Java内置异常类或自定义异常类。
    • 示例:创建Example_06类。
  • 11.5.2 使用throw语句抛出异常
    • 通常系统会自动抛出异常,但是有时希望程序自行抛出异常。
    • throw语句常用在方法中,抛出异常的实例,通常与if语句结合使用。
    • throw语句格式:
      • throw new Exception("对异常的说明");
    • 示例:创建Example_07类。
  • 11.5.3 范例:方法中抛出异常,创建Example_08类。
  • 11.5.4 范例:方法上抛出异常,创建Example_09类。

11.6 自定义异常

  • 11.6.1 创建自定义异常类
    • 创建自定义异常类需要继承自Exception类,并提供一个含有String类型形参的构造方法,该形参就是描述异常的信息,可以通过getMessage方法获取。格式如下:
      1
      2
      3
      4
      5
      
        public class NewException extends Exception{
            public NewException(String e){
                super(s);
            }
        }
      
  • 11.6.2 使用自定义异常类
    • 示例:创建Example_10类。

11.7 异常的使用原则

  • 不要过多使用,会增加系统的负担;
  • 使用try-catch语句捕获异常时,需要对异常做出处理;
  • 语句块覆盖范围不要太大,这样不利于异常的分析;
  • 一个抛出异常的方法被覆盖时,覆盖它的方法必须抛出相同的异常或子异常。

11.8 经典范例

  • 数据库操作异常,创建DBExceptionTest公共类。

第十二章 输入输出

将程序创造更改的数据保存到磁盘文件,或在程序运行时读取磁盘文件。通过本章:了解Java中流的概念;掌握输入输出流的分类和使用方法;掌握带缓存的输入输出流的使用法;理解ZIP压缩输入输出流的应用。

12.1 流概述

  • “流”是一组有序的数据序列,输入/输出流提供一条通道程序,可以使用这条通道把源中的字节序列送到目的地。
  • 源除了磁盘文件,还可以是键盘、鼠标、内存或显示器等。
  • 输入流的来源和输出流的目的地:文件、网络、压缩包、其他。

12.2 输入 / 输出流

Java中定义了许多负责输入输出的类,存放在java.io包中。其中所有输入流都是抽象类InputStream(字节输入流)或Reader(字符输入流)的子类;所有输出流都是抽象类OutputStream或Writer的子类。

  • 12.2.1 输入流
    • InputStream抽象类的子类:AudioInputStream | ByteArrayInputStream | StringBufferInputStreaam | FileInputStream | FilterInputStream | InputStream | ObjectInputStream | SequenceInputStream | PipedIInputStream
    • InputStream类的常用方法:(不是所有子类都支持以下所有方法)
      • read(); 从输入流读取下一字节。返回八位字节值。如果没有下一位返回-1
      • read(byte[] b); 从输入流读取指定长度的字节,以整数形式返回字节值
      • mark(int readlimit); 放置输入流失效标记,读取一定字节数后失效
      • reset(); 将输入流指针重置到当前所做的标记处
      • skip(long n); 跳过输入流上的n个字节,返回实际跳过的字节数
      • markSupported(); 当前输入流是否支持mark和reset操作
      • close(); 关闭输入流并释放所有相关的系统资源
    • Reader抽象类的子类:CharArrayReader | BufferedReader | FilterReader | InputStreamReader | PipedReader | StringReader
    • Reader类的常用方法与InputStream类相似。
    • Java中的字符是Unicode编码的,是双字节的。InputStream处理字节的形式用来处理文本不太方便。Reader类在处理字符时更简单。
  • 12.2.2 输出流
    • OutputStream抽象类的子类:ByteArrayStream | FileOutputStream | FilterOutputStream | ObjectOutputStream | OutputStream | PipedOutputStream
    • OutputStream类的常用方法:(均返回void)
      • write(int b); 将指定字节写入输出流
      • write(byte[] b); 将b.length个字节从指定的byte数组写入输出流
      • write(byte[] b, int off, int len); 将指定byte数组从偏移量off开始写入len个字节
      • flush(); 彻底完成输出并清空缓存区
      • close(); 关闭输出流
    • Writer抽象类的子类:BufferedWriter | CharArrayWriter | FilterWriter | OutputStreamWriter | PipedWriter | PrintWriter | StringWrite
  • 12.2.3 范例:显示指定类型的文件,创建FilesList类。
  • 12.2.4 范例:查找替换文本文件内容,创建ReplaceTool类。

12.3 File类

File类是java.io包中唯一代表磁盘文件本身的对象,而文件是数据流最常用的数据媒体。File类定义了一些与平台无关的方法来操作文件,如创建、修改、重命名等。

File对象主要用来获取文件信息,如路径、长度、读写权限等。

  • 12.3.1 文件的创建和删除
    • File类三种创建方式:
      • new File("C:/....../test.txt");
      • new File(String parent, String child); //分别代表父路径和子路径
      • new File(File f, String child); //f代表父路径对象
    • 创建时如果指定文件已经存在,可通过delete方法将该文件删除后重建。
    • 示例:创建FileTest类。
  • 12.3.2 获取文件信息
    • File类常用方法:
      • getName(); 获取文件名
      • canRead(); 是否可读
      • canWrite(); 是否可写
      • exists(); 是否存在
      • length(); 字节长度
      • getAbsulotePath(); 获取绝对路径
      • getParent(); 获取父路径
      • isFile(); 是否存在
      • isDirectory(); 是否是一个目录
      • isHidden(); 是否隐藏
      • lastModified; 最后修改时间 ·示例:创建FileMethod类。
  • 12.3.3 范例:文件批量重命名,创建RenameTool类。
  • 12.3.4 范例:批量移动文件,创建FileMoveTool类。

12.4 文件输入 / 输出流

使用文件输入/输出流将内存中的数据永久保存到文件中。

  • 12.4.1 FileInputStream与FileOutputStream类
    • 分别继承了InputStream和OutputStream类,用于操作磁盘文件。
    • 常用的构造方法:
      • FileInputStream(String name) //形参代表文件名
      • FileInputStream(File file) //形参为File对象
    • 示例:创建FileIOStream类。
  • 12.4.2 FileReader类和FileWriter类
    • 使用FileOutputStream写文件或者使用FileInputStream读文件时,都是对字节或者字节数组进行读取。由于汉字占两个字节,使用字节流读写容易出现乱码。可以使用FileReader类和FileWriter类。
    • 示例:创建ReadNWriteFile类。
  • 12.4.3 范例:删除文件夹中的所有文件,创建DeleteAllFile类。

12.5 带缓存的输入 / 输出流

缓存可以说是I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区才可能执行skip(), mark(), reset()等操作。

  • 12.5.1 BufferedInputStream类和BuffueredOutputStream类
    • BufferedInputStream类可以对任意InputStream类进行带缓存区的包装以达到性能的优化。
    • BufferedInputStream类的两个构造函数:
      • BufferedInputStream(InputStream in); //默认缓存区大小为32字节
      • BufferedInputStream(InputStream in, int size); //自定义大小
    • 从构造函数可以看出,BufferedInputStream对象位于InputStream类之前:
      • File –> InputStream –> BufferedInputStream –> 目的地
    • BufferedOutputStream类的内容一一对应,多了一个flush()方法,用于将将缓存区的数据强制输出完。flush()方法只对使用了缓存区的OutputStream对象有效,即使不使用flush,在close()之前,系统也会将缓存区的文件刷新到磁盘文件中。
  • 12.5.2 BufferedReader类和BuffueredWriter类
    • 分别继承Reader类和Writer类,以row为单位进行输入和输出:字符数据–>BufferedWrite–>OutputStreamWriter–>OutputStream–>文件
    • BufferedReader类常用方法:
      • read(); 读取单个字符
      • readLine(); 读取一行文本,返回为字符串
      • write(String s, int off, int len); 写入字符串的某一部分
      • flush(); 刷新该流的缓存
      • newLine(); 写入一个行分隔符(换行符)
    • 示例:创建BufferedTest类。
  • 12.5.3 范例:略。

12.6 数据输入 / 输出流

  • 数据输入输出流(DataInputStream和DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型。
  • 构造方法:
    • DataInputStream(InputStream in);
    • DataOutputStream(OutputStream out);
  • DataOutputStream类提供了三种写入字符串的方法:
    • writeBytes(String s);
    • writeChars(String s);
    • writeUTF(String s);
  • Java中的字符是Unicode编码,是双字节的,writeBytes只将每个字符的低字节写入目标设备中;writeChars将整个字符写入;writeUTF将字符串按照UTF编码后的字节长度写入目标设备,然后再写入UTF编码。
  • DataInputStream类只提供了readUTF()方法。因为,在一个连续的字节流中读取一个字符串,如果没有特殊标记作为结尾,无法确定读到什么位置结束。而在DataOutputStream的writeUTF方法中,写入了字符串长度,因此可以通过readUTF准确地读回字符串。
  • 示例:创建DataIOStream公共类。

12.7 ZIP压缩输入 / 输出流

使用ZIP压缩文件可以节省储存空间。使用java.util.zip包中的ZipOutputStream和ZipInputStream类可以实现对文件的压缩和解压缩。

Java实现了I/O数据流与网络数据流的单一接口,因此数据的压缩、网络传输和解压缩的实现比较容易。

向ZIP文件内部读取或写入文件,需要找到对应文件的“目录进入点”,通过ZipEntry类实现。

  • 12.7.1 压缩文件
    • ZipOutputStream类,构造函数:ZipOutputStream(OutputStream out);
    • ZipOutputStream类常用方法:
      • putNextEntry(ZipEntry e); 开始写入一个新的ZipEntry,并将流内的位置移至此入口所指数据的开头。
      • write(byte[] b, int off, int len); 将字节数组写入当前ZIP条目数据
      • finish(); 完成写入并关闭对应的OutputStream
      • setComment(String comment); 可设置ZIP文件的注释文字
    • 示例:创建writeZIP类。
  • 12.7.2 解压缩ZIP文件
    • ZipInputStream类构造方法:ZipInputStream(InputStream in);
    • ZipInputStream类常用方法:
      • read(byte[] b, int off, int len); 读取目标数组b内off偏移量的位置
      • available(); 判断是否已经读取完当前entry的数据,已读完返回0
      • closeEntry(); 关闭当前ZIP条目并定位流,以读取下一个条目
      • skip(long n); 跳过当前ZIP条目中指定的字节数
      • getNextEntry(); 读取下一个ZipEntry,并将流内的位置移至其开头
      • createZipEntry(String name); 以指定的name创建一个新的entry
    • 示例:创建Decompressing类。
  • 12.7.3 范例:略。