欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java基础知识,

来源: javaer 分享于  点击 22623 次 点评:242

Java基础知识,


一、基础知识: 

  • 环境变量path和classpath的作用是什么? 
  • 变量有什么用?为什么要定义变量?什么时候用? 
    答:变量的作用:用来存储数据。 
    为什么要定义变量:用来不断的存放同一类型的常量,并可以重复使用 
  • &和&&的区别? 
    答:(1)&&会出现短路,如果可以通过第一个表达式判断出整个表达式的结果,则不继续后面表达式的运算; 只能操作boolean类型数据; 
    (2)&不会出现短路,将整个表达式都运算。既可以操作boolean数据还可以操作数。 
  • 标示符命名规则: 
    由数字(0-9),大小写英文字母,以及_和$组成。 
    不能以数字开头。 
    不能使用关键字来自定义命名。 
  • 数据类型: 
    (1)基本数据类型(4类8种): 
        整数类型:byte、short、int、long 
        浮点数类型:float、double 
        字符类型:char 
        布尔类型:boolean(ture false) 
    (2)引用数据类型: 类 、接口 、数组 
  • 类型转换 
    精度从高到低 double float long int short(char) byte 
    (1)自动类型转换 将一个低精度—高精度 
    (2)强制类型转换 将一个高精度—低精度(精度会下降) 
  • java语言的三种技术架构 
    J2EE:企业版 是为开发企业环境下的应用程序提供的一套解决方案。 该技术体系中包含的技术如 Servlet、Jsp等,主要针对于Web应用程序开发。 
    J2SE:标准版 是为开发普通桌面和商务应用程序提供的解决方案。 该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发。 比如Java版的扫雷。 
    J2ME:小型版 是为开发电子消费产品和嵌入式设备提供的解决方案。 该技术体系主要应用于小型电子消费类产品,如手机中的应用程序等。 
  • java的跨平台性: 通过Java语言编写的应用程序在不同的系统平台上都可以运行。 
    跨平台的原因: 只要在需要运行java应用程序的操作系统上,先安装一个Java虚拟机(JVM Java Virtual Machine)即可。 
    由JVM来负责Java程序在该系统中的运行。 
  • 有符号数据的表示法(次重点) 
    原码,反码(原码取反),补码(反码+1)。 
  • 函数 
    定义:函数就是定义在类中的具有特定功能的一段独立小程序。 
    特点: 定义函数可以将功能代码进行封装 、 便于对该功能进行复用 、函数只有被调用才会被执行 、 函数的出现提高了代码的复用性 、对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写。 
    函数的应用两个明确: 明确要定义的功能最后的结果是什么? 明确在定义该功能的过程中,是否需要未知内容参与运算 
  • 重载: 
    概念:在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。 
    特点:与返回值类型无关,只看参数列表(参数类型以及参数个数,参数类型及顺序不同)。 
        public void aa(){
            System.out.println("我在aa");
        }
        public void aa(int a){
            System.out.println("我在aa");
        }
        public void aa(int a,int b){
            System.out.println("我在aa");
        }
        public void aa(int a,double b){
            System.out.println("我在aa");
        }
        public void aa(double a,int b){
            System.out.println("我在aa");
        }

    好处:方便于阅读,优化了程序设计。 
  • 数组: 
    概念:同一种数据类型的集合。 
    好处:可以自动给数组中的元素从0开始编号,方便操作这些元素。 
  • 内存结构: 
    栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。 
    堆内存:数组和对象,通过new建立的实例都存放在堆内存中。 
    方法区:静态成员、构造函数、常量池、线程池 
    本地方法区:window系统占用 
    寄存器:
  • 二、面向对象 

    三、多线程: 

    四、集合框架 

    4:基本数据类型的对象包装类 
    (1)为了更方便的操作每个基本数据类型,java对其提供了很多的属性和方法供我们使用。 
    (2)用途: 
    **将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能操作该数据。 
    **常用的操作之一:用于基本数据类型与字符串之间的转换。 
    A:方便操作 
    B:用于和字符串进行相互转换 
    (3)基本数据类型和对象类型的对应 
    byte Byte 
    short Short 
    int Integer 
    long Long 
    float Float 
    double Double 
    boolean Boolean 
    char Character 
    (4)构造方法

        字段摘要:
            static int MAX_VALUE 值为 2^31-1 的常量,它表示 int 类型能够表示的最大值         
            static int MIN_VALUE  值为 -2^31 的常量,它表示 int 类型能够表示的最小值
            static Class<Integer> TYPE 表示基本类型int的Class 实例
    
        Integer(int value) 构造一个新分配的Integer对象,它表示指定的int值。
        Inreger(String s) 注意:s必须是纯数字的字符串。否则会有异常NumberFormatException
    
    (5)几个常用的方法
        Integer.toBinaryString();
            以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
        Integer.toOctalString();
            以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。
        Integer.toHexString();
            以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
        static int Integer.parseInt(String s) 将字符串参数作为有符号的十进制整数进行解析,
            字符串必须是int型范围内的数字字符串
        static int Integer.parseInt(String s,int basic) 
            使用第二个参数指定的基数,将字符串参数解析为有符号的整数.
            字符串必须是int型范围内的数字字符串
        short shortValue() 以short类型返回该Integer的值。          
        int intValue() 以int类型返回该Integer的值。  
        static Integer valueOf(int num) 返回一个表示指定的 int 值的 Integer 实例。
        static Integer valueOf(String s) 返回保存指定的String的值的Integer对象。           
                static Integer valueOf(String s, int radix) 
            返回一个Integer对象,该对象中保存了用第二个参数提供的基数进行
            解析时从指定的String中提取的值。 
    
    (6)类型转换
        int -- Integer
            int num = 20;
            A:Integer i = new Integer(num);
            B:Integer i = Integer.valueOf(num);
        Integer -- int
            Integer i = new Integer(20);
            A:int num = i.intValue();
    
        int -- String
            int num = 20;
            A:String s = String.valueOf(num);
            B:String s = ""+num;
            C:String s = Integer.toString(num);
        String -- int
            String s = "20";
            A:int num = Integer.parseInt(s);
            B:Integer i = new Integer(s);或者Integer i = Integer.valueOf(s);
              int num = i.intValue();   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    6、集合框架: 
    (1)为什么出现集合类? 
    面向对象对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储。 
    集合就是存储对象最常用的一种方式. 
    (2)数组和集合都是容器,两者有何不同? 
    **数组长度固定,而集合长度是可变的 
    **数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象 
    **数组存储数据类型是固定的,而集合存储的数据类型不固定 
    (3)集合类的特点: 
    集合只能存储对象 
    集合的长度是可变的 
    集合可以存储不同类型的对象 
    (4)集合类框架(重要!!!要分清几种容器间的区别): 
    **Collection:顶层接口 
    |—>List:列表,元素是有序的(元素带角标索引),可以有重复元素,可以有null元素。 
    |—>ArrayList(JDK1.2):底层的数据结构是数组数据结构,特点是查询速度快(因为带角标), 
    但是增删速度稍慢,因为当元素多时,增删一个元素则所有元素的角标都得改变 
    线程不同步。默认长度是10,当超过长度时,按50%延长集合长度。 
    |—>LinkedList(JDK1.2):底层数据结构式链表数据结构(即后面一个元素记录前一个), 
    特点:查询速度慢,因为每个元素只知道前面一个元素,但增删速度快 
    因为元素再多,增删一个,只要让其前后的元素重新相连即可 
    线程是不同步的。 
    |—>Vector(JDK1.0):底层数据结构是数组数据结构.特点是查询和增删速度都很慢。 
    默认长度是10,当超过长度时,按100%延长集合长度。 
    线程同步。 
    (Vector功能跟ArrayList功能一模一样,已被ArrayList替代)

           **List使用注意!
            |--->ArrayList:
            (1)当往ArrayList里面存入元素没什么要求时,即只要求有序就行时;
    
            (2)当往ArrayList里面存入元素要求不重复时,比如存入学生对象,当同名同姓时
               视为同一个人,则不往里面存储。则定义学生对象时,需复写equals方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
               public boolean equals(Object obj)
                   {
                    if(!(obj instanceof Student))
                        return false;
                    Student stu = (Student)obj;
                    return this.name.equals(stu.name)&&this.age==stu.age;
                   }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
               则往ArrayList集合通过add存入学生对象时,集合底层自己会调用学生类的equals方法,
               判断重复学生则不存入。
             注:对于List集合,无论是add、contains、还是remove方法,判断元素是否相同,
                 都是通过复写equals方法来判断!
    
            |--->LinkedList
            (1)LinkLedist的特有方法:
                 boolean offerFirst(E e)  在此列表的开头插入指定的元素。
                 boolean offerLast(E e) 在此列表末尾插入指定的元素。
                 E peekFirst() 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
                 E peekLast() 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
                 E pollFirst() 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
                 E pollLast() 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
            (2)通过LinkLedist的特有方法,可以实现某些数据特殊方式的存取,比如堆栈和队列。
    
                一般情况下,使用哪种List接口下的实现类呢?
                如果要求增删快,考虑使用LinkedList
                如果要求查询快,考虑使用ArrayList
                如果要求线程安全,考虑使用Vector。
    
    
    
             |--->Set:集合,元素是无序的(因为没有索引),元素不可以重复。可以有null元素。
                |--->HashSet(JDK1.2):底层数据结构是哈希表、存取速度快、元素唯一、线程不同步。
                     保证性元素唯一的原理:
                     先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true
                     (往HashSet里面存的自定义元素要复写hashCode和equals方法,
                     以保证元素的唯一性!)
                |--->TreeSet:底层数据结构式二叉树。可以对Set集合中的元素进行排序。元素有序、线程不同步。
                     保证元素唯一性的依据:compareTo方法return 0
                     TreeSet排序的第一种方式:让元素自身具备比较性,比如八种基本数据类型或则字符串,
                                 实现Compareble接口,覆盖compareTo方法,
                                 此方式是元素的自然顺序             
                     TreeSet排序的第一种方式:当元素自身不具备比较性(比如存储学生对象时)或者具备的
                                 比较性不是我们所需要的比较性时(比如想字符串的长度排序),
                                 此时就需要让集合自身具备自定义的比较性。 
                                 那如何让集合自身具备比较性呢?可在集合初始化时,
                                 就让集合具备比较方式。即定义一个类,
                                 实现Comparator接口,覆盖compare方法。
    
            **Set集合使用注意事项:
            (1)HashSet:
                  通过new的方式往HashSet里面存的元素的hashCode都不同,但通常我们定义对象,
                  比如学生对象时,虽然是new的两个学生对象,但是当他们name和age一样时,我们认为是
                  同一个对象,所以为了保证元素的唯一性,我们通常在往HashSet集合里面存储元素时,
                  在定义对象的类中通常复写hashCode和equals方法。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
                  public int hashCode()
                      {
                    return name.hashCode()+age*39;
                      }
                      public boolean equals(Object obj)
                      {
                    if(!(obj instanceof Student))
                        return false;
                    Student stu = (Student)obj;
                    return this.name.equals(stu.name)&&this.age==stu.age;
                      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
                 HashSet是如何保证元素唯一性的呢?
                  **如果两元素的hashCode值不同,则不会调用equals方法
                  **如果两元素的hashCode值相同,则继续判断equals是否返回true;
                  **hashCode和equals方法虽然定义在自定义对象类里面,但不是我们手动调用
                    而是往HashSet集合里面存储元素的时候,集合底层自己调用hashCode和equals
                它自己拿对象去判断,自己判断两元素是否是同一个元素。
    
            (2)TreeSet:
                 TreeSet要求往里面存的元素具备比较性,否则会报错。
                 TreeSet排序的第一种方式:让元素自身具备比较性
                  定义对象类,实现Compareble接口,复写compareTo方法,此方式是元素的自然顺序
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
                      class Student implements Comparable
                      {
                        private String name;
                        private int age;
                        public Student(String name,int age)
                        {
                            this.name=name;
                            this.age=age;
                        }
                        public String getName()
                        {
                            return name;
                        }
                        public int getAge()
                        {
                            return age;
                        }
                        public int compareTo(Object obj)
                        {
                            if(!(obj instanceof Student))
                                throw new RuntimeException("不是学生对象!");
                            Student stu = (Student)obj;
                            int num = this.age-stu.age;
                            if(num==0)
                                return this.name.compareTo(stu.name);
                            return num;
                        }
                      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
                TreeSet排序的第一种方式:让集合具备比较性
                     当元素自身不具备比较性(比如存储学生对象时)或者具备的
                     比较性不是我们所需要的比较性时(比如想字符串的长度排序),
                     此时就需要让集合自身具备自定义的比较性。 
                     那如何让集合自身具备比较性呢?可在集合初始化时,
                     就让集合具备比较方式。即定义一个类,
                     实现Comparator接口,覆盖compare方法。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
                     class StringLengthComparator implements Comparator
                     {
                        public int compare(Object obj1,Object obj2)
                        {
                            String s1 = (String)obj1;
                            String s2 = (String)obj2;
                            int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
                            if(num==0)
                                return s1.compareTo(s2);
                            return num;
                        }
                     }
                     class TreeSetTest
                     {
                        public static void main(String[] args)
                        {
                            TreeSet ts = new TreeSet(new StringLengthComparator());
                            ts.add("addfg");
                            ts.add("dfg");
                            ts.add("agtuug");
                            ts.add("vgjkg");
                            sop(ts);
                        }
                     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
                 基本数据类型或字符串对象均实现了Comparable接口,故同种类型基本数据间具备比较性,即自然顺序。
    
    
    **Map:顶层接口,该集合存储的是键值对,而且键是唯一的,Map和Set很像,Set集合底层就是使用了Map集合。
        Map集合没有迭代器,要取出元素必须先将Map集合转换成Set集合才能遍历元素
       |--->HashTable(JDK1.0): 
        底层是哈希表数据结构;
        不可以使用null键和null值;
        用作键的对象必须实现hashCode和equals方法来保证键的唯一性
        线程同步,效率低
       |--->HashMap(JDK1.2):
        底层是哈希表数据结构;
        允许使用null键和null值;
        线程不同步,效率高;
        保证元素唯一性的:
             原理:先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true
             (往HashSet里面存的自定义元素要复写hashCode和equals方法,
             以保证元素的唯一性!)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
            class Student {
                private String name;
                private int age;
                public Student(String name, int age) {
                    super();
                    this.name = name;
                    this.age = age;
                }
                public int getAge() {
                    return age;
                }
                public void setAge(int age) {
                    this.age = age;
                }
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
    
                @Override
                public int hashCode(){
                    return name.hashCode()+age*34;
                }
                @Override
                public boolean equals(Object obj){
    
                    if(!(obj instanceof Student))
                        return false;
                    Student stu = (Student)obj;
                    return this.name.equals(stu.name)&&this.age==stu.age;
                }
            public class HashMapDemo1 {
                public static void main(String[] args) {
                    Map<Student , String> hmap = new HashMap<Student , String>();
                    hmap.put(new Student("001",20), "beijing");
                    hmap.put(new Student("002",25), "hebei");
                    hmap.put(new Student("003",50), "hainan");
                    hmap.put(new Student("001",20), "beijing");
    
                    System.out.println(hmap.size());
                    Set<Student> keySet = hmap.keySet();
                    Iterator<Student> it = keySet.iterator();
                    while(it.hasNext()){
                        Student stu = it.next();
                        String addr = hmap.get(stu);
                        System.out.println(stu.getName()+".."+stu.getAge()+"::"+addr);
                    }   
                }   
            }   
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
       |--->TreeMap(JDK1.0):
        底层是二叉树结构;
        允许使用null键和null值;
        线程不同步;
        可以给Map集合中的键进行排序.
        TreeMap排序的第一种方式:让元素自身具备比较性,比如八种基本数据类型或则字符串,
                 实现Compareble接口,覆盖compareTo方法,
                 此方式是元素的自然顺序             
        TreeMap排序的第一种方式:当元素自身不具备比较性(比如存储学生对象时)或者具备的
                 比较性不是我们所需要的比较性时(比如想字符串的长度排序),
                 此时就需要让集合自身具备自定义的比较性。 
                 那如何让集合自身具备比较性呢?可在集合初始化时,
                 就让集合具备比较方式。即定义一个类,
                 实现Comparator接口,覆盖compare方法。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
            class Student implements Comparable<Student>{
                private String name;
                private int age;
                public Student(String name, int age) {
                    super();
                    this.name = name;
                    this.age = age;
                }
                public int getAge() {
                    return age;
                }
                public void setAge(int age) {
                    this.age = age;
                }
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
                @Override
                public int compareTo(Student stu) {
                    int num = new   Integer(this.age).compareTo(new Integer(stu.age));
                    if(num==0)
                        return this.name.compareTo(stu.name);
                    return num;
                }           
            }
    
            public class HashMapDemo1 {
                public static void main(String[] args) {
    
                    Map<Student , String> tmap = new TreeMap<Student , String>();
                    tmap.put(new Student("001",20), "beijing");
                    tmap.put(new Student("002",25), "hebei");
                    tmap.put(new Student("003",50), "hainan");
                    tmap.put(new Student("001",20), "beijing");
    
                    System.out.println(tmap.size());
                    Set<Student> keySet1 = tmap.keySet();
                    Iterator<Student> it1 = keySet1.iterator();
                    while(it1.hasNext()){
                        Student stu = it1.next();
                        String addr = tmap.get(stu);
                        System.out.println(stu.getName()+".."+stu.getAge()+"::"+addr);      
                    }
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    **Iterator:对collection进行迭代的迭代器.迭代器取代了Enumeration。
        迭代器和枚举的区别:
        迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的collection移除元素
        方法名称得到了改进,简化书写 
    **LisIterator:系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表        
    **Comparable:此接口强行对实现它的每个类的对象进行整体自然排序。使元素具备比较性
    **Comparator:强行对某个对象collection进行整体排序的比较函数,使集合具备比较性
    **Collections:此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
    **Arrays:此类包含用来操作数组(比如排序和搜索)的各种静态方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7、集合类各容器方法: 
    **接口Collection方法摘要(没有构造方法) 
    a)添加: 
    i. boolean add(E e) 
    j. boolean addAll(Collection c) 
    b)删除: 
    i. void clear():清空容器 
    j. boolean remove(Objec object): 
    k. boolean removeAll(Collection c): 
    c)判断: 
    i. boolean contains(Object object):判断是否包含此元素 
    j. boolean containsAll(Collection c):判断是否包含一堆元素 
    k. boolean equals(Object object):比较此collection与指定对象是否相等 
    m. boolean isEmpty():判断是否集合为空 
    d)获取: 
    h. Iterator iterator():取出 
    i. int hashCode():返回此collection的哈希值 
    j. int size():返回此collection中元素的个数 
    k. boolean retainAll(Collection c):取交集 
    m. Object toArray():返回此collection中所有元素的数组 
    n. T[] toArray(T[] a):返回包含此collection中所有元素的数值。 
    *****List集合子类及其方法 
    (1)List接口是Collection接口的一个子接口。 
    (2)List接口中的元素有如下特点(对角标的操作都是特有方法,因为有序): 
    A:元素有序(存储顺序和取出顺序一致) 
    B:元素可以重复 
    (3)List接口中的特有方法 
    A:add(int index,Object obj):在指定位置加入元素 
    B:remove(int index):移除指定位置的元素 
    C:set(int index,Object obj):修改指定位置的元素 
    D:get(int index):获取指定位置的元素 
    E:indexOf(Object obj):获取指定元素的位置 
    F:subList(int start,int end):从一个大的List中截取一个小的List 
    G:listIterator():返回一个List接口特有的迭代器 
    (1)、ArrayList: 
    |—>构造方法摘要:(少用,不是重点) 
    ArrayList():构造一个初始容量为 10 的空列表。 
    ArrayList(Collection

    public static int add(int x,int ...args) {
                    int sum = x;
                    for(int arg:args) {
                        sum += arg;
                    }
                    return sum;
                }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
        **增强for循环代替了迭代器使用的不爽,简化书写
        **增强for循环局限性:
            对集合或者数组进行遍历时,只能取元素,不能对集合进行操作
    (4)基本数据类型的自动装箱和拆箱
        **基本数据类型
            byte    --->    Byte
            short   --->    Short
            int --->    Integer
            long    --->    Long
            float   --->    Float
            double  --->    Double
            char    --->    Character
            boolean --->    Boolean
        **例子:
            **装箱:自动把一个基本数据类型的数据装箱成一个该类型数据的对象引用
                Integer i = 3;(jdk1.5之前这样写是不行的,编译报错)
            **拆箱:自动把一个基本数据类型的对象引用拆箱成一个基本数据类型的数据,再参与运算
                Integer i = 12;
                sop(i+4);
            **享元模式:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    Integer num1 = 12;
                    Integer num2 = 12;
                    System.out.println(num1 == num2);//打印true
    
                    Integer num5 = Integer.valueOf(12);
                    Integer num6 = Integer.valueOf(12);
                    System.out.println(num5 == num6);//打印true
    
                    Integer num3 = 129;
                    Integer num4 = 129;
                    System.out.println(num3 == num4);//打印false
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
                为什么前面的返回true而后面的运算返回false呢?
                对于基本数据类型的整数,装箱成Integer对象时,如果该数值在一个字节内,(-128~127),
                一旦装箱成Integer对象后,就把它缓存到磁里面,当下次,又把该数值封装成Integer对象时
                会先看磁里面有没有该对象,有就直接拿出来用,这样就节省了内存空间。因为比较小的整数,
                用的频率比较高,就没必要每个对象都分配一个内存空间。
                这就是享元模式!比如26个英文字母,10个阿拉伯数字
    (5)枚举
        **为什么要有枚举?
            问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,
            但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
    
            枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。
            枚举可以让编译器在编译时就可以控制源程序中填写的非法值,
            普通变量的方式在开发阶段无法实现这一目标。
        **用普通类如何实现枚举的功能?定义一个Weekday类来模拟实现:
            步骤:
                *私有化构造方法
                *每个元素分别用一个公有的静态成员变量表示(public static final)
                *可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句
                 转移成了一个个独立的类。
        **枚举的应用:
            举例:定义一个Weekday的枚举。
            扩展:枚举类的values,valueOf,name,toString,ordinal等方法
                 (记住,讲课时要先于自定义方法前介绍,讲课更流畅)
            总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。 
                  例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。
        **枚举的高级应用:
            **枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
            **枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。
              把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
            **带构造方法的枚举
              构造方法必须定义成私有的
              如果有多个构造方法,该如何选择哪个构造方法?
              枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
            **带方法的枚举
              定义枚举TrafficLamp
              实现普通的next方法
              实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,
              这些子类采用类似内部类的方式进行定义。增加上表示时间的构造方法     
            **枚举只有一个成员时,就可以作为一种单例的实现方式。     
    (6)泛型:
        **泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
          编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,
          对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
          由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,
          就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
        **ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
            整个称为ArrayList<E>泛型类型
            ArrayList<E>中的E称为类型变量或类型参数
            整个ArrayList<Integer>称为参数化的类型
            ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
            ArrayList<Integer>中的<>念着typeof
            ArrayList称为原始类型
        **参数化类型与原始类型的兼容性:
            参数化类型可以引用一个原始类型的对象,编译报告警告,
            例如,Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?
            原始类型可以引用一个参数化类型的对象,编译报告警告,
            例如,Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
        **参数化类型不考虑类型参数的继承关系:
            Vector<String> v = new Vector<Object>(); //错误!///不写<Object>没错,写了就是明知故犯
            Vector<Object> v = new Vector<String>(); //也错误!
            编译器不允许创建泛型变量的数组。即在创建数组实例时,
            数组的元素不能使用参数化的类型,
            例如,下面语句有错误:
                Vector<Integer> vectorList[] = new Vector<Integer>[10];
        **泛型限定:
            **限定通配符的上边界:
                正确:Vector<? extends Number> x = new Vector<Integer>();
                错误:Vector<? extends Number> x = new Vector<String>();
            **限定通配符的下边界:
                正确:Vector<? super Integer> x = new Vector<Number>();
                错误:Vector<? super Integer> x = new Vector<Byte>();
            **提示:
                限定通配符总是包括自己。
                ?只能用作引用,不能用它去给其他变量赋值
                Vector<? extends Number> y = new Vector<Integer>();
                Vector<Number> x = y;
                上面的代码错误,原理与Vector<Object > x11 = new Vector<String>();相似,
                只能通过强制类型转换方式来赋值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    五、IO流 
    1、IO流概述 
    (1)用来处理设备(硬盘,控制台,内存)间的数据。 
    (2)java中对数据的操作都是通过流的方式。 
    (3)java用于操作流的类都在io包中。 
    (4)按照流操作的数据的类型不同:分为字节流和字符流。字符流是为了方便中文的操作而来的。 
    (5)按照流的流向不同分为:输入流,输出流 
    2、IO流常用基类: 
    (1)字节流 
    输出字节流:OutputStream:字节写入流抽象类 
    |—>FileOutputStream: 
    字节写入流 
    |—>BufferedOutputStream: 
    字节写入流缓冲区 
    |—>PrintStream: 
    打印流 
    输入字节流:InputStream:字节读取流抽象类 
    |—>FileInputStream: 
    字节读取流 
    |—>BufferedInputStream: 
    字节读取流缓冲区 
    (2)字符流 
    输出字符流:Writer:字符写入流的抽象 
    |—>FileWriter: 
    字符写入流 
    |—>BufferedWriter: 
    字符写入流缓冲区 
    |—>OutputStreamWriter: 
    字符通向字节的转换流(涉及键盘录入时用) 
    |—>OutputStreamWriter: 
    打印流,可处理各种类型的数据 
    输入字符流:Reader: 字符读取流的抽象类 
    |—>FileReader: 
    字符读取流 
    |—>LineNumberReader: 
    跟踪行号的缓冲字符读取流 
    |—>BufferedReader: 
    字符读取流缓冲区 
    |—>InputStreamReader: 
    字节通向字符的转换流(涉及键盘录入时用) 
    (3)IO流常用基类方法摘要: 
    **字节写入流:OutputStream: 
    void close() 关闭此输出流并释放与此流有关的所有系统资源。 
    void flush()刷新此输出流并强制写出所有缓冲的输出字节。 
    abstract void write(int b) 将指定的字节写入此输出流。 
    void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。 
    void write(byte[] b, int off, int len) 
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 
    **字节读取流:InputStream: 
    void close() 关闭此输入流并释放与该流关联的所有系统资源。 
    int available() (特有方法!!) 
    返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 
    abstract int read() 从输入流中读取数据的下一个字节。 
    int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 
    int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。 
    long skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。

        **字符写入流:Writer:
            abstract  void close() 关闭此流,但要先刷新它。
            abstract  void flush() 刷新该流的缓冲。
            void write(int c) 写入单个字符。
            void write(char[] cbuf) 写入字符数组。          
            abstract  void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
            void write(String str) 写入字符串。 
            void write(String str, int off, int len) 写入字符串的某一部分。 
    
        **字符读取流:Reader:
            abstract  void close() 关闭该流并释放与之关联的所有资源。
            int read() 读取单个字符。
            int read(char[] cbuf)  将字符读入数组
            abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
            long skip(long n)  跳过字符。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3、IO流常用字节流基类的子类: 
    **写入流: 
    (1)FileOutputStream: 
    **构造方法: 
    FileOutputStream(String name) 
    创建一个向具有指定名称的文件中写入数据的输出文件流。 
    FileOutputStream(String name, boolean append) 
    创建一个向具有指定 name 的文件中写入数据的输出文件流。 
    FileOutputStream(File file) 
    创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 
    FileOutputStream(File file, boolean append) 
    创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 
    **方法摘要: 
    public void flush() 
    void close() 关闭此文件输出流并释放与此流有关的所有系统资源。 
    void write(int b) 将指定字节写入此文件输出流。 
    void write(byte[] b, int off, int len) 
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 
    void write(int b) 将指定字节写入此文件输出流。 
    (2)BufferedOutputStream: 
    **构造方法: 
    BufferedOutputStream(OutputStream out) 
    创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 
    BufferedOutputStream(OutputStream out, int size) 
    创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。 
    **方法摘要: 
    void flush() 刷新此缓冲的输出流。 
    void write(byte[] b, int off, int len) 
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。 
    void write(int b) 将指定的字节写入此缓冲的输出流。 
    (3)PrintStream:打印流,可将各种类型的数据原样打印,有自动刷新功能 
    **构造方法: 
    PrintStream(String fileName) 
    创建具有指定文件名称且不带自动行刷新的新打印流。 
    PrintStream(File file) 
    创建具有指定文件且不带自动行刷新的新打印流。 
    PrintStream(OutputStream out) 
    创建新的打印流。 
    PrintStream(OutputStream out, boolean autoFlush) (当autoFlush为true时具有自动刷新功能) 
    创建新的打印流。 
    **方法摘要: 
    PrintStream append(char c) 
    将指定字符添加到此输出流。 
    void close() 
    关闭流。 
    void flush() 
    刷新该流的缓冲。 
    void print(各种类型的数据:) 
    打印各种类型的数据 
    void println(各种类型的数据:):自动换行 
    打印各种类型的数据 
    void write(byte[] buf, int off, int len) 
    将 len 字节从指定的初始偏移量为 off 的 byte 数组写入此流。 
    void write(int b) 
    将指定的字节写入此流。

    **读取流:
    (1)FileInputStream:
        **构造方法:
        FileInputStream(String name) 
            通过打开一个到实际文件的连接来创建一个 FileInputStream,
            该文件通过文件系统中的路径名 name 指定。
        FileInputStream(File file) 
            通过打开一个到实际文件的连接来创建一个 FileInputStream,
            该文件通过文件系统中的 File 对象 file 指定。
        **方法摘要:
        int available() (字节读取流特有方法!!!)
            返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
        int read() 
            从此输入流中读取一个数据字节。 
        int read(byte[] b) 
            从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 
        int read(byte[] b, int off, int len) 
            从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 
        long skip(long n) 
            从输入流中跳过并丢弃 n 个字节的数据。 
    (2)BufferedInputStream:
        **构造方法:
        BufferedInputStream(InputStream in) 
            创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 
        BufferedInputStream(InputStream in, int size) 
            创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 
        **方法摘要:
        int available() (字节读取流特有方法!!!)
            返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。 
        int read() 
            参见 InputStream 的 read 方法的常规协定。 
        int read(byte[] b, int off, int len) 
            从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。 
        long skip(long n) 
            参见 InputStream 的 skip 方法的常规协定。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4、字符流常用基类的子类 
    **写入流: 
    (1)FileWriter: 
    **构造方法: 
    FileWriter(String fileName) 
    根据给定的文件名构造一个 FileWriter 对象。 
    FileWriter(String fileName, boolean append) 
    根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 
    FileWriter(File file) 
    根据给定的 File 对象构造一个 FileWriter 对象。 
    FileWriter(File file, boolean append) 
    根据给定的 File 对象构造一个 FileWriter 对象。 
    FileWriter(FileDescriptor fd) 
    构造与某个文件描述符相关联的 FileWriter 对象。 
    **方法摘要:跟Writer一样 
    abstract void close() 关闭此流,但要先刷新它。 
    abstract void flush() 刷新该流的缓冲。 
    void write(int c) 写入单个字符。 
    void write(char[] cbuf) 写入字符数组。 
    abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
    void write(String str) 写入字符串。 
    void write(String str, int off, int len) 写入字符串的某一部分。 
    (2)BufferedWriter: 
    **构造方法: 
    BufferedWriter(Writer out) 
    创建一个使用默认大小输出缓冲区的缓冲字符输出流。 
    BufferedWriter(Writer out, int sz) 
    创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 
    **方法摘要: 
    void close() 
    关闭此流,但要先刷新它。 
    void flush() 
    刷新该流的缓冲。 
    void newLine() 
    写入一个行分隔符。 
    void write(char[] cbuf, int off, int len) 
    写入字符数组的某一部分。 
    void write(int c) 
    写入单个字符。 
    void write(String s, int off, int len) 
    写入字符串的某一部分。 
    (3)OutputStreamWriter:字节通向字符的转换流 
    **构造方法: 
    OutputStreamWriter(OutputStream out) 
    创建使用默认字符编码的 OutputStreamWriter。 
    **方法摘要: 
    void write(char[] cbuf, int off, int len) 
    写入字符数组的某一部分。 
    void write(int c) 
    写入单个字符。 
    void write(String str, int off, int len) 
    写入字符串的某一部分。 
    (4)PrintWriter: 
    **构造方法: 
    PrintWriter(String fileName) 
    创建具有指定文件名称且不带自动行刷新的新 PrintWriter。 
    PrintWriter(File file) 
    使用指定文件创建不具有自动行刷新的新 PrintWriter。 
    PrintWriter(Writer out) 
    创建不带自动行刷新的新 PrintWriter。 
    PrintWriter(Writer out, boolean autoFlush) 
    创建新 PrintWriter。 
    PrintWriter(OutputStream out) 
    根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
    PrintWriter(OutputStream out, boolean autoFlush) 
    通过现有的 OutputStream 创建新的 PrintWriter。

        **方法摘要:
        PrintWriter append(char c) 
            将指定字符添加到此 writer。 
        void print(各种类型的数据:) 
            打印各种类型的数据 
        void println(各种类型的数据:):自动换行
            打印各种类型的数据
        void write(char[] buf) 
            写入字符数组。 
        void write(char[] buf, int off, int len) 
            写入字符数组的某一部分。 
        void write(int c) 
            写入单个字符。 
        void write(String s) 
            写入字符串。 
        void write(String s, int off, int len) 
            写入字符串的某一部分。 
    **读取流:
    (1)FileReader:
        **构造方法:
        FileReader(String fileName) 
            在给定从中读取数据的文件名的情况下创建一个新 FileReader。
        FileReader(File file) 
            在给定从中读取数据的 File 的情况下创建一个新 FileReader。 
        FileReader(FileDescriptor fd) 
            在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。 
        **方法摘要:和Reader基类方法一致:
        abstract  void close() 关闭该流并释放与之关联的所有资源。
        int read() 读取单个字符。
        int read(char[] cbuf)  将字符读入数组
        abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
        long skip(long n)  跳过字符。 
    (2)BufferedReader:
        **构造方法:
        BufferedReader(Reader in) 
            创建一个使用默认大小输入缓冲区的缓冲字符输入流。
        **方法摘要:
        int read() 
            读取单个字符。 
        int read(char[] cbuf, int off, int len) 
            将字符读入数组的某一部分。 
        String readLine() 
            读取一个文本行。 
    (3)InputStreamReader:字符通向字节的桥梁:
        **构造方法:
        InputStreamReader(InputStream in) 
            创建一个使用默认字符集的 InputStreamReader。
        **方法摘要:
        int read() 读取单个字符。
        int read(char[] cbuf)  将字符读入数组
        abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
        long skip(long n)  跳过字符。
    (4)LineNumberReader:
        **构造方法:
        LineNumberReader(Reader in) 
            使用默认输入缓冲区的大小创建新的行编号 reader。
        **方法摘要:
        int read() 
            读取单个字符。 
        int read(char[] cbuf, int off, int len) 
            将字符读入数组中的某一部分。 
        String readLine() 
            读取文本行。
        long skip(long n) 
            跳过字符。 
        int getLineNumber() 
            获得当前行号。 
        void setLineNumber(int lineNumber) 
            设置当前行号。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    6、IO流常见需求: 
    **字符流: 
    (1)需求1:在硬盘上创建一个文件并写入信息

    用字符写入流:FileWriter
            FileWriter fw = new FileWriter("g:\\filewriter.txt");
            fw.write("输入信息");
            fw.write("也可以写入字符数组".toCharArray());
            fw.flush();
            fw.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    (2)需求2:在原有文件上续写数据
    
    • 1
    FileWriter fw = new FileWriter("g:\\filewriter.txt",true);
            fw.write("还可以续写信息");
            fw.write("也可以写入字符数组".toCharArray());
            fw.flush();
            fw.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    (3)需求3:读取硬盘上的文本文件,并将数据打印在控制台
        FileReader fr = new FileReader("g:\\filewriter.txt");
        **第一种读取方法:一个一个字节的读
    
    • 1
    • 2
    • 3
    int ch = 0;
            ch = fr.read();
            sop((char)ch);
            fr.close();
    • 1
    • 2
    • 3
    • 4
        **第二种读取方法:利用数组来提高效率
    
    • 1
    char[] buf = new char[1024];
            int len = 0;
            while((len = fr.read(buf))!=-1)
            {
                sop(new String(buf,0,len));
            }
            fr.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    (4)需求4:拷贝文本文件
        利用缓冲区提高数据读写效率
        (无缓冲区就相当于一滴一滴的喝水,有缓冲区就相当于一杯一杯的喝水)
    
    • 1
    • 2
    • 3
    BufferedReader bufr = new BufferedReader(new FileReader("g:\\filewriter.txt"));
            BufferedWriter bufw = new BufferedWriter(new FileWriter("d:\\copyfilewriter.txt"));
            String line = null;
            while((line = bufr.readLine())!=null)
            {
                burw.write(line);
                bufw.newLine();
                bufw.flush();
            }
            bufr.close();
            bufw.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    **字节流:字节流写入时没有刷新 
    (1)需求1:在硬盘上创建一个文件并写入信息(字节流写入时没有刷新) 
    FileOutputStream fos = new FileOutputStream(“g:\filestream.txt”); 
    fos.write(97);//写入一个字节,int:97代表写入char:a 
    fos.write(“也可以写入字节数组”.getBytes());//通常使用此种方式写入,直观! 
    fos.close(); 
    (2)需求2:在硬盘已有文件上续写数据(字节流写入时没有刷新) 
    FileOutputStream fos = new FileOutputStream(“g:\filestream.txt”,true); 
    fos.write(“创建字节写入流时,传进去一个true参数就可以继续写入信息”.getBytes()); 
    fos.close(); 
    (3)需求3:读取硬盘上的文件 
    FileInputStream fis = new FileInputStream(“g:\filestream.txt”); 
    **第一种读法:一个字节一个字节的读(此种读法慢)

    int ch = 0;
            while((ch = fis.read())!=-1)
            {
                sop((char)ch);
            }
    • 1
    • 2
    • 3
    • 4
    • 5
        **第一种读法:利用字节数组读(此种读法效率有一定提高)
    
    • 1
    byte[] buf = new byte[1024];
            int len = 0;
            while((len = fis.read())!=-1)
            {
                sop(new String(buf,0,len));
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    (4)需求4:拷贝字节文件,如图片或者MP3或者电影
        **第一种拷贝:不带缓冲区(慢,还是效率问题)
    
    • 1
    • 2
    FileInputStream fis = new FileInputStream("g:\\1.mp3");
            FileOutputStream fos = new FileOutputStream("g:\\copy1.mp3");
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = fis.read(buf))!=-1)
            {
                fos.(buf,0,len);//字节流写入无需刷新
            }
            fis.close();
            fos.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
        **第二种拷贝:带缓冲区,高效
    
    • 1
    BufferedInputStream bufi = new BufferedInputStream(new FileInputStream("g:\\1.mp3"));
            BufferedOutputStream bufo = new BufferedOutputStream(new FileOutputStream("g:\\copy1.mp3"));
            int ch = 0;
            while((ch = bufi.read())!=-1)
            {
                bufo.write(ch);
            }
            bufi.close();
            bufo.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    **转换流: 
    (1)需求1:读取一个键盘录入 
    InputStream in = System.in;//创建一个键盘录入流,流不关则可以一直录入 
    int by1 = in.read();//一次读一个字节 
    int by2 = in.read();//一次读一个字节 
    sop(by1);//假设键盘录入的是abcd,则打印a 
    sop(by2);//假设键盘录入的是abcd,则打印b 
    in.close(); 
    (2)需求2:键盘录入一行数据打印一行数据,如果录入的是over则结束录入

    InputStream in = System.in;
            StringBuilder sb = new StringBuilder();
            while(true)
            {
                int ch = in.read();
                if(ch=='\r')
                    continue;
                if(ch=='\n')
                {
                    String line = sb.toString();
                    if("over".equals(line))
                        break;
                    sop(line.toUpperCase());//输出大写
                    sb.delete(0.sb.length());//清除上一行录入的数据
    
                }
                else
                    sb.append((char)ch);
            }
            in.close();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    (3)需求3:发现需求2中其实就是读一行的原理,故引入字节通向字符的桥梁:InputStreamReader
        为提高效率加入缓冲区:
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while((line = bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;
            sop(line.toUpperCase());//输出大写
        }
        bufr.close();
    (4)需求4:键盘录入数据并打印到控制台
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
        String line = null;
        while((line = bufr.readLine())!=null)
        {   
            if("over".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();   
        }
        bufr.close();
        bufw.close();
    (5)需求5:将键盘录入的数据存储到硬盘文件
        则只需将(4)中的
        BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
        改为:
        BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(new FileWriter("g:\\demo.txt")));
        即:
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(new FileWriter("g:\\demo.txt")));
        String line = null;
        while((line = bufr.readLine())!=null)
        {   
            if("over".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();   
        }
        bufr.close();
        bufw.close();
    (6)需求6:将硬盘文件的数据打印到控制台
        则只需将(4)中的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

        改为:BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileReader("g:\\demo.txt")));
        BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileReader("g:\\demo.txt")));
        BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
        String line = null;
        while((line = bufr.readLine())!=null)
        {   
            if("over".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();   
        }
        bufr.close();
        bufw.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7、流操作的规律: 
    **流操作的难点:流对象很多,不知道具体用哪个 
    **规律: 
    (1)第一步:先明确源和目的 
    源: 
    文本:用Reader 
    字节:用InputStream 
    目的: 
    文本:用Writer 
    字节:用OutputStream 
    (2)第二步:明确是不是纯文本 
    是:用字符流; 
    不是:用字节流 
    (3)第三步:明确流体系后,通过设备来明确具体使用哪个流对象 
    源设备: 
    键盘:System.in 
    硬盘:文件流File 
    内存:数组流ArrayStream 
    目的设备: 
    键盘:System.out 
    硬盘:文件流File 
    内存:数组流ArrayStream 
    8、File类 
    构造方法: 
    File(String pathname) 
    通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 
    File(String parent, String child) 
    根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 
    File(File parent, String child) 
    根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 
    方法摘要: 
    (1)创建: 
    boolean createNewFile() 
    当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 
    boolean mkdir() 
    创建一级文件夹 
    boolean mkdirs() 
    创建多级文件夹 
    (判断): 
    boolean canExecute() 
    测试应用程序是否可以执行此抽象路径名表示的文件。 
    boolean canRead() 
    测试应用程序是否可以读取此抽象路径名表示的文件。 
    boolean canWrite() 
    测试应用程序是否可以修改此抽象路径名表示的文件。 
    int compareTo(File pathname) 
    按字母顺序比较两个抽象路径名。 
    boolean isAbsolute() 
    测试此抽象路径名是否为绝对路径名。 
    boolean isDirectory() 
    测试此抽象路径名表示的文件是否是一个目录。 
    boolean isFile() 
    测试此抽象路径名表示的文件是否是一个标准文件。 
    boolean isHidden() 
    测试此抽象路径名指定的文件是否是一个隐藏文件。 
    boolean exists() 
    测试此抽象路径名表示的文件或目录是否存在。 
    (3)获取: 
    String getParent() 
    返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。 
    File getParentFile() 
    返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。 
    String getName() 
    返回由此抽象路径名表示的文件或目录的名称。 
    String getPath() 
    将此抽象路径名转换为一个路径名字符串。 
    String getAbsolutePath() 
    返回此抽象路径名的绝对路径名字符串。 
    File getAbsoluteFile() 
    返回此抽象路径名的绝对路径名形式。 
    (4)删除: 
    boolean delete() 
    删除此抽象路径名表示的文件或目录。 
    oid deleteOnExit() 
    在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。 
    (5)获取全部:(非常重要!!!) 
    String[] list() 
    返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 
    String[] list(FilenameFilter filter) 
    返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
    File[] listFiles() 
    返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 
    File[] listFiles(FileFilter filter) 
    返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。

    ****FilenameFilter接口只有一个方法:
        boolean accept(File dir, String name) 
            测试指定文件是否应该包含在某一文件列表中。 
    ****FileFilter接口只有一个方法:
        boolean accept(File dir, String name) 
            测试指定文件是否应该包含在某一文件列表中。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    8、File类常见需求: 
    (1)文件名过滤:列出给定目录的所有.java文件

    public void showFileName(File file)
            {
                String[] filenames = file.list(new FilenameFilter()//匿名内部类
                {
                    public boolean accept(File dir,String name)//复写唯一方法
                    {
                        return name.endsWith(".java");//列出所有.java文件
                    }
                });
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    (2)列出指定目录下的所有文件和文件夹(递归)
    **示例1:不带层次递归:
    
    • 1
    • 2
    public static void showDir(File dir)
        {
            File[] files = dir.listFile();
            for(int i = 0;i<files.length;i++)
            {
                if(files[i].isDirectory&&!files[i].isHidden())
                    showDir(files[i]);
                else
                    sop(files[i]);
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    **示例2:带层次递归:
    
    • 1
    public static void showDir(File dir,int level)
        {
            sop(getLevel(level)+C);//进来先打印层次和目录
            level++;
            File[] files = dir.listFile();
            for(int i = 0;i<files.length;i++)
            {
                if(files[i].isDirectory&&!files[i].isHidden())
                    showDir(files[i]);
                else
                    sop(getLevel(level)+files[i]);//是文件就打印层次和目录
            }
        }
        public static String getLevel(int level)
        {
            sop("|--");
            StringBuilder sb = new StringBuilder();
            for(int i=0;i<level;i++)
            {
                sb.inset(0."|  ")
            }
            return sb.toString();
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    (3)需求:删除带内容的目录:
    
    • 1
    public static void removeDir(File dir)
        {
            File[] files = file.listFile();
            for(int i = 0;i<files.length;i++)
            {
                if(files[i].isDirectory&&!files[i].isHidden())
                    removeDir(files[i]);//如果是文件夹则继续调用函数
                else//如果是文件则删除。注意删除的时候打印删除的结果,防止误删或者重删的情况
                    sop(files[i].toString()+"::"+files[i].delete());
            }
            sop(dir+"::"+dir.delete());
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    (4)需求:将制定目录下的java文件的绝对路径存储到文本文件中。
       思路:
       **对指定目录进行递归
       **获取递归过程中所有java文件的路径
       **将这些路径存储到集合中
       **将集合中的数据写入文件中
     //对指定目录进行递归并将所以Java文件存储到集合中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public static void getFileName(File file,ArrayList<File> arraylist){
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                if(files[i].isDirectory()&&!files[i].isHidden()){
                    getFileName(files[i],arraylist);
                }else{
                    if(files[i].getName().endsWith(".java")){
                        arraylist.add(files[i]);
                    }
                }
            }
        }
        //将集合中所有数据存储到新文件中
        public static void saveFileToNewDir(ArrayList<File> arraylist,File newDir){
            BufferedWriter bufw = null;
            try {
                bufw = new BufferedWriter(new FileWriter(newDir));
                for (File file : arraylist) {
                    String fileAbsolutePath = file.getAbsolutePath();
                    bufw.write(fileAbsolutePath);
                    bufw.newLine();
                    bufw.flush();   
                }
            } catch (Exception e) {
                System.out.println("文件写入失败");
            }finally{
                try {
                    if(bufw!=null)
                        bufw.close();
                } catch (Exception e2) {
                    System.out.println("文件写入流关闭失败");
                }
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    9、Properties 
    (1)Properties是HashTable的子类,具备Map集合的特点,里面存储的是键值对 
    (2)Properties是IO流合集合相结合的集合容器 
    (3)Properties的特点是可以用于存储键值对形式的配置文件 
    (4)构造方法: 
    Properties() 
    创建一个无默认值的空属性列表。 
    Properties(Properties defaults) 
    创建一个带有指定默认值的空属性列表。 
    (5)方法摘要: 
    Object setProperty(String key, String value) 
    调用 Hashtable 的方法 put。 
    String getProperty(String key) 
    用指定的键在此属性列表中搜索属性。 
    void load(InputStream inStream) 
    从输入流中读取属性列表(键和元素对)。 
    void load(Reader reader) 
    按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 
    void list(PrintStream out) 
    将属性列表输出到指定的输出流。 
    void list(PrintWriter out) 
    将属性列表输出到指定的输出流。 
    void store(OutputStream out, String comments) 
    以适合使用 load(InputStream) 方法加载到 Properties 表中的格式, 
    将此 Properties 表中的属性列表(键和元素对)写入输出流。 
    void store(Writer writer, String comments) 
    以适合使用 load(Reader) 方法的格式,将此 Properties 表中的 
    属性列表(键和元素对)写入输出字符。 
    Set stringPropertyNames() 
    返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中 
    未找到同名的键,则还包括默认属性列表中不同的键 
    (6)Properties代码示例:

    public static void show()
        {
            Properties prop = new Properties();
            prop.setProperty("张三","26");
            prop.setProperty("李四","30");
            prop.setProperty("王五","35");
            sop(prop);
            String value = prop.getProperty("张三");
    
            Set<String> keys = prop.stringPropertyName();
            for(String key : values)
            {
                sop(key+":"+prop.getPropety(key));
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    (7)需求:记录应用程序的使用次数,如果使用次数已到,则提示用户注册。 
    思路: 
    **第一次使用时建立一个配置文件用于记录使用次数 
    **每次使用都加载该配置文件,并先判断已使用次数 
    **每次使用完使用次数加1,写入配置文件

        public static void main(String[] args) throws IOException{
            Properties prop = new Properties();//定义Properties,用来和IO流结合
            File file = new File("library\\time.ini");//配置文件
            if(!file.exists())
                file.createNewFile();//如果文件不存在则创建文件(用于第一次使用时创建文件)
            FileInputStream fis = new FileInputStream(file);//定义字节读取流,读取配置文件中记录的使用次数
            prop.load(fis);//载入流,以获取文件中配置的键值对
            int count = 0;//定义使用次数
            String countValue = prop.getProperty("time");//通过键获取值
            if(countValue!=null){//第一次时countValue为null
                count = Integer.parseInt(countValue);//将字符串次数变成数字次数
                if(count>3){
                    System.out.println("您使用次数已到,继续使用请注册!");
                    return;
                }
            }
            count++;//如果使用次数未到则次数加1
            prop.setProperty("time", count+"");//配置新的键值对
            FileWriter fos = new FileWriter(file);
            prop.store(fos, "这是应用程序使用次数的配置文件");//将新的键值对写入文件
            fis.close();
            fos.close();    
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    10、IO中的其他流: 
    (1)打印流: 
    **PrintWriter:字符打印流 
    **构造方法: 
    PrintWriter(String fileName) 
    创建具有指定文件名称且不带自动行刷新的新 PrintWriter。 
    PrintWriter(File file) 
    使用指定文件创建不具有自动行刷新的新 PrintWriter。 
    PrintWriter(Writer out) 
    创建不带自动行刷新的新 PrintWriter。 
    PrintWriter(Writer out, boolean autoFlush) 
    自动刷新 
    PrintWriter(OutputStream out) 
    根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
    PrintWriter(OutputStream out, boolean autoFlush) 
    自动刷新 
    **方法摘要: 
    PrintWriter append(char c) 
    将指定字符添加到此 writer。 
    void close() 
    关闭该流并释放与之关联的所有系统资源。 
    void flush() 
    刷新该流的缓冲。 
    void print(Object obj) 
    打印对象。 
    void print(String s) 
    打印字符串。 
    void println() 
    通过写入行分隔符字符串终止当前行。 
    **PrintStream:字节打印流 
    **构造方法: 
    PrintStream(String fileName) 
    创建具有指定文件名称且不带自动行刷新的新打印流。 
    PrintStream(File file) 
    创建具有指定文件且不带自动行刷新的新打印流。 
    PrintStream(OutputStream out) 
    创建新的打印流。 
    PrintStream(OutputStream out, boolean autoFlush) 
    创建新的打印流。 
    **方法摘要: 
    PrintWriter append(char c) 
    将指定字符添加到此 writer。 
    void close() 
    关闭该流并释放与之关联的所有系统资源。 
    void flush() 
    刷新该流的缓冲。 
    void print(Object obj) 
    打印对象。 
    void print(String s) 
    打印字符串。 
    void println() 
    通过写入行分隔符字符串终止当前行。 
    (2)对象系列化: 
    **对象实体化:找一个介质,能长期的存储对象。 
    **对象的属性在Java程序中,都是存在于对内存中,随着对象的消失而消失, 
    而ObjectOutputStream可以将对象实体化 
    **Serializable接口没有一个方法,也就是说其是一个标记接口。比如盖章的猪肉才是安全的。 
    **只有实现Serializable接口的子类才能被ObjectOutputStream系列化写入流,当某个 
    类实现该接口后,会被Java自动分配UID号,以便编译器识别,区分不同对象。 
    **用ObjectOutputStream系列化的对象存储到文件后,该文件是乱码,也就是不可读的 
    的用ObjectInputStream读取该类对象的属性。 
    **由于对象是有Java给对象分配相应的UID号,而UID号是根据对象的属性不同而分配的。 
    当一个类对象被系列化到文件后,如果该类改动了对象的属性,比如将某个成员变量变成私有 
    则该对象再用ObjectInputStream读取时会报异常,也就是说该系列化到文件的对象不能再被使用了 
    那么,要想继续使用属性被改动后的对象,我们可以自定义给对象分配UID号,让UID号不随对象的属性 
    变化而变化。 
    自定义对象分配UID方法如下: 
    public static final long serialVersion UID = 43L; 
    **注意: 
    静态不能被系列化,因为静态成员变量实在内存的方法区,而ObjectOutputStream只能 
    对对内存里面的数据进行系列化 
    被transient修饰的非静态成员变量也不能被系列化 
    被系列化的对象存储到文件中,该文件是不可读的,所以该文件的扩展名一般 
    不写成.txt,通常后缀名写.object 
    **ObjectOutputStream 
    **ObjectInputStream 
    (3)管道流: 
    PipedInputStream 
    PipedOutputStream 
    (4)随机访问文件:RandomAccess(重要!!!) 
    **自身具备读写方法(很牛逼!又可以读又可以写) 
    **通过skipByte(int x)和seek(int x)来达到随机访问文件 
    **该类不是IO体系子类,而是直接继承Object,但它是IO包中的成员,因为它具备读写方法 
    **该类内部封装了数组,而且通过指针对数组的元素进行操作,可以通过getFilePoint获取指针位置 
    同时可以通过seek改变指针位置 
    **该类完成读写的原理是内部封装了字节输入输出流 
    **通过该类的构造看出,该类只能操作文件,而且操作的文件只能有固定模式: 
    “r”:只读 
    “rw”:读写 
    “rws”: 
    “red”: 
    **构造方法: 
    RandomAccessFile(File file, String mode) 
    创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
    RandomAccessFile(String name, String mode) 
    创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
    **方法摘要: 
    void write(byte[] b) 
    将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。 
    void write(byte[] b, int off, int len) 
    将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。 
    void write(int b) 
    向此文件写入指定的字节。 
    int read() 
    从此文件中读取一个数据字节。 
    int read(byte[] b) 
    将最多 b.length 个数据字节从此文件读入 byte 数组。 
    int read(byte[] b, int off, int len) 
    将最多 len 个数据字节从此文件读入 byte 数组。 
    String readLine() 
    从此文件读取文本的下一行。 
    long getFilePointer() 
    返回此文件中的当前偏移量。 
    long length() 
    返回此文件的长度。 
    void seek(long pos) 
    设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。 
    (4)操作基本数据类型的流对象:DateStream 
    (5)操作字节数组流: 
    ByteArrayInputStream 
    ByteArrayOutputStream 
    11、IO流转换流的字符编码 
    (1)字符流的出现为了方便操作字符,更重要的是加入了编码转换 
    (2)通过子类转换流来完成 
    InputStreamReander 
    OutputStreamWriter 
    (3)在两个子类对象进行构造的时候可以加入编码表 
    (4)编码表: 
    将各个国家的文字用二进制数字表示并一一对应,形成一张表,这就是编码表 
    (5)常见的编码表: 
    **ASCII:美国标准信息交换码,用一个字节的七位表示 
    **ISO8859-1:拉丁码表,欧洲码表,用一个字节的八位表示 
    **GB2312:中文编码表,用两个字节表示 
    **GBK:中文编码表升级,融合录入更多的中文字符,用两个字节表示,为避免和老美重复 
    两字节的最高位都是1,即汉字都是用负数表示 
    **Unicode:国际标准码,融合了多种文字,所有文字都用两个字节表示 
    **UTF-8:用一个字节到三个字节表示。 
    注:Unicode能识别中文,UTF-8也能识别中文,但两种编码表示一个汉字所用的字节数不同 
    Unicode用两个字节,UTF-8用三个字节,故涉及到编码转换。 
    (6)在流中涉及编码表的转换只有转换流: 
    InputStreamReander 
    OutputStreamWriter 
    (7)代码示例:

        public static void write() throws IOException
            {
                OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK");
                osw1.write("你好");
                osw1.close();
    
                OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("utf-8.txt"),"UTF-8");
                osw2.write("你好");
                osw2.close();
            }
            public static void read() throws IOException
            {
                InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
                byte[] buf = new byte[1024];
                int len = isr.read(buf);
                sop(new String(buf,0,len));
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    (8)编码解码
        编码:字符串变成字节数组:String-->getBytes()-->byte[]()
        解码:字节数组变成字符串:byte[]-->new String(byte[],0,len)-->String
    (9)代码示例:
    
    • 1
    • 2
    • 3
    • 4
    public static void main(String[] args)
            {
                //编码解码1:默认编码
                String str1 = "你好";
                byte[] buf1 = str1.getBytes();//默认解码:Unicode,四个字节
    
                //编码解码2:指定编码
                String str2 = "你好";
                byte[] buf2 = str2.getBytes("UTF-8");//指定解码:UTF-8,六个字节
    
    
                //编码解码3:编码正确解码错误
                String str3 = "你好";
                byte[] buf3 = str3.getBytes("GBK");//指定编码:GBK,四个字节
                String str3 = new String(buf3,"ISO8859-1");//错误解码
    
                //编码解码4:错误编码正确解码
                String str4 = "你好";
                byte[] buf4 = str4.getBytes("ISO8859-1");//错误编码
                String str4 = new String(buf4,"GBK");//正确解码,读不出来
    
                //编码解码5:编码对了,但是解码错误了,怎么办呢?
                //此时可以将错误的解码再错编回去,载用正确编码解码
                String str5 = "你好";
                byte[] buf5 = str5.getBytes("GBK");//正确编码
                String str6 = new String(buf5,"ISO8859-1");//错误解码,读不出来
                byte[] buf6 = str6.getBytes("ISO8859-1");//再错误编码
                String str7 = new String(buf6,"GBK");//再正确解码,这样就可以读出来了
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    六、网络编程: 
    1、网络编程概述 
    (1)网络模型 
    OSI参考模型 
    TCP/IP参考模型 
    (2)网络通讯要素 
    IP地址 
    端口号 
    传输协议 
    (3)网络通讯前提: 
    **找到对方IP 
    **数据要发送到指定端口。为了标示不同的应用程序,所以给这些网络应用程序都用数字进行标示 
    。这个表示就叫端口。 
    **定义通信规则。这个规则称为通信协议,国际组织定义了通用协议TCP/IP 
    (4)计算机网络: 
    是指将地理位置不同的具有独立功能的多台计算机及其外部设备, 
    通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下, 
    实现资源共享和信息传递的计算机系统。 
    (5)IP地址: 
    IP地址 = 网络号码+主机地址

        A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
        B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
        C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
    
        特殊地址:
        127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1   
        ipconfig:查看本机IP地址
        xxx.xxx.xxx.0 网络地址
        xxx.xxx.xxx.255 广播地址
    
        A类  1.0.0.1---127.255.255.254   10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)                          (2)127.X.X.X是保留地址,用做循环测试用的。
        B类  128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
        C类  192.0.0.1---223.255.255.254 192.168.X.X是私有地址
        D类  224.0.0.1---239.255.255.254     
        E类  240.0.0.1---247.255.255.254
    (6)各种网络分类方式
        A:按网络覆盖范围划分
          局域网(几米至10公里以内)   城域网(10~100公里)   广域网(几百公里到几千公里)   国际互联网
        B:按网络拓扑结构划分
          总线型网络   星形网络   环型网络   树状网络   混合型网络
        C:按传输介质划分
          有线网   无线网
        D:按网络使用性质划分
          公用网   专用网
    (7)虚拟专用网络(Virtual Private Network ,简称VPN)指的是在公用网络上建立专用网络的技术。
        其之所以称为虚拟网,主要是因为整个VPN网络的任意两个节点之间的连接并没有传统专网
        所需的端到端的物理链路,而是架构在公用网络服务商所提供的网络平台,如Internet、
        ATM(异步传输模式〉、Frame Relay (帧中继)等之上的逻辑网络,
        用户数据在逻辑链路中传输。它涵盖了跨共享网络或公共网络的封装、
        加密和身份验证链接的专用网络的扩展。VPN主要采用了隧道技术、加解密技术、
        密钥管理技术和使用者与设备身份认证技术。
    (8)网络模型:
        ****OSI模型
            应用层
            表示层
            会话层
            传输层
            网络层
            数据连接层
            物理层
        ****TCP/IP模型
            应用层
            传输层
            网际层
            主机至网络层
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2、TCP和UDP 
    (1)UDP和TCP的区别: 
    UDP 
    将数据及源和目的封装成数据包中,不需要建立连接 
    每个数据报的大小在限制在64k内 
    因无连接,是不可靠协议 
    不需要建立连接,速度快 
    TCP 
    建立连接,形成传输数据的通道。 
    在连接中进行大数据量传输 
    通过三次握手完成连接,是可靠协议 
    必须建立连接,效率会稍低 
    注:三次握手: 
    第一次:我问你在么? 
    第二次:你回答在。 
    第三次:我反馈哦我知道你在。 
    3、Socket(UDP传输) 
    **Socket就是为网络服务提供的一种机制。 
    **通信的两端都有Socket。 
    **网络通信其实就是Socket间的通信。 
    **数据在两个Socket间通过IO传输。 
    **玩Socket主要就是记住流程,代码查文档就行 
    (1)UDP传输:DatagramSocket与DatagramPacket 
    **发送端: 
    建立DatagramSocket服务; 
    提供数据,并将数据封装到字节数组中; 
    创建DatagramPacket数据包,并把数据封装到包中,同时指定IP和接收端口 
    通过Socket服务,利用send方法将数据包发送出去; 
    关闭DatagramSocket和DatagramPacket服务。 
    **接收端: 
    建立DatagramSocket服务,并监听一个端口; 
    定义一个字节数组和一个数据包,同时将数组封装进数据包; 
    通过DatagramPacket的receive方法,将接收的数据存入定义好的数据包; 
    通过DatagramPacke关闭t的方法,获取发送数据包中的信息; 
    关闭DatagramSocket和DatagramPacket服务。 
    DatagramSocket与DatagramPacket方法摘要: 
    *****DatagramSocket 
    构造方法: 
    DatagramSocket() 
    构造数据报套接字并将其绑定到本地主机上任何可用的端口。 
    DatagramSocket(int port) 
    创建数据报套接字并将其绑定到本地主机上的指定端口。 
    DatagramSocket(int port, InetAddress laddr) 
    创建数据报套接字,将其绑定到指定的本地地址。 
    方法摘要: 
    void close() 
    关闭此数据报套接字。 
    InetAddress getInetAddress() 
    返回此套接字连接的地址。 
    InetAddress getLocalAddress() 
    获取套接字绑定的本地地址。 
    int getPort() 
    返回此套接字的端口。 
    void receive(DatagramPacket p) 
    从此套接字接收数据报包。 
    void send(DatagramPacket p) 
    从此套接字发送数据报包。 
    ****DatagramPacket 
    构造方法: 
    DatagramPacket(byte[] buf, int length) 
    构造 DatagramPacket,用来接收长度为 length 的数据包。 
    DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
    构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 
    InetAddress getAddress() 
    返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。 
    byte[] getData() 
    返回数据缓冲区。 
    int getLength() 
    返回将要发送或接收到的数据的长度。 
    int getPort() 
    返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。 
    代码示例: 
    **发送端:

        class UDPSend
            {
                public static void main(String[] args) throws Exception
                {
                    DatagramSocket ds = new DatagramSocket();
                    byte[] buf = "这是UDP发送端".getBytes();
                    DatagramPacket dp = new DatagramPacket(
                        buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
                    ds.send(dp);
                    ds.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
        ****接收端
    
    • 1
        class UDPRece
            {
                public static void main(String[] args) throws Exception
                {
                    DatagramSocket ds = new DatagramSocket(10000);
                    byte[] buf = new byte[1024];
                    DatagramPacket dp = new DatagramPacket(buf,buf.length);
                    ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
                    String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
                    String data = new String(dp.getData(),0,dp.getLength());//获取数据
                    int port = dp.getPort();//获取发送端的端口号
                    sop(ip+":"+data+":"+port);
                    ds.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
        需求1:UDP键盘录入数据,并发送给接收端
        发送端:
    
    • 1
    • 2
        class UDPSend
            {
                public static void main(String[] args) throws Exception
                {
    
                    DatagramSocket ds = new DatagramSocket();
                    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
                    String line = null;
                    while((line = bufr.readLine())!=null)
                    {
                        if("886".equals(line))
                            break;
                        byte[] buf = line.getBytes();
                        DatagramPacket dp = new DatagramPacket(
                            buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
                        ds.send(dp);
                    }
                    ds.close();
                }
    
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
        接收端:
    
    • 1
        class UDPRece
            {
                public static void main(String[] args) throws Exception
                {
                    DatagramSocket ds = new DatagramSocket(10000);
                    while(true)
                    {
                        byte[] buf = new byte[1024];
                        DatagramPacket dp = new DatagramPacket(buf,buf.length);
                        ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
                        String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
                        String data = new String(dp.getData(),0,dp.getLength());//获取数据
                        int port = dp.getPort();//获取发送端的端口号
                        sop(ip+":"+data+":"+port);
                        ds.close();
                    }
                }
    
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
        需求2:编写简单的聊天工具
        思路:
            使用多线程技术
        发送端:
    
    • 1
    • 2
    • 3
    • 4
            class UDPSend implements Runnable
            {
                private DatagramSocket ds;
                public UDPSend(){}
                public UDPSend(DatagramSocket ds)
                {
                    this.ds=ds;
                }
                public void run()
                {
                    try
                    {
                        BufferedReader bufr = new BufferedReader(
                                    new InputStreamReader(System.in));
                        String line = null;
                        while((line = bufr.readLine())!=null)
                        {
                            if("886".equals(line))
                                break;
                            byte[] buff = line.getBytes();
                            DatagramPacket dp = new DatagramPacket(
                            buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
                            ds.send(dp);
                        }
                    }
                    catch(Exception e)
                    {
                        throw new RuntimeException("发送失败");
                    }
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
        接收端:
    
    • 1
            class UDPRece implements Runnable
            {
                private DatagramSocket ds;
                public UDPSend(){}
                public UDPSend(DatagramSocket ds)
                {
                    this.ds=ds;
                }
                public void run()
                {
                    try
                    {
                        while(true)
                        {   
                            byte[] buf = new byte[1024];
                            DatagramPacket dp = new DatagramPacket(buf,buf.length);
                            ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
                            String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
                            String data = new String(dp.getData(),0,dp.getLength());//获取数据
                            int port = dp.getPort();//获取发送端的端口号
                            sop(ip+":"+data+":"+port);      
                        }
                    }
                    catch(Exception e)
                    {
                        throw new RuntimeException("接收失败");
                    }
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
        测试类:
    
    • 1
            class UDPTest
            {
                public static void main(String[] args)
                {
                    DatagramSocket sendSocket = new DatagramSocket();
                    DatagramSocket receSocket = new DatagramSocket(10000);
    
                    new Thread(new UDPSend(sendSocket)).start();
                    new Thread(new UDPRece(receSocket)).start();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    (2)TCP传输
        Socket和ServerSocket
        建立客户端和服务器端
        建立连接后,通过Socket中的IO流进行数据的传输
        关闭socket
        同样,客户端与服务器端是两个独立的应用程序。
        ****Socket
        **构造方法:
        Socket() 
            通过系统默认类型的 SocketImpl 创建未连接套接字
        Socket(InetAddress address, int port) 
            创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
        Socket(String host, int port) 
            创建一个流套接字并将其连接到指定主机上的指定端口号。
        **方法摘要:
        void close() 
            关闭此套接字。
        InetAddress getInetAddress() 
            返回套接字连接的地址。
        InputStream getInputStream() 
            返回此套接字的输入流。
        OutputStream getOutputStream() 
            返回此套接字的输出流。 
        int getPort() 
            返回此套接字连接到的远程端口。
        void shutdownInput() 
            此套接字的输入流置于“流的末尾”。 
        void shutdownOutput() 
            禁用此套接字的输出流。 
        String toString() 
            将此套接字转换为 String。
        ****ServerSocket
        **构造方法:
        ServerSocket() 
            创建非绑定服务器套接字。 
        ServerSocket(int port) 
            创建绑定到特定端口的服务器套接字。
        方法摘要:
        Socket accept() 
            侦听并接受到此套接字的连接。
        void close() 
            关闭此套接字。 
        InetAddress getInetAddress() 
            返回此服务器套接字的本地地址。
        ****TCP传输流程:
        **客户端:
        建立Socket服务,并制定要连接的主机和端口;
        获取Socket流中的输出流OutputStream,将数据写入流中,通过网络发送给服务端;
        获取Socket流中的输出流InputStream,获取服务端的反馈信息;
        关闭资源。
        **服务端:
        建立ServerSocket服务,并监听一个端口;
        通过ServerSocket服务的accept方法,获取Socket服务对象;
        使用客户端对象的读取流获取客户端发送过来的数据;
        通过客户端对象的写入流反馈信息给客户端;
        关闭资源;
        ****代码示例:
        客户端:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
            class TCPClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    OutputStream os = s.getOutputStream();
                    out.write("这是TCP发送的数据".getBytes());
                    s.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
        服务端:
    
    • 1
            class TCPServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    Socket s = ss.accept();
    
                    String ip = s.getInetAddress().getHostAddress();
                    sop(ip);
    
                    InputStream is = s.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = is.read(buf);
                    sop(new String(buf,0,len));
                    s.close();
                    ss.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
        TCP需求1:客户端给服务端发送数据,服务端接收到后反馈信息给客户端
        客户端:
    
    • 1
    • 2
            class TCPClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    OutputStream os = s.getOutputStream();
                    out.write("这是TCP发送的数据".getBytes());
    
                    InputStream is = s.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = is.read(buf);
                    sop(new String(buf,0,len));
                    s.close();
                }
            }
            服务端:
            class TCPServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    Socket s = ss.accept();
    
                    String ip = s.getInetAddress().getHostAddress();
                    sop(ip);
    
                    InputStream is = s.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = is.read(buf);
                    sop(new String(buf,0,len));
    
                    OutputStream os = s.getOutputStream();
                    out.write("这是TCP发送的数据".getBytes());
    
                    s.close();
                    ss.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
        TCP需求2:建立一个文本转换服务端,客户给服务端发送文本,服务端将数据转换成大写后返回给客户端
              当客户端输入over时,转换结束
        客户端:
    
    • 1
    • 2
    • 3
            class TCPClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
                    BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
                                            s.getOutputStream()));
                    BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                                            s.getInputStream()));
                    String line = null;
                    while((line = bufr.readLine())!=null)
                    {
                        if("over".equals(line))
                            break;
                        bufOut.write(line);
                        bufOut.newLine();
                        bufOut.flush();
                        String retVal = bufIn.readLine();
                        sop("server:"+retVal);
                    }
                    bufr.close();
                    s.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
        服务端:
    
    • 1
            class TCPServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    Socket s = ss.accept();
    
                    String ip = s.getInetAddress().getHostAddress();
                    sop(ip);
    
                    BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                                            s.getInputStream()));
                    BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
                                            s.getOutputStream()));
    
                    while((line = bufIn.readLine())!=null)
                    {
                        bufOut.write(line.toUpperCase());
                        bufOut.newLine();
                        bufOut.flush();
                    }
                    s.close();
                    ss.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
        **需求3:拷贝文件
        客户端:
    
    • 1
    • 2
            class TCPClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    BufferedReader bufr = new BufferedReader(new FileReader("g:\\demo.txt"));
                    PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                    String line = null;
                    while((line = bufr.readLine())!=null)
                    {
                        pw.println();
                    }
                    s.shutDownOutput();
                    BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                                            s.getInputStream()));
                    String retVal = bufIn.readLine();
                    sop(retVal);
                    bufr.close();
                    s.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
        服务端:
    
    • 1
            class TCPServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    Socket s = ss.accept();
    
                    String ip = s.getInetAddress().getHostAddress();
                    sop(ip);
    
                    BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                                            s.getInputStream()));
                    PrintWriter out = new PrintWriter(new FileWriter"copy.txt",true);
                    String line =null;
                    while((line = bufIn.readLine())!=null)
                    {
                        out.write(line);
                    }
                    PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                    pw.println("上传成功");
                    out.close();
                    s.close();
                    ss.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
        需求4:上传图片
        客户端:
    
    • 1
    • 2
            class TCPClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    FileInputStream fis = new FileInputStream("g:\\1.bmp");
                    OutputStream out = s.getOutputStream();
                    byte[] buf = new byte[1024];
                    int len = 0;
                    while((len = bufr.read())!=-1)
                    {
                        out.write(buf,0,len);
                    }
                    s.shutDownOutput();
    
                    InputStream in = s.getInputStream();
                    byte[] bufIn = new byte[1024];
                    int lenIn = in.read(bufIn);
                    sop(new String(bufIn,0,lenIn);
                    fis.close();
                    s.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
        服务端:
    
    • 1
            class TCPServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    Socket s = ss.accept();
    
                    String ip = s.getInetAddress().getHostAddress();
                    sop(ip);
                    FileOutputStream fos = new FileOutputStream("g:\\copy.bmp");
                    InputStream in = s.getInputStream();
                    byte[] bufIn = new byte[1024];
                    int lenIn = 0;
                    while((lenIn=bufIn.read())!=-1)
                    {
                        fos.write(bufIn,0,lenIn)
                    }
    
                    OutputStream outIn = s.getOutputStream();
                    outIn.write("上传成功".getBytes());
                    fos.close();
                    s.close();
                    ss.close();
                }
            }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
        需求5:客户端并发登陆
            客户端通过键盘录入用户名,服务端对这个用户名进行校验
            如果用户存在,在服务端现实xxx已登录,并在客户端现实欢迎xxx
            如果用户不存在,在服务端现实xxx正在尝试登陆,并在客户端现实xxx用户不存在
            最多登陆三次。
        校验端:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
            class User implements Runnable
            (
                private Socket s;
                public User(){}
                public User(Socket s)
                {
                    this.s=s;
                }
                public void run()
                {
                    try
                    {
                        BufferedReader bufrIn = new BufferedReader(
                                new InputStream(s.getInputStream()))
                        String name = bufrIn.readLine();
                        if(name==null)
                        {
                            sop("用户名为空");
                            break;
                        }
                        BufferedReader bufr = new BufferedReader(
                                new FileReader("user.txt"));
                        PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                        String line = null;
                        boolean flag = false;
                        while((line = bufr.reanLine())!=null)
                        {
                            if(line.equals(name))
                            {
                                flag = true;
                                break;
                            }
                            if(flag)
                            {
                                sop(name+"已登陆");
                                pw.println("欢迎"+name);
                                break;
                            }
                            else
                            {
                                sop(name+"正尝试登陆");
                                pw.println(name+"用户不存在");
                            }
    
                        }
                        s.close();
                    }
                    catch(Exception e)
                    {
                        throw new RuntimeException("用户校验失败");
                    }
                }
            )
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
        客户端:
    
    • 1
            class LoginClient
            {
                public static void main(String[] args)
                {
                    Socket s = new Socket("192.168.1.253",10000);
                    BufferedReader bufr = new BufferedReader(
                                new InputStreamReader(System.in)));
                    PrintWriter out = new PrintWriter(s.getOutputStream(),true);
                    BufferedReader bufIn = new BufferedReader(
                                new InputStreamReader(s.getInputStream()));
                    for(int i=0;i<3;i++)
                    {
                        String line = bufr.readLine();
                        if(line == null)
                        {
                            sop("用户名不能为空!");
                            break;
                        }
                        out.write(line);
                        String retVal = bufIn.readLine();
                        sop(retVal);    
                    }
                    bufr.close();
                    s.close();
                }
            }
    • 服务端
    class LoginServer
            {
                public static void main(String[] args)
                {
                    ServerSocket ss = new ServerSocket(10000);
                    while(true)
                    {
                        Socket s = ss.accept();
                        new Thread(new User()).start();
                    }
                }
            }

    相关文章

      暂无相关文章
    相关栏目:

    用户点评