java高级-集合和IO

学习笔记 专栏收录该内容
21 篇文章 0 订阅
泛型
    * 概述
        JDK1.5后出现的新特性
        解决程序中的安全问题
        减少了程序人员的代码量
        泛型出现以后,将运行时期的安全隐患,暴露在编译时期
        避免了强制类型转换
    * 格式:
        * 泛型类: 
            声明:class 类名<T>{         //T被称为类型参数变量,T可以为任意合法标识符
            使用:
                extends 类名<实际类型>{ //使用时传递的类型被称为实际类型参数,如果不写实际类型,则默认为Object
                new 类名<实际类型>(); 
        * 泛型方法: 
            修饰词 <T> 返回值 方法名称(参数列表){   //参数可使用T,如save(T t)或save(Class<T> clazz).返回值也可以用T
        集合就是泛型类: List<String> list = new ArrayList<String>();
        注意:
            声明时 类名<T> 称为泛型类型
            使用时 ArrayList<Integer> 称为 参数化的类型ParameterizedType
            T相当于变量名,可以为任意合法标识符
            静态方法中不能使用类的泛型参数,只能使用方法声明中的泛型,因为类的泛型参数在创建对象时才指定
    * 通配符
        ? 表示通配符,表示任意类型,例:Class<?> clazz = this.getClass();
        ? Extends E:可以接收E类型和E的子类型。
        ? Super E:可以接收E类型或者E的父类型。
    * 名词解释:
        * 泛型擦除:
            泛型是编译时期的安全机制,编译时通过泛型机制,编译器多了对元素类型进行检查的步骤,如果检查通过,产生的class文件是不带有泛型的。(在编译阶段使用泛型,运行阶段取消泛型,即擦除)
        * 泛型补偿:
            JVM在运行时,会获取元素的类型,并用该类型对元素进行转换即可。
    * 在反射中的使用情景: 
        * 类的泛型参数 : 泛型转换(通过子类对象获得父类类型参数变量的运行时实际类型的class对象)
            //获得带泛型信息的父类type对象
            ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
            //获得第一个泛型参数的运行时实际类型的class对象
            Class clazz = (Class) type.getActualTypeArguments()[0];
        * 方法的泛型参数 : 通过参数限定返回值类型
            public <T> T getInstance(Class<T> clazz){



集合
    * 概述:
        集合是一个容器,用来存储对象.长度可变化
    * 理解: 
        提供了多种查询,添加,删除数据的方法
        每一个容器因为自身的数据结构不同,进行了单独的描述和对象的封装,因为这些对象有共性就进行向上抽取,形成了集合框架
        学习体系结构的技巧:查阅顶层内容、建立低层对象
        注意: 集合存储的是对象的引用,不是对象本身
    * 和数组的区别:
        1、数组定义时长度是固定的(必须明确元素类型和长度) 集合定义时,可以不用明确长度,长度是可变的。
        2、数组存储是同一类型的数据,集合存储的是对象,而对象可以是任意类型
        3、数组可以存储基本数据值,而集合只能存对象(基本类型会先装箱)。
    * 体系结构
        * 体系
            Collection<E>
                List
                    ArrayList
                    LinkedList
                    Vector
                Queue
                    LinkedList
                Set
                    HashSet
                    TreeSet
            Map<K,V>
                HashMap
                    LinkedHashMap
                Hashtable
                    Properties
                TreeMap
        * 相关类
            Iterator接口 : 迭代器,用于遍历集合
            Comparable接口 : 用于集合排序 : 自然顺序,排序的默认顺序由此接口指定
            Comparator接口 : 用于集合排序 : 比较器,自定义的排序顺序
            Collections类 : Collection的工具类
        * 说明:
            Collection : Collection 层次结构 中的根接口
            list(序列) : 有序的 collection. (有索引. 元素可重复)
            Set : 一个不包含重复元素的 collection. (无索引. 元素不可重复)
            Queue(队列) : 队列通常(但并非一定)以 FIFO(先进先出)的方式排序各个元素。(方便 移除队列的头和添加元素到队列尾部)
            ArrayList : List 接口的大小可变数组的实现。(有索引. 查找快,增删慢. 元素可重复,可为null. 不可同步)
            LinkedList : List 接口的链接列表实现。实现 Queue 接口,为 add、poll 等提供先进先出队列操作。(有索引. 查找慢,增删快. 元素可重复,可为null. 不可同步)
            Vector(向量) : Vector 类可以实现可增长的对象数组。(有索引. 元素可重复,不可为null. 可同步)
            HashSet : 实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。(无序的. 元素可为null,不可重复. 不可同步)
            TreeSet : 实现 Set 接口,该接口由 TreeMap 实例支持。(有序的. 元素被添加时就会进行排序. 元素可为null,不可重复. 不可同步)
            
            Map : 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射一个值。
            HashMap : 基于哈希表的 Map 接口的实现。(无序的. 键和值可为null. 不可同步)
            Hashtable : 实现一个哈希表,该哈希表将键映射到相应的值。(无序的. 键和值不可为null. 可同步)
            TreeMap : SortedMap 接口的基于红黑树的实现。(有序的. 元素被添加时就会进行排序. 键和值可为null. 不可同步)
            LinkedHashMap : Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。(有序的. 键和值可为null. 不可同步)
            Properties : Properties 类表示了一个持久的属性集(对应于Properties配置文件)。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 
            
            Set实质上是Map实例
            Vector 和 Hashtable已不赞成使用
            以上推荐使用的类都是不同步的,可使用Collections中的方法获取对应的同步对象
    * 特点
        Collection<E>       集合
            List                有索引. 元素可重复
                ArrayList           查找快,增删慢. 元素可为null. 不可同步
                LinkedList          查找慢,增删快. 元素可为null. 不可同步
                Vector              元素不可为null. 可同步
            Queue               队列,先进先出
                LinkedList
            Set                 无索引. 元素不可重复
                HashSet             无序的. 元素可为null. 不可同步
                TreeSet             有序的. 元素可为null. 不可同步(元素被添加时就会进行排序)
            
        Map<K,V>            映射
            HashMap             无序的. 键和值可为null. 不可同步
                LinkedHashMap       有序的. 键和值可为null. 不可同步
            Hashtable           无序的. 键和值不可为null. 可同步
                Properties          值的类型固定为字符串,用于操作Properties配置文件(与IO配合使用)
            TreeMap             有序的. 键和值可为null. 不可同步(元素被添加时就会进行排序)
        
        集合有两大体系,Collection接口及其子类又称单列集合,Map接口及其子类又称双列集合
        集合最常用子类ArrayList,LinkedList
        映射最常用子类HashMap,LinkedHashMap
        集合最常用操作:存放数据,获取数据,遍历,排序,数组的相互转换
        映射最常用操作:存放数据,获取数据,遍历
        有点难度的知识点 : 集合怎么判断对象是否相等,集合排序
        Properties类与IO配合使用,所以放到IO后讲



Collection接口及其子类          
    * Collection接口方法
         boolean add(E o) 
                确保此 collection 包含指定的元素(可选操作)。 
         boolean addAll(Collection<? extends E> c) 
                将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 
         void clear() 
                移除此 collection 中的所有元素(可选操作)。 
         boolean contains(Object o) 
                如果此 collection 包含指定的元素,则返回 true。 
         boolean containsAll(Collection<?> c) 
                如果此 collection 包含指定 collection 中的所有元素,则返回 true。 
         boolean isEmpty() 
                如果此 collection 不包含元素,则返回 true。 
         Iterator<E> iterator() 
                返回在此 collection 的元素上进行迭代的迭代器。 
         boolean remove(Object o) 
                从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 
         boolean removeAll(Collection<?> c) 
                移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 
         int size() 
                返回此 collection 中的元素数。 
         Object[] toArray() 
                返回包含此 collection 中所有元素的数组。 
         <T> T[] toArray(T[] a) 
                返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 
    * List接口方法
         void add(int index, E element) 
                在列表的指定位置插入指定元素(可选操作)。 
         E get(int index) 
                返回列表中指定位置的元素。 
         int indexOf(Object o) 
                返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回 -1。 
         int lastIndexOf(Object o) 
                返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回 -1。 
         E remove(int index) 
                移除列表中指定位置的元素(可选操作)。 
         E set(int index, E element) 
                用指定元素替换列表中指定位置的元素(可选操作)。 
    * Set接口方法:无特殊方法
    * 所有Collection子类相同的构造方法
        类名() 
            构造一个初始容量为 10 的空列表。 
        类名(Collection<? extends E> c) 
            构造一个包含指定 collection 的元素的列表
    * LinkedList
        * 常用方法:
            void addFirst(E o) 
                将给定元素插入此列表的开头。 
            void addLast(E o) 
                将给定元素追加到此列表的结尾。 
            E getFirst() 
                返回此列表的第一个元素。 
            E getLast() 
                返回此列表的最后一个元素。 
            E peek() 
                找到但不移除此列表的头(第一个元素)。 
            E poll() 
                找到并移除此列表的头(第一个元素)。 
            E removeFirst() 
                移除并返回此列表的第一个元素。 
            E removeLast() 
                移除并返回此列表的最后一个元素。 
    * TreeSet
        * 概述:对存储到这个集合中的对象,进行自然排序或指定比较器排序
        * 构造方法:
            TreeSet(Comparator<? super E> c) 
                构造一个新的空 set,该 set 根据指定的比较器进行排序。
            如果不使用带比较器的构造方法,则Set中存放的元素必须实现Comparable接口指定对象的自然顺序
        * 常用方法:
            E first() 
                返回已排序 set 中当前的第一个(最小)元素。 
            E last() 
                返回已排序 set 中当前的最后一个(最大)元素。 
    * 相关类
        * Iterator接口(java.util)
            * 对集合进行迭代的迭代器。
            * 常用方法
                 boolean hasNext() 
                          如果仍有元素可以迭代,则返回 true。 
                 E next() 
                          返回迭代的下一个元素。 
                 void remove() 
                          从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。 
        * Comparable接口(java.lang)
            * 概述
                由集合中存放的元素实现
                此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
                sort方法或TreeSet类不指定比较器,就会按照自然顺序排序,即通过此接口的compareTo方法进行排序
            * 常用方法
                int compareTo(T o) 
                    比较此对象与指定对象的顺序。
                    返回值分为三种:负数,0,正数. 0表示两个数相等
        * Comparator接口(java.util)
            * 概述
                可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
                还可以使用 Comparator 来控制某些数据结构(如 TreeSet 或 TreeMap)的顺序。
            * 常用方法
                 int compare(T o1, T o2) 
                    比较用来排序的两个参数。 
                    返回值分为三种:负数,0,正数. 0表示两个数相等
        * Collections类(java.util)
            * 操作Collection的工具类,完全由静态方法组成
            * 常用方法
                static <T extends Object & Comparable<? super T>> T  max(Collection<? extends T> coll) 
                    根据元素的自然顺序,返回给定 collection 的最大元素。 
                static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) 
                    根据指定比较器产生的顺序,返回给定 collection 的最大元素。 
                static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) 
                    根据元素的自然顺序 返回给定 collection 的最小元素。 
                static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) 
                    根据指定比较器产生的顺序,返回给定 collection 的最小元素。 
                static void reverse(List<?> list) 
                    反转指定列表中元素的顺序。 
                static <T> Comparator<T> reverseOrder(Comparator<T> cmp) 
                    返回一个比较器,它强行反转指定比较器的顺序。 
                static <T extends Comparable<? super T>> void sort(List<T> list) 
                     根据元素的自然顺序 对指定列表按升序进行排序。 
                static <T> void sort(List<T> list, Comparator<? super T> c) 
                    根据指定比较器产生的顺序对指定列表进行排序。 
                还有返回线程安全的集合方法
    * 最常用操作
        * 存放数据
            void add(Object o)
        * 遍历集合
            1. 使用Iterator(迭代器)类
                Iterator<String> iterator = list.iterator();
                while(iterator.hasNext()){
                    String o = iterator.next();
                    System.out.println(o);
                }
            2. 使用增强for循环,实质还是迭代器
                for(String o : list){
                    System.out.println(o);
                }
            3. 直接输出对象,可输出所有数据
        * List子类特有方式
            * 通过索引获取数据
                Object get(int index)
            * 遍历集合的另一种方式:通过索引一个一个取
                for(int i=0;i<list.size();i++){
                    System.out.println(list.get(i));
                }
        * 集合和数组的相互转换
            * 数组转集合:
                java.utils.Arrays的方法
                 static <T> List<T> asList(T... a) 
                    数组转换为集合。 由数组转换成的集合不能进行增删操作(会报异常)
                    数组中的元素是引用类型时,转换的集合其实还是原来的数组,原来的数组改变,转换的集合也跟着改变
                    数组中的元素是基本类型时,集合会将数组添加到第一位
            * 集合转数组:
                集合本身的方法  
                 Object[] toArray() 
                    返回包含此 collection 中所有元素的数组。 
                 <T> T[] toArray(T[] a) 
                    返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 
                    //参数的T[]可以传一个空数组,例new int[0]
    * Set如何判断对象是否相等
        * HashSet : 基于哈希表,通过对象的哈希值(hashCode方法) 和 equals方法确定.
        * TreeSet : 通过自然顺序或排序器的方法判断.(不通过equals)
        如果对象相等,则不会添加后面的对象.
        可重写对象的相关方法,使集合达到不添加重复对象的目的
        
        * HashSet重写hashCode方法和equals方法
            public class HelloService{
                private Integer age;
                private String name;
                public HelloService(int age,String name){
                    this.age = age;
                    this.name = name;
                }
                
                public int hashCode() {
                    System.out.println("hashCode()");
                    return name.hashCode() + age.hashCode();
                }
                
                public boolean equals(Object obj) {
                    System.out.println("equals()");
                    return age.equals(age) && name.equals(name);
                }

                public String toString() {
                    return age + "--" + name;
                }
                
                public static void main(String[] args) throws Exception{
                    Set<HelloService> set = new HashSet<HelloService>();
                    set.add(new HelloService(1,"b"));
                    set.add(new HelloService(1,"b"));
                    set.add(new HelloService(1,"a"));
                    System.out.println(set);
                }
            }
    * 集合排序:
        TreeSet在元素添加时会自动排序
        其它集合可使用下面的两个方法进行排序
            static <T extends Comparable<? super T>> void sort(List<T> list) 
                根据元素的自然顺序 对指定列表按升序进行排序。 
            static <T> void sort(List<T> list, Comparator<? super T> c) 
                根据指定比较器产生的顺序对指定列表进行排序。 
        示例
            自然顺序:(由集合中的元素实现接口)
                public class HelloService implements Comparable<HelloService>{
                    private Integer age;
                    private String name;
                    public HelloService(int age,String name){
                        this.age = age;
                        this.name = name;
                    }
                    
                    public int compareTo(HelloService o) {
                        //按年龄升序排列
                        System.out.println("compareTo()");
                        return  age-o.age;
                    }
                    
                    public String toString() {
                        return age + "--" + name;
                    }
                    
                    public static void main(String[] args) throws Exception{
                        Set<HelloService> set = new TreeSet<HelloService>();
                        set.add(new HelloService(1,"a"));
                        set.add(new HelloService(2,"b"));
                        System.out.println(set);
                    }
                }
            自定义排序器:(任意类实现接口,然后通过构造函数传递给sort方法 或 TreeMap,TreeSet)
                public class HelloService implements Comparator<HelloService>{
                    private Integer age;
                    private String name;
                    public HelloService(int age,String name){
                        this.age = age;
                        this.name = name;
                    }
                    
                    public int compare(HelloService o1, HelloService o2) {
                        //按name升序排列,如果一样 按age降序排列
                        System.out.println("compare()");
                        int x = o1.name.compareTo(o2.name);
                        return  x == 0 ? o2.age - o1.age : x;
                    }
                    
                    public String toString() {
                        return age + "--" + name;
                    }
                    
                    public static void main(String[] args) throws Exception{
                        Set<HelloService> set = new TreeSet<HelloService>(new HelloService(0,""));
                        set.add(new HelloService(1,"b"));
                        set.add(new HelloService(2,"b"));
                        set.add(new HelloService(1,"a"));
                        System.out.println(set);
                    }
                }



Map接口及其子类
    * Map接口方法
         void clear() 
                从此映射中移除所有映射关系(可选操作)。 
         boolean containsKey(Object key) 
                如果此映射包含指定键的映射关系,则返回 true。 
         boolean containsValue(Object value) 
                如果此映射为指定值映射一个或多个键,则返回 true。 
         Set<Map.Entry<K,V>> entrySet() 
                返回此映射中包含的映射关系的 set 视图。 
         V get(Object key) 
                返回此映射中映射到指定键的值。 
         boolean isEmpty() 
                如果此映射未包含键-值映射关系,则返回 true。 
         Set<K> keySet() 
                返回此映射中包含的键的 set 视图。 
         V put(K key, V value) 
                将指定的值与此映射中的指定键相关联(可选操作)。 如果键已经存在,会覆盖值,并返回原来的值
         void putAll(Map<? extends K,? extends V> t) 
                从指定映射中将所有映射关系复制到此映射中(可选操作)。 
         V remove(Object key) 
                如果存在此键的映射关系,则将其从映射中移除(可选操作)。 
         int size() 
                返回此映射中的键-值映射关系数。 
         Collection<V> values() 
                返回此映射中包含的值的 collection 视图。 
    * 所有Map子类相同的构造方法(除Properties)
        类名() 
            构造一个具有默认初始容量 和默认加载因子 (0.75) 的空 HashMap。
        类名(Map<? extends K,? extends V> m) 
            构造一个映射关系与指定 Map 相同的 HashMap。
    * HashMap
        * 基于哈希表的 Map 接口的实现
    * LinkedHashMap
        * Map 接口的哈希表和链接列表实现, 保证顺序的map,取出的顺序和存入的一致
    * TreeMap
        * 对存储到这个Map中的对象,对键进行自然排序或指定比较器排序
        * 构造方法:
            TreeMap(Comparator<? super K> c) 
                构造一个新的空映射,该映射根据给定的比较器进行排序。
            如果不使用带比较器的构造方法,则Map中存放的键的类型必须实现Comparable接口指定对象的自然顺序
        * 常用方法:
             K firstKey() 
                返回有序映射中当前第一个(最小的)键。 
             K lastKey() 
                返回有序映射中当前最后一个(最大的)键。 
    * Map如何判断键是否相等
        * HashMap , Hashtable 和 LinkedHashMap是基于哈希表的. 通过对象的哈希值(hashCode方法) 和 equals方法确定.
        * TreeMap : 通过自然顺序或排序器的方法判断.(不通过equals)
        如果相等,会使用后添加的值覆盖前面的键的值(不会覆盖前面的键);否则会添加新的键值对
    * 最常用操作
        * 存放数据
            void put(Object key,Object value)
        * 获取数据
            Object get(Object key)
        * 遍历
            * 获取装有Map.Entry的Set
                for(Map.Entry<String, String> entry : map.entrySet()){
                    String key = entry.getKey();
                    String value = entry.getValue();
                    System.out.println(key + " --> " + value);
                }
            * 获取装有key的Set
                for(String key : map.keySet()){
                    String value = map.get(key);
                    System.out.println(key + " --> " + value);
                }
            * toString(),可展示所有数据



哈希表
    * 哈希值:
        通过hashCode方法得到,就是一个普通的十进制数,作用是为程序人员提供参考
        当你需要将对象存储到哈希表结构的结合的时候,必须参考这个哈希值
        哈希值其实是JVM提供给程序开发者一个整数参考,和实际的地址值无关
    * 哈希表结构判断对象是否相等的方法:
        先判断两个对象的哈希值是否相等(调用自身的hashCode方法)
            * 如果相等,调用equals方法,判断是否相等
            * 如果不相等,就是不相等



native关键字(了解)
    在Object类中可以看到很多native关键字修饰的方法
    1. native修饰的方法 不和普通方法在一起运行,而是在本地方法栈中运行
    2. native修饰的方法 调用了操作系统底层资源



File类
    * 用来描述文件或目录,可以对文件或目录进行操作
    * 构造方法
        File(String pathname) 
            通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。 
        File(String parent, String child) 
            根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 中间有没有分隔符无所谓
        File(File parent, String child) 
            根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
    * 常用字段
        static String separator 
          与系统有关的默认名称分隔符。 windows下为\,Linux下为/
        static String pathSeparator 
          与系统有关的路径分隔符字符。 windows下为;,Linux下为:
    * 常用方法
        * 文件和文件夹共有操作
             boolean delete() 
                删除此抽象路径名表示的文件或目录。 
                如果此路径名表示一个目录,则此目录必须为空才能删除.
                彻底删除,不会移动到回收站
             boolean exists() 
                测试此抽象路径名表示的文件或目录是否存在。
             String getAbsolutePath() 
                返回抽象路径名的绝对路径名字符串
             String getCanonicalPath() 
                返回抽象路径名的规范路径名字符串。 会经过解析,把..去掉
             String getName() 
                返回由此抽象路径名表示的文件或目录的名称。 
             String getParent() 
                返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。 
             String getPath() 
                将此抽象路径名转换为一个路径名字符串。 
             boolean isAbsolute() 
                测试此抽象路径名是否为绝对路径名。 
             注意:toString方法返回路径名(构造方法传什么路径,就显示什么路径,不一定是绝对路径).
        * 文件操作:
             boolean isFile() 
                测试此抽象路径名表示的文件是否是一个标准文件。
             long lastModified() 
                返回此抽象路径名表示的文件最后一次被修改的时间。 
             long length() 
                返回由此抽象路径名表示的文件的长度。
             boolean renameTo(File dest) 
                重新命名此抽象路径名表示的文件。如果文件路径修改,带有剪切功能
             boolean canRead() 
                测试应用程序是否可以读取此抽象路径名表示的文件。 
             boolean canWrite() 
                测试应用程序是否可以修改此抽象路径名表示的文件。 
             boolean createNewFile() 
                当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。 
        * 文件夹操作
             boolean isDirectory() 
                测试此抽象路径名表示的文件是否是一个目录。 
             String[] list() 
                返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。 
             String[] list(FilenameFilter filter) 
                返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。 
             File[] listFiles() 
                返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。 
             File[] listFiles(FileFilter filter) 
                返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。 
             static File[] listRoots() 
                列出可用的文件系统根目录。 windows为所有盘符,Linux为/
             boolean mkdir() 
                创建此抽象路径名指定的目录。 
             boolean mkdirs() 
                创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。 
            注意:
                list方法返回的是文件名,listFiles返回的是文件,包含全路径名.后者更常用
                FileFilter为一个接口,有一个方法 boolean accept(File pathname) 测试指定抽象路径名是否应该包含在某个路径名列表中。 



递归
    * 递归是一种编程技巧,方法自己调用自己
    * 使用场景
        功能的主体运算没有变化,但是每次运算的时候参与运算的参数发生了变化
    * 注意事项
        递归一定要有结束条件,不能无限进栈
        递归的次数不要过大,否则导致栈内存溢出
    * 递归在IO技术中的应用
        进行多级目录的操作
    * 例一:求1-100的和
        public static void main(String[] args){
            int a = sum(100);
            System.out.println(a);
        }
        public static int sum(int num){
            if(num==1){
                return 1;
            }else{
                return num + sum(num-1);
            }
        }
    * 例二:斐波那契数列,兔子问题
        public static void main(String[] args) throws Exception{
            //1 1 2 3 5 8
            for(int i=1;i<20;i++){
                System.out.print(sum(i) + "  ");
            }
        }
        public static int sum(int month){
            if(month<3){
                return 1;
            }else{
                return sum(month-1)+sum(month-2);
            }
        }
    * 例三:删除目录(里面的文件全部删除)
        public static void deleteDir(File file){
            if(file.isDirectory()){
                //删除文件夹中的内容
                File[] files = file.listFiles();
                for(File f : files){
                    deleteDir(f);
                }
            }
            //删除文件 或 删除空的文件夹
            file.delete();
        }



编码表(字符集)
    * 编码表的由来
        计算机只能识别二进制数据,为了方便应用计算机,让它可以识别各个国家的文字。
        就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
    * 常见的编码表
        ASCII:美国标准信息交换码。用一个字节的7位可以表示。
        ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
        GB2312:中国的中文编码表,国标码,只能显示简体中文。
        Big5: 大五码,繁体中文,香港那边用
        GBK:GB2312升级版,支持繁体,融合了更多的中文文字符号。
        Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
        UTF-8:最多用三个字节来表示一个字符。包含所有文字(可以认为是Unicode的升级版).可变长编码(2-6字节)
    * 编码:字符串-->字节数组
    * 解码:字节数组-->字符串
    * 理解:
        ASCII规定了一些常用符号,数字和字母的编码规则,所有编码表都要遵守,如
            ASCII值为9、10 和13 分别代表制表、换行和回车字符
            ASCII值为65~90为26个大写英文字母,97~122号为26个小写英文字母
            ASCII值为48~57为0到9十个阿拉伯数字
        ISO8859-1不支持中文,其它编码支持中文,但用不同的编码表分别进行编码和解码,可能会出现中文乱码问题
        ANSI 可以理解为系统默认编码,在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在繁体中文Windows操作系统中,ANSI编码代表Big5等等



IO(Input/Output)
    * 流的概念
        java中数据的传输以流的形式体现(向水在管道中流动一样)
    * 流的分类
        * 流按流向分为:输入流,输出流。
            输入流:程序从外部读取数据
            输出流:程序向外部写出数据
        * 流按操作数据分为两种:字节流与字符流。
            字节流:以字节为单位操作数据,可以操作任何数据,如文本,图片,视频
            字符流:专门用来处理字符数据的流对象,处理字符比较方便(有行的概念),其实内部使用的还是字节流
        * 流按功能分为两种: 基本流(节点流) 和 过滤流(处理流)
            基本流 : 直接读取或写入对象,提供基本功能
            过滤流 : 将基本流包装起来,提供一些额外功能
    * 体系结构
        * 字节流
            InputStream
                FileInputStream
                FilterInputStream
                    BufferedInputSteam
                ByteArrayInputStream
            OutputStream
                FileOutputStream
                FilterOutputStream
                    BufferedOutputStream
                    PrintStream
                ByteArrayOutputStream
        * 字符流
            Reader
                InputStreamReader
                    FileReader
                BufferedReader
            Writer
                OutputStreamWriter
                    FileWriter
                BufferedWriter
                PrintWriter
        * 说明:
            InputStream : 此抽象类是表示字节输入流的所有类的超类。 
            FileInputStream : FileInputStream 从文件系统中的某个文件中获取输入字节。(基本流,直接与文件交互,提供基本功能)
            FilterInputStream : FilterInputStream 中可以包含其他一些输入流,它将这些流用作其基本数据源,它可以提供一些额外的功能。(过滤流的父类,一般使用它的子类)
            BufferedInputSteam : BufferedInputStream 为其它字节输入流添加了功能,即缓冲输入和支持 mark 和 reset 方法的能力。(过滤流,提供缓冲功能)
            ByteArrayInputStream : ByteArrayInputStream 包含一个内部缓冲区,该缓冲区存储从流中读取的字节。(基本流,可以读取字节数组中的数据)
            
            OutputStream : 此抽象类是表示输出字节流的所有类的超类。
            FileOutputStream : 文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。(基本流,直接与文件交互,提供基本功能)
            FilterOutputStream : 此类是过滤输出流的所有类的超类。这些流位于已存在的输出流(基础 输出流)之上,它们将已存在的输出流作为其基本数据接收器,可提供一些额外的功能。(过滤流的父类,一般使用它的子类)
            BufferedOutputStream : 该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入基础输出流中,而不必为每次字节写入调用基础系统。(过滤流,提供缓冲功能)
            PrintStream : PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。(过滤流,方便打印各种类型的数据,不会抛异常,可设置自动刷新)
            ByteArrayOutputStream : 此类实现了一个输出流,其中的数据被写入一个字节数组。(基本流,可以将数据写入到字节数组中)

            Reader : 用于读取字符流的抽象类。
            InputStreamReader : InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。(处理流,可以将字节流转换为字符流,以字符接收,方便读取)
            FileReader : 用来读取字符文件的便捷类。(基本流,以当前项目编码读取字符文件)
            BufferedReader : 从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。(过滤流,提供缓冲功能) 
            
            Writer : 写入字符流的抽象类。
            OutputStreamWriter : OutputStreamWriter 是字符流通向字节流的桥梁:使用指定的 charset 将要向其写入的字符编码为字节。(处理流,可以将字符流转换为字节流,直接操作字符流,方便字符的写入)
            FileWriter : 用来写入字符文件的便捷类。(基本流,以当前项目编码写入字符)
            BufferedWriter : 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。(过滤流,提供缓冲功能) 
            PrintWriter : 向文本输出流打印对象的格式化表示形式。(过滤流,方便打印各种类型的数据,不会抛异常,可设置某些方法的自动刷新println、printf 或 format ,可直接跟字节流打交道)
    * 特点
        * 字节流
            InputStream                 * 字节输入流的抽象父类
                FileInputStream             * 文件输入流(基本流,用于对文件的读取)
                FilterInputStream           * 过滤流的父类
                    BufferedInputSteam          * 缓冲流(过滤流,提供缓冲功能)
                ByteArrayInputStream        * 字节数组输入流(基本流,可以读取字节数组中的数据)
            OutputStream                * 字节输出流的抽象父类
                FileOutputStream            * 文件输出流(基本流,用于对文件的写入)
                FilterOutputStream          * 过滤流的父类
                    BufferedOutputStream        * 缓冲流(过滤流,提供缓冲功能)
                    PrintStream                 * 打印流(过滤流,方便打印各种类型的数据,不会抛异常,可指定自动刷新,不能追加内容)
                ByteArrayOutputStream       * 字节数组输出流(基本流,可以将数据写入到字节数组中)
        * 字符流
            Reader                  * 字符输入流的抽象父类
                InputStreamReader       * 字节字符转换流(过滤流,可以将字节流转换为字符流,以字符读取,比较方便)
                    FileReader              * 字符文件输入流(基本流,用于对字符文件的读取,以当前项目编码)
                BufferedReader          * 缓冲流(过滤流,提供缓冲功能,可以读一行)
            Writer                  * 字符输出流的抽象父类
                OutputStreamWriter      * 字节字符转换流(过滤流,可以将字符流转换为字节流,以字符写入,比较方便)
                    FileWriter              * 字符文件输出流(基本流,用于对字符文件的写入,以当前项目编码)
                BufferedWriter          * 缓冲流(过滤流,提供缓冲功能,可以写一个新行)
                PrintWriter             * 字符打印流(过滤流,方便打印各种类型的数据,不会抛异常,某些方法可指定自动刷新println、printf 或 format,有换行方法,可直接跟字节流打交道,不能追加内容)
        
        最常用操作:读取,写入文件. 复制文件
        最常用字节流:FileInputStream,FileOutputStream
        最常用字符流:InputStreamReader,BufferedReader,OutputStreamWriter,BufferedWriter,PrintWriter
        ByteArrayInputStream和ByteArrayOutputStream可完成字节流和字节数组的相互转换
        PrintStream和PrintWriter可设置自动刷新(在构造方法中指定),可以打印各种类型的数据,但是不能追加
        FileReader和FileWriter以当前项目编码写入文件
        System.in类型为InputStream,默认输入地点为键盘;System.out类型为PrintStream,默认输出地点为显示器
        非字符文件读取和写入只能使用字节流,而字符文件通常使用字符流,因为字符流操作字符比较方便,可以读取一行或写入一个换行符
        字节输出流不需要刷新,字符输出流需要刷新,否则到关流时才能看到效果.在需要实时看到结果的程序中不要忘了字符输出流的刷新(比如聊天软件)
        获取当前项目编码:new FileReader(文件路径).getEncoding() //文件必须存在
        * 注意:
            用完流后要关闭.当使用过滤流时,只关闭最外层的过滤流即可,被包装的流会被过滤流关闭
            关闭流通常要放到try finally块中的finally中
            是否追加 : 是通过FileOutputStream或FileWriter的构造方法决定的
            字符编码 : 是通过InputStreamReader或OutputStreamReader的构造方法决定的,而字节流要用到new String(byte[] b,String encoding)和"".getByte(String encding)
            换行符 : windows记事本中的换行为"\r\n",Linux下为"\n",也可用PrintStream或PrintWriter的println()或BufferedWriter的newLine()
            在读取文件时,必须保证该文件已存在,否则在创建流对象时出异常。
            (重点)在写入一个文件时,在创建流对象(非追加)时,如果目录下有同名文件将被覆盖。没有时会自动创建。
            FileReader类只能按默认编码读取,所以读取字符文件用InputStreamReader包装FileInputStream,指定编码更常用
            FileWriter类只能按默认编码写入,所以写入字符文件用OutputStreamWriter包装FileOutputStream,指定编码更常用
            读方法(read,readLine)具有线程阻塞效果
            对于字节数组流,关闭是无效的,可以继续使用(因为此类并没有调用低层的资源,而是直接在操作内存中的数组)
        * 三种读取/写出方式:
            1. 一个一个字节或字符读/写
            2. 利用自定义数组缓冲(最常用,数组长度100*1024效率比较高)
            3. JDK提供的缓冲流



字节流
    * 字节输入流
        * InputStream常用方法
             int available() 
                    返回此输入流方法的下一个调用方可以不受阻塞地从此输入流读取(或跳过)的字节数。(可以判断本地文件大小,但不能判断网络传输中接收文件的大小)
             void close() 
                    关闭此输入流并释放与该流关联的所有系统资源。 
             void mark(int readlimit) 
                    在此输入流中标记当前的位置。 
             boolean markSupported() 
                    测试此输入流是否支持 mark 和 reset 方法。 (字节数组输入流支持,文件输入流和缓存流不支持)
             abstract int read() 
                    从输入流读取下一个数据字节。 
             int read(byte[] b) 
                    从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中。 
             int read(byte[] b, int off, int len) 
                    将输入流中最多 len 个数据字节读入字节数组。 
             void reset() 
                    将此流重新定位到对此输入流最后调用 mark 方法时的位置。 
             long skip(long n) 
                    跳过和放弃此输入流中的 n 个数据字节。 
        * 基本流
            * FileInputStream(读取文件)
                * 常用构造方法
                    FileInputStream(File file) 
                            通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
                    FileInputStream(String name)
                            通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
            * ByteArrayInputStream(读取字节数组)
                * 常用构造方法
                    ByteArrayInputStream(byte[] buf) 
                            创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 buf为要读取的数组
                    ByteArrayInputStream(byte[] buf, int offset, int length) 
                            创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。 
        * 过滤流
            * BufferedInputSteam(缓冲流)
                * 常用构造方法 
                    BufferedInputStream(InputStream in) 
                            创建 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。缓存区为8k
                    BufferedInputStream(InputStream in, int size) 
                            创建具有指定缓冲区大小的 BufferedInputStream,并保存其参数,即输入流 in,以便将来使用。
        * 常用操作
            * 读取一个字符文件
                //确定资源
                InputStream in = new FileInputStream(path);
                BufferedInputStream buff = new BufferedInputStream(in);
                //读取并打印
                byte[] b = new byte[1024*4];    //4kb
                int len = 0;
                while( (len = buff.read(b))!=-1 ){
                    String s = new String(b,0,len,"gbk");   //字节数组转为字符串
                    System.out.println(s);
                }
                //关闭流
                buff.close();
    * 字节输出流
        * OutputStream常用方法
            void close() 
                    关闭此输出流并释放与此流有关的所有系统资源。 
            void flush() 
                    刷新此输出流并强制写出所有缓冲的输出字节。 
            void write(byte[] b) 
                    将 b.length 个字节从指定的字节数组写入此输出流。 
            void write(byte[] b, int off, int len) 
                    将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。 
            abstract void write(int b) 
                    将指定的字节写入此输出流。 
        * 基本流
            * FileOutputStream(写入文件)
                * 常用构造方法:
                    FileOutputStream(File file) 
                            创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 
                    FileOutputStream(File file, boolean append) 
                            创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 
                    FileOutputStream(String name) 
                            创建一个向具有指定名称的文件中写入数据的输出文件流。 
                    FileOutputStream(String name, boolean append) 
                            创建一个向具有指定 name 的文件中写入数据的输出文件流。 
            * ByteArrayOutputStream(写入字节数组)
                * 常用构造方法:
                    ByteArrayOutputStream() 
                        创建一个新的字节数组输出流。
                * 常用方法:
                     void reset() 
                              将此字节数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。 
                     int size() 
                              返回缓冲区的当前大小。 
                     byte[] toByteArray() 
                              创建一个新分配的字节数组。 
                     String toString() 
                              将缓冲区的内容转换为字符串,根据平台的默认字符编码将字节转换成字符。 
                     String toString(String enc) 
                              将缓冲区的内容转换为字符串,根据指定的字符编码将字节转换成字符。 
                     void writeTo(OutputStream out) 
                              将此字节数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。 
        * 过滤流
            * BufferedOutputStream(缓冲流)
                * 常用构造方法:
                    BufferedOutputStream(OutputStream out) 
                        创建一个新的缓冲输出流,以将数据写入指定的基础输出流。缓存区默认8k
                    BufferedOutputStream(OutputStream out, int size) 
                        创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的基础输出流。
            * PrintStream(打印流)
                * 特点
                    方便打印(可直接打印各种类型的数据,还有换行符),不会抛异常,可指定自动刷新
                    自动刷新:每当写入字节数组、调用其中一个 println 方法或写入新行字符或字节 ('\n') 时都会刷新输出缓冲区
                * 常用构造方法:
                    PrintStream(File file) 
                              创建具有指定文件且不带自动行刷新的新打印流。 
                    PrintStream(File file, String csn) 
                              创建具有指定文件名称和字符集且不带自动行刷新的新打印流。 
                    PrintStream(OutputStream out) 
                              创建新的打印流。 
                    PrintStream(OutputStream out, boolean autoFlush) 
                              创建新的打印流。 
                    PrintStream(OutputStream out, boolean autoFlush, String encoding) 
                              创建新的打印流。 
                    PrintStream(String fileName) 
                              创建具有指定文件名称且不带自动行刷新的新打印流。 
                    PrintStream(String fileName, String csn) 
                              创建具有指定文件名称和字符集且不带自动行刷新的新打印流。 
                * 常用方法:
                    boolean checkError() 
                              刷新流并检查其错误状态。 
                    PrintStream format(String format, Object... args) 
                              使用指定格式字符串和参数将格式化字符串写入此输出流中。 和printf相同
                    void print(Object obj) 
                              打印对象。 
                    PrintStream printf(String format, Object... args) 
                              使用指定格式字符串和参数将格式化的字符串写入此输出流的便捷方法。例:out.printf("李%1$s","凯"); 
                    void println() 
                              通过写入行分隔符字符串终止当前行。 
                    void println(Object x) 
    * 常用操作
        * 写入一个字符文件(追加)
            //确定资源
            FileOutputStream out = new FileOutputStream(path,true);//true表示追加
            BufferedOutputStream buff = new BufferedOutputStream(out);
            //写入
            buff.write("你好".getBytes("gbk"));//获得gbk的字节数组
            //关闭流
            buff.close();
        * 复制一个文件(不一定是字符文件)
            //确定资源
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(path));
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(path2));
            //读取并写出
            byte[] b = new byte[1024*4];    //4kb
            int len = 0;
            while( (len = in.read(b))!=-1 ){
                out.write(b,0,len);
            }
            //关闭流
            in.close();
            out.close();
        * 复制一个文件夹(有点难度,可以先试试复制单级目录,然后再加递归复制多级)
            public static void main(String[] args) throws Exception{
                File srcFile = new File("E:\\abc");
                File targetPath = new File("D:\\");
                copyDir(srcFile,targetPath);
            }
            
            //复制目录或文件
            public static void copyDir(File srcFile,File targetPath) throws IOException{
                if(!srcFile.exists()){
                    throw new RuntimeException("要复制的文件不存在");
                }
                if(!targetPath.isDirectory()){
                    throw new RuntimeException("目标地址不是一个文件夹");
                }
                //目标文件名(或文件夹名)
                String name = getName(srcFile,targetPath);
                //目标文件
                File file = new File(targetPath,name);
                //复制
                copyDir2(srcFile,file);
            }
            
            //复制目录或文件(递归)
            private static void copyDir2(File srcFile,File file) throws IOException{
                if(srcFile.isDirectory()){
                    //目录
                    // * 创建目录
                    file.mkdir();
                    // * 复制文件
                    File[] files = srcFile.listFiles();
                    for(File f : files){
                        File newFile = new File(file.getPath(),f.getName());//组装路径
                        copyDir2(f,newFile);
                    }
                }else{
                    //文件
                    copyFile(srcFile,file);
                }
            }
            
            //返回目标文件名称
            private static String getName(File srcFile,File targetPath){
                String name = null;
                for(int i=2;;i++){
                    if(srcFile.getParent().equals(targetPath.getPath())){
                        //所在文件夹一样,目标文件的名称为源文件名称+数字
                        if(srcFile.isDirectory()){
                            name = srcFile.getName()+i;
                        }else{
                            String[] s = srcFile.getName().split("\\.");//根据.分割
                            if(s.length>1){
                                //有后缀
                                name = s[0] + i + "." + s[1];
                            }else{
                                //没有后缀
                                name = s[0] + i;
                            }
                        }
                    }else{
                        //目标文件为源文件名称
                        if(i==2){
                            name = srcFile.getName();
                        }else{
                            name = srcFile.getName() + i;
                        }
                    }
                    
                    //文件名不重复则退出循环
                    if(!new File(targetPath,name).exists()){
                        break;
                    }
                }
                return name;
            }
            
            //复制文件
            private static void copyFile(File srcFile,File targetFile){
                FileInputStream in = null;
                FileOutputStream out = null;
                try {
                    //获取流
                    in = new FileInputStream(srcFile);
                    out = new FileOutputStream(targetFile);
                    //复制
                    byte[] b = new byte[100*1024];
                    int len = 0;
                    while( (len=in.read(b))!=-1 ){
                        out.write(b,0,len);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }finally{
                    //关闭流
                    if(in!=null){
                        try{
                            in.close();
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                    if(out!=null){
                        try{
                            out.close();
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }



字符流
    * 字符输入流
        * Reader常用方法
             abstract void close() 
                      关闭该流。 
             void mark(int readAheadLimit) 
                      标记流中的当前位置。 
             boolean markSupported() 
                      判断此流是否支持 mark() 操作。 
             int read() 
                      读取单个字符。 
             int read(char[] cbuf) 
                      将字符读入数组。 
             abstract int read(char[] cbuf, int off, int len) 
                      将字符读入数组的某一部分。 
             int read(CharBuffer target) 
                      试图将字符读入指定的字符缓冲区。 
             boolean ready() 
                      判断是否准备读取此流。 
             void reset() 
                      重置该流。 
             long skip(long n) 
                      跳过字符。 
        * 基本流
            * FileReader(读取字符文件)
                * 此类只能按默认编码读取,所以用InputStreamReader包装FileInputStream,指定编码更常用
                * 常用构造方法:
                    FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader。 
                    FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。 
        * 过滤流
            * InputStreamReader(用字符流形式操作字节流)
                * 常用构造方法:
                    InputStreamReader(InputStream in) 
                        创建一个使用默认字符集的 InputStreamReader。 
                    InputStreamReader(InputStream in, String charsetName) 
                        创建使用指定字符集的 InputStreamReader。 
                * 常用方法:
                    String getEncoding() 
                        返回此流使用的字符编码的名称。 
            * BufferedReader(缓存)
                * 常用构造方法:
                    BufferedReader(Reader in) 
                        创建一个使用默认大小输入缓冲区的缓冲字符输入流。缓存区默认16k
                    BufferedReader(Reader in, int sz) 
                        创建一个使用指定大小输入缓冲区的缓冲字符输入流。
                * 常用方法:
                    String readLine() 
                        读取一个文本行。没有返回null 
        * 常用操作
            * 读取一个字符文件
                //FileReader类只能按默认编码读取,所以用InputStreamReader包装FileInputStream,指定编码更常用
                BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(path),"gbk"));
                String str = null;
                while( (str = buff.readLine())!=null ){
                    System.out.println(str);
                }
                buff.close();
    * 字符输出流
        * Writer常用方法
             Writer append(char c) 
                    将指定字符追加到此 writer。 
             Writer append(CharSequence csq) 
                    将指定字符序列追加到此 writer。 
             Writer append(CharSequence csq, int start, int end) 
                    将指定字符序列的子序列追加到此 writer.Appendable。 
             abstract  void close() 
                    关闭此流,但要先刷新它。 
             abstract  void flush() 
                    刷新此流。 
             void write(char[] cbuf) 
                    写入字符数组。 
             abstract  void write(char[] cbuf, int off, int len) 
                    写入字符数组的某一部分。 
             void write(int c) 
                    写入单个字符。 
             void write(String str) 
                    写入字符串。 
             void write(String str, int off, int len) 
                    写入字符串的某一部分。 
        * 基本流
            * FileWriter(写入字符文件)
                * FileWriter类只能按默认编码写入,所以用OutputStreamWriter包装FileOutputStream,指定编码更常用
                * 常用构造方法:
                    FileWriter(File file) 
                        在给出 File 对象的情况下构造一个 FileWriter 对象。 
                    FileWriter(File file, boolean append) 
                        在给出 File 对象的情况下构造一个 FileWriter 对象。 
                    FileWriter(String fileName) 
                        在给出文件名的情况下构造一个 FileWriter 对象。 
                    FileWriter(String fileName, boolean append) 
                        在给出文件名的情况下构造 FileWriter 对象,它具有指示是否挂起写入数据的 boolean 值。 
        * 过滤流
            * OutputStreamWriter(用字符流形式操作字节流)
                * 常用构造方法:
                    OutputStreamWriter(OutputStream out) 
                        创建使用默认字符编码的 OutputStreamWriter。 
                    OutputStreamWriter(OutputStream out, String charsetName) 
                        创建使用指定字符集的 OutputStreamWriter。 
                * 常用方法:
                    String getEncoding() 
                        返回此流使用的字符编码的名称。 
            * BufferedWriter(缓存)
                * 常用构造方法:
                    BufferedWriter(Writer out) 
                        创建一个使用默认大小输出缓冲区的缓冲字符输出流。缓存区默认16k
                    BufferedWriter(Writer out, int sz) 
                        创建一个使用指定大小输出缓冲区的新缓冲字符输出流。
                * 常用方法:
                    void newLine() 
                        写入一个行分隔符。 
            * PrintWriter(打印流)
                * 特点
                    可直接打印各种类型的数据,不会抛异常,某些方法可指定自动刷新println、printf 或 format,有换行方法,可直接跟字节流打交道
                    缺点:不能追加
                * 常用构造方法:
                    PrintWriter(File file) 
                            使用指定文件创建不具有自动行刷新的新 PrintWriter。 
                    PrintWriter(File file, String csn) 
                            创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。 
                    PrintWriter(OutputStream out) 
                            根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
                    PrintWriter(OutputStream out, boolean autoFlush) 
                            通过现有的 OutputStream 创建新的 PrintWriter。 
                    PrintWriter(String fileName) 
                            创建具有指定文件名称且不带自动行刷新的新 PrintWriter。 
                    PrintWriter(String fileName, String csn) 
                            创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。 
                    PrintWriter(Writer out) 
                            创建不带自动行刷新的新 PrintWriter。 
                    PrintWriter(Writer out, boolean autoFlush) 
                            创建新 PrintWriter。 
                * 常用方法:
                     boolean checkError() 
                            如果流没有关闭,则刷新流且检查其错误状态。 
                     PrintWriter format(String format, Object... args) 
                            使用指定格式字符串和参数将一个格式化字符串写入此 writer 中。 
                     void print(Object obj) 
                            打印对象。 
                     PrintWriter printf(String format, Object... args) 
                            使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。 
                     void println() 
                            通过写入行分隔符字符串终止当前行。 
                     void println(Object x) 
                            打印 Object,然后终止该行。 
        * 常用操作
            * 写入一个字符文件(追加)
                //FileWriter类只能按默认编码写入,所以用OutputStreamWriter包装FileOutputStream,指定编码更常用
                BufferedWriter buff = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path,true),"gbk"));
                buff.write("你好");
                buff.close();
            * 复制一个字符文件
                BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(path),"gbk"));
                PrintWriter writer = new PrintWriter(path2,"gbk");
                String str = null;
                //读一行,写一行
                while( (str = buff.readLine())!=null ){
                    writer.print(str);
                }
                buff.close();
                writer.close();



方法增强
    对方法功能进行改变
    方式:
        1 继承,编写实现类,复写父类的方法。(前提:确定父类)
        2 设计模式:装饰者。(前提:确定父接口)
        3 动态代理



装饰模式(装饰者模式)
    * 为接口实现类增强方法功能,实质:重写接口中需要的方法
    * 前提:
        已有类A实现接口I,且要使用的是此接口的方法
    * 步骤:
        1.创建一个类B,实现接口I,有一个A类型的成员变量(可通过构造方法接收)
        2.重写I接口的所有方法,对要增强的方法进行修改,对不增强的方法进行A的实现调用
        3.在使用时 创建B的对象转换为I接口类型,就可以使用了
    * 代码示例:
        interface I {
            void fun1();
            void fun2();
        }
        class A implements I{
            public void fun1() {
                System.out.println("A_fun1()");
            }
            public void fun2() {
                System.out.println("A_fun2()");
            }
        }
        class B implements I{
            private A a;
            public B(A a){
                this.a = a;
            }
            public void fun1() {
                //要增强的方法
                System.out.println("B_fun1()");
            }
            public void fun2() {
                //不需要增强的方法,调用A对象的实现
                a.fun2();
            }
        }
        class C{
            public static void main(String[] args) {
                I i = new B(new A());
                i.fun1();
                i.fun2();
            }
        }
    * 和继承比较
        继承存在局限性:单继承
        继承造成体系过于臃肿
        所有要修饰的类抽取一个父类,然后通过装饰者模式增强父类中的方法,只需一个装饰类即可完成装饰所有要装饰的类
    * 网上的定义
        * 概述
            装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
        * 装饰模式的特点
            (1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
            (2) 装饰对象包含一个真实对象的引用(reference)
            (3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
            (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
    * 缺点:要实现接口的所有方法,而我们需要增强的只有其中的很少的方法.可以参见<动态代理>.



其它IO对象
    * LineNumberReader : 跟踪行号的缓冲字符输入流。过滤流,BufferedReader的子类
        * 常用构造方法: 
            LineNumberReader(Reader in) 使用默认输入缓冲区的大小创建新的行编号 reader。 
        * 常用方法:
             int getLineNumber() 
                获得当前行号。 
             void setLineNumber(int lineNumber) 
                设置当前行号。 
    * Scanner : 一个可以使用正则表达式来分析基本类型和字符串的简单文本扫描器。 
        例: Scanner scanner = new Scanner(System.in);
            String str = scanner.next();
    * System.in 和 System.out 
        类型分别为InputStream 和 PrintStream.默认输入或输出地点分别为键盘和显示器
        System有两个相关方法:
            static void setIn(InputStream in) 
                重新分配“标准”输入流。 
            static void setOut(PrintStream out) 
                重新分配“标准”输出流。



Properties 
    * 概述
        Properties 类是Hashtable的一个子类(映射),表示了一个持久的属性集(对应于Properties配置文件)。
        Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 
        Properties 与IO配合可实现数据永久性存储(将键值对存储到配置文件中)
    * 构造方法
        Properties() 
            创建一个无默认值的空属性列表。
    * 常用方法
        String getProperty(String key) 
            用指定的键在此属性列表中搜索属性。
        void load(InputStream inStream) 
            从输入流中读取属性列表(键和元素对)。 
        Object setProperty(String key, String value) 
            调用 Hashtable 的方法 put。 
        void store(OutputStream out, String comments) 
          将此 Properties 表中的属性列表(键和元素对)写入输出流。 第二个参数为注释,会被添加到配置文件第一行,为""即可
    * 常用操作:
        * 读取并修改Properties文件(位置classPath下)
            //读取值
            Properties proc=new Properties();
            //InputStream in = 本类.class.getClassLoader().getResourceAsStream("config.properties");
            InputStream in = 本类.class.getResourceAsStream("/config.properties");
            proc.load(in);
            String value=proc.getProperty("name");
            System.out.println(value);
            //设置值
            String path = 本类.class.getResource("/config.properties").getPath();
            FileOutputStream out = new FileOutputStream(path);
            proc.setProperty("name", "zhangsan");
            proc.store(out, "");
        * 也可用ResourceBundle类读取(java.util)
            ResourceBundle bundle = ResourceBundle.getBundle("文件名不加后缀");//文件在src下
            String value= bundle.getString(String key);
        * 注意:
            当行首为#时,该行被跳过,不会被读取到映射中
            配置文件中中文会被显示为Unicode码(你好-->\u4F60\u597D)



对象序列化和反序列化
    * 概述
        * 序列化 : 就是将对象通过IO流写在文件中保存起来
        * 反序列化 : 将文件中保存的对象通过IO流读取出来
    * 注意:只有实现Serializable接口的类才支持序列化和反序列化功能
        Serializable : java.io包下的接口,没有任何方法和字段,只用来标识类及子类可以被序列化和反序列化.
    * 序列化
        * ObjectOutputStream
            * 构造方法:
                ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。
            * 常用方法:
                void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。 
        * 示例:
            ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("C:\\obj.txt"));
            out.writeObject(对象);
            out.close();
        * 注意:
            静态变量不会被序列化(静态变量不属于对象)
            被transient关键字修饰的变量称为瞬态变量,不能被序列化,例:transient String name = "zhangsan";
            对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。
    * 反序列化
        * ObjectInputStream
            * 构造方法:
                ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。
            * 常用方法:
                 Object readObject() 从 ObjectInputStream 读取对象。 
        * 示例:
            ObjectInputStream in=new ObjectInputStream(new FileInputStream("C:\\obj.txt"));
            Object obj=in.readObject();
            in.close();
        * 注意:
            反序列化时一定要有被序列化对象的字节码文件,否则反序列化失败
            如果被序列化对象的字节码文件在序列化对象之后发生了改变,反序列化会失败(反序列化时会根据字节码文件生成默认序列号,和序列化时的默认序列号不一致,反序列化会失败)
            强烈建议在序列化前给对象添加一个固定序列号(静态,终态的成员变量),使如果在不影响使用的情况下修改了类文件,反序列化也可以成功,例:static final long serialVersionUID = 42L;


  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

qq1123734918

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值