java基础总结

   1 一、基础知识:
   2 1、JVM、JRE和JDK的区别:
   3     JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性。
   4                   java语言是跨平台,jvm不是跨平台的。
   5     JRE(Java Runtime Environment):java的运行环境,包括jvm+java的核心类库。    
   6     JDK(Java Development Kit):java的开发工具,包括jre+开发工具
   7 
   8 2、环境变量path和classpath的作用是什么?
   9     (1)path是配置Windows可执行文件的搜索路径,即扩展名为.exe的程序文件所在的目录,
  10        用于指定DOS窗口命令的路径。
  11     (2)Classpath是配置class文件所在的目录,用于指定类搜索路径,JVM就是通过它来寻找该类的class类文件的。    
  12 
  13 
  14     -- 从jdk5开始平时练习可以只配置path;
  15     -- jdk jre 也可以拷贝别人安装的;
  16     -- 开发工具:eclipse MyEclipse 
  17     
  18 3、变量有什么用?为什么要定义变量?什么时候用?
  19     答:变量的作用:用来存储数据。
  20         为什么要定义变量:用来不断的存放同一类型的常量,并可以重复使用
  21 
  22 4、&和&&的区别?
  23     答:(1)&&会出现短路,如果可以通过第一个表达式判断出整个表达式的结果,则不继续后面表达式的运算;
  24          只能操作boolean类型数据;
  25         (2)&不会出现短路,将整个表达式都运算。既可以操作boolean数据还可以操作整数。
  26 
  27 5、标示符命名规则:
  28     由数字(0-9),大小写英文字母,以及_和$组成。
  29     不能以数字开头。
  30     不能使用关键字、保留字来自定义命名。
  31     类名:大驼峰
  32     方法,变量:小驼峰
  33 
  34 6、数据类型:
  35   --java 语言是强类型的语言;
  36   要是一个定义的变量,必须先行声明(指定变量类型),才只能使用;
  37     (1)基本数据类型(4类8种):
  38         整数类型:byte、short、int、long
  39         浮点数类型:float、double(双精度)
  40         字符类型:char  (一个字符类型可以存一个汉字)
  41         布尔类型:boolean(ture false)
  42     (2)引用数据类型:
  43   44         接口
  45         数组
  46         集合
  47 
  48 7、类型转换
  49     精度从高到低  double  float  long  int  short(char)  byte 
  50     (1)自动类型转换  将一个低精度---高精度 
  51     (2)强制类型转换  将一个高精度---低精度(精度会下降)
  52 
  53 8、java语言的三种技术架构
  54     J2EE:企业版
  55     是为开发企业环境下的应用程序提供的一套解决方案。
  56     该技术体系中包含的技术如 Servlet、Jsp等,主要针对于Web应用程序开发。
  57     J2SE:标准版
  58     是为开发普通桌面和商务应用程序提供的解决方案。
  59     该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发。
  60     比如Java版的扫雷。
  61     J2ME:小型版
  62     是为开发电子消费产品和嵌入式设备提供的解决方案。
  63     该技术体系主要应用于小型电子消费类产品,如手机中的应用程序等。
  64 
  65 9、java的跨平台性:
  66     通过Java语言编写的应用程序在不同的系统平台上都可以运行。
  67     跨平台的原因:
  68     只要在需要运行java应用程序的操作系统上,先安装一个Java虚拟机(JVM Java Virtual Machine)即可。
  69     由JVM来负责Java程序在该系统中的运行。
  70 
  71 10、有符号数据的表示法(次重点)
  72     原码,反码(原码取反),补码(反码+1)。
  73 
  74 11、函数
  75     定义:函数就是定义在类中的具有特定功能的一段独立小程序。        
  76     特点:
  77         定义函数可以将功能代码进行封装
  78         便于对该功能进行复用
  79         函数只有被调用才会被执行
  80         函数的出现提高了代码的复用性
  81         对于函数没有具体返回值的情况,返回值类型用关键字void表示,
  82         那么该函数中的return语句如果在最后一行可以省略不写。
  83     函数的应用两个明确:
  84         明确要定义的功能最后的结果是什么?
  85         明确在定义该功能的过程中,是否需要未知内容参与运算
  86 
  87         //复制数组中的前三个元素到新数组 ,返回值类型
  88         public   int[]  copys(int[] a){
  89         
  90         }
  91 
  92 12、重载:
  93     概念:在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。    
  94     特点:与返回值类型无关,只看参数列表(参数类型以及参数个数)。    
  95     好处:方便于阅读,优化了程序设计。    
  96 
  97 
  98     
  99 13、数组:
 100     概念:同一种数据类型的集合。    
 101     好处:可以自动给数组中的元素从0开始编号,方便操作这些元素。
 102 
 103 14、内存结构:
 104     栈内存:用于存储局部变量,对象的引用,当数据使用完,所占空间会自动释放。
 105     堆内存:数组和对象,通过new建立的实例都存放在堆内存中。
 106     方法区:静态成员、构造函数、常量池、线程池
 107     本地方法区:window系统占用
 108     寄存器:
 109 
 110 逻辑控制语句:
 111 if  else if else
 112  switch()
 113  while
 114  do while
 115  for()
 116  forEach
 117 
 118  break;结束循环
 119  continue;跳过本次循环
 120  return ;方法结束,返回方法的返回值
 121  
 122 
 123 
 124 二、面向对象
 125 -- java中一条指令的结束;
 126 -- 类:通过抽象获得的模板;
 127  -- 类中的属性描述的是具体对象的特征;
 128  -- 类中的方法是描述具体对象的功能;
 129 1、面向对象思想:
 130     (1)概述:面向对象是相对于面向过程(C语言)而言的,面向过程强调的是功能,面向对象强调的是将功能封装进对象,
 131          强调具备功能的对象;
 132     (2)思想特点:
 133          A:是符合人们思考习惯的一种思想;
 134          B:将复杂的事情简单化了;
 135          C:将程序员从执行者变成了指挥者;
 136 
 137          比如我要达到某种结果,我就寻找能帮我达到该结果的功能的对象,如我要洗衣服我就买洗衣机,
 138          至于怎么洗我不管。
 139     (3)特征:
 140         封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式
 141         继承: 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义
 142               这些属性和行为,只要继承那个类即可。
 143         多态: 一个对象在程序不同运行时刻代表的多种状态,父类或者接口的引用指向子类对象
 144 2、类和对象:
 145     类:对现实世界中某类事物的描述,是抽象的,概念上的定义。
 146     对象:事物具体存在的个体。
 147 
 148 3:成员变量和局部变量的区别(重点)
 149     (1)作用域
 150         成员变量:针对整个类有效。
 151         局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
 152     (2)存储位置
 153         成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
 154         局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。
 155               当方法调用完,或者语句结束后,就自动释放。
 156     (3)初始值
 157         成员变量:有默认初始值。类加载是初始化
 158         局部变量:没有默认初始值,使用前必须赋值。
 159 
 160 4、匿名对象
 161     (1)匿名对象就是没有名字的对象。是对象的一种简写形式。 new  类();
 162     (2)应用场景
 163         A:只调用一次类中的方法。
 164         B:可以作为实际参数在方法传递中使用  public void play(Animal a)
 165 
 166 5、封装:
 167     指隐藏对象的属性和实现细节,仅对外提供公共访问方式;比如电脑机箱、笔记本等
 168     好处:
 169         将变化隔离;
 170         方便使用;
 171         提高复用性;
 172         提高安全性
 173 
 174 6、关键字private:封装在代码中的体现
 175     (1)私有的意思,权限修饰符
 176     (2)用来修饰成员变量和成员函数
 177     (3)用private修饰的成员只在本类中有效
 178     (4)私有是封装的一种体现
 179 
 180 7、构造方法:
 181     (1)特点:
 182         方法名与类名相同
 183         没有返回类型
 184         没有返回值
 185     (2)作用:构造函数是用于创建对象,并对其进行初始化赋值,对象一但建立就自动调用相对应的构造函数,
 186     (3)构造方法的注意事项:
 187         A:如果一个自定义类没有构造方法,系统会默认给出一个无参构造方法。
 188         B:如果一个自定义类提供了有参构造方法,那么,系统将不再给出无参构造方法。
 189           这个时候,你可以不使用无参构造方法。
 190           如果你想使用,那么,就必须手动给出无参构造方法。
 191 
 192         建议:一般情况下,我们的自定义类都要手动给出无参构造方法。
 193     (4)构造方法和成员方法的区别
 194         A:格式区别
 195             构造方法和类名相同,并且没有返回类型,也没有返回值。
 196             普通成员方法可以任意起名,必须有返回类型,可以没有返回值。
 197         B:作用区别
 198             构造方法用于创建对象,并进行初始化值。
 199             普通成员方法是用于完成特定功能的。
 200         C:调用区别
 201             构造方法是在创建对象时被调用的,一个对象建立,只调用一次相应构造函数
 202             普通成员方法是由创建好的对象调用,可以调用多次
 203 
 204 8、构造代码块:
 205     (1)作用:给对象进行初始化,对象一建立就执行,而且优先于构造函数执行
 206     (2)构造代码块和构造函数的区别:
 207         构造代码块是给所有不同对象的共性进行统一初始化
 208         构造函数是给对应的对象进行初始化
 209 
 210 9、this关键字
 211     (1)this关键字代表本类对象的一个引用,谁调用this所在的方法,this就代表谁  
 212     (2)this的使用场景
 213         A:用于区分同名成员变量和局部变量;(就近原则)
 214         B:在定义函数时,该函数内部要用到调用该函数的对象时,因为此时对象还没建立,故this代表此对象
 215         B:构造函数间调用
 216             **这个时候,this(参数)必须作为第一条语句存在。
 217 
 218 10、Person p = new Person();在内存中做了哪些事情。
 219     (1)将Person.class文件加载进内存中。
 220     (2)如果p定义在主方法中,那么,就会在栈空间开辟一个变量空间p。
 221     (3)在堆内存给对象分配空间。
 222     (4)对对象中的成员进行默认初始化。
 223     (5)对对象中的成员进行显示初始化。
 224     (6)调用构造代码块对对象进行初始化。(如果没有就不执行)
 225     (7)调用构造方法对对象进行初始化。对象初始化完毕。
 226     (8)将对象的内存地址赋值给p变量,让p变量指向该对象。
 227 
 228 11、static关键字:
 229     (1)静态的意思,用来修饰成员变量和成员函数
 230     (2)静态的特点:
 231         随着类的加载而加载
 232         优先于对象存在
 233         对所有对象共享
 234         可以被类名直接调用
 235     (3)静态的注意事项
 236         A:静态方法只能访问静态成员
 237             为什么:因为静态的内容是随着类的加载而加载,它是先进内存的。
 238         B:静态方法中不能使用this,super关键字
 239         C:主方法是静态的
 240             public static void main(String[] args)
 241             public:公共的意思,是最大权限修饰符。
 242             static:由于jvm调用main方法的时候,没有创建对象。
 243                    只能通过类名调用。所以,main必须用static修饰。
 244             void:由于main方法是被jvm调用,不需要返回值。用void修饰。
 245             main:main是主要的意思,所以jvm采用了这个名字。是程序的入口。
 246 
 247             String[]:字符串数组
 248             args:数组名
 249 
 250             在运行的时候,通过java命令给args数组赋值。
 251             格式:java MainTest hello world 
 252     (4)静态变量和成员变量的区别
 253         A:调用方式
 254             静态变量也称为类变量,可以直接通过类名调用。也可以通过对象名调用。
 255             这个变量属于类。
 256             成员变量也称为实例变量,只能通过对象名调用。这个变量属于对象。
 257         B:存储位置
 258             静态变量存储在方法区长中的静态区。
 259             成员变量存储在堆内存。
 260         C:生命周期
 261             静态变量随着类的加载而存在,随着类的消失而消失。生命周期长。
 262             成员变量随着对象的创建而存在,随着对象的消失而消失。
 263         D:与对象的相关性
 264             静态变量是所有对象共享的数据。
 265             成员变量是每个对象所特有的数据。
 266     (5)静态的优点和弊端
 267         优点:
 268         对对象的共享数据进行单独空间的存储,节省内存,没有必要每个对象都存储一份
 269         可直接被类名调用
 270         弊端:
 271         生命周期过长,随着类的消失而消失
 272         访问出现权限,即静态虽好但只能访问静态
 273     (6)什么使用使用静态呢?
 274         A:当所有对象共享某个数据的时候,就把这个成员变量定义为静态修饰的。
 275         B:当某个方法没有访问该类中的非静态成员,就可以把这个方法定义为静态修饰。
 276 
 277         静态的生命周期比较长,所以一般不推荐使用。
 278     (7)静态代码块
 279         A:它只执行一次,它比main还先执行。
 280         B:执行顺序
 281             静态代码块--构造代码块--构造方法
 282 
 283 12、制作API(次重点)
 284     API(全拼):Application Program Interface 应用程序编程接口。
 285     (1)类中的内容需要用文档注释。   /**
 286                         
 287                     */
 288                     /*
 289                     */
 290                     //
 291 
 292     (2)使用JDKin目录下的javadoc工具。
 293         格式:javadoc -d 目录 -author -version ArrayTool.java
 294  
 295 13、单例设计模式:
 296     (1)设计模式:
 297         解决某类问题行之有效的方法,是一种思想,是规律的总结
 298     (2)用来保证某个类在内存中只有一个对象
 299     (3)保证唯一性的思想及步骤
 300         **为了避免其他程序建立该类对象,先禁止其他程序建立该类对象,即将构造函数私有化
 301         **为了其他程序访问到该类对象,须在本类中创建一个该类私有对象
 302         **为了方便其他程序访问到该类对象,可对外提供一个公共访问方式
 303 
 304     比如API中的Runtime类就是单例设计模式。
 305 
 306     (4)单例设计模式的两种方式
 307         A:饿汉式 当类加载的时候,就创建对象。    
 308         class Student
 309         {
 310             private Student(){}
 311             
 312             private static final Student s = new Student();
 313             
 314             public static Student getInstance()
 315             {
 316                 return s;
 317             }
 318         }
 319         B:懒汉式 当使用的使用,才去创建对象。
 320         class Student
 321         {
 322             private Student(){}
 323 
 324             private static final Student s = null;
 325             
 326             public static Student getInstance()
 327             {
 328                 if(s==null) 
 329                 {
 330                     //线程1就进来了,线程2就进来了。
 331                     s = new Student();
 332                 }
 333                 return s;
 334             }
 335         }
 336     饿汉式和懒汉式的区别:
 337         **
 338         饿汉式是类一加载进内存就创建好了对象;
 339         懒汉式则是类才加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,
 340         对象才开始创建。
 341         **
 342         懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,解决线程安全问题
 343         可以加同步来解决。但是加了同步之后,每一次都要比较锁,效率就变慢了,
 344         所以可以加双重判断来提高程序效率。
 345         注:开发常用饿汉式,因为饿汉式简单安全。懒汉式多线程的时候容易发生问题
 346 
 347 14、Math类的使用(重点)
 348     (1)数学操作类:该类没有构造函数,方法均为静态的    
 349     (2)掌握内容
 350         A:成员变量
 351             **E:比任何其他值都更接近e(即自然对数的底数)的double值。
 352             **PI:比任何其他值都更接近pi(即圆的周长与直径之比)的double值。
 353         B:成员方法
 354             **static double abs(double a) 
 355                 返回 double 值的绝对值。返回绝对值
 356             **static double ceil(double a) 
 357                 返回最小的(最接近负无穷大)double 值,该值大于等于参数,并等于某个整数。 
 358             **static double floor(double a) 
 359                 返回最大的(最接近正无穷大)double 值,该值小于等于参数,并等于某个整数。 
 360             **max:返回两个值中较大的那个
 361             **min:返回两个值中较小的那个
 362             **static long round(double a) 返回最接近参数的 long。
 363               static int round(float a) 返回最接近参数的 int。 
 364             **static double random() 
 365                 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。 
 366             **static double pow(double a, double b) 
 367                 返回第一个参数的第二个参数次幂的值。 
 368             **static double sqrt(double a) 
 369                  返回正确舍入的 double 值的正平方根。 
 370 15、Random类的使用(重点)
 371     (1)产生随机数的类
 372     (2)掌握内容
 373         A:构造方法
 374             **Random() 创建一个新的随机数生成器。 
 375             **Random(long seed) 使用单个 long 种子创建一个新的随机数生成器。
 376         B:成员方法
 377             **int nextInt() 返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。 
 378             **int nextInt(int n) 返回一个伪随机数,它是取自此随机数生成器序列的、
 379             在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
 380 16、Scanner类的使用
 381     (1)可以获取从键盘的输入数据
 382     (2)掌握内容
 383         构造方法:
 384             Scanner(InputStream source) 构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
 385             如:Scanner sc = new Scanner(System.in);
 386         方法摘要
 387             sc.nextInt();获取整型数据
 388             sc.nextLine();获取字符串数据
 389 17、继承(重点)
 390     (1)把很多类的相同特征和行为进行抽取,用一个类来描述。让多个类和这个类产生一个关系。
 391        这样的话,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。
 392     (2)继承的体系结构
 393         A:多个具体的对象,不断的向上抽取共享的内容,最终形成了一个体系。这个体系叫做继承体系。
 394         B:继承体系的学习和使用原则
 395             **学习顶层的内容。因为他是整个体系的共性内容。
 396             **创建子类使用。也就是使用底层的具体对象。
 397     (3)继承的特点:
 398         A:java中只能单继承,没有多继承。
 399         B:java可以有多重(层)继承。
 400     (4)继承的好处:
 401         继承的出现提高了代码的复用性。
 402         继承的出现让类与类之间产生了关系,提供了多态的前提。
 403     (5)子父类中的成员关系
 404         A:成员变量
 405             在子类方法中使用一个变量时:
 406             首先,在方法的局部变量中找这个变量,有则使用。
 407             否则,在本类中找成员变量,有则使用。
 408             否则,在父类中找成员变量,有则使用。
 409             否则,报错。
 410         B:成员方法
 411             用子类对象使用一个方法时。
 412             首先,在子类中找这个方法,有则使用。
 413             否则,在父类中找这个方法,有则使用。
 414             否则,报错。
 415 
 416         重写和重载的区别?
 417             重载:在同一类中。方法名相同,参数列表不同。重载可以改变返回类型。
 418             重写:在不同类中(子父类中)。
 419                   方法声明相同(返回类型,方法名,参数列表均相同)。
 420         重写需要注意:
 421             **子类方法的访问权限要大于等于父类方法的访问权限。
 422             **静态只能重写静态。但是这种情况一般不会出现。
 423 
 424         构造方法
 425             **子类的实例化过程
 426                 ***子类创建对象时,会先去创建父类的对象。
 427                     默认是去调用父类的无参构造方法。
 428                 ***子类构造方法中,第一行默认是super()
 429                 ***为什么子类中第一行会默认有super()
 430                     因为他继承父类的成员使用,使用前这些成员必须初始化,
 431                     而他们是父类的成员,所以,必须通过父类进行初始化。
 432                     所以,会先创建一个父类的对象。
 433             **当父类没有无参构造方法时
 434                 必须使用this或者super调用其他的构造方法。
 435     (6)this和super的区别
 436         this:代表本类对象的引用。
 437         super:代表父类的存储空间。
 438 18、final关键字(重点)
 439     (1)最终的意思,可以用于修饰类,方法,变量。
 440     (2)final修饰的类不能被继承。
 441        final修饰的方法不能被重写。
 442        final修饰的变量是一个常量。只能被赋值一次。
 443        内部类只能访问被final修饰的局部变量。
 444 19、抽象类(重点)
 445     (1)多个类有相同的方法声明,但是方法体不一样。这个时候,我们考虑把方法声明进行抽取。
 446        让子类继承后,自己去实现方法体。没有方法体的方法,我们需要用抽象标志下。
 447        抽象的关键字是:abstract。
 448     (2)抽象类:
 449         该方法称为抽象方法,包含抽象方法的类就是抽象类。
 450     (3)抽象类的特点:
 451         A:抽象类和抽象方法都要用abstract进行修饰
 452         B:抽象类不能被实例化
 453         C:抽象类中不一定有抽象方法,但是,有抽象方法的类一定是抽象类。
 454     (4)抽象类中数据的特点
 455         A:成员变量
 456             抽象类中可以有变量,也可以有常量。
 457         B:成员方法
 458             抽象类中可以有抽象方法,也可以有非抽象方法。
 459         C:构造方法
 460             抽象类是一个类,所以,它有构造方法。
 461             虽然本身不能实例化。但是可以给子类实例化使用。
 462     (5)抽象类中的问题
 463         A:抽象类中是否有构造方法?能不能被实例化?如果不能,为什么有构造方法?
 464           抽象类有构造方法。
 465               抽象类不能被实例化。
 466           抽象类中的构造方法供子类实例化调用。
 467         B:抽象关键字abstract不可以和哪些关键字共存?
 468           **private:
 469             私有内容子类继承不到,所以,不能重写。
 470             但是abstract修饰的方法,要求被重写。两者冲突。
 471               **final
 472             final修饰的方法不能被重写。
 473             而abstract修饰的方法,要求被重写。两者冲突。            
 474           **static
 475             假如一个抽象方法能通过static修饰,那么这个方法,就可以直接通过类名调用。
 476             而抽象方法是没有方法体的,这样的调用无意义。所以,不能用static修饰。
 477         C:抽象类中可不可以没有抽象方法?如果可以,这样的类有什么用吗?
 478           抽象类可以没有抽象方法。
 479           抽象类中没有抽象方法的作用,只是为了不让别的类建立该抽象类对象。这个在awt中有体现。
 480 20、接口interface
 481     (1)当一个类中的方法都是抽象的时候,java提供了另一种表示方式,叫接口。
 482        用interface关键字表示。类与接口关系用implements表示。
 483     (2)接口的成员特点
 484         A:成员变量
 485             是常量,默认修饰 public static final    
 486         B:成员方法
 487             都是抽象的,默认修饰 public abstract    
 488     (3)关系
 489         A:类与类的关系
 490             是继承关系。类与类只能单继承,可以多重继承。
 491         B:类和接口的关系
 492             是实现关系。类可以多实现接口。
 493             类在继承一个类的同时,可以实现多个接口。
 494         C:接口和接口的关系
 495             是继承关系。接口可以多继承接口。
 496 
 497         类只能写成:先继承后实现
 498     (4)接口的特点
 499         A:是对外暴露的规则
 500         B:是功能的扩展
 501         C:接口的出现降低耦合性。
 502             耦合(类与类之间的关系) 继承
 503             内聚(类完成功能的能力) Dog {Animal a}
 504             编程规范:低耦合,高内聚。
 505         D:接口可以多实现。如:CPU和主板、笔记本的USB插口、插座
 506     (5)接口和抽象类的区别
 507         A:抽象类只能被单继承
 508            接口可以多实现,接口的出现避免了多继承的局限性。
 509         B:抽象类中的数据特点:
 510                 成员变量:可以是变量,也可以是常量
 511                 成员方法:可以是抽象方法,也可以是非抽象方法
 512                 构造方法:有构造方法
 513            接口中的数据特点:
 514                 成员变量:是常量。默认修饰 public static final
 515                 成员方法:都是抽象方法。都有默认修饰 public abstract
 516                 构造方法:没有构造方法
 517         C:抽象类中定义的是继承体系中的共性功能。
 518            接口中定义的是继承体系中的扩展功能。
 519         D:抽象类被继承是"is a"关系:xx是yy的一种
 520            接口被实现是"like a"关系:xx像yy的一种
 521 21、多态:
 522     (1)同一个对象,在程序不同时刻的多种运行状态。举例:动物,狗是狗,狗是动物。水(气态,液态,固态)
 523     (2)多态前提
 524         A:存在着继承或者实现关系
 525         B:有方法的重写
 526         C:父类(接口)引用指向子类(实现)对象
 527     (3)多态的好处和弊端:
 528         好处:多态的存在提高了程序的扩展性和后期可维护性
 529         弊端:虽然可以预先使用,但是只能访问父类中已有的功能,运行的是后期子类的功能内容。
 530               不能预先使用子类中定义的特有功能。
 531     (4)多态中对象调用成员的特点
 532         Fu f = new Zi();
 533         
 534         A:成员变量
 535             编译看左边,运行看左边
 536         B:成员方法 
 537             编译看左边,运行看右边
 538         C:静态方法
 539             编译看左边,运行看左边
 540     (5)多态的思想
 541         指挥同一批对象做事情。举例:带兵打仗,下课等。
 542 22、instanceof关键字
 543         A:用于判断某个对象是否是某种类型。
 544         B:格式
 545             对象名 instanceof 子类(实现)名
 546 23、Object类:
 547     (1)是所有类的根类,超类。
 548        java中提供的类以及我们自定义的类都直接或者间接的继承自Object类。
 549     (2)Object类中的方法
 550         A:void finalize() 
 551           当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
 552         B:Class getClass()
 553           获取对象的字节码文件的描述类,后面再讲反射的时候还会在说这个类。
 554           String name = s.getClass().getName();
 555         C:int hashCode()
 556           获取对象的哈希值。其实就是对象的内存地址值十进制表示
 557         D:String toString()
 558           返回对象的字符串表示。
 559           表示格式:
 560           getClass().getName()+"@"+Integer.toHexString(hashCode());
 561 
 562           一般我们输出对象名的时候,其实底层调用的就是该对象的toString()方法。
 563           这种返回没有意义,所以,我们会重写这个方法,显示类的成员变量信息。
 564         E:boolean equals(Object obj)
 565           用于比较两个对象的地址值是否相同。
 566           我们获取对象后,比较它的地址值意义不大。所以也会对这个方法进行重写。
 567           重写要完成什么功能,是根据需求定的。
 568     (3)==和equals的用法:
 569         A:==怎么用?
 570             **可以用于比较基本数据类型,比较的就是基本数据类型的值是否相等。
 571             **可以用于比较引用数据类型,比较的是对象的地址值是否相等。
 572         B:equals怎么用?
 573             equals只能用于比较引用数据类型的。
 574             **Object提供的equals是用于比较对象地址值是否相同。
 575             **自定义类中,如果重写了equals方法,那么就是按照你自己的需求来比较的。
 576 
 577 24、package关键字
 578     (1)包:其实就是文件夹。用于区分不同包下相同的类名。
 579     (2)好处:
 580         A:对类文件进行分类管理。
 581         B:给类提供了多层命名空间
 582             aaa.Demo
 583             bbb.Demo
 584         C:写在程序文件的第一行。
 585         D:包也是一种封装形式。
 586 25、import关键字
 587     (1)导入包的关键字
 588     (2)格式:
 589         import 包名;
 590     (3)注意:
 591         A:一个程序文件中只有一个package,可以有多个import。
 592         B:用来导包中的类,不导入包中的包。
 593         C:通常写import  mypack.Demo,明确自己使用的类。  
 594     (4)关键字的顺序
 595         类,包,导包这些关键的顺序。
 596         包 -- >  到包 -- > 类
 597 26、不同修饰符可以修饰哪些内容
 598             本类中    同一个包中 不同包中的子类中 不同包中
 599     private        OK    
 600     默认friedly    OK    Ok        
 601     protected    OK    Ok        OK
 602     public        OK    Ok        OK            Ok
 603 
 604             类    构造方法    成员变量    成员方法        
 605     private            OK        OK        OK
 606     默认        Ok    Ok        Ok        OK
 607     protected        OK        OK        Ok
 608     public          Ok    Ok        OK        OK
 609     static                    OK        Ok
 610     final        Ok            OK        OK
 611     abstract    Ok                    OK
 612 
 613     一般格式:
 614         成员变量:
 615         权限修饰符+static/final+数据类型+成员变量名
 616         public static final int NUM = 10;
 617         
 618         成员方法:
 619         权限修饰符+static/final/abstract+返回类型+方法名
 620 27、内部类(次重点)
 621     (1)把一个类定义在某个类中的,这个类就被称为内部类,内置类,嵌套类。
 622     (2)访问特点:
 623         A:内部类可以直接访问外部类中的成员,因为内部类持有外部类的引用,
 624           格式为:外部类名.this
 625         B:外部类要想访问内部类的成员,必须创建对象访问。
 626     (3)内部类的访问格式:
 627         A:当内部类定义在外部类的成员位置,而且非私有,则可以在其他外部类中直接建立内部类对象
 628           格式:外部类名.内部类名  变量名 = new 外部类对象.内部类对象
 629             如:Outer.Inner in = new Outer().new Inner()
 630         B:当内部类在外部类成员位置,且被static修饰时
 631             **外部其他类可直接访问静态内部类的非静态成员
 632               格式:new 外部类名.内部类名().内部类成员
 633               如:new Outer.Inner().function();
 634             **外部其他类可直接访问静态内部类的静态成员
 635               格式:new 外部类名.内部类名.内部类成员
 636               如:new Outer.Inner.function();
 637     (4)什么使用时候内部类呢?
 638         假如有A类和B类,A类想直接访问B类的成员,B类访问A类成员的时候,
 639         需要创建A类对象进行访问,这个时候,就可以把A类定义为B类的内部类。
 640     (5)内部类的位置
 641         A:成员位置
 642             **可以被private修饰(Body,Heart)
 643             **可以被static修饰。(它访问的外部类的成员必须是静态的)    
 644         B:局部位置
 645             **可以直接访问外部类中的成员,因为还持有外部类的持用
 646             也可以直接访问局部成员,但是局部成员要用final修饰。      
 647         注意:局部内部类不能用private和static修饰        
 648     (6)通过class文件我们就可以区分是否带有内部类,以及内部类的位置
 649         Outer$Inner:成员内部类
 650         Outer$1Inner:局部内部类
 651 28、匿名内部类(局部内部类的简写) (重点)
 652         (1)前提:继承一个类或者实现一个接口
 653         (注意不要弄混匿名内部类的前提和多态的前提)
 654         (2)格式:
 655             new 父类名或者接口名()
 656             {
 657                 重写父类方法或者实现接口中的方法。
 658                 也可以自定义其他方法。
 659             };
 660         (3)什么时候定义匿名内部类?
 661             匿名内部类只是为了简化书写,匿名内部类有局限,通常定义匿名内部类时,该类方法不超过3个
 662         (4)匿名内部类的好处和弊端:
 663             好处:简化代码书写
 664             弊端:
 665                 不能直接调用自己的特有方法
 666                 不能执行强转换动作
 667                 如果该类里面方法较多,不允许使用匿名内部类
 668 29、模板设计模式:
 669     在定义功能时,功能的一部分是确定的,有一部分是不确定的,而且确定的部分在使用不确定的部分,
 670     可将不确定的部分暴露出去,由该类的子类去完成。
 671     如:求一段程序的运行时间例子。
 672 30、异常
 673     (1)程序运行过程中的不正常现象就叫异常。
 674     (2)导致程序运行不正常的现象有很多,所以,就有很多的异常对象。
 675        而这些异常对象存在着共性的内容,所以,可以不断的进行抽取。最终形成了异常的体系结构。
 676        异常体系的根类是:Throwable
 677        Throwable:
 678         |--Error:重大的问题,我们处理不了。也不需要编写代码处理。比如说内存溢出。
 679         |--Exception:一般性的错误,是需要我们编写代码进行处理的。
 680             |--RuntimeException:运行时异常,这个我们也不需要处理。
 681                                 其实就是为了让他在运行时出问题,然后我们回来修改代码。
 682     (3)异常的分类        
 683         异常有两种:
 684         编译时被检测异常:
 685             该异常在编译时,如果没有处理(没有抛也没有try),编译失败。
 686             该异常被标识,代表这可以被处理。
 687         运行时异常(编译时不检测)
 688             在编译时,不需要处理,编译器不检查。
 689             该异常的发生,建议不处理,让程序停止。需要对代码进行修正。
 690     (4)异常体系的特点:
 691         异常体系中的所有类及其子类对象都具备可抛性。也就是说可以被throw和throws关键字所操作。
 692     (5)main方法是如何处理异常的。
 693         A:在main里面编写代码进行处理
 694         B:交给jvm自己进行处理。采用的是jvm的默认处理方式。
 695           其实就是相当于调用了异常对象的printStackTrace()方法。
 696     (6)Throwable类的学习
 697         getMessage():获取异常信息,返回字符串。
 698         toString():获取异常类名和异常信息,返回字符串。
 699         printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
 700     (7)异常的处理·
 701         A:try...catch...finally
 702         基本格式:
 703             try
 704             {
 705                 可能出现异常的代码
 706             }
 707             catch(异常对象)
 708             {    
 709                 异常处理代码
 710             }
 711             finally
 712             {
 713                 释放资源
 714             }
 715         
 716         变形格式:
 717             try...catch
 718             try...catch...catch...
 719             try...catch...catch...finally
 720         **多个异常同时被捕获的时候,记住一个原则:
 721             先逮小的,再逮大的。
 722         **finally:永远被执行,除非退出jvm。System.exit(0);
 723             面试题2个。
 724             ***:final,finally,finalize区别。
 725                final是最终的意思。它可以用于修饰类,成员变量,成员方法。
 726                它修饰的类不能被继承,它修饰的变量时常量,它修饰的方法不能被重写。
 727 
 728                finally:是异常处理里面的关键字。
 729                它其中的代码永远被执行。特殊情况:在执行它之前jvm退出。System.exit(0);
 730 
 731                finalize:是Object类中的一个方法。
 732                它是于垃圾回收器调用的方式。
 733 
 734             ***:假如catch中有return语句, finally里中的代码会执行吗?
 735                是在return前,还是在return后呢?
 736                会,在return前执行finally里面的代码。
 737     (8)Exception和RuntimeException的区别
 738         A:Exception:一般性的错误,是需要我们编写代码进行处理的。    
 739         B:RuntimeException:运行时异常,这个我们也不需要处理。
 740                        其实就是为了让他在运行时出问题,然后我们回来修改代码。
 741             在用throws抛出一个的时候,如果这个异常是属于RuntimeException的体系的时候,
 742             我们在调用的地方可以不用处理。(RuntimeException和RuntimeException的子类)
 743             
 744             在用throws抛出一个的时候,如果这个异常是属于Exception的体系的时候,
 745             我们在调用的地方必须进行处理或者继续抛出。
 746     (9)自定义异常
 747         定义类继承Exception或者RuntimeException
 748         1,为了让该自定义类具备可抛性。
 749         2,让该类具备操作异常的共性方法。
 750         class MyExcepiton extends Exception
 751         {
 752             MyExcepiton(){}
 753 
 754             MyExcepiton(String message)
 755             {
 756                 super(message);
 757             }
 758         }
 759 
 760         class MyException extends RuntimeException
 761         {
 762             MyExcepiton(){}
 763 
 764             MyExcepiton(String message)
 765             {
 766                 super(message);
 767             }
 768         }
 769     (10)throws和throw的区别
 770         A:有throws的时候可以没有throw。
 771            有throw的时候,如果throw抛的异常是Exception体系,那么必须有throws在方法上声明。
 772         B:throws用于方法的声明上,其后跟的是异常类名,后面可以跟多个异常类,之间用逗号隔开
 773            throw用于方法体中,其后跟的是一个异常对象名
 774         
 775 
 776 
 777 
 778 
 779 三、多线程:
 780 1、进程和线程:
 781     进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
 782     线程:进程内部的一条执行路径或者一个控制单元。
 783     两者的区别:
 784         一个进程至少有一个线程
 785         进程在执行过程中拥有独立的内存单元,而多个线程共享内存;
 786 2、jvm多线程的启动是多线程吗?
 787     java的虚拟机jvm启动的是单线程,就有发生内存泄露的可能,而我们使用java程序没出现这样的问题,
 788     也就是jvm启动至少有两个线程,一个执行java程序,一个执行垃圾回收。所以是多线程。    
 789 2、多线程的优势:
 790     解决了多部分同时运行的问题,提高效率
 791 3、线程的弊端:
 792     线程太多会导致效率的降低,因为线程的执行依靠的是CPU的来回切换。
 793 4、什么叫多线程:
 794     一个进程中有多个线程,称为多线程。
 795 5、实现多线程的方法:
 796     实现多线程可以通过继承Thread类和实现Runnable接口。
 797     (1)继承Thread
 798         定义一个类继承Thread类
 799         复写Thread类中的public void run()方法,将线程的任务代码封装到run方法中
 800         直接创建Thread的子类对象,创建线程
 801         调用start()方法,开启线程(调用线程的任务run方法)
 802         //另外可以通过Thread的getName()获取线程的名称。
 803 
 804     (2)实现Runnable接口;
 805         定义一个类,实现Runnable接口;
 806         覆盖接口的public void run()的方法,将线程的任务代码封装到run方法中;
 807         创建Runnable接口的子类对象
 808         将Runnabl接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象
 809                        (原因:线程的任务都封装在Runnable接口子类对象的run方法中。
 810                  所以要在线程对象创建时就必须明确要运行的任务)。
 811         调用start()方法,启动线程。
 812     
 813     两种方法区别:
 814         (1)实现Runnable接口避免了单继承的局限性
 815         (2)继承Thread类线程代码存放在Thread子类的run方法中
 816            实现Runnable接口线程代码存放在接口的子类的run方法中;
 817            在定义线程时,建议使用实现Runnable接口,因为几乎所有多线程都可以使用这种方式实现
 818 6、创建线程是为什么要复写run方法?
 819     Thread类用于描述线程。Thread类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
 820 7、start()和run方法有什么区别?
 821     调用start方法方可启动线程,而run方法只是thread的一个普通方法,调用run方法不能实现多线程;
 822     Start()方法:
 823         start方法用来启动线程,实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的
 824         代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,
 825         一旦得到cpu时间片(执行权),就开始执行run()方法,这里方法run()称为线程体,
 826         它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。    
 827     Run()方法:
 828         run()方法只是Thread类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,
 829         其程序执行路径还是只有一条,还是要等待run方法体执行完毕后才可继续执行下面的代码,
 830         这样就没有达到多线程的目的。
 831 8、线程的几种状态:
 832     新建:new一个Thread对象或者其子类对象就是创建一个线程,当一个线程对象被创建,但是没有开启,这个时候,
 833           只是对象线程对象开辟了内存空间和初始化数据。            
 834     就绪:新建的对象调用start方法,就开启了线程,线程就到了就绪状态。
 835           在这个状态的线程对象,具有执行资格,没有执行权。
 836     运行:当线程对象获取到了CPU的资源。
 837           在这个状态的线程对象,既有执行资格,也有执行权。
 838     冻结:运行过程中的线程由于某些原因(比如wait,sleep),释放了执行资格和执行权。
 839               当然,他们可以回到运行状态。只不过,不是直接回到。
 840           而是先回到就绪状态。
 841     死亡:当线程对象调用的run方法结束,或者直接调用stop方法,就让线程对象死亡,在内存中变成了垃圾。              
 842 9、sleep()和wait()的区别:
 843      (1)这两个方法来自不同的类,sleep()来自Thread类,和wait()来自Object类。
 844      (2)sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,
 845         要让b线程睡觉要在b的代码中调用sleep。而wait()是Object类的非静态方法
 846      (3)sleep()释放资源不释放锁,而wait()释放资源释放锁;
 847      (4)使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
 848 10、多线程安全问题:
 849     (1)原因:当程序的多条语句在操作线程共享数据时(如买票例子中的票就是共享资源),由于线程的随机性导致
 850             一个线程对多条语句,执行了一部分还没执行完,另一个线程抢夺到cpu执行权参与进来执行,
 851             此时就导致共享数据发生错误。比如买票例子中打印重票和错票的情况。    
 852     (2)解决方法:对多条操作共享数据的语句进行同步,一个线程在执行过程中其他线程不可以参与进来
 853 11、Java中多线程同步是什么?
 854      同步是用来解决多线程的安全问题的,在多线程中,同步能控制对共享数据的访问。如果没有同步,当一个线程在
 855      修改一个共享数据时,而另外一个线程正在使用或者更新同一个共享数据,这样容易导致程序出现错误的结果。 
 856 12、什么是锁?锁的作用是什么?
 857     锁就是对象
 858     锁的作用是保证线程同步,解决线程安全问题。
 859     持有锁的线程可以在同步中执行,没有锁的线程即使获得cpu执行权,也进不去。
 860 13、同步的前提:
 861     (1)必须保证有两个以上线程
 862     (2)必须是多个线程使用同一个锁,即多条语句在操作线程共享数据
 863     (3)必须保证同步中只有一个线程在运行
 864 14、同步的好处和弊端
 865     好处:同步解决了多线程的安全问题
 866     弊端:多线程都需要判断锁,比较消耗资源
 867 15、同步的两种表现形式:
 868     (1)同步代码块:
 869         可以指定需要获取哪个对象的同步锁,使用synchronized的代码块同样需要锁,但他的锁可以是任意对象
 870         考虑到安全问题,一般还是使用同一个对象,相对来说效率较高。
 871 
 872         注意:
 873         **虽然同步代码快的锁可以使任何对象,但是在进行多线程通信使用同步代码快时,
 874           必须保证同步代码快的锁的对象和,否则会报错。
 875         **同步函数的锁是this,也要保证同步函数的锁的对象和调用wait、notify和notifyAll的对象是
 876           同一个对象,也就是都是this锁代表的对象。
 877         格式:
 878         synchronized(对象)
 879         {
 880             需同步的代码;
 881         }
 882     (2)同步函数
 883         同步方法是指进入该方法时需要获取this对象的同步锁,在方法上使用synchronized关键字,
 884         使用this对象作为锁,也就是使用了当前对象,因为锁住了方法,所以相对于代码块来说效率相对较低。
 885         注:静态同步函数的锁是该方法所在的类的字节码文件对象,即类名.class文件
 886         格式:
 887         修饰词 synchronized 返回值类型 函数名(参数列表)
 888         {
 889             需同步的代码;
 890         }
 891 
 892     在jdk1.5后,用lock锁取代了synchronized,个人理解也就是对同步代码块做了修改,
 893     并没有提供对同步方法的修改,主要还是效率问题吧。
 894 16、多线程的单例设计模式:保证某个类中内存中只有一个对象
 895     (1)饿汉式:
 896         class Single
 897         {
 898             private Single(){}//将构造函数私有化,不让别的类建立该类对象
 899             private static final Single s=new Single();//自己建立一个对象
 900             public static Single getInstance()//提供一个公共访问方式
 901             {
 902                 return s;
 903             }
 904         }
 905     (2)懒汉式:
 906         class Single
 907         {
 908             private Single(){} 
 909             private static Single s;
 910             public static Single getInstance()
 911             {
 912                 if(s==null)
 913                     s=new Single();
 914                 return s;
 915             }
 916         }
 917     饿汉式和懒汉式的区别:
 918         **
 919         饿汉式是类一加载进内存就创建好了对象;
 920         懒汉式则是类加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,对象才开始创建。    
 921         **
 922         懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,解决线程安全问题
 923         可以加同步来解决。但是加了同步之后,每一次都要比较锁,效率就变慢了,
 924         所以可以加双重判断来提高程序效率。
 925         如将上述懒汉式的Instance函数改成同步:
 926         public static Single getInstance()
 927         {
 928             if(s==null)
 929             {
 930                 synchronized(Single.class)
 931                 {
 932                     if(s==null) 
 933                         s=new Single();
 934                 }
 935             }
 936             return s;
 937         }
 938 17、死锁
 939     两个线程对两个同步对象具有循环依赖时,就会发生死锁。即同步嵌套同步,而锁却不同。
 940 18、wait()、sleep()、notify()、notifyAll()
 941     wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 
 942     sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。 
 943     notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
 944          而是由JVM确定唤醒哪个线程(一般是最先开始等待的线程),而且不是按优先级。 
 945     notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
 946 18、为什么wait()、notify()、notifyAll()这些用来操作线程的方法定义在Object类中?
 947     (1)这些方法只存在于同步中;
 948     (2)使用这些方法时必须要指定所属的锁,即被哪个锁调用这些方法;
 949     (3)而锁可以是任意对象,所以任意对象调用的方法就定义在Object中。
 950 19、多线程间通讯:
 951     多线程间通讯就是多个线程在操作同一资源,但是操作的动作不同.
 952         (1)为什么要通信
 953         多线程并发执行的时候, 如果需要指定线程等待或者唤醒指定线程, 那么就需要通信.比如生产者消费者的问题,
 954         生产一个消费一个,生产的时候需要负责消费的进程等待,生产一个后完成后需要唤醒负责消费的线程,
 955         同时让自己处于等待,消费的时候负责消费的线程被唤醒,消费完生产的产品后又将等待的生产线程唤醒,
 956         然后使自己线程处于等待。这样来回通信,以达到生产一个消费一个的目的。        
 957         (2)怎么通信
 958         在同步代码块中, 使用锁对象的wait()方法可以让当前线程等待, 直到有其他线程唤醒为止.
 959         使用锁对象的notify()方法可以唤醒一个等待的线程,或者notifyAll唤醒所有等待的线程.
 960         多线程间通信用sleep很难实现,睡眠时间很难把握。
 961     
 962     
 963 20、Lock和Condition
 964     实现提供比synchronized方法和语句可获得的更广泛的锁的操作,可支持多个相关的Condition对象
 965     Lock是个接口
 966     锁是控制多个线程对共享数据进行访问的工具。
 967 
 968     JDK1.5中提供了多线程升级的解决方案:
 969     将同步synchonized替换成了显示的Lock操作,将Object中的wait、notify、notifyAll替换成了Condition对象。
 970     该对象可以Lock锁进行获取
 971 
 972     Lock的方法摘要:
 973         void lock()  获取锁。 
 974         Condition newCondition() 返回绑定到此 Lock 实例的新 Condition 实例。 
 975         void unlock() 释放锁。
 976     Condition方法摘要:
 977         void await() 造成当前线程在接到信号或被中断之前一直处于等待状态。
 978         void signal() 唤醒一个等待线程。          
 979         void signalAll() 唤醒所有等待线程。
 980            
 981 21、停止线程:
 982     stop方法已经过时,如何停止线程?
 983         停止线程的方法只有一种,就是run方法结束。如何让run方法结束呢?
 984         开启多线程运行,运行代码通常是循环体,只要控制住循环,就可以让run方法结束,也就是结束线程。
 985 
 986         特殊情况:当线程属于冻结状态,就不会读取循环控制标记,则线程就不会结束。
 987         为解决该特殊情况,可引入Thread类中的Interrupt方法结束线程的冻结状态;
 988         当没有指定的方式让冻结线程恢复到运行状态时,需要对冻结进行清除,强制让线程恢复到运行状态
 989 22、interrupt:
 990     void interrupt() 中断线程: 
 991         中断状态将被清除,它还将收到一个 InterruptedException
 992 22、守护线程(后台线程)
 993     setDaemon(boolean on):将该线程标记为守护线程或者用户线程。
 994                 当主线程结束,守护线程自动结束,比如圣斗士星矢里面的守护雅典娜,
 995                 在多线程里面主线程就是雅典娜,守护线程就是圣斗士,主线程结束了,
 996                 守护线程则自动结束。
 997     当正在运行的线程都是守护线程时,java虚拟机jvm退出;所以该方法必须在启动线程前调用;
 998 
 999     守护线程的特点:
1000         守护线程开启后和前台线程共同抢夺cpu的执行权,开启、运行两者都没区别,
1001         但结束时有区别,当所有前台线程都结束后,守护线程会自动结束。        
1002 23、多线程join方法:
1003     void join() 等待该线程终止。
1004     void join(long millis)  等待该线程终止的时间最长为 millis 毫秒。
1005         throws InterruptedException         
1006     特点:当A线程执行到B线程的join方法时,A就会等待B线程都执行完,A才会执行
1007     作用: join可以用来临时加入线程执行;
1008 24、多线程优先级:yield()方法
1009     yield():暂停当前正在执行的线程对象,并执行其他线程
1010     setPriority(int newPriority):更改线程优先级
1011     int getPriority() 返回线程的优先级。
1012     String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组
1013            
1014     (1)MAX_PRIORITY:最高优先级(10级)
1015     (1)Min_PRIORITY:最低优先级(1级)
1016     (1)Morm_PRIORITY:默认优先级(5级)
1017 
1018 25、什么是ThreadLocal类,怎么使用它?
1019     ThreadLocal类提供了线程局部 (thread-local) 变量。是一个线程级别的局部变量,并非“本地线程”。
1020     ThreadLocal 为每个使用该变量的线程,提供了一个独立的变量副本,每个线程修改副本时不影响其它线程对象的副本
1021 
1022     下面是线程局部变量(ThreadLocal variables)的关键点:
1023         一个线程局部变量(ThreadLocal variables)为每个线程方便地提供了一个单独的变量。
1024         ThreadLocal 实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。 
1025         当多个线程访问 ThreadLocal 实例时,每个线程维护 ThreadLocal 提供的独立的变量副本。
1026         常用的使用可在 DAO 模式中见到,当 DAO 类作为一个单例类时,
1027         数据库链接(connection)被每一个线程独立的维护,互不影响。(基于线程的单例)
1028 26、什么时候抛出InvalidMonitorStateException异常?为什么?
1029     调用 wait ()/notify ()/notifyAll ()中的任何一个方法时,如果当前线程没有获得该对象的锁,
1030     那么就会抛出 IllegalMonitorStateException 的异常
1031     也就是说程序在没有执行对象的任何同步块或者同步方法时,
1032     仍然尝试调用 wait ()/notify ()/notifyAll ()时。由于该异常是 RuntimeExcpetion 的子类,
1033     所以该异常不一定要捕获(尽管你可以捕获只要你愿意
1034     作为 RuntimeException,此类异常不会在 wait (),notify (),notifyAll ()的方法签名提及。 
1035 27、在静态方法上使用同步时会发生什么事?
1036     同步静态方法时会获取该类的“Class”对象,所以当一个线程进入同步的静态方法中时,
1037     线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。
1038     它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。
1039 28、当一个同步方法已经执行,线程能够调用对象上的非同步实例方法吗?
1040     可以,一个非同步方法总是可以被调用而不会有任何问题。
1041     实际上,Java 没有为非同步方法做任何检查,锁对象仅仅在同步方法或者同步代码块中检查。
1042     如果一个方法没有声明为同步,即使你在使用共享数据Java照样会调用,而不会做检查是否安全,
1043     所以在这种情况下要特别小心。一个方法是否声明为同步取决于临界区访问(critial section access),
1044     如果方法不访问临界区(共享资源或者数据结构)就没必要声明为同步的。
1045 29、在一个对象上两个线程可以调用两个不同的同步实例方法吗?
1046     不能,因为一个对象已经同步了实例方法,线程获取了对象的对象锁。
1047     所以只有执行完该方法释放对象锁后才能执行其它同步方法。
1048 30、什么是线程饿死,什么是活锁?
1049     线程饿死和活锁虽然不像死锁一样是常见的问题,但是对于并发编程的设计者来说就像一次邂逅一样。
1050     当所有线程阻塞,或者由于需要的资源无效而不能处理,不存在非阻塞线程使资源可用。
1051     JavaAPI 中线程活锁可能发生在以下情形:
1052     当所有线程在程序中执行 Object.wait (0),参数为 0 的 wait 方法。
1053     程序将发生活锁直到在相应的对象上有线程调用 Object.notify ()或者 Object.notifyAll ()。
1054     当所有线程卡在无限循环中。
1055 
1056 
1057 
1058 四、集合框架
1059 Collection    Map
1060 List Set
1061 1:String类:字符串(重点)
1062     (1)多个字符组成的一个序列,叫字符串。
1063        生活中很多数据的描述都采用的是字符串的。而且我们还会对其进行操作。
1064        所以,java就提供了这样的一个类供我们使用。
1065     (2)创建字符串对象
1066         A:String():无参构造
1067             **举例:
1068               String s = new String();
1069               s = "hello";
1070               sop(s);
1071         B:String(byte[] bys):传一个字节数组作为参数 *****
1072             **举例
1073               byte[] bys = {97,98,99,100,101};
1074               String s = new String(bys);
1075               sop(s);
1076         C:String(byte[] bys,int index,int length):把字节数组的一部分转换成一个字符串 *****
1077             **举例
1078               byte[] bys = {97,98,99,100,101};
1079               String s = new String(bys,1,2);
1080               sop(s);
1081         D:String(char[] chs):传一个字符数组作为参数 *****
1082             **举例
1083               char[] chs = {'a','b','c','d','e'};
1084               String s = new String(chs);
1085               sop(s);
1086         E:String(char[] chs,int index,int length):把字符数组的一部分转换成一个字符串 *****
1087             **举例
1088               char[] chs = {'a','b','c','d','e'};
1089               String s = new String(chs,1,2);
1090               sop(s);    
1091         F:String(String str):把一个字符串传递过来作为参数
1092               char[] chs = {'a','b','c','d','e'};
1093               String ss = new String(s);
1094               sop(ss);
1095         G:直接把字符串常量赋值给字符串引用对象(最常用) *****
1096             **举例
1097               String s = "hello";
1098               sop(s);
1099     (3)面试题
1100         A:请问String s = new String("hello");创建了几个对象。
1101           两个。一个"hello"字符串对象,在方法区的常量池;一个s对象,在栈内存。
1102 
1103         B:请写出下面的结果
1104             String s1 = new String("abc");
1105             Strign s2 = new String("abc");
1106             String s3 = "abc";
1107             String s4 = "abc";
1108 
1109             sop(s1==s2);  //false
1110             sop(s1==s3);  //false
1111             sop(s3==s4);  //true
1112         C:字符串对象一旦被创建就不能被改变。
1113             指的是字符串常量值不改变。
1114     (4)字符串中各种功能的方法
1115         A:判断
1116         ****    boolean equals(Object anObject):判断两个字符串的内容是否相同,复写了Object的方法
1117         ****    boolean equalsIgnoreCase(String anotherString):判断两个字符串的内容是否相同,
1118                                     不区分大小写
1119         ****    boolean contains(String s):判断一个字符串中是否包含另一个字符串
1120                         注意:判断字符串是否包含特殊字符.直接表示为str.contains(".")
1121             boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
1122             boolean startsWith(String suffix):测试此字符串是否以指定的前缀开始
1123             boolean isEmpty():测试字符串是否为空
1124         B:获取
1125         *****    int length():返回此字符串的长度
1126         *****    char charAt(int index):返回指定索引处的 char值
1127         *****    int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。 
1128             int indexOf(int ch, int fromIndex):返回在此字符串中第一次出现指定字符处的索引,
1129                                从指定的索引开始搜索。 
1130             int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。 
1131             int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次
1132                                 出现处的索引,从指定的索引开始。 
1133         ***    int lastIndexOf(int ch):返回指定字符在此字符串中最后一次出现处的索引。 
1134             int lastIndexOf(int ch, int fromIndex) 
1135                 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。 
1136             int lastIndexOf(String str) 
1137                 返回指定子字符串在此字符串中最右边出现处的索引。 
1138             int lastIndexOf(String str, int fromIndex) 
1139                 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 
1140         *****    String substring(int beginIndex) (注意:该方法substring的String是小写!!!)
1141                 返回一个新的字符串,它是此字符串的一个子字符串。 
1142             String substring(int beginIndex, int endIndex) (注意该方法的String是小写!!!)
1143                 返回一个新字符串,它是此字符串的一个子字符串,包含头不包含尾。 
1144         C:转换
1145         *****    byte[] getBytes():(很常用!)从字符串到字节数组的方法
1146             void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 
1147                 将字符从此字符串复制到目标字符数组。 
1148         *****    char[] toCharArray():(很常用!)从字符串到字符数组的方法
1149         ****    static String copyValueOf(char[] data) 
1150                 返回指定数组中表示该字符序列的 String。 
1151             static String copyValueOf(char[] data, int offset, int count) 
1152                 返回指定数组中表示该字符序列的 String。 
1153         *****    static String valueOf(数据类型):把该数据类型的数据转换成字符串。
1154         ***    String toLowerCase():把字符串转换成小写
1155             String toUpperCase():把字符串转换成大写
1156         ***    字符串的连接
1157             String concat(String str):将指定字符串连接到此字符串的结尾。
1158         D:替换
1159             String replace(char oldChar, char newChar):用新字符替换旧字符(替换所有)
1160             String replace(String target, String replacement):用新的子串换旧串
1161         E:分割
1162             String[] split(String regex):根据指定的字符串把一个字符串分割成一个字符串数组
1163         F:    
1164             String trim():去除字符串的前后空格
1165         G:    
1166             int compareTo(String anotherString) 
1167                 按字典顺序比较两个字符串。 
1168             int compareToIgnoreCase(String str) 
1169                 按字典顺序比较两个字符串,不考虑大小写。 
1170     (5)练习
1171         1:模拟登录,给三次机会,并提示还有几次.
1172         默认的用户名和密码为admin。 区分大小写。
1173         自己从键盘输入用户名和密码。
1174 
1175         2:给定一个字符串统计,统计大写字母,小写字母,数字出现的个数.
1176         ***注意:不包括特殊字符
1177         从键盘输入一个不包含特殊字符的字符串(只有26个字母和0-9组成)。
1178 
1179         3:给定一个字符串,把它变成首字母大写,其他字母小写的字符串.
1180         从键盘输入一个字符串,全部26个字母组成的。
1181 
1182         4:子串在整串中出现的次数。
1183         也就是说:获取一个字符串中,指定的字串在该字符串中出现的次数.
1184         例如:
1185         "nbasdnbafllgnbahjnbakqqqqlnba"  在这个字符串中,多有个nba.
1186 
1187         5:对字符串中字符进行自然顺序排序。
1188         "basckd"-->"abcdks"
1189 
1190         先留做思考内容:
1191         6:两个字符串的最大相同子串。
1192         两个字符串的最大相同子串。
1193         比如:
1194         "sadabcdfghjkl"
1195         werabcdtyu"
1196 
1197 2:StringBuffer
1198     (1)字符串的缓冲区,是一个容器。
1199     (2)它和String的区别
1200         它是缓冲区可变长度的。
1201     (3)构造方法
1202         StringBuffer() 构造一个其中不带字符的字符串缓冲区,初始容量为 16 个字符。
1203         StringBuffer(int num) 构造一个不带字符,但具有指定初始容量的字符串缓冲区。
1204         StringBuffer(String str) 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。
1205     (4)常用方法
1206         A:增加数据
1207             **append :添加各种类型的数据
1208             **insert : 在容器指定位置插入各种类型的数据。
1209         B:删除数据
1210             **deleteCharAt : 删除指定位置的字符
1211             **delete 还可以用于清空StringBuffer的缓冲区
1212         C:替换
1213             **replace
1214         D:获取 
1215             **charAt 
1216         E:长度和容量
1217             **length() 元素的个数
1218             **capacity 元素的理论值
1219         F:获取元素的位置
1220             **indexOf
1221             **lastIndexOf
1222         G:截取
1223             **substring(int start)
1224             **substring(int start,int end)
1225         H:反转
1226             **reverse
1227     (5)字符串和StringBuffer的转换
1228         String-->StringBuffer通过构造:
1229             如:StringBuffer sb = new StringBuffer(String str)
1230         StringBuffer--String通过toString方法 
1231             如:StringBuffer sb = new StringBuffer();
1232                sb.toString();
1233 
1234 3:StringBuilder
1235     和StringBuffer的功能是一样的,但是有区别:
1236     StringBuffer(JDK1.0)是线程安全的。
1237     StringBuilder(JDK1.5)不保证线程安全。
1238 
1239     一般来说,我们写的程序都是单线程的,所以,用StringBuilder,效率高。
1240 
1241     JDK版本的升级原则:
1242     A:提高效率
1243     B:提高安全性
1244     C:简化书写
1245 
1246 4:基本数据类型的对象包装类
1247     (1)为了更方便的操作每个基本数据类型,java对其提供了很多的属性和方法供我们使用。
1248     (2)用途:
1249         **将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能操作该数据。
1250         **常用的操作之一:用于基本数据类型与字符串之间的转换。
1251         A:方便操作
1252         B:用于和字符串进行相互转换
1253     (3)基本数据类型和对象类型的对应
1254         byte        Byte
1255         short        Short 
1256         int        Integer
1257         long        Long
1258         float        Float
1259         double        Double
1260         boolean        Boolean
1261         char        Character
1262     (4)构造方法
1263 
1264         字段摘要:
1265             static int MAX_VALUE 值为 2^31-1 的常量,它表示 int 类型能够表示的最大值         
1266             static int MIN_VALUE  值为 -2^31 的常量,它表示 int 类型能够表示的最小值
1267             static Class<Integer> TYPE 表示基本类型int的Class 实例
1268           
1269         Integer(int value) 构造一个新分配的Integer对象,它表示指定的int值。
1270         Inreger(String s) 注意:s必须是纯数字的字符串。否则会有异常NumberFormatException
1271                                 
1272     (5)几个常用的方法
1273         Integer.toBinaryString();
1274             以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
1275         Integer.toOctalString();
1276             以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。
1277         Integer.toHexString();
1278             以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
1279         static int Integer.parseInt(String s) 将字符串参数作为有符号的十进制整数进行解析,
1280             字符串必须是int型范围内的数字字符串
1281         static int Integer.parseInt(String s,int basic) 
1282             使用第二个参数指定的基数,将字符串参数解析为有符号的整数.
1283             字符串必须是int型范围内的数字字符串
1284         short shortValue() 以short类型返回该Integer的值。          
1285         int intValue() 以int类型返回该Integer的值。  
1286         static Integer valueOf(int num) 返回一个表示指定的 int 值的 Integer 实例。
1287         static Integer valueOf(String s) 返回保存指定的String的值的Integer对象。           
1288                 static Integer valueOf(String s, int radix) 
1289             返回一个Integer对象,该对象中保存了用第二个参数提供的基数进行
1290             解析时从指定的String中提取的值。 
1291 
1292     (6)类型转换
1293         int -- Integer
1294             int num = 20;
1295             A:Integer i = new Integer(num);
1296             B:Integer i = Integer.valueOf(num);
1297         Integer -- int
1298             Integer i = new Integer(20);
1299             A:int num = i.intValue();
1300         
1301         int -- String
1302             int num = 20;
1303             A:String s = String.valueOf(num);
1304             B:String s = ""+num;
1305             C:String s = Integer.toString(num);
1306         String -- int
1307             String s = "20";
1308             A:int num = Integer.parseInt(s);
1309             B:Integer i = new Integer(s);或者Integer i = Integer.valueOf(s);
1310               int num = i.intValue();    
1311 6、集合框架:
1312     (1)为什么出现集合类?
1313         面向对象对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储。
1314         集合就是存储对象最常用的一种方式.
1315     (2)数组和集合都是容器,两者有何不同?
1316         **数组长度固定,而集合长度是可变的    
1317         **数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象    
1318         **数组存储数据类型是固定的,而集合存储的数据类型不固定        
1319     (3)集合类的特点:
1320         集合只能存储对象
1321         集合的长度是可变的
1322         集合可以存储不同类型的对象
1323     (4)集合类框架(重要!!!要分清几种容器间的区别):
1324         **Collection:顶层接口
1325              |--->List:列表,元素是有序的(元素带角标索引),可以有重复元素,可以有null元素。
1326                     |--->ArrayList(JDK1.2):底层的数据结构是数组数据结构,特点是查询速度快(因为带角标),
1327                            但是增删速度稍慢,因为当元素多时,增删一个元素则所有元素的角标都得改变
1328                            线程不同步。默认长度是10,当超过长度时,按50%延长集合长度。                   
1329                 |--->LinkedList(JDK1.2):底层数据结构式链表数据结构(即后面一个元素记录前一个),
1330                             特点:查询速度慢,因为每个元素只知道前面一个元素,但增删速度快
1331                             因为元素再多,增删一个,只要让其前后的元素重新相连即可
1332                             线程是不同步的。                            
1333                 |--->Vector(JDK1.0):底层数据结构是数组数据结构.特点是查询和增删速度都很慢。
1334                         默认长度是10,当超过长度时,按100%延长集合长度。
1335                         线程同步。
1336                         (Vector功能跟ArrayList功能一模一样,已被ArrayList替代)
1337 
1338 
1339            **List使用注意!
1340             |--->ArrayList:
1341             (1)当往ArrayList里面存入元素没什么要求时,即只要求有序就行时;
1342                
1343             (2)当往ArrayList里面存入元素要求不重复时,比如存入学生对象,当同名同姓时
1344                视为同一个人,则不往里面存储。则定义学生对象时,需复写equals方法
1345                public boolean equals(Object obj)
1346                {
1347                 if(!(obj instanceof Student))
1348                     return false;
1349                 Student stu = (Student)obj;
1350                 return this.name.equals(stu.name)&&this.age==stu.age;
1351                }
1352                则往ArrayList集合通过add存入学生对象时,集合底层自己会调用学生类的equals方法,
1353                判断重复学生则不存入。
1354              注:对于List集合,无论是add、contains、还是remove方法,判断元素是否相同,
1355                  都是通过复写equals方法来判断!
1356 
1357             |--->LinkedList
1358             (1)LinkLedist的特有方法:
1359                  boolean offerFirst(E e)  在此列表的开头插入指定的元素。
1360                  boolean offerLast(E e) 在此列表末尾插入指定的元素。
1361                  E peekFirst() 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
1362                  E peekLast() 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
1363                  E pollFirst() 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
1364                  E pollLast() 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
1365             (2)通过LinkLedist的特有方法,可以实现某些数据特殊方式的存取,比如堆栈和队列。
1366 
1367                 一般情况下,使用哪种List接口下的实现类呢?
1368                 如果要求增删快,考虑使用LinkedList
1369                 如果要求查询快,考虑使用ArrayList
1370                 如果要求线程安全,考虑使用Vector。
1371 
1372 
1373 
1374              |--->Set:集合,元素是无序的(因为没有索引),元素不可以重复。可以有null元素。
1375                 |--->HashSet(JDK1.2):底层数据结构是哈希表、存取速度快、元素唯一、线程不同步。
1376                      保证性元素唯一的原理:
1377                      先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true
1378                      (往HashSet里面存的自定义元素要复写hashCode和equals方法,
1379                      以保证元素的唯一性!)
1380                 |--->TreeSet:底层数据结构式二叉树。可以对Set集合中的元素进行排序。元素有序、线程不同步。
1381                      保证元素唯一性的依据:compareTo方法return 0
1382                      TreeSet排序的第一种方式:让元素自身具备比较性,比如八种基本数据类型或则字符串,
1383                                  实现Compareble接口,覆盖compareTo方法,
1384                                  此方式是元素的自然顺序             
1385                      TreeSet排序的第一种方式:当元素自身不具备比较性(比如存储学生对象时)或者具备的
1386                                  比较性不是我们所需要的比较性时(比如想字符串的长度排序),
1387                                  此时就需要让集合自身具备自定义的比较性。 
1388                                  那如何让集合自身具备比较性呢?可在集合初始化时,
1389                                  就让集合具备比较方式。即定义一个类,
1390                                  实现Comparator接口,覆盖compare方法。
1391 
1392             **Set集合使用注意事项:
1393             (1)HashSet:
1394                   通过new的方式往HashSet里面存的元素的hashCode都不同,但通常我们定义对象,
1395                   比如学生对象时,虽然是new的两个学生对象,但是当他们name和age一样时,我们认为是
1396                   同一个对象,所以为了保证元素的唯一性,我们通常在往HashSet集合里面存储元素时,
1397                   在定义对象的类中通常复写hashCode和equals方法。
1398                   public int hashCode()
1399                   {
1400                 return name.hashCode()+age*39;
1401                   }
1402                   public boolean equals(Object obj)
1403                   {
1404                 if(!(obj instanceof Student))
1405                     return false;
1406                 Student stu = (Student)obj;
1407                 return this.name.equals(stu.name)&&this.age==stu.age;
1408                   }
1409 
1410                  HashSet是如何保证元素唯一性的呢?
1411                   **如果两元素的hashCode值不同,则不会调用equals方法
1412                   **如果两元素的hashCode值相同,则继续判断equals是否返回true;
1413                   **hashCode和equals方法虽然定义在自定义对象类里面,但不是我们手动调用
1414                     而是往HashSet集合里面存储元素的时候,集合底层自己调用hashCode和equals
1415                 它自己拿对象去判断,自己判断两元素是否是同一个元素。
1416 
1417             (2)TreeSet:
1418                  TreeSet要求往里面存的元素具备比较性,否则会报错。
1419                  TreeSet排序的第一种方式:让元素自身具备比较性
1420                   定义对象类,实现Compareble接口,复写compareTo方法,此方式是元素的自然顺序
1421                   class Student implements Comparable
1422                   {
1423                     private String name;
1424                     private int age;
1425                     public Student(String name,int age)
1426                     {
1427                         this.name=name;
1428                         this.age=age;
1429                     }
1430                     public String getName()
1431                     {
1432                         return name;
1433                     }
1434                     public int getAge()
1435                     {
1436                         return age;
1437                     }
1438                     public int compareTo(Object obj)
1439                     {
1440                         if(!(obj instanceof Student))
1441                             throw new RuntimeException("不是学生对象!");
1442                         Student stu = (Student)obj;
1443                         int num = this.age-stu.age;
1444                         if(num==0)
1445                             return this.name.compareTo(stu.name);
1446                         return num;
1447                     }
1448                   }
1449                 TreeSet排序的第一种方式:让集合具备比较性
1450                      当元素自身不具备比较性(比如存储学生对象时)或者具备的
1451                      比较性不是我们所需要的比较性时(比如想字符串的长度排序),
1452                      此时就需要让集合自身具备自定义的比较性。 
1453                      那如何让集合自身具备比较性呢?可在集合初始化时,
1454                      就让集合具备比较方式。即定义一个类,
1455                      实现Comparator接口,覆盖compare方法。
1456                  class StringLengthComparator implements Comparator
1457                  {
1458                     public int compare(Object obj1,Object obj2)
1459                     {
1460                         String s1 = (String)obj1;
1461                         String s2 = (String)obj2;
1462                         int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
1463                         if(num==0)
1464                             return s1.compareTo(s2);
1465                         return num;
1466                     }
1467                  }
1468                  class TreeSetTest
1469                  {
1470                     public static void main(String[] args)
1471                     {
1472                         TreeSet ts = new TreeSet(new StringLengthComparator());
1473                         ts.add("addfg");
1474                         ts.add("dfg");
1475                         ts.add("agtuug");
1476                         ts.add("vgjkg");
1477                         sop(ts);
1478                     }
1479                  }
1480 
1481                  
1482                                      
1483                  基本数据类型或字符串对象均实现了Comparable接口,故同种类型基本数据间具备比较性,即自然顺序。
1484     
1485                   
1486     **Map:顶层接口,该集合存储的是键值对,而且键是唯一的,Map和Set很像,Set集合底层就是使用了Map集合。
1487         Map集合没有迭代器,要取出元素必须先将Map集合转换成Set集合才能遍历元素
1488        |--->HashTable(JDK1.0): 
1489         底层是哈希表数据结构;
1490         不可以使用null键和null值;
1491         用作键的对象必须实现hashCode和equals方法来保证键的唯一性
1492         线程同步,效率低
1493        |--->HashMap(JDK1.2):
1494         底层是哈希表数据结构;
1495         允许使用null键和null值;
1496         线程不同步,效率高;
1497         保证元素唯一性的:
1498              原理:先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true
1499              (往HashSet里面存的自定义元素要复写hashCode和equals方法,
1500              以保证元素的唯一性!)
1501         class Student {
1502             private String name;
1503             private int age;
1504             public Student(String name, int age) {
1505                 super();
1506                 this.name = name;
1507                 this.age = age;
1508             }
1509             public int getAge() {
1510                 return age;
1511             }
1512             public void setAge(int age) {
1513                 this.age = age;
1514             }
1515             public String getName() {
1516                 return name;
1517             }
1518             public void setName(String name) {
1519                 this.name = name;
1520             }
1521             
1522             @Override
1523             public int hashCode(){
1524                 return name.hashCode()+age*34;
1525             }
1526             @Override
1527             public boolean equals(Object obj){
1528                 
1529                 if(!(obj instanceof Student))
1530                     return false;
1531                 Student stu = (Student)obj;
1532                 return this.name.equals(stu.name)&&this.age==stu.age;
1533             }
1534         public class HashMapDemo1 {
1535             public static void main(String[] args) {
1536                 Map<Student , String> hmap = new HashMap<Student , String>();
1537                 hmap.put(new Student("001",20), "beijing");
1538                 hmap.put(new Student("002",25), "hebei");
1539                 hmap.put(new Student("003",50), "hainan");
1540                 hmap.put(new Student("001",20), "beijing");
1541                 
1542                 System.out.println(hmap.size());
1543                 Set<Student> keySet = hmap.keySet();
1544                 Iterator<Student> it = keySet.iterator();
1545                 while(it.hasNext()){
1546                     Student stu = it.next();
1547                     String addr = hmap.get(stu);
1548                     System.out.println(stu.getName()+".."+stu.getAge()+"::"+addr);
1549                 }    
1550             }    
1551         }            
1552        |--->TreeMap(JDK1.0):
1553         底层是二叉树结构;
1554         允许使用null键和null值;
1555         线程不同步;
1556         可以给Map集合中的键进行排序.
1557         TreeMap排序的第一种方式:让元素自身具备比较性,比如八种基本数据类型或则字符串,
1558                  实现Compareble接口,覆盖compareTo方法,
1559                  此方式是元素的自然顺序             
1560         TreeMap排序的第一种方式:当元素自身不具备比较性(比如存储学生对象时)或者具备的
1561                  比较性不是我们所需要的比较性时(比如想字符串的长度排序),
1562                  此时就需要让集合自身具备自定义的比较性。 
1563                  那如何让集合自身具备比较性呢?可在集合初始化时,
1564                  就让集合具备比较方式。即定义一个类,
1565                  实现Comparator接口,覆盖compare方法。
1566         class Student implements Comparable<Student>{
1567             private String name;
1568             private int age;
1569             public Student(String name, int age) {
1570                 super();
1571                 this.name = name;
1572                 this.age = age;
1573             }
1574             public int getAge() {
1575                 return age;
1576             }
1577             public void setAge(int age) {
1578                 this.age = age;
1579             }
1580             public String getName() {
1581                 return name;
1582             }
1583             public void setName(String name) {
1584                 this.name = name;
1585             }
1586             @Override
1587             public int compareTo(Student stu) {
1588                 int num = new     Integer(this.age).compareTo(new Integer(stu.age));
1589                 if(num==0)
1590                     return this.name.compareTo(stu.name);
1591                 return num;
1592             }            
1593         }
1594 
1595         public class HashMapDemo1 {
1596             public static void main(String[] args) {
1597                             
1598                 Map<Student , String> tmap = new TreeMap<Student , String>();
1599                 tmap.put(new Student("001",20), "beijing");
1600                 tmap.put(new Student("002",25), "hebei");
1601                 tmap.put(new Student("003",50), "hainan");
1602                 tmap.put(new Student("001",20), "beijing");
1603                 
1604                 System.out.println(tmap.size());
1605                 Set<Student> keySet1 = tmap.keySet();
1606                 Iterator<Student> it1 = keySet1.iterator();
1607                 while(it1.hasNext()){
1608                     Student stu = it1.next();
1609                     String addr = tmap.get(stu);
1610                     System.out.println(stu.getName()+".."+stu.getAge()+"::"+addr);        
1611                 }
1612             }
1613         }
1614     
1615 
1616     **Iterator:对collection进行迭代的迭代器.迭代器取代了Enumeration。
1617         迭代器和枚举的区别:
1618         迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的collection移除元素
1619         方法名称得到了改进,简化书写 
1620     **LisIterator:系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表        
1621     **Comparable:此接口强行对实现它的每个类的对象进行整体自然排序。使元素具备比较性
1622     **Comparator:强行对某个对象collection进行整体排序的比较函数,使集合具备比较性
1623     **Collections:此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
1624     **Arrays:此类包含用来操作数组(比如排序和搜索)的各种静态方法
1625 
1626 7、集合类各容器方法:
1627 **接口Collection方法摘要(没有构造方法)        
1628     a)添加:                            
1629         i.  boolean add(E e)                            
1630         j.  boolean addAll(Collection c)
1631     b)删除:
1632         i.  void clear():清空容器
1633         j.  boolean remove(Objec object):
1634         k.  boolean removeAll(Collection c):
1635     c)判断:
1636         i.  boolean contains(Object object):判断是否包含此元素
1637         j.  boolean containsAll(Collection c):判断是否包含一堆元素
1638         k.  boolean equals(Object object):比较此collection与指定对象是否相等
1639         m.  boolean isEmpty():判断是否集合为空
1640     d)获取:
1641         h.  Iterator iterator():取出
1642         i.  int hashCode():返回此collection的哈希值
1643         j.  int size():返回此collection中元素的个数
1644         k.  boolean retainAll(Collection c):取交集
1645         m.  Object toArray():返回此collection中所有元素的数组
1646         n.  T[] toArray(T[] a):返回包含此collection中所有元素的数值。
1647 *****List集合子类及其方法
1648     (1)List接口是Collection接口的一个子接口。
1649     (2)List接口中的元素有如下特点(对角标的操作都是特有方法,因为有序):
1650         A:元素有序(存储顺序和取出顺序一致)
1651         B:元素可以重复
1652     (3)List接口中的特有方法
1653         A:add(int index,Object obj):在指定位置加入元素
1654         B:remove(int index):移除指定位置的元素
1655         C:set(int index,Object obj):修改指定位置的元素
1656         D:get(int index):获取指定位置的元素
1657         E:indexOf(Object obj):获取指定元素的位置
1658         F:subList(int start,int end):从一个大的List中截取一个小的List
1659         G:listIterator():返回一个List接口特有的迭代器
1660 (1)、ArrayList:
1661     |--->构造方法摘要:(少用,不是重点)
1662     ArrayList():构造一个初始容量为 10 的空列表。
1663     ArrayList(Collection<? extends E> c): 构造一个包含指定 collection 的元素的列表,                           
1664     ArrayList(int initialCapacity): 构造一个具有指定初始容量的空列表。
1665     |--->方法摘要:
1666     |--->添加:
1667     boolean add(E e): 将指定的元素添加到此列表的尾部。
1668     void add(int index, E element): 将指定的元素插入此列表中的指定位置。
1669     boolean addAll(Collection<? extends E> c):按照指定 collection 的迭代器所返回的元素顺序,
1670                          将该 collection 中的所有元素添加到此列表的尾部 
1671     boolean addAll(int index, Collection<? extends E> c): 从指定的位置开始,将指定 collection
1672                                    中的所有元素插入到此列表中。 
1673     |--->删除:
1674     void clear(): 移除此列表中的所有元素。
1675     E remove(int index): 移除此列表中指定位置上的元素。 
1676     boolean remove(Object o): 移除此列表中首次出现的指定元素(如果存在)。
1677     protected  void removeRange(int fromIndex, int toIndex): 
1678             移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
1679     boolean removeAll(Collection<?> c): 从列表中移除指定 collection 中包含的其所有元素 
1680     |--->获取:
1681     E get(int index): 返回此列表中指定位置上的元素。
1682     int indexOf(Object o): 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
1683     int lastIndexOf(Object o) 返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。   
1684     public List<E> subList(int fromIndex,int toIndex): 返回列表中指定的 fromIndex(包括 )                                           和 toIndex(不包括)之间的部分视图。
1685     Iterator<E> iterator(): 返回按适当顺序在列表的元素上进行迭代的迭代器。
1686     ListIterator<E> listIterator(int index):返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
1687     |--->修改:(特有方法!!)
1688         E set(int index, E element): 用指定的元素替代此列表中指定位置上的元素。 
1689 (2)LinkedList:
1690     |--->构造方法摘要:
1691         LinkedList(): 构造一个空列表。 
1692         LinkedList(Collection<? extends E> c): 构造一个包含指定 collection 中的元素的列表,
1693                                这些元素按其 collection 的迭代器返回的顺序排列。
1694     |--->方法摘要:(特有的)
1695         |--->添加
1696             void addFirst(E e): 将指定元素插入此列表的开头。 
1697             void addLast(E e): 将指定元素添加到此列表的结尾。 
1698         |--->获取元素,但不删除元素
1699              E get(int index): 返回此列表中指定位置处的元素。           
1700              E getFirst(): 返回此列表的第一个元素。          
1701              E getLast(): 返回此列表的最后一个元素。
1702         |--->获取元素且删除元素
1703              E remove(): 获取并移除此列表的头(第一个元素)。          
1704              E remove(int index): 移除此列表中指定位置处的元素。         
1705              boolean remove(Object o): 从此列表中移除首次出现的指定元素(如果存在)。         
1706              E removeFirst(): 移除并返回此列表的第一个元素。 
1707              E removeLast(): 移除并返回此列表的最后一个元素。
1708         |--->修改
1709              E set(int index, E element) 将此列表中指定位置的元素替换为指定的元素。 
1710 (3)Vector
1711     |--->构造方法摘要:
1712         Vector(): 构造一个空向量,使其内部数据数组的大小为 10,其标准容量增量为零。          
1713         Vector(Collection<? extends E> c):  构造一个包含指定 collection 中的元素的向量,
1714                             这些元素按其 collection 的迭代器返回元素的顺序排列。
1715     |--->方法摘要:
1716         |--->添加:
1717             boolean add(E e): 将指定元素添加到此向量的末尾。
1718             void add(int index, E element): 在此向量的指定位置插入指定的元素。         
1719             boolean addAll(Collection<? extends E> c):
1720                      将指定 Collection 中的所有元素添加到此向量的末尾, 
1721                      按照指定 collection 的迭代器所返回的顺序添加这些元素。 
1722             boolean addAll(int index, Collection<? extends E> c): 在指定位置将指定 Collection 中的所有元素插入到此向量中。
1723         |--->获取:
1724             Enumeration<E> elements(): 返回此向量的组件的枚举。
1725                Vector特有的取出方式:
1726                枚举和迭代器很像,其实枚举和迭代器是一样的,只是因为枚举的名称和方法的名称
1727                名字都过长,所以枚举被迭代器取代了。
1728             |--->枚举Enumeration的方法摘要:
1729                  boolean hasMoreElements(): 测试此枚举是否包含更多的元素。 
1730                  E nextElement(): 如果此枚举对象至少还有一个可提供的元素,
1731                           则返回此枚举的下一个元素。 
1732 *****Set集合子类及其方法
1733 (1)HashSet:它不保证set的迭代顺序;特别是它不保证该顺序恒久不变.此类允许使用null元素。 
1734     |--->构造方法:
1735         HashSet() 构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
1736         HashSet(Collection<? extends E> c) 构造一个包含指定 collection 中的元素的新 set。
1737     |--->方法摘要:
1738         boolean add(E e) 如果此 set 中尚未包含指定元素,则添加指定元素。   
1739         void clear() 从此 set 中移除所有元素。      
1740         Object clone() 返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。       
1741         boolean contains(Object o) 如果此 set 包含指定元素,则返回 true。       
1742         boolean isEmpty() 如果此 set 不包含任何元素,则返回 true。       
1743         Iterator<E> iterator() 返回对此 set 中元素进行迭代的迭代器。       
1744         boolean remove(Object o) 如果指定元素存在于此 set 中,则将其移除。       
1745         int size() 返回此 set 中的元素的数量(set 的容量)。  
1746 (2)TreeSet:使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序.
1747     |--->构造方法:
1748         TreeSet() 构造一个新的空 set,该set根据其元素的自然顺序进行排序。          
1749         TreeSet(Collection<? extends E> c) 
1750              构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。 
1751         TreeSet(Comparator<? super E> comparator)  构造一个新的空 TreeSet,它根据指定比较器进行排序。
1752     |--->方法摘要:
1753         添加:
1754          boolean add(E e)  将指定的元素添加到此 set(如果该元素尚未存在于 set 中)。
1755          boolean addAll(Collection<? extends E> c) 将指定 collection 中的所有元素添加到此 set 中。
1756          删除:
1757           void clear() 移除此 set 中的所有元素。 
1758           boolean remove(Object o)  将指定的元素从 set 中移除(如果该元素存在于此 set 中)。 
1759           E pollFirst() 获取并移除第一个(最低)元素;如果此 set 为空,则返回 null。 
1760           E pollLast() 获取并移除最后一个(最高)元素;如果此 set 为空,则返回 null。 
1761         获取:
1762           Iterator<E> iterator()  返回在此 set 中的元素上按升序进行迭代的迭代器。
1763           E first() 返回此 set 中当前第一个(最低)元素。
1764           E last() 返回此 set 中当前最后一个(最高)元素。
1765           int size()  返回 set 中的元素数(set 的容量)。
1766         判断:
1767          boolean isEmpty()  如果此 set 不包含任何元素,则返回 true。 
1768          boolean contains(Object o) 如果此 set 包含指定的元素,则返回 true。 
1769 **Map:将键映射到值的对象。Map集合没有迭代器!Map集合特点:该集合存储键值对。而且键是唯一的。
1770     |--->方法摘要:
1771        |--->添加:
1772           V put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。           
1773           void putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中
1774        |--->删除:
1775               void clear()  从此映射中移除所有映射关系(可选操作)。 
1776           V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
1777        |--->判断
1778           boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。 
1779               boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。
1780               boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true。 
1781            |--->获取
1782           int size() 返回此映射中的键-值映射关系数。 
1783               Collection<V> values()  返回此映射中包含的值的 Collection 视图。
1784 
1785       重点:Map集合没有迭代器,以下是Map的两种取出方式:
1786       第一种:Set<K> keySet()
1787         返回此映射中包含的键的Set视图,将Map集合中所有的键存入Set集合,然后再通过Set集合的
1788         迭代器取出所有的键,再根据get方法获取每个键的值;
1789       第二种:Set<Map.Entry<K,V>> entrySet() 
1790         返回此映射中包含的映射关系的Set视图,将Map集合中的映射关系存入到Set集合中,
1791         这个映射关系的数据类型是Map.entry,再通过Map.Entry类的方法再要取出关系里面的键和值
1792         Map.Entry的方法摘要:
1793             boolean equals(Object o)  比较指定对象与此项的相等性。              
1794             K getKey()  返回与此项对应的键。              
1795             V getValue() 返回与此项对应的值。               
1796             int hashCode() 返回此映射项的哈希码值。
1797             V setValue(V value) 用指定的值替换与此项对应的值(特有!!!)。
1798 8、Map集合和Collection集合的区别?
1799     1,
1800     Map中一次存储是键值对。
1801     Collection中一次存储是单个元素。
1802     2,
1803     Map的存储使用的put方法。
1804     Collection存储使用的是add方法。 
1805     3,
1806     Map集合没有迭代器,Map的取出,是将Map转成Set,在使用迭代器取出。
1807     Collection取出,使用就是迭代器。
1808     4,
1809     如果对象很多,必须使用集合存储。
1810     如果元素存在着映射关系,可以优先考虑使用Map存储或者用数组,
1811     如果没有映射关系,可以使用Collection存储。
1812 8、迭代器:Iterator(Map集合没有迭代器)
1813     (1)迭代器就是取出集合元素的方式
1814     (2)迭代器的作用
1815         因为每个集合中元素的取出方式都不一样,于是就把元素的取出方式进行抽取,并定义在集合内部,
1816         这样取出方式就可以直接访问集合内部的元素;
1817         而每个容器的数据结构不同,所以取出动作的细节也不一样,但是有共性内容:判断和取出。
1818         那么就将共性内容进行抽取,从而形成了接口Iterater
1819     (3)获取迭代器的方法:
1820         Iterator<E> iterator() 返回在此 collection 的元素上进行迭代的迭代器。 
1821         Iterator<E> iterator() 返回在此 set 中的元素上进行迭代的迭代器。      
1822     (3)迭代器方法:
1823         boolean hasNext() 如果仍有元素可以迭代,则返回 true。
1824         E next() 返回迭代的下一个元素。       
1825         void remove() 从迭代器指向的collection中移除迭代器返回的最后一个元素(可选操作)。
1826 9、列表迭代器:ListIterator
1827     (1)List集合特有的迭代器ListIterator是Iterator的子接口,在迭代时,不可以通过集合对象的
1828        方法操作集合中的元素,因为会发生ConcurrentModificationException(当方法检测到对象的并发修改,
1829        但不允许这种修改时,抛出此异常)
1830     (2)Iterator方法有限,只能对元素进行判断、取出和删除的操作
1831        ListIterator可以对元素进行添加和修改动作等。
1832     (3)获取列表迭代器方法:
1833         ListIterator<E> listIterator() 返回此列表元素的列表迭代器(按适当顺序)。 
1834         ListIterator<E> listIterator(int index) 
1835             返回此列表中的元素的列表迭代器(按适当顺序),从列表中指定位置开始。 
1836     (4)列表迭代器方法:
1837         void add(E e) 将指定的元素插入列表(可选操作)。
1838         boolean hasPrevious()  如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。 
1839         int nextIndex() 返回对 next 的后续调用所返回元素的索引。         
1840         E previous() 返回列表中的前一个元素。       
1841         int previousIndex() 返回对 previous 的后续调用所返回元素的索引。       
1842         void set(E e) 用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。 
1843 10、堆栈和队列
1844     堆栈:先进后出,比如杯子里的水
1845     队列:先进先出,比如水管的水
1846 11、集合类各种容器的使用注意细节:
1847     (1)迭代器:
1848         **迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
1849           也就是在迭代循环中调用一次next方法一次就要hasNext判断一次,比如语句
1850           sop(it.next()+"..."+it.next())会发生上述异常。
1851         **迭代器的next方法返回值类型是Object,所以要记得类型转换,应用泛型后就不用强转
1852     (2)List集合:
1853         **List集合里面的元素因为是带角标,所以List集合里面的元素都是有序的,
1854           另外List集合可以包含重复元素,也可以包含null。  
1855         **List集合有迭代器Iterator,还有一个特有迭代器列表ListIterator
1856         **List集合中判断元素是否相同都是用equals方法,无论contains、remove都依赖equals方法
1857           比如往ArrayList集合里面存放学生,同名同年龄视为同一个人,此时就需要在学生类复写Object类
1858           里面的equals方法(非常重要!!!要注意!!)
1859     (3)Set集合:
1860         **Set接口里面存放的是元素是无序的,不可以有重复元素,可以包含null
1861         **Set集合只有一种取出方式,就是迭代器Iterator
1862         **Set集合功能和Collection是一致的,没有特殊方法
1863         |--->HashSet:
1864         **集合里面存放的元素是无序的,唯一的
1865         **底层数据结构是哈希表,哈希表结构的数据都是无序的,哈希表结构的操作效率都高效
1866         **线程不同步
1867         **保证元素唯一性的原理是:通过复写hashCode和equals方法
1868             ****如果两元素的hashCode值相同,则继续判断两元素equals是否为真
1869             ****如果两元素的hashCode值不同,则不会调用equals方法。
1870         **当我们往HashSet集合存放自定义的元素时(比如学生对象),通常都要复写hashCode和equals方法,
1871           而且hashCode和equals方法不通过我们调用,HashSet集合底层内部自己调用,自己拿元素去比较
1872         |--->TreeSet
1873         **TreeSet集合可以对存放的元素进行排序,弥补了Set集合元素无序的缺点,且元素是唯一的
1874         **底层数据结构是二叉树,二叉树结构都是有序的
1875         **线程不同步
1876         **TreeSet集合要求往集合里存放的元素自身具备比较性,否则会报错
1877         **TreeSet集合保证元素唯一性的依据是:通过compareTo或者compare方法中的来保证元素的唯一性。
1878             TreeSet排序的第一种方式:让元素自身具备比较性,
1879                         定义元素类实现Compareble接口,覆盖compare方法,
1880                         此方式是元素的自然顺序。
1881             TreeSet排序的第二种方式:让集合具备比较性
1882                         当元素自身不具备比较性或者具备的比较性不是
1883                         我们所需要的比较性时,此时就需要让集合具备自定义的比较性。
1884                         那如何让集合自身具备比较性呢?
1885                         可在集合初始化时,就让集合具备比较方式。
1886                         即定义一个类,实现Comparator接口,覆盖compare方法。
1887             注:
1888             **判断元素唯一时,当主要条件一样时,判断次要条件
1889             **两种排序方式都在时,以比较器为主!!!
1890     (4)Map集合:
1891         |--Hashtable
1892             底层是哈希表结构
1893             线程安全的,并且键和值不能为null。
1894         |--HashMap
1895             底层是哈希表结构
1896             线程不安全的,键和值可以为null。
1897             |--LinkedHashMap
1898                 底层是链表和哈希表
1899                 线程不安全
1900         |--TreeMap
1901             底层是二叉树
1902             线程不安全的
1903 12、如果你想将一组对象按一定顺序存取,在不考虑并发访问的情况下会使用____C_____ , 
1904     反之则会使用____A_____;如果你想存储一组无序但唯一的对象,你会使用___B______ ; 
1905     如果你想按关键字对对象进行存取,在不考虑并发访问的情况下会使用___D______ ,反之则会使用_____E____。
1906 A. Vector
1907 B. HashSet
1908 C. ArrayList
1909 D. HashMap
1910 E. Hashtable
1911 13、泛型:
1912     (1)为什么会出现泛型?
1913         因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患,
1914         如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题。
1915         JDK1.5后出现了泛型,用于解决集合框架的安全问题。
1916         泛型是一个类型安全机制。
1917     (2)泛型定义格式:通过<>来定义要操作的引用数据类型
1918         ArrayList<String> al = new ArrayList<String>;
1919     (3)泛型的好处:
1920         **将运行时期出现的ClassCastException(类型转换异常)问题转移到编译时期;
1921         **避免了强制转换的麻烦
1922     (4)什么时候定义泛型?
1923         泛型在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。
1924         当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可
1925     (5)泛型的形式
1926         **泛型类:即自定义泛型类
1927             A:当类中要操作的引用数据类型不确定时,早起定义Object来完成扩展,现在定义泛型来完成
1928             B:局限性:泛型类定义的泛型,在整个类中有效,如果该泛型类的方法被调用,
1929                当泛型类的对象明确要操作的类型后,所有要操作的类型就被固定。
1930         **泛型方法:泛型放在返回值前面,修饰符的后面
1931             A:为了避免泛型类的局限性,让不同方法可以操作不同的类型,而且类型还不确定,
1932               则可以将泛型定义在方法上
1933             B:特殊之处:静态方法不可以反问类上定义的泛型
1934               如果静态方法操作的应用数据类型不确定,可以讲泛型定义在静态方法上
1935         **泛型接口:
1936             当泛型定义在接口上时,则子类中要指定实现接口类型,同时还可以子类也可以定义为泛型类
1937     (6)泛型的高级应用:?通配符
1938         **当指定两种泛型的集合,则迭代时也要定义两种泛型的迭代器,麻烦,此时可通过将迭代器的泛型
1939           改为?,如Iterator<?> it=al.iterator();
1940         **两种泛型限定
1941             向上限定: ? extends E  ;E可以接收E类型或者E的子类
1942             向下限定: ? super E  ;E可以接收E类型或者E的父类
1943 14、高级for循环
1944     (1)JDK1.5新特性,代替迭代器使用时的不爽,简化书写,底层原理是迭代器凡是支持迭代器的都支持高级for循环
1945        高级for循环,只用于集合和数组的遍历,集合只能用Collection不能用Map集合
1946        只能把Map集合转化成Set集合,才能用for循环。
1947     (2)格式
1948         for(数据类型 变量名:被遍历的集合(Collection)或者数组)
1949         {
1950             
1951         }
1952         (3)局限性:
1953         必须要有遍历的目标
1954         对集合或者数组进行遍历时,只能获取集合元素,不能对集合元素进行操作
1955         迭代器除了遍历,还可以进行remove操作集合中的元素
1956         列表迭代器还可以在遍历过程中进行增删改查的操作
1957     (4)传统for循环和高级for循环的区别
1958         高级for循环有一个局限性,就是必须要有遍历的目标(集合或者数组)
1959         遍历数组时建议使用传统for循环,因为可以定义角标,比如打印100次helloworld时用传统for循环方便
1960 15、可变参数
1961     (1)数组的可变参数
1962         格式:
1963             int... arr
1964     (3)方法的可变参数
1965         格式:
1966             public static void show(String str,int... arr)
1967             {
1968 
1969             }
1970         注意:可变参数一定要放在参数列表的最后面
1971 16、静态导入:
1972     **import static java.util.Arrays.*  导入的是Arrays这个类中所有的静态方法
1973     **当类名重名时,需要制定具体的报名
1974     **当方法重名时,需要制定具体所属的对象或者类
1975 17、Collections类:
1976     (1)此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
1977     (2)静态方法摘要:
1978         static <T> boolean addAll(Collection<? super T> c, T... elements) 
1979             将所有指定元素添加到指定 collection 中。
1980         static <T> void fill(List<? super T> list, T obj) 
1981             使用指定元素替换指定列表中的所有元素。
1982         static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) 
1983             使用另一个值替换列表中出现的所有某一指定值。 
1984         static void reverse(List<?> list) 
1985             反转指定列表中元素的顺序。 
1986         static <T> Comparator<T>  reverseOrder() 
1987             返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序
1988         static <T> Comparator<T> reverseOrder(Comparator<T> cmp) 
1989             返回一个比较器,它强行逆转指定比较器的顺序。 
1990     (3)Collections类特牛的方法:
1991         集合有一个共同的缺点,那就是线程不安全,被多线程操作时,容易出现问题,虽然可以自己加锁
1992         但是麻烦。Collections提供特牛的方法,就是给它一个不同步的集合,它返回一个同步的安全的集合
1993 
1994         static <T> Collection<T> synchronizedCollection(Collection<T> c) 
1995             返回指定 collection 支持的同步(线程安全的)collection。 
1996         static <T> List<T>  synchronizedList(List<T> list) 
1997             返回指定列表支持的同步(线程安全的)列表。 
1998         static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 
1999             返回由指定映射支持的同步(线程安全的)映射。 
2000         static <T> Set<T> synchronizedSet(Set<T> s) 
2001             返回指定 set 支持的同步(线程安全的)set。 
2002         static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
2003             返回指定有序映射支持的同步(线程安全的)有序映射。 
2004         static <T> SortedSet<T>  synchronizedSortedSet(SortedSet<T> s)
2005             返回指定有序 set 支持的同步(线程安全的)有序 set。 
2006 18、Arrays类:
2007     此类包含用来操作数组(比如排序和搜索)的各种方法。里面都是静态方法。
2008     如果指定数组引用为 null,则此类中的方法都会抛出 NullPointerException。
2009     (1)静态方法摘要:
2010         static <T> List<T> asList(T... a)
2011             返回一个受指定数组支持的固定大小的列表。
2012         注意:
2013             A:该方法将一个数组变成集合后,不可以使用集合的增删方法,因为数组的长度是固定的!
2014                   如果增删,则发生UnsupportedOprationException(不支持操作异常)
2015             B:如果数组中的元素都是基本数据类型,则该数组变成集合时,会将该数组作为集合的一个
2016               元素出入集合
2017             C:如果数组中的元素都是对象,如String,那么数组变成集合后,数组中的元素就直接转成
2018               集合中的元素
2019 19、数组变集合以及集合变数组的对比:
2020     (1)数组变集合:
2021         方法:static <T> List<T> asList(T... a) 返回一个受指定数组支持的固定大小的列表。
2022         好处:可以使用集合的思想和方法操作数组中的元素,数组是一个对象,但是数组中的功能很少
2023     (2)集合变数组:
2024         方法:Collction中的toArray方法
2025         好处:可以限定对集合元素的操作,防止对集合的元素进行增删,因为数组长度是固定的。
2026 
2027 20、Collections类和Arrays类的使用。(重点)
2028     A:Collections
2029         排序
2030         二分查找
2031         发转
2032     B:Arrays
2033         把数组变成字符串输出
2034         排序
2035         二分查找
2036 21、System:
2037     (1)描述系统信息的类
2038     (2)该类没有构造方法,该类的方法和属性都是静态的
2039     (3)字段摘要:
2040         static InputStream in  “标准”输入流。   
2041         static PrintStream out  “标准”输出流。         
2042     (4)方法摘要:
2043         static void exit(int status) 终止当前正在运行的 Java 虚拟机。 
2044         static void gc() 运行垃圾回收器。
2045         static Properties getProperties()  确定当前的系统属性          
2046         static String getProperty(String key) 获取指定键指示的系统属性。     
2047         static String getProperty(String key, String def) 获取用指定键描述的系统属性。 
2048         static void setIn(InputStream in) 重新分配“标准”输入流。           
2049         static void setOut(PrintStream out) 重新分配“标准”输出流。 
2050         static void setProperties(Properties props) 将系统属性设置为 Properties 参数。           
2051         static String setProperty(String key, String value) 设置指定键指示的系统属性。
2052 22、Runtime:
2053     (1)每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。
2054        可以通过 getRuntime 方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。
2055     (2)该类没有构造函数,也就是它不能直接创建对象,但是它里里面的方法又不是静态的
2056        ,故它一定有一个方法返回本类对象
2057     (3)故该类是单例设计模式,保证在内存中只有一个对象
2058     (4)方法摘要:
2059         Process exec(String command) 在单独的进程中执行指定的字符串命令
2060         void gc() 运行垃圾回收器。
2061         static Runtime getRuntime() 返回与当前 Java 应用程序相关的运行时对象
2062         void exit(int status) 通过启动虚拟机的关闭序列,终止当前正在运行的 Java 虚拟机
2063 23、Date:
2064     (1)Date接口表示特定的瞬间,精确到毫秒
2065     (2)构造方法
2066         Date() 分配 Date 对象并初始化此对象,以表示分配它的时间(精确到毫秒)。
2067         Date(long date) 分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,
2068              即1970年1月1日00:00:00GMT)以来的指定毫秒数。
2069     (3)方法摘要:
2070         int compareTo(Date anotherDate) 比较两个日期的顺序。          
2071         boolean equals(Object obj) 比较两个日期的相等性。
2072 24、Calendar:
2073     (1)直接已知子类: GregorianCalendar 
2074     (2)构造方法:
2075         protected  Calendar() 构造一个带有默认时区和语言环境的 Calendar。         
2076         protected  Calendar(TimeZone zone, Locale aLocale)  构造一个带有指定时区和语言环境的 Calendar。         
2077     (3)方法摘要:
2078         static Calendar getInstance() 使用默认时区和语言环境获得一个日历。
2079 
2080 
2081 四、jdk1.5的新特性
2082     (1)静态导入:
2083         **import语句可以导入一个类或某个包中的所有类
2084         **import static语句导入一个类中的某个静态方法或所有静态方法
2085           静态导入后,静态方法前面就不用写类名.方法的方式类调用
2086         **语法举例: 
2087             import static java.lang.Math.sin;//导入一个静态方法
2088             import static java.lang.Math.*; //导入一个类中的所有静态方法
2089         **静态导入使用注意:
2090             当类名重复时,需要制定具体的包名;
2091             当方法重名时,需要制定具体所属的对象或者类
2092     (2)可变参数:
2093         **可变参数的特点:
2094             *可变参数只能出现在参数列表的最后;
2095             *...位于变量类型和变量名之间,前后有无空格都可以;
2096             *调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,
2097              在方法体中以数组的形式访问可变参数。
2098         **可变参数举例:
2099             *变量类型... 变量名 如 int... arr 表示可变参数数组
2100             *public static void show(String str , int... arr){}
2101     (3)增强for循环:
2102         **语法:
2103             for ( type 变量名:集合变量名 )  { … } 
2104         **注意事项:
2105             迭代变量必须在( )中定义!
2106             集合变量可以是数组或实现了Iterable接口的集合类
2107         **举例: 
2108             public static int add(int x,int ...args) {
2109                 int sum = x;
2110                 for(int arg:args) {
2111                     sum += arg;
2112                 }
2113                 return sum;
2114             }
2115         **增强for循环代替了迭代器使用的不爽,简化书写
2116         **增强for循环局限性:
2117             对集合或者数组进行遍历时,只能取元素,不能对集合进行操作
2118     (4)基本数据类型的自动装箱和拆箱
2119         **基本数据类型
2120             byte    --->    Byte
2121             short    --->    Short
2122             int    --->    Integer
2123             long    --->    Long
2124             float    --->    Float
2125             double    --->    Double
2126             char    --->    Character
2127             boolean    --->    Boolean
2128         **例子:
2129             **装箱:自动把一个基本数据类型的数据装箱成一个该类型数据的对象引用
2130                 Integer i = 3;(jdk1.5之前这样写是不行的,编译报错)
2131             **拆箱:自动把一个基本数据类型的对象引用拆箱成一个基本数据类型的数据,再参与运算
2132                 Integer i = 12;
2133                 sop(i+4);
2134             **享元模式:
2135                 Integer num1 = 12;
2136                 Integer num2 = 12;
2137                 System.out.println(num1 == num2);//打印true
2138 
2139                 Integer num5 = Integer.valueOf(12);
2140                 Integer num6 = Integer.valueOf(12);
2141                 System.out.println(num5 == num6);//打印true
2142 
2143                 Integer num3 = 129;
2144                 Integer num4 = 129;
2145                 System.out.println(num3 == num4);//打印false
2146 
2147                 为什么前面的返回true而后面的运算返回false呢?
2148                 对于基本数据类型的整数,装箱成Integer对象时,如果该数值在一个字节内,(-128~127),
2149                 一旦装箱成Integer对象后,就把它缓存到磁里面,当下次,又把该数值封装成Integer对象时
2150                 会先看磁里面有没有该对象,有就直接拿出来用,这样就节省了内存空间。因为比较小的整数,
2151                 用的频率比较高,就没必要每个对象都分配一个内存空间。
2152                 这就是享元模式!比如26个英文字母,10个阿拉伯数字
2153     (5)枚举
2154         **为什么要有枚举?
2155             问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,
2156             但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
2157 
2158             枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。
2159             枚举可以让编译器在编译时就可以控制源程序中填写的非法值,
2160             普通变量的方式在开发阶段无法实现这一目标。
2161         **用普通类如何实现枚举的功能?定义一个Weekday类来模拟实现:
2162             步骤:
2163                 *私有化构造方法
2164                 *每个元素分别用一个公有的静态成员变量表示(public static final)
2165                 *可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句
2166                  转移成了一个个独立的类。
2167         **枚举的应用:
2168             举例:定义一个Weekday的枚举。
2169             扩展:枚举类的values,valueOf,name,toString,ordinal等方法
2170                  (记住,讲课时要先于自定义方法前介绍,讲课更流畅)
2171             总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。 
2172                   例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。
2173         **枚举的高级应用:
2174             **枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
2175             **枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。
2176               把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
2177             **带构造方法的枚举
2178               构造方法必须定义成私有的
2179               如果有多个构造方法,该如何选择哪个构造方法?
2180               枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
2181             **带方法的枚举
2182               定义枚举TrafficLamp
2183               实现普通的next方法
2184               实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,
2185               这些子类采用类似内部类的方式进行定义。增加上表示时间的构造方法      
2186             **枚举只有一个成员时,就可以作为一种单例的实现方式。        
2187     (6)泛型:
2188         **泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
2189           编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,
2190           对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
2191           由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,
2192           就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
2193         **ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
2194             整个称为ArrayList<E>泛型类型
2195             ArrayList<E>中的E称为类型变量或类型参数
2196             整个ArrayList<Integer>称为参数化的类型
2197             ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
2198             ArrayList<Integer>中的<>念着typeof
2199             ArrayList称为原始类型
2200         **参数化类型与原始类型的兼容性:
2201             参数化类型可以引用一个原始类型的对象,编译报告警告,
2202             例如,Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?
2203             原始类型可以引用一个参数化类型的对象,编译报告警告,
2204             例如,Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
2205         **参数化类型不考虑类型参数的继承关系:
2206             Vector<String> v = new Vector<Object>(); //错误!///不写<Object>没错,写了就是明知故犯
2207             Vector<Object> v = new Vector<String>(); //也错误!
2208             编译器不允许创建泛型变量的数组。即在创建数组实例时,
2209             数组的元素不能使用参数化的类型,
2210             例如,下面语句有错误:
2211                 Vector<Integer> vectorList[] = new Vector<Integer>[10];
2212         **泛型限定:
2213             **限定通配符的上边界:
2214                 正确:Vector<? extends Number> x = new Vector<Integer>();
2215                 错误:Vector<? extends Number> x = new Vector<String>();
2216             **限定通配符的下边界:
2217                 正确:Vector<? super Integer> x = new Vector<Number>();
2218                 错误:Vector<? super Integer> x = new Vector<Byte>();
2219             **提示:
2220                 限定通配符总是包括自己。
2221                 ?只能用作引用,不能用它去给其他变量赋值
2222                 Vector<? extends Number> y = new Vector<Integer>();
2223                 Vector<Number> x = y;
2224                 上面的代码错误,原理与Vector<Object > x11 = new Vector<String>();相似,
2225                 只能通过强制类型转换方式来赋值。
2226 
2227 
2228 
2229 五、IO流
2230 1、IO流概述
2231     (1)用来处理设备(硬盘,控制台,内存)间的数据。
2232     (2)java中对数据的操作都是通过流的方式。
2233     (3)java用于操作流的类都在io包中。
2234     (4)按照流操作的数据的类型不同:分为字节流和字符流。字符流是为了方便中文的操作而来的。    
2235     (5)按照流的流向不同分为:输入流,输出流
2236 2、IO流常用基类:
2237     (1)字节流
2238         输出字节流:OutputStream:字节写入流抽象类
2239                 |--->FileOutputStream:
2240                             字节写入流
2241                 |--->BufferedOutputStream:
2242                             字节写入流缓冲区
2243                 |--->PrintStream:
2244                             打印流
2245         输入字节流:InputStream:字节读取流抽象类
2246                 |--->FileInputStream:
2247                             字节读取流
2248                 |--->BufferedInputStream:
2249                             字节读取流缓冲区
2250     (2)字符流    
2251         输出字符流:Writer:字符写入流的抽象
2252                 |--->FileWriter:
2253                             字符写入流
2254                 |--->BufferedWriter:
2255                             字符写入流缓冲区
2256                 |--->OutputStreamWriter:
2257                             字符通向字节的转换流(涉及键盘录入时用)
2258                 |--->OutputStreamWriter:    
2259                             打印流,可处理各种类型的数据
2260         输入字符流:Reader: 字符读取流的抽象类
2261                 |--->FileReader:
2262                             字符读取流
2263                     |--->LineNumberReader:
2264                                 跟踪行号的缓冲字符读取流
2265                 |--->BufferedReader:
2266                             字符读取流缓冲区
2267                 |--->InputStreamReader:
2268                             字节通向字符的转换流(涉及键盘录入时用)
2269     (3)IO流常用基类方法摘要:
2270         **字节写入流:OutputStream:
2271             void close() 关闭此输出流并释放与此流有关的所有系统资源。
2272             void flush()刷新此输出流并强制写出所有缓冲的输出字节。
2273             abstract  void write(int b)  将指定的字节写入此输出流。
2274             void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。    
2275             void write(byte[] b, int off, int len) 
2276                     将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 
2277         **字节读取流:InputStream:
2278             void close() 关闭此输入流并释放与该流关联的所有系统资源。
2279             int available() (特有方法!!)
2280                 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 
2281             abstract  int read() 从输入流中读取数据的下一个字节。 
2282             int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
2283             int read(byte[] b, int off, int len)  将输入流中最多 len 个数据字节读入 byte 数组。
2284             long skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。
2285            
2286      
2287            
2288          
2289 
2290             
2291         **字符写入流:Writer:
2292             abstract  void close() 关闭此流,但要先刷新它。
2293             abstract  void flush() 刷新该流的缓冲。
2294             void write(int c) 写入单个字符。
2295             void write(char[] cbuf) 写入字符数组。          
2296             abstract  void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
2297             void write(String str) 写入字符串。 
2298             void write(String str, int off, int len) 写入字符串的某一部分。 
2299 
2300         **字符读取流:Reader:
2301             abstract  void close() 关闭该流并释放与之关联的所有资源。
2302             int read() 读取单个字符。
2303             int read(char[] cbuf)  将字符读入数组
2304             abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
2305             long skip(long n)  跳过字符。 
2306 3、IO流常用字节流基类的子类:
2307     **写入流:
2308     (1)FileOutputStream:
2309         **构造方法:
2310         FileOutputStream(String name) 
2311             创建一个向具有指定名称的文件中写入数据的输出文件流。
2312         FileOutputStream(String name, boolean append) 
2313             创建一个向具有指定 name 的文件中写入数据的输出文件流。
2314         FileOutputStream(File file) 
2315             创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 
2316         FileOutputStream(File file, boolean append) 
2317             创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
2318         **方法摘要:
2319         public void flush()
2320         void close() 关闭此文件输出流并释放与此流有关的所有系统资源。
2321         void write(int b) 将指定字节写入此文件输出流。
2322         void write(byte[] b, int off, int len) 
2323             将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 
2324         void write(int b) 将指定字节写入此文件输出流。
2325     (2)BufferedOutputStream:
2326         **构造方法:
2327         BufferedOutputStream(OutputStream out) 
2328             创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 
2329         BufferedOutputStream(OutputStream out, int size) 
2330             创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。 
2331         **方法摘要:
2332         void flush() 刷新此缓冲的输出流。          
2333         void write(byte[] b, int off, int len) 
2334             将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。 
2335         void write(int b) 将指定的字节写入此缓冲的输出流。
2336     (3)PrintStream:打印流,可将各种类型的数据原样打印,有自动刷新功能
2337         **构造方法:
2338         PrintStream(String fileName) 
2339             创建具有指定文件名称且不带自动行刷新的新打印流。
2340         PrintStream(File file) 
2341             创建具有指定文件且不带自动行刷新的新打印流。
2342         PrintStream(OutputStream out) 
2343             创建新的打印流。
2344         PrintStream(OutputStream out, boolean autoFlush) (当autoFlush为true时具有自动刷新功能)
2345             创建新的打印流。
2346         **方法摘要:
2347         PrintStream append(char c) 
2348             将指定字符添加到此输出流。
2349         void close() 
2350             关闭流。 
2351         void flush() 
2352             刷新该流的缓冲。
2353         void print(各种类型的数据:) 
2354             打印各种类型的数据 
2355         void println(各种类型的数据:):自动换行
2356             打印各种类型的数据 
2357         void write(byte[] buf, int off, int len) 
2358             将 len 字节从指定的初始偏移量为 off 的 byte 数组写入此流。 
2359         void write(int b) 
2360             将指定的字节写入此流。 
2361 
2362     **读取流:
2363     (1)FileInputStream:
2364         **构造方法:
2365         FileInputStream(String name) 
2366             通过打开一个到实际文件的连接来创建一个 FileInputStream,
2367             该文件通过文件系统中的路径名 name 指定。
2368         FileInputStream(File file) 
2369             通过打开一个到实际文件的连接来创建一个 FileInputStream,
2370             该文件通过文件系统中的 File 对象 file 指定。
2371         **方法摘要:
2372         int available() (字节读取流特有方法!!!)
2373             返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
2374         int read() 
2375             从此输入流中读取一个数据字节。 
2376         int read(byte[] b) 
2377             从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 
2378         int read(byte[] b, int off, int len) 
2379             从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 
2380         long skip(long n) 
2381             从输入流中跳过并丢弃 n 个字节的数据。 
2382     (2)BufferedInputStream:
2383         **构造方法:
2384         BufferedInputStream(InputStream in) 
2385             创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 
2386         BufferedInputStream(InputStream in, int size) 
2387             创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 
2388         **方法摘要:
2389         int available() (字节读取流特有方法!!!)
2390             返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。 
2391         int read() 
2392             参见 InputStream 的 read 方法的常规协定。 
2393         int read(byte[] b, int off, int len) 
2394             从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。 
2395         long skip(long n) 
2396             参见 InputStream 的 skip 方法的常规协定。
2397     
2398 4、字符流常用基类的子类
2399     **写入流:
2400     (1)FileWriter:
2401         **构造方法:
2402         FileWriter(String fileName) 
2403             根据给定的文件名构造一个 FileWriter 对象。 
2404         FileWriter(String fileName, boolean append) 
2405             根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 
2406         FileWriter(File file) 
2407             根据给定的 File 对象构造一个 FileWriter 对象。 
2408         FileWriter(File file, boolean append) 
2409             根据给定的 File 对象构造一个 FileWriter 对象。 
2410         FileWriter(FileDescriptor fd) 
2411             构造与某个文件描述符相关联的 FileWriter 对象。
2412         **方法摘要:跟Writer一样
2413         abstract  void close() 关闭此流,但要先刷新它。
2414         abstract  void flush() 刷新该流的缓冲。
2415         void write(int c) 写入单个字符。
2416         void write(char[] cbuf) 写入字符数组。          
2417         abstract  void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 
2418         void write(String str) 写入字符串。 
2419         void write(String str, int off, int len) 写入字符串的某一部分。 
2420     (2)BufferedWriter:
2421         **构造方法:
2422         BufferedWriter(Writer out) 
2423             创建一个使用默认大小输出缓冲区的缓冲字符输出流。 
2424         BufferedWriter(Writer out, int sz) 
2425             创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 
2426         **方法摘要:
2427         void close() 
2428             关闭此流,但要先刷新它。 
2429         void flush() 
2430              刷新该流的缓冲。 
2431         void newLine() 
2432              写入一个行分隔符。 
2433         void write(char[] cbuf, int off, int len) 
2434              写入字符数组的某一部分。 
2435         void write(int c) 
2436              写入单个字符。 
2437         void write(String s, int off, int len) 
2438              写入字符串的某一部分。 
2439     (3)OutputStreamWriter:字节通向字符的转换流
2440         **构造方法:
2441         OutputStreamWriter(OutputStream out) 
2442             创建使用默认字符编码的 OutputStreamWriter。
2443         **方法摘要:
2444         void write(char[] cbuf, int off, int len) 
2445             写入字符数组的某一部分。 
2446         void write(int c) 
2447             写入单个字符。 
2448         void write(String str, int off, int len) 
2449             写入字符串的某一部分。
2450     (4)PrintWriter:
2451         **构造方法:
2452         PrintWriter(String fileName) 
2453             创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
2454         PrintWriter(File file) 
2455             使用指定文件创建不具有自动行刷新的新 PrintWriter。
2456         PrintWriter(Writer out) 
2457             创建不带自动行刷新的新 PrintWriter。 
2458         PrintWriter(Writer out, boolean autoFlush) 
2459             创建新 PrintWriter。 
2460         PrintWriter(OutputStream out) 
2461             根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
2462         PrintWriter(OutputStream out, boolean autoFlush) 
2463             通过现有的 OutputStream 创建新的 PrintWriter。
2464         
2465         **方法摘要:
2466         PrintWriter append(char c) 
2467             将指定字符添加到此 writer。 
2468         void print(各种类型的数据:) 
2469             打印各种类型的数据 
2470         void println(各种类型的数据:):自动换行
2471             打印各种类型的数据
2472         void write(char[] buf) 
2473             写入字符数组。 
2474         void write(char[] buf, int off, int len) 
2475             写入字符数组的某一部分。 
2476         void write(int c) 
2477             写入单个字符。 
2478         void write(String s) 
2479             写入字符串。 
2480         void write(String s, int off, int len) 
2481             写入字符串的某一部分。 
2482     **读取流:
2483     (1)FileReader:
2484         **构造方法:
2485         FileReader(String fileName) 
2486             在给定从中读取数据的文件名的情况下创建一个新 FileReader。
2487         FileReader(File file) 
2488             在给定从中读取数据的 File 的情况下创建一个新 FileReader。 
2489         FileReader(FileDescriptor fd) 
2490             在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。 
2491         **方法摘要:和Reader基类方法一致:
2492         abstract  void close() 关闭该流并释放与之关联的所有资源。
2493         int read() 读取单个字符。
2494         int read(char[] cbuf)  将字符读入数组
2495         abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
2496         long skip(long n)  跳过字符。 
2497     (2)BufferedReader:
2498         **构造方法:
2499         BufferedReader(Reader in) 
2500             创建一个使用默认大小输入缓冲区的缓冲字符输入流。
2501         **方法摘要:
2502         int read() 
2503             读取单个字符。 
2504         int read(char[] cbuf, int off, int len) 
2505             将字符读入数组的某一部分。 
2506         String readLine() 
2507             读取一个文本行。 
2508     (3)InputStreamReader:字符通向字节的桥梁:
2509         **构造方法:
2510         InputStreamReader(InputStream in) 
2511             创建一个使用默认字符集的 InputStreamReader。
2512         **方法摘要:
2513         int read() 读取单个字符。
2514         int read(char[] cbuf)  将字符读入数组
2515         abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
2516         long skip(long n)  跳过字符。
2517     (4)LineNumberReader:
2518         **构造方法:
2519         LineNumberReader(Reader in) 
2520             使用默认输入缓冲区的大小创建新的行编号 reader。
2521         **方法摘要:
2522         int read() 
2523             读取单个字符。 
2524         int read(char[] cbuf, int off, int len) 
2525             将字符读入数组中的某一部分。 
2526         String readLine() 
2527             读取文本行。
2528         long skip(long n) 
2529             跳过字符。 
2530         int getLineNumber() 
2531             获得当前行号。 
2532         void setLineNumber(int lineNumber) 
2533             设置当前行号。 
2534 6、IO流常见需求:
2535 ****字符流:
2536     (1)需求1:在硬盘上创建一个文件并写入信息
2537         用字符写入流:FileWriter
2538         FileWriter fw = new FileWriter("g:\filewriter.txt");
2539         fw.write("输入信息");
2540         fw.write("也可以写入字符数组".toCharArray());
2541         fw.flush();
2542         fw.close();
2543     (2)需求2:在原有文件上续写数据
2544         FileWriter fw = new FileWriter("g:\filewriter.txt",true);
2545         fw.write("还可以续写信息");
2546         fw.write("也可以写入字符数组".toCharArray());
2547         fw.flush();
2548         fw.close();
2549     (3)需求3:读取硬盘上的文本文件,并将数据打印在控制台
2550         FileReader fr = new FileReader("g:\filewriter.txt");
2551         **第一种读取方法:一个一个字节的读
2552         int ch = 0;
2553         ch = fr.read();
2554         sop((char)ch);
2555         fr.close();
2556         **第二种读取方法:利用数组来提高效率
2557         char[] buf = new char[1024];
2558         int len = 0;
2559         while((len = fr.read(buf))!=-1)
2560         {
2561             sop(new String(buf,0,len));
2562         }
2563         fr.close();
2564     (4)需求4:拷贝文本文件
2565         利用缓冲区提高数据读写效率
2566         (无缓冲区就相当于一滴一滴的喝水,有缓冲区就相当于一杯一杯的喝水)
2567         BufferedReader bufr = new BufferedReader(new FileReader("g:\filewriter.txt"));
2568         BufferedWriter bufw = new BufferedWriter(new FileWriter("d:\copyfilewriter.txt"));
2569         String line = null;
2570         while((line = bufr.readLine())!=null)
2571         {
2572             burw.write(line);
2573             bufw.newLine();
2574             bufw.flush();
2575         }
2576         bufr.close();
2577         bufw.close();
2578 ****字节流:字节流写入时没有刷新
2579     (1)需求1:在硬盘上创建一个文件并写入信息(字节流写入时没有刷新)
2580         FileOutputStream fos = new FileOutputStream("g:\filestream.txt");
2581         fos.write(97);//写入一个字节,int:97代表写入char:a
2582         fos.write("也可以写入字节数组".getBytes());//通常使用此种方式写入,直观!
2583         fos.close();
2584     (2)需求2:在硬盘已有文件上续写数据(字节流写入时没有刷新)
2585         FileOutputStream fos = new FileOutputStream("g:\filestream.txt",true);
2586         fos.write("创建字节写入流时,传进去一个true参数就可以继续写入信息".getBytes());
2587         fos.close();    
2588     (3)需求3:读取硬盘上的文件
2589         FileInputStream fis = new FileInputStream("g:\filestream.txt");
2590         **第一种读法:一个字节一个字节的读(此种读法慢)
2591         int ch = 0;
2592         while((ch = fis.read())!=-1)
2593         {
2594             sop((char)ch);
2595         }
2596         **第一种读法:利用字节数组读(此种读法效率有一定提高)
2597         byte[] buf = new byte[1024];
2598         int len = 0;
2599         while((len = fis.read())!=-1)
2600         {
2601             sop(new String(buf,0,len));
2602         }
2603     (4)需求4:拷贝字节文件,如图片或者MP3或者电影
2604         **第一种拷贝:不带缓冲区(慢,还是效率问题)
2605         FileInputStream fis = new FileInputStream("g:\1.mp3");
2606         FileOutputStream fos = new FileOutputStream("g:\copy1.mp3");
2607         byte[] buf = new byte[1024];
2608         int len = 0;
2609         while((len = fis.read(buf))!=-1)
2610         {
2611             fos.(buf,0,len);//字节流写入无需刷新
2612         }
2613         fis.close();
2614         fos.close();
2615         **第二种拷贝:带缓冲区,高效
2616         BufferedInputStream bufi = new BufferedInputStream(new FileInputStream("g:\1.mp3"));
2617         BufferedOutputStream bufo = new BufferedOutputStream(new FileOutputStream("g:\copy1.mp3"));
2618         int ch = 0;
2619         while((ch = bufi.read())!=-1)
2620         {
2621             bufo.write(ch);
2622         }
2623         bufi.close();
2624         bufo.close();
2625 ****转换流:
2626     (1)需求1:读取一个键盘录入
2627         InputStream in = System.in;//创建一个键盘录入流,流不关则可以一直录入
2628         int by1 = in.read();//一次读一个字节
2629         int by2 = in.read();//一次读一个字节
2630         sop(by1);//假设键盘录入的是abcd,则打印a
2631         sop(by2);//假设键盘录入的是abcd,则打印b
2632         in.close();    
2633     (2)需求2:键盘录入一行数据打印一行数据,如果录入的是over则结束录入
2634         InputStream in = System.in;
2635         StringBuilder sb = new StringBuilder();
2636         while(true)
2637         {
2638             int ch = in.read();
2639             if(ch=='
')
2640                 continue;
2641             if(ch=='
')
2642             {
2643                 String line = sb.toString();
2644                 if("over".equals(line))
2645                     break;
2646                 sop(line.toUpperCase());//输出大写
2647                 sb.delete(0.sb.length());//清除上一行录入的数据
2648 
2649             }
2650             else
2651                 sb.append((char)ch);
2652         }
2653         in.close();
2654     (3)需求3:发现需求2中其实就是读一行的原理,故引入字节通向字符的桥梁:InputStreamReader
2655         为提高效率加入缓冲区:
2656         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
2657         String line = null;
2658         while((line = bufr.readLine())!=null)
2659         {
2660             if("over".equals(line))
2661                 break;
2662             sop(line.toUpperCase());//输出大写
2663         }
2664         bufr.close();
2665     (4)需求4:键盘录入数据并打印到控制台
2666         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
2667         BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
2668         String line = null;
2669         while((line = bufr.readLine())!=null)
2670         {    
2671             if("over".equals(line))
2672                 break;
2673             bufw.write(line.toUpperCase());
2674             bufw.newLine();
2675             bufw.flush();    
2676         }
2677         bufr.close();
2678         bufw.close();
2679     (5)需求5:将键盘录入的数据存储到硬盘文件
2680         则只需将(4)中的
2681         BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
2682         改为:
2683         BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(new FileWriter("g:\demo.txt")));
2684         即:
2685         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
2686         BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(new FileWriter("g:\demo.txt")));
2687         String line = null;
2688         while((line = bufr.readLine())!=null)
2689         {    
2690             if("over".equals(line))
2691                 break;
2692             bufw.write(line.toUpperCase());
2693             bufw.newLine();
2694             bufw.flush();    
2695         }
2696         bufr.close();
2697         bufw.close();
2698     (6)需求6:将硬盘文件的数据打印到控制台
2699         则只需将(4)中的
2700         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
2701         改为:
2702         BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileReader("g:\demo.txt")));
2703         即:
2704         BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileReader("g:\demo.txt")));
2705         BufferedWriter bufw = new BufferedWriter(new OntputStreamWriter(System.out));
2706         String line = null;
2707         while((line = bufr.readLine())!=null)
2708         {    
2709             if("over".equals(line))
2710                 break;
2711             bufw.write(line.toUpperCase());
2712             bufw.newLine();
2713             bufw.flush();    
2714         }
2715         bufr.close();
2716         bufw.close();
2717 7、流操作的规律:
2718     ****流操作的难点:流对象很多,不知道具体用哪个
2719     ****规律:
2720     (1)第一步:先明确源和目的
2721         源:
2722             文本:用Reader
2723             字节:用InputStream
2724         目的:
2725             文本:用Writer
2726             字节:用OutputStream
2727     (2)第二步:明确是不是纯文本
2728         是:用字符流;
2729         不是:用字节流
2730     (3)第三步:明确流体系后,通过设备来明确具体使用哪个流对象
2731         源设备:
2732             键盘:System.in
2733             硬盘:文件流File
2734             内存:数组流ArrayStream
2735         目的设备:
2736             键盘:System.out
2737             硬盘:文件流File
2738             内存:数组流ArrayStream
2739 8、File类
2740     构造方法:
2741     File(String pathname) 
2742         通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 
2743     File(String parent, String child) 
2744         根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
2745     File(File parent, String child) 
2746         根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
2747     方法摘要:
2748     (1)创建:
2749      boolean createNewFile() 
2750         当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 
2751      boolean mkdir() 
2752         创建一级文件夹
2753      boolean mkdirs() 
2754         创建多级文件夹
2755     (判断):
2756      boolean canExecute() 
2757         测试应用程序是否可以执行此抽象路径名表示的文件。 
2758      boolean canRead() 
2759         测试应用程序是否可以读取此抽象路径名表示的文件。 
2760      boolean canWrite() 
2761         测试应用程序是否可以修改此抽象路径名表示的文件。
2762      int compareTo(File pathname) 
2763         按字母顺序比较两个抽象路径名。 
2764      boolean isAbsolute() 
2765         测试此抽象路径名是否为绝对路径名。 
2766      boolean isDirectory() 
2767         测试此抽象路径名表示的文件是否是一个目录。 
2768      boolean isFile() 
2769         测试此抽象路径名表示的文件是否是一个标准文件。 
2770      boolean isHidden() 
2771         测试此抽象路径名指定的文件是否是一个隐藏文件。
2772      boolean exists() 
2773         测试此抽象路径名表示的文件或目录是否存在。 
2774     (3)获取:
2775      String getParent() 
2776         返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。 
2777      File getParentFile() 
2778         返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。 
2779      String getName() 
2780         返回由此抽象路径名表示的文件或目录的名称。
2781      String getPath() 
2782         将此抽象路径名转换为一个路径名字符串。 
2783      String getAbsolutePath() 
2784         返回此抽象路径名的绝对路径名字符串。
2785      File getAbsoluteFile() 
2786         返回此抽象路径名的绝对路径名形式。
2787     (4)删除:
2788      boolean delete() 
2789         删除此抽象路径名表示的文件或目录。 
2790      oid deleteOnExit() 
2791         在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。 
2792     (5)获取全部:(非常重要!!!)
2793      String[] list() 
2794         返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 
2795      String[] list(FilenameFilter filter) 
2796         返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
2797      File[] listFiles() 
2798         返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 
2799      File[] listFiles(FileFilter filter) 
2800         返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
2801     
2802     ****FilenameFilter接口只有一个方法:
2803         boolean accept(File dir, String name) 
2804             测试指定文件是否应该包含在某一文件列表中。 
2805     ****FileFilter接口只有一个方法:
2806         boolean accept(File dir, String name) 
2807             测试指定文件是否应该包含在某一文件列表中。
2808 8、File类常见需求:
2809     (1)文件名过滤:列出给定目录的所有.java文件
2810         public void showFileName(File file)
2811         {
2812             String[] filenames = file.list(new FilenameFilter()//匿名内部类
2813             {
2814                 public boolean accept(File dir,String name)//复写唯一方法
2815                 {
2816                     return name.endsWith(".java");//列出所有.java文件
2817                 }
2818             });
2819         }
2820     (2)列出指定目录下的所有文件和文件夹(递归)
2821     **示例1:不带层次递归:
2822     public static void showDir(File dir)
2823     {
2824         File[] files = dir.listFile();
2825         for(int i = 0;i<files.length;i++)
2826         {
2827             if(files[i].isDirectory&&!files[i].isHidden())
2828                 showDir(files[i]);
2829             else
2830                 sop(files[i]);
2831         }
2832     }
2833     **示例2:带层次递归:
2834     public static void showDir(File dir,int level)
2835     {
2836         sop(getLevel(level)+C);//进来先打印层次和目录
2837         level++;
2838         File[] files = dir.listFile();
2839         for(int i = 0;i<files.length;i++)
2840         {
2841             if(files[i].isDirectory&&!files[i].isHidden())
2842                 showDir(files[i]);
2843             else
2844                 sop(getLevel(level)+files[i]);//是文件就打印层次和目录
2845         }
2846     }
2847     public static String getLevel(int level)
2848     {
2849         sop("|--");
2850         StringBuilder sb = new StringBuilder();
2851         for(int i=0;i<level;i++)
2852         {
2853             sb.inset(0."|  ")
2854         }
2855         return sb.toString();
2856     }
2857     (3)需求:删除带内容的目录:
2858     public static void removeDir(File dir)
2859     {
2860         File[] files = file.listFile();
2861         for(int i = 0;i<files.length;i++)
2862         {
2863             if(files[i].isDirectory&&!files[i].isHidden())
2864                 removeDir(files[i]);//如果是文件夹则继续调用函数
2865             else//如果是文件则删除。注意删除的时候打印删除的结果,防止误删或者重删的情况
2866                 sop(files[i].toString()+"::"+files[i].delete());
2867         }
2868         sop(dir+"::"+dir.delete());
2869     }
2870     (4)需求:将制定目录下的java文件的绝对路径存储到文本文件中。
2871        思路:
2872        **对指定目录进行递归
2873        **获取递归过程中所有java文件的路径
2874        **将这些路径存储到集合中
2875        **将集合中的数据写入文件中
2876      //对指定目录进行递归并将所以Java文件存储到集合中
2877     public static void getFileName(File file,ArrayList<File> arraylist){
2878         File[] files = file.listFiles();
2879         for (int i = 0; i < files.length; i++) {
2880             if(files[i].isDirectory()&&!files[i].isHidden()){
2881                 getFileName(files[i],arraylist);
2882             }else{
2883                 if(files[i].getName().endsWith(".java")){
2884                     arraylist.add(files[i]);
2885                 }
2886             }
2887         }
2888     }
2889     //将集合中所有数据存储到新文件中
2890     public static void saveFileToNewDir(ArrayList<File> arraylist,File newDir){
2891         BufferedWriter bufw = null;
2892         try {
2893             bufw = new BufferedWriter(new FileWriter(newDir));
2894             for (File file : arraylist) {
2895                 String fileAbsolutePath = file.getAbsolutePath();
2896                 bufw.write(fileAbsolutePath);
2897                 bufw.newLine();
2898                 bufw.flush();    
2899             }
2900         } catch (Exception e) {
2901             System.out.println("文件写入失败");
2902         }finally{
2903             try {
2904                 if(bufw!=null)
2905                     bufw.close();
2906             } catch (Exception e2) {
2907                 System.out.println("文件写入流关闭失败");
2908             }
2909         }
2910     }
2911 9、Properties
2912 (1)Properties是HashTable的子类,具备Map集合的特点,里面存储的是键值对
2913 (2)Properties是IO流合集合相结合的集合容器
2914 (3)Properties的特点是可以用于存储键值对形式的配置文件
2915 (4)构造方法:
2916     Properties() 
2917         创建一个无默认值的空属性列表。 
2918     Properties(Properties defaults) 
2919         创建一个带有指定默认值的空属性列表。 
2920 (5)方法摘要:
2921     Object setProperty(String key, String value) 
2922         调用 Hashtable 的方法 put。
2923     String getProperty(String key) 
2924         用指定的键在此属性列表中搜索属性。 
2925     void load(InputStream inStream) 
2926         从输入流中读取属性列表(键和元素对)。 
2927     void load(Reader reader) 
2928         按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 
2929     void list(PrintStream out) 
2930         将属性列表输出到指定的输出流。 
2931     void list(PrintWriter out) 
2932         将属性列表输出到指定的输出流。
2933     void store(OutputStream out, String comments) 
2934         以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
2935         将此 Properties 表中的属性列表(键和元素对)写入输出流。 
2936     void store(Writer writer, String comments) 
2937         以适合使用 load(Reader) 方法的格式,将此 Properties 表中的
2938         属性列表(键和元素对)写入输出字符。 
2939     Set<String> stringPropertyNames() 
2940         返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中
2941         未找到同名的键,则还包括默认属性列表中不同的键 
2942 (6)Properties代码示例:
2943     public static void show()
2944     {
2945         Properties prop = new Properties();
2946         prop.setProperty("张三","26");
2947         prop.setProperty("李四","30");
2948         prop.setProperty("王五","35");
2949         sop(prop);
2950         String value = prop.getProperty("张三");
2951 
2952         Set<String> keys = prop.stringPropertyName();
2953         for(String key : values)
2954         {
2955             sop(key+":"+prop.getPropety(key));
2956         }
2957     }
2958 (7)需求:记录应用程序的使用次数,如果使用次数已到,则提示用户注册。
2959    思路:
2960    **第一次使用时建立一个配置文件用于记录使用次数
2961    **每次使用都加载该配置文件,并先判断已使用次数
2962    **每次使用完使用次数加1,写入配置文件
2963     public static void main(String[] args) throws IOException{
2964         Properties prop = new Properties();//定义Properties,用来和IO流结合
2965         File file = new File("library\time.ini");//配置文件
2966         if(!file.exists())
2967             file.createNewFile();//如果文件不存在则创建文件(用于第一次使用时创建文件)
2968         FileInputStream fis = new FileInputStream(file);//定义字节读取流,读取配置文件中记录的使用次数
2969         prop.load(fis);//载入流,以获取文件中配置的键值对
2970         int count = 0;//定义使用次数
2971         String countValue = prop.getProperty("time");//通过键获取值
2972         if(countValue!=null){//第一次时countValue为null
2973             count = Integer.parseInt(countValue);//将字符串次数变成数字次数
2974             if(count>3){
2975                 System.out.println("您使用次数已到,继续使用请注册!");
2976                 return;
2977             }
2978         }
2979         count++;//如果使用次数未到则次数加1
2980         prop.setProperty("time", count+"");//配置新的键值对
2981         FileWriter fos = new FileWriter(file);
2982         prop.store(fos, "这是应用程序使用次数的配置文件");//将新的键值对写入文件
2983         fis.close();
2984         fos.close();    
2985     }
2986 10、IO中的其他流:
2987     (1)打印流:
2988         **PrintWriter:字符打印流
2989             ****构造方法:
2990             PrintWriter(String fileName) 
2991                 创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
2992             PrintWriter(File file) 
2993                 使用指定文件创建不具有自动行刷新的新 PrintWriter。
2994             PrintWriter(Writer out) 
2995                 创建不带自动行刷新的新 PrintWriter。 
2996             PrintWriter(Writer out, boolean autoFlush) 
2997                 自动刷新
2998             PrintWriter(OutputStream out) 
2999                 根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 
3000             PrintWriter(OutputStream out, boolean autoFlush) 
3001                 自动刷新
3002             ****方法摘要:
3003             PrintWriter append(char c) 
3004                 将指定字符添加到此 writer。 
3005             void close() 
3006                 关闭该流并释放与之关联的所有系统资源。 
3007             void flush() 
3008                 刷新该流的缓冲。 
3009             void print(Object obj) 
3010                 打印对象。 
3011             void print(String s) 
3012                 打印字符串。
3013             void println() 
3014                 通过写入行分隔符字符串终止当前行。 
3015         **PrintStream:字节打印流
3016             ****构造方法:
3017             PrintStream(String fileName) 
3018                 创建具有指定文件名称且不带自动行刷新的新打印流。
3019             PrintStream(File file) 
3020                 创建具有指定文件且不带自动行刷新的新打印流。
3021             PrintStream(OutputStream out) 
3022                 创建新的打印流。 
3023             PrintStream(OutputStream out, boolean autoFlush) 
3024                 创建新的打印流。 
3025             ****方法摘要:
3026             PrintWriter append(char c) 
3027                 将指定字符添加到此 writer。 
3028             void close() 
3029                 关闭该流并释放与之关联的所有系统资源。 
3030             void flush() 
3031                 刷新该流的缓冲。 
3032             void print(Object obj) 
3033                 打印对象。 
3034             void print(String s) 
3035                 打印字符串。
3036             void println() 
3037                 通过写入行分隔符字符串终止当前行。
3038     (2)对象系列化:
3039         **对象实体化:找一个介质,能长期的存储对象。
3040         **对象的属性在Java程序中,都是存在于对内存中,随着对象的消失而消失,
3041           而ObjectOutputStream可以将对象实体化
3042         **Serializable接口没有一个方法,也就是说其是一个标记接口。比如盖章的猪肉才是安全的。
3043         **只有实现Serializable接口的子类才能被ObjectOutputStream系列化写入流,当某个
3044           类实现该接口后,会被Java自动分配UID号,以便编译器识别,区分不同对象。
3045         **用ObjectOutputStream系列化的对象存储到文件后,该文件是乱码,也就是不可读的
3046           的用ObjectInputStream读取该类对象的属性。
3047         **由于对象是有Java给对象分配相应的UID号,而UID号是根据对象的属性不同而分配的。
3048           当一个类对象被系列化到文件后,如果该类改动了对象的属性,比如将某个成员变量变成私有
3049           则该对象再用ObjectInputStream读取时会报异常,也就是说该系列化到文件的对象不能再被使用了
3050           那么,要想继续使用属性被改动后的对象,我们可以自定义给对象分配UID号,让UID号不随对象的属性
3051           变化而变化。
3052           自定义对象分配UID方法如下:
3053             public static final long serialVersion UID = 43L;
3054         **注意:
3055             静态不能被系列化,因为静态成员变量实在内存的方法区,而ObjectOutputStream只能
3056             对对内存里面的数据进行系列化
3057             被transient修饰的非静态成员变量也不能被系列化
3058             被系列化的对象存储到文件中,该文件是不可读的,所以该文件的扩展名一般
3059             不写成.txt,通常后缀名写.object
3060         **ObjectOutputStream
3061         **ObjectInputStream
3062     (3)管道流:
3063         PipedInputStream
3064         PipedOutputStream
3065     (4)随机访问文件:RandomAccess(重要!!!)
3066         **自身具备读写方法(很牛逼!又可以读又可以写)
3067         **通过skipByte(int x)和seek(int x)来达到随机访问文件
3068         **该类不是IO体系子类,而是直接继承Object,但它是IO包中的成员,因为它具备读写方法
3069         **该类内部封装了数组,而且通过指针对数组的元素进行操作,可以通过getFilePoint获取指针位置
3070           同时可以通过seek改变指针位置
3071         **该类完成读写的原理是内部封装了字节输入输出流
3072         **通过该类的构造看出,该类只能操作文件,而且操作的文件只能有固定模式:
3073             "r":只读
3074             "rw":读写
3075             "rws":
3076             "red":
3077         **构造方法:
3078         RandomAccessFile(File file, String mode) 
3079             创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
3080         RandomAccessFile(String name, String mode) 
3081             创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
3082         **方法摘要:
3083         void write(byte[] b) 
3084             将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。 
3085         void write(byte[] b, int off, int len) 
3086             将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。 
3087         void write(int b) 
3088             向此文件写入指定的字节。 
3089         int read() 
3090             从此文件中读取一个数据字节。 
3091         int read(byte[] b) 
3092             将最多 b.length 个数据字节从此文件读入 byte 数组。 
3093         int read(byte[] b, int off, int len) 
3094             将最多 len 个数据字节从此文件读入 byte 数组。
3095         String readLine() 
3096             从此文件读取文本的下一行。 
3097         long getFilePointer() 
3098             返回此文件中的当前偏移量。 
3099         long length() 
3100             返回此文件的长度。 
3101         void seek(long pos) 
3102             设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
3103     (4)操作基本数据类型的流对象:DateStream
3104     (5)操作字节数组流:
3105         ByteArrayInputStream
3106         ByteArrayOutputStream
3107 11、IO流转换流的字符编码
3108     (1)字符流的出现为了方便操作字符,更重要的是加入了编码转换
3109     (2)通过子类转换流来完成
3110         InputStreamReander
3111         OutputStreamWriter
3112     (3)在两个子类对象进行构造的时候可以加入编码表
3113     (4)编码表:
3114         将各个国家的文字用二进制数字表示并一一对应,形成一张表,这就是编码表
3115     (5)常见的编码表:
3116         **ASCII:美国标准信息交换码,用一个字节的七位表示
3117         **ISO8859-1:拉丁码表,欧洲码表,用一个字节的八位表示
3118         **GB2312:中文编码表,用两个字节表示
3119         **GBK:中文编码表升级,融合录入更多的中文字符,用两个字节表示,为避免和老美重复
3120                两字节的最高位都是1,即汉字都是用负数表示
3121         **Unicode:国际标准码,融合了多种文字,所有文字都用两个字节表示
3122         **UTF-8:用一个字节到三个字节表示。
3123         注:Unicode能识别中文,UTF-8也能识别中文,但两种编码表示一个汉字所用的字节数不同
3124         Unicode用两个字节,UTF-8用三个字节,故涉及到编码转换。
3125     (6)在流中涉及编码表的转换只有转换流:
3126         InputStreamReander
3127         OutputStreamWriter
3128     (7)代码示例:
3129         public static void write() throws IOException
3130         {
3131             OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK");
3132             osw1.write("你好");
3133             osw1.close();
3134 
3135             OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("utf-8.txt"),"UTF-8");
3136             osw2.write("你好");
3137             osw2.close();
3138         }
3139         public static void read() throws IOException
3140         {
3141             InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
3142             byte[] buf = new byte[1024];
3143             int len = isr.read(buf);
3144             sop(new String(buf,0,len));
3145         }
3146     (8)编码解码
3147         编码:字符串变成字节数组:String-->getBytes()-->byte[]()
3148         解码:字节数组变成字符串:byte[]-->new String(byte[],0,len)-->String
3149     (9)代码示例:
3150         public static void main(String[] args)
3151         {
3152             //编码解码1:默认编码
3153             String str1 = "你好";
3154             byte[] buf1 = str1.getBytes();//默认解码:Unicode,四个字节
3155 
3156             //编码解码2:指定编码
3157             String str2 = "你好";
3158             byte[] buf2 = str2.getBytes("UTF-8");//指定解码:UTF-8,六个字节
3159 
3160             
3161             //编码解码3:编码正确解码错误
3162             String str3 = "你好";
3163             byte[] buf3 = str3.getBytes("GBK");//指定编码:GBK,四个字节
3164             String str3 = new String(buf3,"ISO8859-1");//错误解码
3165 
3166             //编码解码4:错误编码正确解码
3167             String str4 = "你好";
3168             byte[] buf4 = str4.getBytes("ISO8859-1");//错误编码
3169             String str4 = new String(buf4,"GBK");//正确解码,读不出来
3170 
3171             //编码解码5:编码对了,但是解码错误了,怎么办呢?
3172             //此时可以将错误的解码再错编回去,载用正确编码解码
3173             String str5 = "你好";
3174             byte[] buf5 = str5.getBytes("GBK");//正确编码
3175             String str6 = new String(buf5,"ISO8859-1");//错误解码,读不出来
3176             byte[] buf6 = str6.getBytes("ISO8859-1");//再错误编码
3177             String str7 = new String(buf6,"GBK");//再正确解码,这样就可以读出来了
3178         }
3179 
3180 
3181 
3182 六、网络编程:
3183 1、网络编程概述
3184     (1)网络模型
3185         OSI参考模型
3186         TCP/IP参考模型
3187     (2)网络通讯要素
3188         IP地址
3189         端口号
3190         传输协议
3191     (3)网络通讯前提:
3192         **找到对方IP
3193         **数据要发送到指定端口。为了标示不同的应用程序,所以给这些网络应用程序都用数字进行标示
3194           。这个表示就叫端口。
3195         **定义通信规则。这个规则称为通信协议,国际组织定义了通用协议TCP/IP
3196     (4)计算机网络:
3197         是指将地理位置不同的具有独立功能的多台计算机及其外部设备,
3198         通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,
3199         实现资源共享和信息传递的计算机系统。
3200     (5)IP地址:
3201         IP地址 = 网络号码+主机地址
3202 
3203         A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
3204         B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
3205         C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
3206 
3207         特殊地址:
3208         127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1   
3209         ipconfig:查看本机IP地址
3210         xxx.xxx.xxx.0 网络地址
3211         xxx.xxx.xxx.255 广播地址
3212 
3213         A类    1.0.0.1---127.255.255.254    10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)                            (2)127.X.X.X是保留地址,用做循环测试用的。
3214         B类    128.0.0.1---191.255.255.254    172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
3215         C类    192.0.0.1---223.255.255.254    192.168.X.X是私有地址
3216         D类    224.0.0.1---239.255.255.254     
3217         E类    240.0.0.1---247.255.255.254
3218     (6)各种网络分类方式
3219         A:按网络覆盖范围划分
3220           局域网(几米至10公里以内)   城域网(10~100公里)   广域网(几百公里到几千公里)   国际互联网
3221         B:按网络拓扑结构划分
3222           总线型网络   星形网络   环型网络   树状网络   混合型网络
3223         C:按传输介质划分
3224           有线网   无线网
3225         D:按网络使用性质划分
3226           公用网   专用网
3227     (7)虚拟专用网络(Virtual Private Network ,简称VPN)指的是在公用网络上建立专用网络的技术。
3228         其之所以称为虚拟网,主要是因为整个VPN网络的任意两个节点之间的连接并没有传统专网
3229         所需的端到端的物理链路,而是架构在公用网络服务商所提供的网络平台,如Internet、
3230         ATM(异步传输模式〉、Frame Relay (帧中继)等之上的逻辑网络,
3231         用户数据在逻辑链路中传输。它涵盖了跨共享网络或公共网络的封装、
3232         加密和身份验证链接的专用网络的扩展。VPN主要采用了隧道技术、加解密技术、
3233         密钥管理技术和使用者与设备身份认证技术。
3234     (8)网络模型:
3235         ****OSI模型
3236             应用层
3237             表示层
3238             会话层
3239             传输层
3240             网络层
3241             数据连接层
3242             物理层
3243         ****TCP/IP模型
3244             应用层
3245             传输层
3246             网际层
3247             主机至网络层
3248 2、TCP和UDP
3249     (1)UDP和TCP的区别:
3250         UDP
3251         将数据及源和目的封装成数据包中,不需要建立连接
3252         每个数据报的大小在限制在64k内
3253         因无连接,是不可靠协议
3254         不需要建立连接,速度快
3255         TCP
3256         建立连接,形成传输数据的通道。
3257         在连接中进行大数据量传输
3258         通过三次握手完成连接,是可靠协议
3259         必须建立连接,效率会稍低
3260         注:三次握手:
3261         第一次:我问你在么?
3262         第二次:你回答在。
3263         第三次:我反馈哦我知道你在。
3264 3、Socket(UDP传输)
3265     **Socket就是为网络服务提供的一种机制。
3266     **通信的两端都有Socket。
3267     **网络通信其实就是Socket间的通信。
3268     **数据在两个Socket间通过IO传输。
3269     **玩Socket主要就是记住流程,代码查文档就行
3270     (1)UDP传输:DatagramSocket与DatagramPacket
3271         **发送端:
3272         建立DatagramSocket服务;
3273         提供数据,并将数据封装到字节数组中;
3274         创建DatagramPacket数据包,并把数据封装到包中,同时指定IP和接收端口
3275         通过Socket服务,利用send方法将数据包发送出去;
3276         关闭DatagramSocket和DatagramPacket服务。
3277         **接收端:
3278         建立DatagramSocket服务,并监听一个端口;
3279         定义一个字节数组和一个数据包,同时将数组封装进数据包;
3280         通过DatagramPacket的receive方法,将接收的数据存入定义好的数据包;
3281         通过DatagramPacke关闭t的方法,获取发送数据包中的信息;
3282         关闭DatagramSocket和DatagramPacket服务。
3283         DatagramSocket与DatagramPacket方法摘要:
3284         *****DatagramSocket
3285         构造方法:
3286         DatagramSocket() 
3287             构造数据报套接字并将其绑定到本地主机上任何可用的端口。
3288         DatagramSocket(int port) 
3289             创建数据报套接字并将其绑定到本地主机上的指定端口。 
3290         DatagramSocket(int port, InetAddress laddr) 
3291             创建数据报套接字,将其绑定到指定的本地地址。 
3292         方法摘要:
3293         void close() 
3294             关闭此数据报套接字。
3295         InetAddress getInetAddress() 
3296             返回此套接字连接的地址。 
3297         InetAddress getLocalAddress() 
3298             获取套接字绑定的本地地址。
3299         int getPort() 
3300             返回此套接字的端口。 
3301         void receive(DatagramPacket p) 
3302             从此套接字接收数据报包。 
3303         void send(DatagramPacket p) 
3304             从此套接字发送数据报包。
3305         ****DatagramPacket
3306         构造方法:
3307         DatagramPacket(byte[] buf, int length) 
3308             构造 DatagramPacket,用来接收长度为 length 的数据包。
3309         DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
3310             构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
3311         InetAddress getAddress() 
3312             返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。 
3313         byte[] getData() 
3314             返回数据缓冲区。 
3315         int getLength() 
3316             返回将要发送或接收到的数据的长度。
3317         int getPort() 
3318             返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。    
3319         代码示例:
3320         ****发送端:
3321         class UDPSend
3322         {
3323             public static void main(String[] args) throws Exception
3324             {
3325                 DatagramSocket ds = new DatagramSocket();
3326                 byte[] buf = "这是UDP发送端".getBytes();
3327                 DatagramPacket dp = new DatagramPacket(
3328                     buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
3329                 ds.send(dp);
3330                 ds.close();
3331             }
3332         }
3333         ****接收端
3334         class UDPRece
3335         {
3336             public static void main(String[] args) throws Exception
3337             {
3338                 DatagramSocket ds = new DatagramSocket(10000);
3339                 byte[] buf = new byte[1024];
3340                 DatagramPacket dp = new DatagramPacket(buf,buf.length);
3341                 ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
3342                 String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
3343                 String data = new String(dp.getData(),0,dp.getLength());//获取数据
3344                 int port = dp.getPort();//获取发送端的端口号
3345                 sop(ip+":"+data+":"+port);
3346                 ds.close();
3347             }
3348         }
3349         需求1:UDP键盘录入数据,并发送给接收端
3350         发送端:
3351         class UDPSend
3352         {
3353             public static void main(String[] args) throws Exception
3354             {
3355 
3356                 DatagramSocket ds = new DatagramSocket();
3357                 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
3358                 String line = null;
3359                 while((line = bufr.readLine())!=null)
3360                 {
3361                     if("886".equals(line))
3362                         break;
3363                     byte[] buf = line.getBytes();
3364                     DatagramPacket dp = new DatagramPacket(
3365                         buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
3366                     ds.send(dp);
3367                 }
3368                 ds.close();
3369             }
3370                 
3371         }
3372         接收端:
3373         class UDPRece
3374         {
3375             public static void main(String[] args) throws Exception
3376             {
3377                 DatagramSocket ds = new DatagramSocket(10000);
3378                 while(true)
3379                 {
3380                     byte[] buf = new byte[1024];
3381                     DatagramPacket dp = new DatagramPacket(buf,buf.length);
3382                     ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
3383                     String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
3384                     String data = new String(dp.getData(),0,dp.getLength());//获取数据
3385                     int port = dp.getPort();//获取发送端的端口号
3386                     sop(ip+":"+data+":"+port);
3387                     ds.close();
3388                 }
3389             }
3390             
3391         }
3392         需求2:编写简单的聊天工具
3393         思路:
3394             使用多线程技术
3395         发送端:
3396         class UDPSend implements Runnable
3397         {
3398             private DatagramSocket ds;
3399             public UDPSend(){}
3400             public UDPSend(DatagramSocket ds)
3401             {
3402                 this.ds=ds;
3403             }
3404             public void run()
3405             {
3406                 try
3407                 {
3408                     BufferedReader bufr = new BufferedReader(
3409                                 new InputStreamReader(System.in));
3410                     String line = null;
3411                     while((line = bufr.readLine())!=null)
3412                     {
3413                         if("886".equals(line))
3414                             break;
3415                         byte[] buff = line.getBytes();
3416                         DatagramPacket dp = new DatagramPacket(
3417                         buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
3418                         ds.send(dp);
3419                     }
3420                 }
3421                 catch(Exception e)
3422                 {
3423                     throw new RuntimeException("发送失败");
3424                 }
3425             }
3426         }
3427         接收端:
3428         class UDPRece implements Runnable
3429         {
3430             private DatagramSocket ds;
3431             public UDPSend(){}
3432             public UDPSend(DatagramSocket ds)
3433             {
3434                 this.ds=ds;
3435             }
3436             public void run()
3437             {
3438                 try
3439                 {
3440                     while(true)
3441                     {    
3442                         byte[] buf = new byte[1024];
3443                         DatagramPacket dp = new DatagramPacket(buf,buf.length);
3444                         ds.receive(dp);//将发送端发送的数据包接收到接收端的数据包中
3445                         String ip = dp.getAddress().getHosyAddress();//获取发送端的ip
3446                         String data = new String(dp.getData(),0,dp.getLength());//获取数据
3447                         int port = dp.getPort();//获取发送端的端口号
3448                         sop(ip+":"+data+":"+port);        
3449                     }
3450                 }
3451                 catch(Exception e)
3452                 {
3453                     throw new RuntimeException("接收失败");
3454                 }
3455             }
3456         }
3457         测试类:
3458         class UDPTest
3459         {
3460             public static void main(String[] args)
3461             {
3462                 DatagramSocket sendSocket = new DatagramSocket();
3463                 DatagramSocket receSocket = new DatagramSocket(10000);
3464 
3465                 new Thread(new UDPSend(sendSocket)).start();
3466                 new Thread(new UDPRece(receSocket)).start();
3467             }
3468         }
3469     (2)TCP传输
3470         Socket和ServerSocket
3471         建立客户端和服务器端
3472         建立连接后,通过Socket中的IO流进行数据的传输
3473         关闭socket
3474         同样,客户端与服务器端是两个独立的应用程序。
3475         ****Socket
3476         **构造方法:
3477         Socket() 
3478             通过系统默认类型的 SocketImpl 创建未连接套接字
3479         Socket(InetAddress address, int port) 
3480             创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
3481         Socket(String host, int port) 
3482             创建一个流套接字并将其连接到指定主机上的指定端口号。
3483         **方法摘要:
3484         void close() 
3485             关闭此套接字。
3486         InetAddress getInetAddress() 
3487             返回套接字连接的地址。
3488         InputStream getInputStream() 
3489             返回此套接字的输入流。
3490         OutputStream getOutputStream() 
3491             返回此套接字的输出流。 
3492         int getPort() 
3493             返回此套接字连接到的远程端口。
3494         void shutdownInput() 
3495             此套接字的输入流置于“流的末尾”。 
3496         void shutdownOutput() 
3497             禁用此套接字的输出流。 
3498         String toString() 
3499             将此套接字转换为 String。
3500         ****ServerSocket
3501         **构造方法:
3502         ServerSocket() 
3503             创建非绑定服务器套接字。 
3504         ServerSocket(int port) 
3505             创建绑定到特定端口的服务器套接字。
3506         方法摘要:
3507         Socket accept() 
3508             侦听并接受到此套接字的连接。
3509         void close() 
3510             关闭此套接字。 
3511         InetAddress getInetAddress() 
3512             返回此服务器套接字的本地地址。
3513         ****TCP传输流程:
3514         **客户端:
3515         建立Socket服务,并制定要连接的主机和端口;
3516         获取Socket流中的输出流OutputStream,将数据写入流中,通过网络发送给服务端;
3517         获取Socket流中的输出流InputStream,获取服务端的反馈信息;
3518         关闭资源。
3519         **服务端:
3520         建立ServerSocket服务,并监听一个端口;
3521         通过ServerSocket服务的accept方法,获取Socket服务对象;
3522         使用客户端对象的读取流获取客户端发送过来的数据;
3523         通过客户端对象的写入流反馈信息给客户端;
3524         关闭资源;
3525         ****代码示例:
3526         客户端:
3527         class TCPClient
3528         {
3529             public static void main(String[] args)
3530             {
3531                 Socket s = new Socket("192.168.1.253",10000);
3532                 OutputStream os = s.getOutputStream();
3533                 out.write("这是TCP发送的数据".getBytes());
3534                 s.close();
3535             }
3536         }
3537         服务端:
3538         class TCPServer
3539         {
3540             public static void main(String[] args)
3541             {
3542                 ServerSocket ss = new ServerSocket(10000);
3543                 Socket s = ss.accept();
3544 
3545                 String ip = s.getInetAddress().getHostAddress();
3546                 sop(ip);
3547 
3548                 InputStream is = s.getInputStream();
3549                 byte[] buf = new byte[1024];
3550                 int len = is.read(buf);
3551                 sop(new String(buf,0,len));
3552                 s.close();
3553                 ss.close();
3554             }
3555         }
3556         TCP需求1:客户端给服务端发送数据,服务端接收到后反馈信息给客户端
3557         客户端:
3558         class TCPClient
3559         {
3560             public static void main(String[] args)
3561             {
3562                 Socket s = new Socket("192.168.1.253",10000);
3563                 OutputStream os = s.getOutputStream();
3564                 out.write("这是TCP发送的数据".getBytes());
3565                 
3566                 InputStream is = s.getInputStream();
3567                 byte[] buf = new byte[1024];
3568                 int len = is.read(buf);
3569                 sop(new String(buf,0,len));
3570                 s.close();
3571             }
3572         }
3573         服务端:
3574         class TCPServer
3575         {
3576             public static void main(String[] args)
3577             {
3578                 ServerSocket ss = new ServerSocket(10000);
3579                 Socket s = ss.accept();
3580 
3581                 String ip = s.getInetAddress().getHostAddress();
3582                 sop(ip);
3583 
3584                 InputStream is = s.getInputStream();
3585                 byte[] buf = new byte[1024];
3586                 int len = is.read(buf);
3587                 sop(new String(buf,0,len));
3588 
3589                 OutputStream os = s.getOutputStream();
3590                 out.write("这是TCP发送的数据".getBytes());
3591 
3592                 s.close();
3593                 ss.close();
3594             }
3595         }
3596         TCP需求2:建立一个文本转换服务端,客户给服务端发送文本,服务端将数据转换成大写后返回给客户端
3597               当客户端输入over时,转换结束
3598         客户端:
3599         class TCPClient
3600         {
3601             public static void main(String[] args)
3602             {
3603                 Socket s = new Socket("192.168.1.253",10000);
3604                 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
3605                 BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
3606                                         s.getOutputStream()));
3607                 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
3608                                         s.getInputStream()));
3609                 String line = null;
3610                 while((line = bufr.readLine())!=null)
3611                 {
3612                     if("over".equals(line))
3613                         break;
3614                     bufOut.write(line);
3615                     bufOut.newLine();
3616                     bufOut.flush();
3617                     String retVal = bufIn.readLine();
3618                     sop("server:"+retVal);
3619                 }
3620                 bufr.close();
3621                 s.close();
3622             }
3623         }
3624         服务端:
3625         class TCPServer
3626         {
3627             public static void main(String[] args)
3628             {
3629                 ServerSocket ss = new ServerSocket(10000);
3630                 Socket s = ss.accept();
3631 
3632                 String ip = s.getInetAddress().getHostAddress();
3633                 sop(ip);
3634                 
3635                 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
3636                                         s.getInputStream()));
3637                 BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(
3638                                         s.getOutputStream()));
3639 
3640                 while((line = bufIn.readLine())!=null)
3641                 {
3642                     bufOut.write(line.toUpperCase());
3643                     bufOut.newLine();
3644                     bufOut.flush();
3645                 }
3646                 s.close();
3647                 ss.close();
3648             }
3649         }
3650         **需求3:拷贝文件
3651         客户端:
3652         class TCPClient
3653         {
3654             public static void main(String[] args)
3655             {
3656                 Socket s = new Socket("192.168.1.253",10000);
3657                 BufferedReader bufr = new BufferedReader(new FileReader("g:\demo.txt"));
3658                 PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
3659                 String line = null;
3660                 while((line = bufr.readLine())!=null)
3661                 {
3662                     pw.println();
3663                 }
3664                 s.shutDownOutput();
3665                 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
3666                                         s.getInputStream()));
3667                 String retVal = bufIn.readLine();
3668                 sop(retVal);
3669                 bufr.close();
3670                 s.close();
3671             }
3672         }
3673         服务端:
3674         class TCPServer
3675         {
3676             public static void main(String[] args)
3677             {
3678                 ServerSocket ss = new ServerSocket(10000);
3679                 Socket s = ss.accept();
3680 
3681                 String ip = s.getInetAddress().getHostAddress();
3682                 sop(ip);
3683                 
3684                 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
3685                                         s.getInputStream()));
3686                 PrintWriter out = new PrintWriter(new FileWriter"copy.txt",true);
3687                 String line =null;
3688                 while((line = bufIn.readLine())!=null)
3689                 {
3690                     out.write(line);
3691                 }
3692                 PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
3693                 pw.println("上传成功");
3694                 out.close();
3695                 s.close();
3696                 ss.close();
3697             }
3698         }
3699         需求4:上传图片
3700         客户端:
3701         class TCPClient
3702         {
3703             public static void main(String[] args)
3704             {
3705                 Socket s = new Socket("192.168.1.253",10000);
3706                 FileInputStream fis = new FileInputStream("g:\1.bmp");
3707                 OutputStream out = s.getOutputStream();
3708                 byte[] buf = new byte[1024];
3709                 int len = 0;
3710                 while((len = bufr.read())!=-1)
3711                 {
3712                     out.write(buf,0,len);
3713                 }
3714                 s.shutDownOutput();
3715 
3716                 InputStream in = s.getInputStream();
3717                 byte[] bufIn = new byte[1024];
3718                 int lenIn = in.read(bufIn);
3719                 sop(new String(bufIn,0,lenIn);
3720                 fis.close();
3721                 s.close();
3722             }
3723         }
3724         服务端:
3725         class TCPServer
3726         {
3727             public static void main(String[] args)
3728             {
3729                 ServerSocket ss = new ServerSocket(10000);
3730                 Socket s = ss.accept();
3731 
3732                 String ip = s.getInetAddress().getHostAddress();
3733                 sop(ip);
3734                 FileOutputStream fos = new FileOutputStream("g:\copy.bmp");
3735                 InputStream in = s.getInputStream();
3736                 byte[] bufIn = new byte[1024];
3737                 int lenIn = 0;
3738                 while((lenIn=bufIn.read())!=-1)
3739                 {
3740                     fos.write(bufIn,0,lenIn)
3741                 }
3742 
3743                 OutputStream outIn = s.getOutputStream();
3744                 outIn.write("上传成功".getBytes());
3745                 fos.close();
3746                 s.close();
3747                 ss.close();
3748             }
3749         }
3750         需求5:客户端并发登陆
3751             客户端通过键盘录入用户名,服务端对这个用户名进行校验
3752             如果用户存在,在服务端现实xxx已登录,并在客户端现实欢迎xxx
3753             如果用户不存在,在服务端现实xxx正在尝试登陆,并在客户端现实xxx用户不存在
3754             最多登陆三次。
3755         校验端:
3756         class User implements Runnable
3757         (
3758             private Socket s;
3759             public User(){}
3760             public User(Socket s)
3761             {
3762                 this.s=s;
3763             }
3764             public void run()
3765             {
3766                 try
3767                 {
3768                     BufferedReader bufrIn = new BufferedReader(
3769                             new InputStream(s.getInputStream()))
3770                     String name = bufrIn.readLine();
3771                     if(name==null)
3772                     {
3773                         sop("用户名为空");
3774                         break;
3775                     }
3776                     BufferedReader bufr = new BufferedReader(
3777                             new FileReader("user.txt"));
3778                     PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
3779                     String line = null;
3780                     boolean flag = false;
3781                     while((line = bufr.reanLine())!=null)
3782                     {
3783                         if(line.equals(name))
3784                         {
3785                             flag = true;
3786                             break;
3787                         }
3788                         if(flag)
3789                         {
3790                             sop(name+"已登陆");
3791                             pw.println("欢迎"+name);
3792                             break;
3793                         }
3794                         else
3795                         {
3796                             sop(name+"正尝试登陆");
3797                             pw.println(name+"用户不存在");
3798                         }
3799 
3800                     }
3801                     s.close();
3802                 }
3803                 catch(Exception e)
3804                 {
3805                     throw new RuntimeException("用户校验失败");
3806                 }
3807             }
3808         )
3809         客户端:
3810         class LoginClient
3811         {
3812             public static void main(String[] args)
3813             {
3814                 Socket s = new Socket("192.168.1.253",10000);
3815                 BufferedReader bufr = new BufferedReader(
3816                             new InputStreamReader(System.in)));
3817                 PrintWriter out = new PrintWriter(s.getOutputStream(),true);
3818                 BufferedReader bufIn = new BufferedReader(
3819                             new InputStreamReader(s.getInputStream()));
3820                 for(int i=0;i<3;i++)
3821                 {
3822                     String line = bufr.readLine();
3823                     if(line == null)
3824                     {
3825                         sop("用户名不能为空!");
3826                         break;
3827                     }
3828                     out.write(line);
3829                     String retVal = bufIn.readLine();
3830                     sop(retVal);    
3831                 }
3832                 bufr.close();
3833                 s.close();
3834             }
3835         }
3836         服务端:
3837         class LoginServer
3838         {
3839             public static void main(String[] args)
3840             {
3841                 ServerSocket ss = new ServerSocket(10000);
3842                 while(true)
3843                 {
3844                     Socket s = ss.accept();
3845                     new Thread(new User()).start();
3846                 }
3847             }
3848         }
原文地址:https://www.cnblogs.com/archimedes-euler/p/9975839.html