JAVASE学习总结(二)

一、集合框架和泛型
JAVA集合框架提供了一套性能优良、使用方便的接口和类,它们存放于java.util包中。JAVA的集合类主要由Map接口和Collection接口派生而来。Collection接口有两个常用的子接口:List接口和Set接口。所以通常说JAVA集合框架由三大类接口构成。如下图: 
    


1.List接口
        Collection接口是最基本的集合接口,可以存储一组不唯一、无序的对象。而List接口继承自Collection接口,是有序的集合。用户可以通过索引访问List接口中的元素。List接口中允许存放重复的元素,也就是说List可以存放一组不唯一、但有序的对象。
List接口有两个常用的实现类:ArrayList和LinkedList

1.1 ArrayList类
        ArrayList类对数组进行了封装,实现了长度可变的数组,和数组有相同的存储方式,在内存在分配连续的空间,所以被称为动态数组。但是他不等同于数组,他可以添加任何类型的数据,并且添加的数据都将转换成Object类型,而且只能添加同一类型的数据。
        ArrayList类提供了很多方法用于操作数据: 

 
示例:
        public static void mai(String[] args){
                List list = new ArrayList();
                list.add("TOM");
                list.add("JOSE");
                list.add("JACK"); //向列表中添加元素。
                System.out.println(list.contains("JIM"));  //判断列表中是否有JIM这个元素。返回false.
                list.remove(0);//将列表中第一个元素(TOM)删除。
                list.set(0,"SAM");//将列表中第一个元素替换为SAM.
                for(int i=0;i<list.size();i++){ //for循环遍历集合
                        String name = (String)list.get(i); //须强制类型转换,因为存储在集合中的数据都转换成了Object类型
                        System.out.println(name);
                }
                System.out.println(list.indexOf("JACK")); //返回JACK在集合中出现的索引值。
                for(Object obj:list){  //foreach遍历集合
                        String name = (String)obj;
                        System.out.println(name);
                }
                list.clear();//清空list中的数据。
                System.out.println(list.isEmpty());//判断list集合是否为空。
        }

ArrayList的优点:因为它可以使用索引直接访问数据,所以他遍历元素和随机访问元素的效率比较高。
                  缺点:因为和数组的存储方式相同,在内存中分配了连续的空间,再添加和删除非尾部元素时会导致后面的元素移动,造成了操作性能低下。

1.2 LinkedList类
        LinkedList采用了链表的存储方式,优点在于插入、删除元素时效率比较高;缺点是查找效率很低。当对数据添加和删除或修改比较多时,采用LinkedList存储数据。
        LinkedList除包括ArrayList类所包含的方法外,还提供了以下方法:

 
2. Set接口
        Set接口是Collection接口的另外一个常用接口,他可以存储一组唯一、无序的对象。(不能保存重复的对象)
        Set接口常用的实现类是HashSet
2.1 HashSet类
        特点:查找效率高
                   ⊙存储唯一的对象
                   
⊙HashSet类是非线程安全的
           
HashSet类常用的方法List中的方法基本相同,但是值得注意的是:HashSet类没有get()方法,无法通过get()方法取出每个对象,所以Set接口无法使用普通for循环遍历,只能使用foreach或者Iterator接口遍历。
示例:
        //关键代码:
        Student stu1 = new Student(001,"TOM");
        Studnet stu2 = new Student(002,"JIM");
        Set stuSet = new HashSet();
        stuSet.add(stu1);
        stuSet.add(stu2);
        for(Object obj:stuSet){   //foreach遍历
                Student student = (Student)obj;
                System.out.println(student.getID()+"  "+student.getName());
        } 
        //也可以用Iterator接口遍历  Iterator接口的三个方法:iterator()方法获取迭代器、hasNext()方法判断是否有下一个元素、
       // next()方法得到一个元素。
        Iterator it = stuSet.iterator(); //iterator()方法获取迭代器,返回一个Iterator对象
        while(it.hasNext()){     //hasNext()方法判断是否存在下一个可访问的元素,如果仍有元素可以迭代,返回true.
                Student student = (Student)it.next();   //next()方法 返回访问的下一个元素
                System.out.println(student.getID()+"  "+student.getName());
        }
        
2.2 TreeSet类
        使用元素的自然顺序对元素进行排序,插入该 set 的所有元素都必须实现 Comparable 接口。Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序(升序),类的 compareTo 方法被称为它的自然比较方法

/*
TreeSet的性能比 HashSet差但是我们  在需要排序的时候可以用TreeSet  因为他是
自然排序也就是 升序 
下面是TreeSet实现代码  
这个类也似只能通过迭代器迭代元素
*/
import java.util.*;
class Test
{  
   public static void main(String []args)
  {
   TreeSet<Point> ts=new TreeSet<Point>() ; 
   ts.add(new Point(2,3));
   ts.add(new Point(1,7));
   ts.add(new Point(8,8));
   ts.add(new Point(1,3));
   ts.add(new Point(0,4)); 
   Iterator i=ts.iterator();  //迭代器
   while(i.hasNext())
   {
    System.out.println(i.next());
   }
  }
}

class  Point implements Comparable<Point>   //实现 Comparable 接口  插入到TreeSet集合中的元素必须实现 
{
 int x,y;
 Point(int x,int y)
 {
  this.x=x;
  this.y=y;
 }
 Point()
 {
  this.x=this.y=0;
 }
 public int compareTo(Point o)  //实现Comparable中的 compareTo()方法
 {
  Point p=(Point)o;
  int num=x>p.x?1:(x==p.x?0:-1) ;
  if(num==0)
    return y>p.y?1:(y==p.y?0:-1);
  return num ;
  
 }
 public String toString()
 {
  return "x="+x+",y="+y;
 }

}

3.Map接口
        Map接口存储一组成对的键-值对象,提供了key到value的映射,通过key来检索。key不要求有序,但是不可以重复,而value不要求有序,但可以重复。
Map接口没有add()方法,常用的方法有:
        put(key,value)方法  将相互关联的一个key与value放入集合,如果此Map中已经包含了该key与value,则旧值被替换。
        remove(key)方法    删除与key相关联的映射,如果无此key,则返回null
        get(key)方法          获得与key相关联的value
        containsKey(key)   判断集合中是否存在key
        containsValue(value) 判断集合中是否存在value
        isEmpty()    判断集合中是否存在元素
        clear()      清空集合中的所有元素
        size()        返回集合中元素的数量,即该集合的长度
        keySet()   获取所有key的元素
        values()    获取所有value的集合
3.1 HashMap类
            最常用的Map实现类是HashMap,优点是查询指定元素效率高。
            示例:
                    //关键代码:
                    Student stu1 = new Student("张三","男");
                    Student stu2 = new Student("李四","女");
                    Map stus = new HashMap();
                    stus.put("Jack",stu1);
                    stus.put("Jose",stu2);
                    if(stus.containsKey("Jack")){     //containsKey()判断是否存在与key相关联的元素。
                            Student stu = (Student)stus.get("Jack");
                            System.out.println("Jack的中文名字是:"+stu.getName());
                    } 
                    System.out.println("学生的英文名字分别是:");
                    for(Object obj : stus.keySet()){
                            System.out.println(obj.toString());
                    } 
                    System.out.println("学生的详细信息是:");
                    for(Object obj:values()){   //foreach遍历         values()方法用于获取该集合中所有value的集合
                            Student student = (Student) obj;
                            System.out.println(student.getName()+"  "+student.getSex());
                    } 
                    //用iterator遍历如下:
                    Iterator iter = stus.values().iterator();
                    while(iter.hasNext()){
                            Student students = (Student)iter.next();
                            System.out.println(students.getName()+"  "+students.getSex());
                    } 

3.2 TreeMap类
            该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
            示例:
                    
  1. public class TestSort {  
  2. public static void main(String[] args) {  
  3.     TreeMap map = new TreeMap();        
  4.   
  5.         for(int i=0; i<3; i++) {  
  6.   
  7.         String  s = ""+(int)(Math.random()*1000);  
  8.   
  9.         map.put(s,s);  
  10.   
  11.     }  
  12.   
  13.     map.put("abcd","abcd");  
  14.   
  15.     map.put("Abc""Abc");  
  16.   
  17.     map.put("bbb","bbb");  
  18.   
  19.     map.put("BBBB""BBBB");  
  20.   
  21.     map.put("北京","北京");  
  22.   
  23.     map.put("中国","中国");  
  24.   
  25.     map.put("上海""上海");  
  26.   
  27.     map.put("厦门""厦门");  
  28.   
  29.     map.put("香港""香港");  
  30.   
  31.     map.put("碑海""碑海");  
  32.   
  33.     Collection col = map.values();  
  34.   
  35.     Iterator it = col.iterator();  
  36.   
  37.     while(it.hasNext()) {  
  38.   
  39.         System.out.println(it.next());  
  40.   
  41.     }  
  42.   
  43. }  
  44.   
  45.  

  1. public class CollatorComparator implements Comparator {  
  2.   
  3. Collator collator = Collator.getInstance();  
  4.   
  5.  public int compare(Object element1, Object element2) {  
  6.   
  7.     CollationKey key1 = collator.getCollationKey(element1.toString());  
  8.   
  9.     CollationKey key2 = collator.getCollationKey(element2.toString());  
  10.   
  11.     return key1.compareTo(key2);  
  12.   
  13. }  
  14.   
  15. }  

运行结果:

132

205

287

Abc

BBBB

abcd

bbb

上海

中国

北京

厦门

碑海

香港

4.Collections类操作集合
        Collections 类是JAVA提供的一个集合操作工具类,它包含了大量的静态方法,用于实现对集合元素的排序、查找和替换等操作。
        Collections和Collection是不同的,前者是集合的操作类,后者是集合接口。
4.1 对集合元素排序、查找
        在JAVA中,如果想实现一个类的对象之间比较大小,那么这个类就要实现Comparable接口。此接口强行对实现它的每个类的对象进行整体排序,也称为类的自然排序。类的compareTo()方法用于比较此对象与指定对象的顺序。
        int compareTo(Object obj);
实现Comparable接口的对象列表可以通过Collections.sort()方法(Arrays.sort()方法)进行自动排序。
而Collections.binarySearch()方法可以对集合元素进行查找。
示例:
        关键代码:
        public class Student implements Comparable{   //定义了学生类并实现了Comparable接口。
                private int number = 0;
                private String name;
                private String gender;
                public int getNumber(){
                        return number;
                }
                public void setNumber(int number){
                        this.number = number;
                }
                ...省略name 、gender的get() set()方法
                public int comparaTo(Object obj){  //重写了Comparable接口中的comparaTo(Object obj)方法
                        Student stu = (Student)obj;
                        if(this.number==stu.getNumber){
                                return 0;
                        }else if(this.number>stu.getNumber){
                                return 1;
                        }else{
                                return -1;
                        }
                }
        } 

class StudentTest {
        pubilc static void main(String[] args){
                Studnet student1 = new Student();
                studnet1.setNumber(5);
                
Studnet student2 = new Student();
                studnet1.setNumber(3); 
                Studnet student3 = new Student();
                studnet1.setNumber(2); 
                Studnet student4 = new Student();
                studnet1.setNumber4); 
                Studnet student5 = new Student();
                studnet1.setNumber(1); 
                ArrayList<Student> list = new ArrayList<Student>();
                list.add(student1);
                
list.add(student2); 
                list.add(student3); 
                list.add(student4); 
                list.add(student5); 
                System.out.println("排序前:")
                for(Object obj:list){  //foreach遍历
                        Studnet stu = (Student)obj;
                        System.out.println(stu.getNumber()+" "+stu.getName()+" "+stu.getGender());
                }
                
Collections.sort(list);  //使用Collections的sort()方法对list进行排序。 
                System.out.println("排序后:");
                Iterator iterator = list.iterator(); //使用Iterator遍历
                while(iterator.hasNext()){
                        Student stus = (Student)iterator.next();
                        System.out.println(
stu.getNumber()+" "+stu.getName()+" "+stu.getGender());
                }
                //使用Collections的binarySearch()方法对list进行查找
                int index = Collections.binarySearch(list,student2);
                System.out.println("student2的索引是:"+index);
                //使用Collections的fill()方法使用指定值替换列表中所有的元素;
replaceAll()方法使用另一个值替换 
                //   列表中出现的所有指定元素。reverse()方法反转列表中元素的顺序。
 
                Collections.reverse(list);                
                Collections.fill(list,student1);
                Collections.replaceAll(list,studnet1,student5);
        }
}

5.泛型
        将对象的类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。泛型的本质就是参数化类型。 
        创建集合时使用泛型指定集合中元素的类型,从集合中取出元素时无需进行强制类型转换。如果把非指定类型的元素放入集合时,会提示编译错误。
        示例:
                Map<String,Stduent> students = new HashMap<String,Student>();
                students.put("Jack",student1);
                students.put("Jose",student2);
                for(String key:students.keySet()){//遍历key值
                        System.out.println(key);//key无需再强制类型转换
                } 
                for(Student stu:students.values()){ //stu无需再强制类型转换
                        Sytem.out.println(stu.getName()+" "+stu.getSex())
                }
                Iterator it = studnets.iterator();
                while(it.hasNext()){
                        Studnet stus = it.next();//   it.next()获取到的对象无需再强制类型转换
                        System.out.println(stus.getName()+" "+suts.getSex());
                }
学习泛型还需了解两个重要的概念:
        a.参数化类型:参数化类型包含了一个类或者接口,以及实际的类型参数列表。
        b.类型变量:是一种非限定性标识符,用来指定类、接口或者方法的类型。

二、JAVA中常用的实用类
        1.JAVA API
                API除了有“应用程序编程接口”的意思外,还特指API帮助文档。
                API提供了以下常用的包:
                java.lang 包含了java程序的基础类和接口。如包装类、Math类、String类等
                java.util  包含了系统辅助类或者工具类。如Collection、list、Map等集合类等
                java.io    包含了输入输出有关的类。如InputStream \OutputStream 、Reader\Writer类等
                java.net  包含了与网络有关的类。如:Socket、ServerSocket类等
                java.sql   包含了与数据库有关的类。如:Connection、Statement类等 
        2.枚举类
                枚举类是由一组固定的常量组成的类,使用关键字enum定义。
                例如定义标识性别的枚举类:
                public enum Genders{       //使用关键字enum而且修饰符一般为public
                        Male,Female           //各个常量之间用","隔开
                }
                示例:
                public enum Week{     //定义枚举类
                        MON,TUE,WED,THR,FRI,SAT,SUN
                }
                class WeekDemo{
                public void doWhat(Week day){
                        switch(day){
                                case MON:
                                case TUE:
                                case WED:
                                case THU:
                                case FRI:
                                        System.out.println("工作日,努力工作");
                                        break;
                                case SAT:
                                case SUN:
                                        System.out.println("休息日,钓鱼、看电影");
                                        break;
                                default:
                                        System.out.println("一个星期就7天");
                        }
                }
                public static void main(String[] args){
                        WeekDemo wd = new WeekDemo();
                        wd.doWhat(Week.THU);
                        wd.doWhat(Week.SAT);
                }
              }
        在程序中使用枚举类的好处:
                a.是代码易于维护,有助于确保为变量指定合法、期望的值。
                b.便于输入,使用枚举赋值,只需在枚举名后面输入“.”就能将所有枚举值显示出来。
    3.包装类
        JAVA语言是面向对象的,但JAVA中的基本数据类型却不是面向对象的,为了解决这个不足,JAVA为8个基本数据类型都分别设计了一个对应的类,称为包装类。
        包装类的主要用途有两个:
        a.包装类作为和基本数据类型对应的类存在,方便对象的操作。
        b.包装类包含了每种基本数据类型的相关属性,如最大、最小值以及相关的操作方法。
       
        包装类和基本数据类型的转换
            1.基本数据类型转换成包装类
                a>使用包装类的两个构造方法
                public Type(type value)
                public Type(String value)
                使用new关键字将一个基本数据类型的值包装成一个对象。如,要把int包装成Integer类
                int x = 21;
                Integer intX = new Integer(21); //第一种构造方法public Type(type value)
                Integer intX = new Integer("21");//第二种构造方法public Type(String value)
                char y = w;
                Character charY = new Character('w');//正确
                Character charY = new Character("w"); //这种形式是错误的,因为char y是字符,不是字符串
                b>使用包装类的方法valueOf()
                如:
                Integer intX = Integer.valueOf("21"); //正确
                Character charY = Character.valueOf("w");//错误,y是char类型不是String类型
                Character charY = Character.valueOf('w');正确
            2.包装类转换成基本数据类型
                方法:public type typeValue(); 如:byteValue()、charValue()分别返回byte、char值。
                Integer integer = new Integer(25);
                int intX = integer.intValue()//调用Integer包装类的intValue()方法
            3.基本数据类型和包装类自动转换
                JAVA5.0之后,实现了包装类和基本数据类型的自动转换,编译器会自动完成。
                如:
                Integer intObject = 5;//基本数据类型转换成包装类
                int intValue = intObject; //包装类转换成基本数据类型
            注:包装类对象只有在基本数据类型需要用对象来表示时才使用,并不是用来取代基本数据类型的。否则相互转换会增加系统的额外负担。
    4.Math类
            java.lang.Math类是一个final类,提供了一些基本数学运算和几何运算的方法。 
            Math类常见的方法有:
            static double abs(double a)   返回double值得绝对值。如:Math.abs(-3.3);返回3.3
            static double max(double a,double b) 返回最大值。如:Math.max(2.5,6.3);返回6.3
            static double random();随机返回一个double值,该值大于等于0.0且小于1.0  (>=0.0&&<1.0)
            如:随机产生0-9的数
            int number = (int)(Math.random()*10);
    5.String类
            String类提供了很多方法,如,获取字符串的长度,比较、连接、提取、替换等等。
            a>length()返回字符串的长度
            b>equals()比较两个字符串的值是否相同。str1.equals(str2);
                注:java中"=="和equals()方法应用于字符串时,所判断的内容是不同的。"=="判断的是两个字符串在内存中的地址是否相同,也就是判断是否是同一个对象,而equals()判断的是两个字符串的值是否相等。用equals()比较两个字符串"java"和"JAVA"时是不相等的,但他们都是同一门课程,因此需要使用另一个方法equalsIgnoreCase()方法。这个方法比较字符串时会忽略字符的大小写。
            c>equalsIgnoreCase()//忽略大小写
                toLowerCase()//转换成小写
                toUpperCase() //转换成大写
            d>concat()方法//连接字符串。如:str1.concat(str2);返回一个新的字符串str1str2
                连接字符串也可以用"+"来连接
            e> indexOf(int ch)
                indexOf(String str)  //搜索第一个出现的字符ch(字符串str)
                lastIndexOf(int ch)
                lastIndexOf(String str)//搜索最后一个出现的字符ch(字符串str)
                substring(int index)//提取从索引位置开始的字符串部分
                substring(beginindex,endindex)//提取两个索引之间的字符串部分
                trim()//返回一个前后不含任何空格的字符串副本
                示例:判断邮箱名称和JAVA文件名称是否合法
                 public class Test{
                    public static void main(String[] args){
                            boolean fileflag = false;//文件信号量标识
                            boolean mainflag = false;//邮箱标识
                            Scanner input = new Scanner(System.in);
                            String filename = input.next();
                            String mailname = input.next();
                            //检查JAVA文件名是否合法
                            int index = filename.lastIndexOf(‘.’);//"."的位置
                            if(index!=-1&&index!=0&&filename.substing(index+1,filename.length()).equals("java")){
                                    fileflag = true;
                            }else{
                                    System.out.println("文件名无效");
                            }
                            //检查邮箱格式是否合法
                            if(mailname.indexOf(‘@’)!=-1&&mailname.indexOf(‘@’)!=0&&mailname.indexof(‘.’)>mailna
                            me.indexOf(’@‘)){
                                        mailflag = true;
                            }else{
                                        System.out.println("无效的邮箱名");
                            }
                            if(fileflag&&mailflag){
                                    System.out.println("提交成功");
                            }else{
                                    System.out.prinltn("提交失败");
                            }
                    }
            }
            f> split()//拆分字符串
            示例:关键代码:
                String words ="abc+def+ghi+jkl";
                String[] word = new String[10];
                word = words.split("+");//将字符串按"+"拆分
                for(String str:word){
                        System.out.println(str);
                }
        6.StringBuffer类和StringBuilder类
        StringBuffer类的声明和初始化
            StringBuffer sb = new StringBuffer("浪子回头");
        StringBuffer常用的方法
            a> toString() //转换为字符串类型
            b> append() //追加字符串 str.append(args); 该方法不同于String的concat()方法的是StringBuffer类可
                                以将任何类型的值追加到字符串后面。
                示例:
                //关键代码:
                StringBuffer sb = new StringBuffer("浪子回头");
                StringBuffer sb2 = sb.append("金不换");
                int num = 100000000;
                StringBuffer sb3 = sb2.append(num);//追加了一个int类型的整数
                System.out.println(sb3);
                运行结果:浪子回头金不换100000000
            c> insert(index,args)方法   将参数插入到指定的位置后返回,参数可以是任何类型。
                示例:从后往前每隔3位插入","
                String num = "1234567890";
                StringBuffer sb = new StringBuffer(num);
                for(int i=sb.length()-3;i>0;i=i-3){
                        sb.insert(i,',');
                }
                System.out.prinltn(sb.toString());
        StringBuilder类
            StringBuilder类是一个可变的字符序列,此类提供一个与StringBuffer兼容的API,它比StringBuffer实
                                现快。
 7.String 、StringBuffer、StringBuilder的区别
         String:字符串常量                   
                String 是不可变的对象,在每次对String进行改变的时候其实等于生成了一个新的String对象,然后
                            指向新的String对象地址。
        StringBuffer: 字符串变量
                StringBuffer是可变的字符串,在每次对StringBuffer对象进行改变时,会对StringBuffer自身进行
                            操作,而不会形成新的对象。在字符串连接操作中,Stringbuffer比String效率
        StringBuilder: 字符串变量
                StringBuilder它与StringBuffer类等价,区别在于StringBuffer类是线程安全的,StringBuilder类是
                            单线程的,不提供同步。
8.日期和时间类
        Date类、Calendar类、SimpleDateFormat类等
        Date date = new Date();//获取系统当前时间
        Calendar类是Date类的增强版,它是个抽象类,可以通过静态方法getInstance()方法获得Calendar对象
        SimpleDateFormat类用来格式化时间
        示例:关键代码:
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        System.out.println("当前时间为:"+sdf.format(date));
        输出结果:当前时间为:2013年8月30日 14:47:34
        Calendar示例关键代码:
        Calendar c = Calendar.getInstance();
        System.out.println(c.get(Calendar.YEAR)+"年"+(c.get(Calendar.MONTH)+1)+"月"
            +c.get(Calendar.DAY_OF_MONTH)+"日"); 
        Ststem.out.println("星期"+(c.get(Calendar.DAY_OF_WEEK)-1);
9.Random类
        Random类用于生成随机数。
        构造方法:Random()/Random(long seed)种子随机数生成器
        示例:生成10个10以内大于或等于0的整数
            Random rand = new Random(100);
            Random rand2 = new Random(100)
            for(int i=0;i<10;i++){
                    int num = rand.nextInt(10);
                    System.out.println("第"+(i+1)+"个随机数为:"+num);
            } 
            for(int i=0;i<10;i++){
                    int num2 = rand2.nextInt(10);
                    System.out.println(
"第"+(i+1)+"个随机数为:"+num2);
            }
             //两个随机数生成器用同一个种子,生成的随机数相同。
        示例:随机购买双色球
             
import java.util.HashSet;
            import java.util.Random;
            import java.util.Set;
            public class Test {
            public static void main(String[] args) {
            System.out.println("=============机选福利彩票============");
            System.out.println("普通号码:");
            Random r = new Random();
            Set<Integer> num = new HashSet<Integer>();
            while(num.size()<6){
            num.add(r.nextInt(33)+1);
            }
            Object[] nums = num.toArray();
            for(int i=0;i<num.size();i++){
            System.out.println("第"+(i+1)+"个数为:"+nums[i]);
            }
            System.out.println("=================================");
            Random r2 = new Random();
            System.out.println("特别号码:"+(r2.nextInt(16)+1));
            }
            }
               运行结果:
                =============机选福利彩票============
                    普通号码:
                    第1个数为:22
                    第2个数为:8
                    第3个数为:26
                    第4个数为:29
                    第5个数为:28
                    第6个数为:13
                    =================================
                    特别号码:16
 三、输入流\输出流
        输入输出流是用来操作数据的读写的,而数据一般都是保存在文件File当中的。
       1. File类用来操作文件或目录
            File类常用的方法有:
            boolean exists()//检测文件是否存在
            getAbsolutePath()//返回文件的绝对路径
            getName()//返回文件的名称
            delete()//删除指定的文件
            createNewFile()//创建空文件,不创建文件夹
            isDirectory()//测试此File对象表示的是否是目录
            mkdir()//创建由该File对象表示的目录
            mkdirs()//创建包括父目录的目录
            lastModified()//返回文件的最后修改日期
            length()//返回文件的大小,单位:字节
            示例:
            
import java.io.File;
            import java.io.IOException;
            import java.text.SimpleDateFormat;
            import java.util.Date;
            public class FileTest {
            public static void main(String[] args) {
            File f = new File("test.txt");
            if(!f.exists()){
            try {
            f.createNewFile();
            } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            }
            }
            long modifiedTime = f.lastModified();
            Date date=new Date(modifiedTime);
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:MM");
                String dd=sdf.format(date);
            System.out.println("File name:" + f.getName()  + " \tFile create Time: "+dd);
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getName());
            System.out.println(f.length());

                }

        }
        结果:
                
File name:test.txt File create Time: 2013-08-30 16:08
                D:\eclipse\workspace\testJava\test.txt
                test.txt
                0
  2.JAVA中的流
        流按流向分为输入流和输出流,输入流有字节流(InputStream)和字符流(Reader),输出流也有字节流
                (OutputStream)和字符流(Writer)。
        示例:用字节流读取文件(读写数组的大小会影响数据的完整性,会发生多读多写现象)
        
import java.io.FileInputStream;
        import java.io.FileNotFoundException;
        import java.io.FileOutputStream;
        import java.io.IOException;
        public class FileInOut {
        public static void main(String[] args) {
        try {
        FileInputStream fis = new FileInputStream("D:\\CollectionTest.java");
        FileOutputStream fos = new FileOutputStream("D:\\Collection.java");
        System.out.println("File size is:"+fis.available()+"  File is copying...");
        byte[] buf = new byte[1024];
        int len=0;                                           
        while((len=fis.read(buf))!=-1){                
        fos.write(buf,0,len);              
        }
        System.out.println("file is copyed");
        fis.close();
        fos.close();
        } catch (FileNotFoundException e) {
        e.printStackTrace();
        } catch (IOException e) {
        e.printStackTrace();
        }
        }
    }
    示例2:用字符流读写文件 (Reader\Writer)
                   
FileInputStream fis = new FileInputStream("d:\\Collection.java");
                    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                    FileOutputStream fos = new FileOutputStream("D:\\Collection2.java");
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
                    String line = null;
                    while((line = br.readLine())!=null){
                            bw.write(line);
                            bw.newLine();
                            bw.flush();
                    }
                    fis.close();
                    fos.close();
                    br.close();
                    bw.close();

        示例3:使用字节流DataInputStream\DataOutputStream读写二进制文件
        public class DataInOut {
        public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("d:\\Collection.java");
        DataInputStream dis = new DataInputStream(fis);
        FileOutputStream fos = new FileOutputStream("d:\\Collection2.java");
        DataOutputStream dos = new DataOutputStream(fos);
        int len;
        while((len=dis.read())!=-1){
        dos.write(len);
        }
        fis.close();
        dos.close();
        }
        }
        DataInputStream\DataOutputStream搭配使用可以按照与平台无关的方式从流中读写基本数据类型的数据
        其中提供了readUTF()和writeUTF()方法可以读写UTF-8字符编码的数据。

3.序列化保存对象信息和反序列化获取对象信息
        序列化:就是将对象的状态存储到特定介质(硬盘、网络)中的过程
        JAVA中只有实现了Serializable接口的类的对象才能被序列化。JDK中有些类库如String类、包装类、Date
        类等都实现了Serializable接口。
        对象序列化的步骤分两大步:
            a>创建一个对象输出流(ObjectOutputStream),它可以包装一个其他类型的输出流,如文件输出流
                (FileOutputStream)
            b>通过对象输出流的wirteObject()方法写对象,也就是输出可序列化对象。
        反序列化:就是从介质中获取对象信息,然后重新构建为对象的过程
        反序列化的步骤分两大步:
            a> 创建一个对象输入流(ObjectInputStream),可以包装一个输人流,如文件输入流(FileInputStream)
            b> 通过对象输入流的readObject()方法读取对象,返回一个Object类型的对象。
        序列化和反序列化示例:    
        import java.io.FileInputStream;
        import java.io.FileNotFoundException;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.io.ObjectInputStream;
        import java.io.ObjectOutputStream;
        import java.io.Serializable;
        import java.util.ArrayList;
        import java.util.List;

        class Student implements Serializable{
private static final long serialVersionUID = 1L;
private int ID;
private transient String password; //用transient关键字修饰的属性不能被序列化(安全)
private String name;
private String sex;
public Student(){
}
public Student(int ID,String password,String name,String sex){
this.ID = ID;
this.name =name;
this.sex = sex;
}
public void setID(int ID){
this.ID = ID;
}
public int getID(){
return ID;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setSex(String sex){
this.sex = sex;
}
public String getSex(){
return sex;
}

        }
        public class SerializableTest {

/**
* 使用序列化保存对象信息\使用反序列化获取对象信息
* @param args
*/
public static void main(String[] args) throws IOException {
Student stu1 = new Student(1,"admin","JIM","male");
Student stu2 = new Student(2,"admin","JOSE","female");
Student stu3 = new Student(3,"admin","JACK","female");
List<Student> stulist = new ArrayList<Student>();
stulist.add(stu1);
stulist.add(stu2);
stulist.add(stu3);
try {
ObjectOutputStream oos = 
                                new ObjectOutputStream(new FileOutputStream("D:\\Serializable.txt"));
oos.writeObject(stulist); //将stulist对象写入oos中,即:D:\Serializable.txt中
if(oos!=null){
oos.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {//反序列化获取对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Serializable.txt"));
//将读取到的对象保存到ArrayList中
                                
ArrayList<Student> list2 = (ArrayList<Student>) ois.readObject();
System.out.println("Students massage is:");
for(Student students:list2){  //遍历ArrayList:  list2
System.out.println("ID:  "+students.getID()+"   密码: "+students.getPassword()
+"    NAME:  "+students.getName()+"    GENDER:  "+students.getSex());
}
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
    }
        }

         反序列化结果:
        Students massage is:
        ID:  1   密码: null    NAME:  JIM    GENDER:  male            //由于学生类的“密码”属性被transient修饰
        ID:  2   密码: null    NAME:  JOSE    GENDER:  female            //所以不能被序列化,提高了安全性。
        ID:  3   密码: null    NAME:  JACK    GENDER:  female

    序列化的算法规则:
    a> 所有保存到磁盘中的对象都有一个序列号
    b> 当程序试图序列化一个对象时,会先检查是否已经被序列化,只有序列化后的对象才能被转换成字节输出
    c> 如果对象已经被序列化,则程序直接输出一个序列化编号,而不重新序列化。
 
 4.反射
        4.1 定义:JAVA中的反射是指在运行状态中,动态获取信息以及动态调用对象方法的功能。
        4.2 JAVA反射有三个动态性质:
            a>运行时生成对象实例
            b>运行期间调用方法
            c>运行时更改属性
        4.3 JAVA反射常用API
            a> Class类:反射的核心类,反射所有的操作都是围绕该类生成的。通过该类可以获取类的属性、方法
            b> Field类:表示类的属性,可以获取和设置类中的属性值
            c> Method类:表示类的方法,可以获取类中方法的信息,或者执行方法
            d> Constructor类:表示类的构造方法
        4.4 使用反射的基本步骤:
            a> 获得需要操作的类的Class对象
            b> 调用Class的方法获取Field、Method等对象
            c> 使用反射API进行操作
            1>获取Class对象有3中方式
                调用对象的getClass()方法
                    如:Student stu = new Student();
                          Class cls = stu.getClass();
                 调用类的Class属性     //通常使用该方法获取Class对象
                    如:Class cls = Student.class;
                 使用Class类的forName()方法
                    如:Class cls = Class.forName("java.test.Student");//必须写路径全称,完整的包名
            2>从Class对象获取信息
                访问Class对应的类的构造方法
                访问Class对应的类的方法
                
访问Class对应的类的属性
            3>通过反射创建对象
                使用Class对象的newInstance()方法创建对象
                如: Class cls = Student.class;
                       Student stu = (Student)cls.newInstance() //使用默认构造方法实例化一个学生对象  
                使用Consstructor对象创建对象
                如:
                    Class cls = Student.class;
                    Constructor con = cls.getConstructor(String.class,String.class);//指定构造方法
                    Student stu = (Student)con.newInstance("Tom","female");   //使用指定构造方法创建对象
            4>通过反射访问类的属性
                使用Field对象可以获取对象的属性,并且可以对获取到的属性进行取值或赋值操作
                    Student stu = new Student();
                    Class cls = Student.class;//获取Student类的Class对象
                    Field name = cls.getDeclaredField("name");//getDeclearedField()方法可获取各访问级别的属性
                    name.setAccessible(true);//设置 通过反射访问该属性时取消权限检查
                    name.set(stu,"Jack");//调用set()方法给stu对象重新赋值
                    Field age = cls.getDeclearedField("age");
                    age.setAccessible(true);
                    age.setInt(stu,30);//这里调用的是setInt()方法,age为int类型,name 为String,所以用set() 
            5>通过反射访问类的方法
                 使用Method对象的invoke()方法可以调用对象的方法
                    Student stu = new Student();
                    Class cls = Student.class;
                    Method met1 = cls.getMethod("setName",String.class);//得到Student类的setName()方法
                    met1.invoke(stu,"TOM");//通过invoke()方法调用setName()方法为stu对象的name赋值
                    Method met2 = cls.getMethod("getName",null)//null表示该方法无参数 
                    Object o = met2.invoke(stu,null);//invoke()调用getName()方法得到stu对象的name值
                    System.out.println(o.toString());
            6>使用Array类动态创建和访问数组
                Array类的对象可以代表所有的数组。程序可以通过使用Array类来动态创建数组、操作数组元素
                     //创建一个元素类型为String,长度为10的数组
                    Object arr = Array.newInstance(String.class,10); //使用Array.newInstance()动态创建数组
                    //依次向数组中的元素赋值
                    Array.set(arr,0,"work");
                    Array.set(arr,1,"study");
                    //从数组中取出元素的值
                    Object o1 = Array.get(arr,0);
                    Object o2 = Array.get(arr,1);

5.多线程
    5.1 进程
        进程是程序的一次动态执行过程,它对应了从代码加载、执行、结束的一个完整过程。
        进程的特点是:
            进程是系统运行程序的基本单元。
            每一个进程都有自己独立的内存空间和系统资源。
            每一个进程的内部数据和状态都是完全独立的。
    5.2 线程
        线程是进程中执行运算的最小单位,一个进程在执行过程中可以产生多个线程,用来完成不同的工作称之为
        多线程。
    5.3 创建线程的两种方法:
        继承Thread类:它的缺点是继承了Thread类的线程类不能再继承别的类。
            如:public class MyThread extends Thread{
                            public void run(){
                                    //重写父类Thread的run()方法
                            }
                    }
                    public class Test{
                            MyThread mt = new MyThread();//实例化线程对象
                            mt.start(); //启动线程
                    }
        实现Runnable接口:当一个线程继承了另一个类时,就只能用实现Runnable接口来创建线程。
            如:public class MyThread implements Runnable{
                            public void run(){
                                    //同样要重写Runnable接口中的run()方法
                            }
                    }
                    public class Test{
                            new Thread(new MyThread()).start();//实例化并启动线程。
                    }
    5.4 线程的状态
        线程的生命周期可以分为4个阶段,即线程的4种状态:新生状态、可运行状态、阻塞状态、死亡状态。
    5.5 线程的调度
        a>线程的调度按线程的优先级进行调度。优先级高的先执行。
        b>线程的优先级用1-10表示,1表示最高优先级,默认优先级为5 。线程的优先级可以通过setPriority()方法
            更改。如myThread.setPriority(3);设置优先级为3。
        c> join()方法使当前线程暂停执行,等待调用该方法的线程执行完毕后再继续执行。
            Thread.currentThread().getName()方法可以获取当前线程的名称。
            示例:用join()的方法实现两个线程间的数据传递
                
class MyThread implements Runnable{
                public String name;
                public void run(){
                name = "Jack";
                    }
                }
                public class TestThread{
                public static void main(String[] args) {
                MyThread mt= new MyThread();
                Thread t =new Thread(mt);
                t.start();
                try {
                t.join();    //让主线程暂停,等待t线程执行完之后,主线程再继续执行。否则name的值为null
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
                System.out.println("name="+mt.name);
                }

            }
        d> sleep()方法可以阻塞线程 。如thread.sleep(1000)//线程睡眠1秒
  5.6 线程同步 
    当两个或多个线程需要访问同一资源时,确保该资源在同一时刻只能被一个线程使用的方式称为线程同步。
    实现线程同步有两种方式:同步方法、同步代码块。这两中方式都使用synchronized关键字实现。5.0以后还提
    供了Lock和Condition
接口用来实现线程同步。
  5.7线程间通信
    JAVA提供了很多方法实现线程间的通信:
        synchronized :      wait()、notify()、notifyAll()
        Lock : lock()、unlock()
        Condition : await()、signal()、signalAll()
     示例:使用synchronized 同步方法
        
/**
         * 生产者消费者线程间通信
         * */
        class Resource{ //创建公共资源类
        private String name;
        private int count =1;
        private boolean flag;
        public synchronized void produce(String name){        //同步方法
        while(flag){         //用while()循环判断标记flag
        try {
        this.wait();
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        this.name=name+count++;
        System.out.println(Thread.currentThread().getName()
                                                                            +"..............生产者生产了............. "+this.name);
        flag = true;
        this.notifyAll();
            }
        public synchronized void consume(){
        while(!flag){
        try {
        this.wait();
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        System.out.println(Thread.currentThread().getName()+"....消费者消费了.... "+this.name);
        flag =false;
        this.notifyAll();
                }
        }

        class Producer implements Runnable{
        private Resource res;
        Producer (Resource res){
        this.res =res;
        }
        public void run(){
        for(int i=0;i<100;i++){
        res.produce("商品");
        }
            }
        }

        class Consumer implements Runnable{
        private Resource res;
        Consumer (Resource res){
        this.res =res;
        }
        public void run(){
        for(int i=0;i<100;i++){
        res.consume();
        }
            }
        }
        public class TestSynchronized {

        public static void main(String[] args) {
        Resource res = new Resource();
        new Thread(new Producer(res)).start();
        new Thread(new Producer(res)).start();//启动两个生产者线程
        new Thread(new Consumer(res)).start();
        new Thread(new Consumer(res)).start();//启动两个消费者线程。

        }
        }
      输出结果:
        Thread-1..............生产者生产了............. 商品1
        Thread-3....消费者消费了.... 商品1
        Thread-1..............生产者生产了............. 商品2
        Thread-3....消费者消费了.... 商品2
        Thread-1..............生产者生产了............. 商品3
        Thread-3....消费者消费了.... 商品3
        Thread-1..............生产者生产了............. 商品4
        Thread-3....消费者消费了.... 商品4
        Thread-1..............生产者生产了............. 商品5
        Thread-3....消费者消费了.... 商品5
    
        示例2:使用synchronized 同步代码块 

        import java.util.Random;

        public class ZhangSan {

        /**
        * 用两个线程控制主管A和主管B给张三调工资的工作。
        */
            private static char AB ='A';
        private static int money = 5000;
        public int add(){
        money+=300;
        System.out.println("张三工作努力,加工资300,工资为:"+money);
        return money;
        }
        public int reduce(){
        money-=300;
        System.out.println("张三工作不努力,扣工资300,工资为:"+money);
        return money;
        }
        public static void main(String[] args) {
       final ZhangSan zs = new ZhangSan();
        new Thread(new Runnable(){
        public void run(){
        for(int i=0;i<3;i++){
        synchronized(zs){ //同步代码块 同步代码块的锁是任意对象
        if(AB!='A'){
        try {
        zs.wait();
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        Random random = new Random();
        int work = random.nextInt(2)+1;
        if(work==2){
        System.out.println("主管A:");
        zs.reduce();
        }else{
        System.out.println("主管A:");
        zs.add();
        }
        AB = 'B';
        zs.notify();
        }
        }
        }
        }).start();
        new Thread(new Runnable(){
        public void run(){
        for(int i=0;i<3;i++){
        synchronized(zs){   //同步代码块 同步代码块的锁是任意对象,两个线程间同步锁
        if(AB!='B'){    //必须相同,也就是要用同一个对象作为锁。
        try {
        zs.wait();
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        Random random = new Random();
        int work = random.nextInt(2)+1;
        if(work==2){
        System.out.println("主管B:");
        zs.reduce();
        }else{
        System.out.println("主管B:");
        zs.add();
        }
        AB = 'A';
        zs.notify();
        }
        }
            }
        }).start();
            }

        }
        输出结果:
        主管A:
        张三工作努力,加工资300,工资为:5300
        主管B:
        张三工作不努力,扣工资300,工资为:5000
        主管A:
        张三工作不努力,扣工资300,工资为:4700
        主管B:
        张三工作努力,加工资300,工资为:5000
        主管A:
        张三工作努力,加工资300,工资为:5300
        主管B:
        张三工作努力,加工资300,工资为:5600
       
        示例3:使用Lock、Condition接口实现线程同步通信
        import java.util.concurrent.locks.Condition;
        import java.util.concurrent.locks.Lock;
        import java.util.concurrent.locks.ReentrantLock;
        /**
         * 生产者消费者线程间通信
         * */
        class Resource{
        private String name;
        private int count =1;
        private boolean flag;
        final Lock lock = new ReentrantLock(); //创建锁
        final Condition produce =lock.newCondition();//创建该线程的Condition对象
        final Condition consume =lock.newCondition();//创建该线程的Condition对象
        public  void produce(String name) throws InterruptedException{ //不使用synchronized
        lock.lock();//上锁
        try {
        while(flag)
        produce.await(); //自己等待
        this.name=name+count++;
        System.out.println(Thread.currentThread().getName()
                                                            +"..............生产者生产了............. "+this.name);
        flag = true;
        consume.signal();//唤醒对方
        } finally{
        lock.unlock();//放锁
        }
        }
        public  void consume() throws InterruptedException{//不使用synchronized
        lock.lock();//上锁
        try {
        while(!flag)
        consume.await();//自己等待
        System.out.println(Thread.currentThread().getName()
                                                                                    +"....消费者消费了.... "+this.name);
        flag = false;
        produce.signal();//唤醒对方
        } finally{
        lock.unlock();//放锁
        }
        }
        }

        class Producer implements Runnable{
        private Resource res;
        Producer (Resource res){
        this.res =res;
        }
        public void run(){
        for(int i=0;i<100;i++){
        try {
        res.produce("商品");
        } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
        }
        }
        }

        class Consumer implements Runnable{
        private Resource res;
        Consumer (Resource res){
        this.res =res;
            }
        public void run(){
        for(int i=0;i<100;i++){
        try {
        res.consume();
        } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
        }
        }
        }
        public class TestSynchronized {

        public static void main(String[] args) {
        Resource res = new Resource();
        new Thread(new Producer(res)).start();
        new Thread(new Producer(res)).start();
        new Thread(new Consumer(res)).start();
        new Thread(new Consumer(res)).start();
        }
      }

     输出结果同示例2.

6.Socket网络编程技术
    6.1 TCP协议的Socket编程
        java.net包中的Socket类、ServerSocket类,分别用来实现双向连接的客户端和服务器端,他们基于TCP协
    议进行工作的,工作的过程如同打电话,双方都接通了才能开始通话。Socket借助数据流来完成数据的传递。
    示例:图片的并发上传。
        需要三个类:Server类、ServerThread线程类、Client类
        
       
import java.io.IOException;
        import java.net.ServerSocket;
        import java.net.Socket;

        public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(20013);
while(true){
Socket s = ss.accept();
new Thread(new ServerThread(s)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
        }
        }

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ServerThread implements Runnable {
private Socket s ;
public ServerThread(Socket s){
this.s =s;
}
public void run(){
try{
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
int count = 1;
File file = new File(ip+"("+(count)+")"+".jpg");
while(file.exists()){
file = new File(ip+"("+(count++)+")"+".jpg");
}
FileOutputStream fos = new FileOutputStream("c:\\myDoc\\"+file);
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len;
while((len=is.read(buf))!=-1){
fos.write(buf,0,len);
}
OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
fos.close();
is.close();
os.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost",20013);
FileInputStream fis = new FileInputStream("c:\\1.jpg");
OutputStream os = s.getOutputStream();
byte[] buf = new byte[1024];//建立缓冲区。
int len;
while((len=fis.read(buf))!=-1){
os.write(buf,0,len);
}
s.shutdownOutput();
InputStream is  = s.getInputStream();
byte[] bufIn = new byte[1024];
System.out.println(new String(bufIn,0,is.read(bufIn)));
fis.close();
os.close();
is.close();
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
}

示例2:基于TCP协议的文件上传下载

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class FileDown extends Thread {
// 文件的保存路径
private String fileDir;
// socket服务器端口号
private int port;
// 是否停止
private boolean stop;

public String getFileDir() {
return fileDir;
}

public void setFileDir(String fileDir) {
this.fileDir = fileDir;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}

public boolean isStop() {
return stop;
}

public void setStop(boolean stop) {
this.stop = stop;
}
public static void main(String[] args) {
FileDown fd = new FileDown();
fd.setFileDir("c:\\myDoc\\");
fd.setPort(9005);
fd.start();
}

/**
* 文件下载
*/
@Override
public void run() {
Socket socket = null;
try {
ServerSocket ss = new ServerSocket(port);
do {
socket = ss.accept();

// public Socket accept() throws
// IOException侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
System.out.println("建立socket链接");
DataInputStream inputStream = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
// 本地保存路径,文件名会自动从服务器端继承而来。
int bufferSize = 8192;
byte[] buf = new byte[bufferSize];
long passedlen = 0;
long len = 0;

// 获取文件名
String file=fileDir + inputStream.readUTF();
DataOutputStream fileOut = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(file)));
len = inputStream.readLong();

System.out.println("文件的长度为:" + len + "\n");
System.out.println("开始接收文件!" + "\n");

while (true) {
int read = 0;
if (inputStream != null) {
read = inputStream.read(buf);
}
passedlen += read;
if (read == -1) {
break;
}
// 下面进度条本为图形界面的prograssBar做的,这里如果是打文件,可能会重复打印出一些相同的百分比
System.out.println("文件接收了" + (passedlen * 100 / len)
+ "%\n");
fileOut.write(buf, 0, read);
}
System.out.println("接收完成,文件存为" + file + "\n");

fileOut.close();
} while (!stop);
} catch (Exception e) {
System.out.println("接收消息错误" + "\n");
e.printStackTrace();
return;
}
}
}

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.Socket;

public class FileUp{
// 上传的文件路径
private String filePath;
// socket服务器地址和端口号
private String host;
private int port;

public String getFilePath() {
return filePath;
}

public void setFilePath(String filePath) {
this.filePath = filePath;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}

public String getHost() {
return host;
}

public void setHost(String host) {
this.host = host;
}
public static void main(String[] args) {
FileUp fu = new FileUp();
fu.setHost("127.0.0.1");
fu.setPort(9005);
fu.setFilePath("c:\\");
fu.uploadFile("1.jpg");
}

/**
* 客户端文件上传
* @param fileName 文件名
*/
public void uploadFile(String fileName) {
Socket s = null;
try {
s = new Socket(host, port);

// 选择进行传输的文件
File fi = new File(filePath + fileName);
System.out.println("文件长度:" + (int) fi.length());

DataInputStream fis = new DataInputStream(new FileInputStream(filePath + fileName));
DataOutputStream ps = new DataOutputStream(s.getOutputStream());
// 将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In
// Java
// 4th里有现成的代码。
//design pattern 设计模式  <<Head First Design Pattern>><<Head First 设计模式>><<Head First Java>>
ps.writeUTF(fi.getName());
ps.flush();
ps.writeLong((long) fi.length());
ps.flush();

int bufferSize = 8192;
byte[] buf = new byte[bufferSize];

while (true) {
int read = 0;
if (fis != null) {
read = fis.read(buf);
}

if (read == -1) {
break;
}
ps.write(buf, 0, read);
}
ps.flush();
// 注意关闭socket链接哦,不然客户端会等待server的数据过来,
// 直到socket超时,导致数据不完整。
fis.close();
ps.close();
s.close();
System.out.println("文件传输完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}


6.2 基于UDP协议的Socket编程
    利用DatagramPacket对象封装和处理数据,利用DatagramSocket对象发送和接受数据。
    示例:
         import java.io.IOException;
        import java.net.DatagramPacket;
        import java.net.DatagramSocket;
        import java.net.SocketAddress;
        import java.net.SocketException;

        //服务器端
        public class Server {

public static void main(String[] args) {
try {
//创建接收方套接字,并绑定端口号。
DatagramSocket ds = new DatagramSocket(8888);
//确定数据包接收的数据的数组大小。
byte[] buf = new byte[1024];
//创建接收类型的数据包,数据将存储在数组中。
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//通过套接字接收数据。
ds.receive(dp);
//解析发送方发送的数据
String message = new String(buf,buf.length);
System.out.println("Cilent say:"+message);
String reply = "Hello,I'm Server!";
byte[] replys = reply.getBytes();
SocketAddress sa = dp.getSocketAddress();
DatagramPacket dp2 = new DatagramPacket(replys,replys.length,sa);
ds.send(dp2);
//关闭资源。
ds.close();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    }
        }
    //客户端
         
import java.io.IOException;
        import java.net.DatagramPacket;
        import java.net.DatagramSocket;
        import java.net.InetAddress;
        public class Cilent {
public static void main(String[] args) {
try{
String message = "Hello,I'm Cilent.";
byte[] buf = message.getBytes();
InetAddress ia = InetAddress.getByName("localhost");
int port = 8888;
DatagramPacket dp = new DatagramPacket(buf,buf.length,ia,port);
DatagramSocket ds = null;
ds =  new DatagramSocket();
ds.send(dp);
byte[] buf2 = new byte[1024];
DatagramPacket dp2 = new DatagramPacket(buf2,buf2.length);
ds.receive(dp2);
String reply = new String(buf2,0,dp2.getLength());
System.out.println("Server say:"+reply);
ds.close();
}catch(IOException e){
e.printStackTrace();
}
    }
        }




 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值