注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 小五思科技术学习笔记之SSH
 帮助

J2se学习总结


2008-03-13 20:53:47
 标签:学习 总结 J2se   [推送到技术圈]

Java的一些规定
 
1、若在源文件中定义了声明为public的类,需要将类所在的源文件的文件名取名为类名
2、在同一个源文件中有且只能有一个定义为public的类
3、编译时文件名大小写是不敏感的,执行的时候加载的类名是大小写敏感的
 
Java的语法
 
1、byte类型是一个有符号的8位的整数(-128~127)。其他语言的字节类型通常是无符号的整数。
2、为了保持精度,byte型与byte型或整数运算时,将转换为整型后运算。将结果赋值给byte变量需要类型转换。
3、short类型(-32768~32767)
4、java中的char类型可以表示0~65535个字符,利用unicode编码格式
5、可以使用单引号字符或者整数对char型赋值
6、java中小数常量被认为double型,若要表明为float型,在其后加f
7、float是4个字节,double是8个字节
8、java中的boolean只有两个取值true和false
9、java中条件判断只能使用true或者false
 
java中的数组
 
1、java中一维数组在定义的时候是不能够分配空间的,例:
       int num[];//中括号中不能写大小
   只有在定义完成之后为数组分配大小
       num = new int[3];
   java中数组定义建议采取下面的形式:
       int[] num;
   数组可以在定义时进行初始化:
       int[] num = {1, 2, 3};
   或者
       int[] num = new int[]{1, 2, 3};
   注意不要写为:
       int[] num = new int[3]{1, 2, 3};
2、java中的二维数组
   定义:
       int[][] num;
   分配空间:
       num = new int[1][2];
3、java中二维数组每行的列数可以不相同:
       int[][] num;
       num = new int[3][];
       num[0] = new int[1];
       num[1] = new int[2];
       num[2] = new int[3];
   有些像c/c++中的指针数组
4、java中定义一个数值型数组的时候,会自动将数组的元素全部赋值为0
5、当用初始值填充数组时,不要在中括号中填写大小,例:
       int[][] num = new int[2][]{{1, 2, 3}, {4, 5, 6}}; //error
6、java支持不规则数组元素
       int[][] num = {{1, 2, 3}, {4, 5}, {6}};
  
java中的自增操作
 
1、表现形式与c/c++中一样
 
java的移位运算符
 
1、左移<<
   带符号右移>>
   无符号右移>>>
 
java的包
 
1、package语句必须是java源文件中的第一条语句。如果不加package语句,则指定为缺省包或者无名包。
2、包对应着文件系统的目录层次结构。在package语句中,用.来指明包(目录)的层次。
   如果在源文件中定义了package(给类取了包名),则类的完整的名字为:包名.类名 。
3、java中提供的包(package)和文件系统的目录层次结构是相对应的。当为类定义了包名时,  
   要求在硬盘上有相应包名的目录,该目录下有类文件。
4、可以使用/分隔包名和类名,通常使用.
5、包名可以使用多重限定名,例:package p1.p2.p3;//即顶层包p1有子包p2,p2有子包p3,包 
   p3中有当前类。注意:文件系统中应该有相应的目录层次结构。
6可以使用javac的-d参数指定在什么位置生成类的文件,并且会根据源文件中定义的包名生成相应的目录层次结构。未指定-d则在当前目录生成类文件,并且不会生成package指定的目录
层次。
 
import语句
 
1、引入包中的类:import java.io.File;
2、引入整个包: import java.io.*;
3在同一包中的类可以相互引用,无需import语句。
4、java.lang包是自动导入的,不需要显式的加上import语句。
5除非有必要尽量避免导入一个包中的所有类。
 
类的说明符
 
1、类的访问说明符
   (1)public
   (2)default(不加访问说明符时)
2、类的其它修饰符
   (1)final     表明类为最终类,不能派生其它子类
   (2)abstract 抽象类
3将目录下的所有源文件都编译生成:javac -d . *.java
   好处是不需要考虑哪个类先生成了。
4、class关键字前没有加任何访问说明符时,类为缺省类。不同包中的类无法访问。
5、在不同的包之间访问类时,只能访问到包中声明为public的类。
6、缺省的类访问说明符,表明类只能被同一包中的类访问。
 
方法的访问说明符
 
1、方法的访问说明符
   (1)public                   
   (2)protected               
   (3)default(不加访问说明符时)
   (4)private
       
              public    protected    default        private
    同类        v               v           v             v
    同包        v               v           v
    子类        v               v
    不同包      v
       
2、方法的其它修饰符
   (1)static
   (2)final
   (3)abstract
   (4)native
   (5)synchronized
3final方法:为了确保某个函数的行为在继承过程中保持不变,并且不能被覆盖
   (overridden),可以使用final方法。
4、抽象的方法和抽象类:
   *在类中没有方法体的方法就是抽象方法。
   *含有抽象方法的类,即为抽象类。
   *如果一个子类没有实现抽象基类中所有的抽象方法,则子类也成为一个抽象类。
   *我们可以将一个没有任何抽象方法的类声明为abstract,避免由这个类产生任何的对象。
   *抽象类需要声明abstract
 
垃圾回收
 
1、java虚拟机退出之前,会去调用函数finalize()
2、java虚拟机中,垃圾回收是作为一个低优先级的线程在运行。在内存不够的情况下,才会运行垃圾收集器。
3、使用System的静态方法gc()运行垃圾回收器。
 
接口
 
1、接口中所有的方法都是抽象的,定义了一类行为的集合,行为的实现由其实现类来完成。
2、使用interface定义接口,而不是class。
3、类使用implements关键字实现接口。
4、接口中所有的方法都是public abstract。
5、实现一个接口时,如果类需要实例话,则要实现接口中所有的方法。
6、接口不能实例化为一个对象,但实现了接口的类可以作为接口的实例。
7、在接口中声明方法时,不能使用native、static、final、synchronized、private、
   protected等修饰符。
8、和public类一样,public接口也必须定义在与接口同名的文件中。
9、接口中可以有数据成员,这些成员默认都是public static final。
10、访问接口的数据成员的几种形式:
        接口.接口数据成员名称
        实现了接口的类的名称.接口数据成员名称
        实现了接口的类的实例.接口数据成员名称
11、一个接口可以继承自另一个接口。
12java中不允许类的多继承,但允许接口的多继承。
13、在java中,一个类可以实现多个接口。
14、一个类在继承另外一个类的同时,可以实现多个接口。
 
内部类
 
1、内部类:在一个类中定义另外一个类,这个类就叫做内部类或内置类(inner class)。
2、内部类可以让我们将逻辑上相关的一组类组织起来,并由外部类(outer class)来控制内部类的可见性。
3、当我们建立一个inner class时,其对象就拥有了与外部类对象之间的一种关系,这就是通过一个特殊的this reference形成的,使得内部类对象可以随意的访问外部类中的所有的成员。
4、内部类可以随意的访问外部类中所有的成员方法和成员变量(包括私有的成员方法和成员变
   量)。
5、java中凡是用new产生的对象,都是在堆内存中分配的。
6、在内部类中引用外部成员变量可以使用以下形式:
   外部类名.this.成员变量
   例:outer.this.varname
7、若main函数不在外部类中,引用外部类中的内部类,如声明一个内部类,形式如下:
       Outer.Inner inner;
8、如果想要直接实例化一个内部类对象,必须要有一个引用指向外部类对象
   如何在main方法中直接产生内部类对象:
       Outer.Inner inner = outer.new Inner();
9、内部类定义可以放在函数、条件语句、语句块中,并且不管内部类嵌套的层次有多深,都可以访外部类的成员。
10、若方法的内部有内部类,方法定义的局部变量需要被内部类所访问,则需要将变量声明为final 。
11、对于一个类,访问权限可以是缺省的或者是public的。而对于一个内部类,还也可以声明为
    protected 或者 private、abstract、final、static 。如果内部类声明为
    abstract,则内部类就不能实例化了。需要在外部类中再定义一个内部类,从声明为
    abstract的类派生出来,然后再实例化。一个静态的内部类,只能访问外部类中静态
    的成员变量或者一个静态的成员方法。
12、静态的内部类可以有静态的成员函数或变量,非静态内部类中不能有静态的声明。
13、在方法中定义的内部类,如果要访问方法中定义的本地变量或者方法的参数,则变量必须被声明为final。
14、内部类可以声明为private或protected;还可以声明为abstract或final。
15、内部类可以声明为static的,但此时就不能再使用外部类的非static的成员变量和非static的成员方法;
16、非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可以声明static成员。
17、产生一个派生类对象的时候,会调用基类的构造函数,产生一个基类的对象。
18要产生一个内部类对象,首先需要产生一个外部类的对象,然后才能产生内部类对象。从而建立起内部类对象到外部类对象的一个引用关系。
19、为什么使用内部类?
    *在内部类(inner class)中,可以随意的访问外部类成员,这可以让我们更好地组织管理我们的代码,增强代码的可读性。
    *内部类可以用于创建适配器类,适配器类是用于实现接口的类。使用内部类来实现接口,可以更好地定位与接口关联的方法在代码中的位置。
 
java中的异常处理
 
1、java通过异常类表明异常,所有的异常都有个叫做Exception的基类。
2、派生自Exception的异常类,不一定都在java.lang包中。
3、Exception类派生自java.lang.Throwable,从Throwable派生了2个类:
   *Error类:从该类派生的有VitualMachineError(包含了OutOfMemoryError和
             StackOverflowError)和AWTError
   *Exception:从该类派生的有RuntimeException和IOException等
              RuntimeException通常代表了程序编写时的一些错误,这类错误在java中不需
                              要捕获,由java运行时系统自动抛出并自动处理。
4、打开一个不存在的文件、网络连接中断、数组下标越界、正在加载的类文件丢失等都会引发
   异常。
5、java中的异常类定义了程序中遇到的轻微的错误条件。
6、java中的错误类定义了程序中不能恢复的严重错误条件。如内存溢出、类文件格式错误等。
   这一类错误由java运行系统处理,不需要我们去处理。
7、java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给
   java运行时系统,这个过程称为抛出(throw)异常。
8、当java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给
   其处理,这一过程称为捕获(catch)异常。
9、如果java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的java程序也将退出。
10、try/catch/finally语句。
11、一旦引发了异常,调用方法下面的语句就不会再执行了。
12、Exception的方法来自其基类Throwable。
    几个主要的方法:
    getMessage()
    toString()
    printStackTrace()
13、告诉用户使用自己写的方法调用时有可能产生异常,让其做好准备,可以使用java的异常声明语法去声明一个异常,在方法的参数列表后面使用throws关键字抛出一个异常。当我们声明要抛出一个异常,java编译器在编译的时候就会强制我们去捕获这个异常。
14、抛出一个异常的时候,会抛给它的调用者。
    main函数可以将异常抛给java运行时系统。
15、实际编写代码的时候,最好将自行捕获到,在自己的代码中进行处理,打印出一个准确而又
    详尽的信息提示给用户,或者对发生的异常进行补救。
16、所有的异常都是Exception所派生出来的,所以写异常捕获代码时一般将具体的异常捕获放
    在前面,将通用型的放在后面。也就是说由特殊到一般的写catch语句。
17、除了RuntimeException这类异常之外的异常,当我们抛出的时候java编译器都会强制的要
    求我们去进行捕获。
18、在catch到异常后,可以不进行处理,将异常对象再次抛出:
           throw e;
19、throw和throws的区别:
    *当我们声明抛出异常的时候,使用throws关键字;
    *当我们抛出异常的时候,使用throw关键字。
20、程序执行到throw语句,程序将会发生跳转。
21、可以抛出一个新的异常:
          throw new Exception("new exception");
22、定义自己的异常类:
    *派生自Exception;
    *构造方法;
    *构造方法中调用基类的构造方法;(super())
23、声明异常的时候,可以同时声明抛出多个异常。
24、不管程序执行有没有发生异常,finally语句中的代码都会执行(在return前也会执行)。
25、当程序终止运行的时候,finally语句就不会执行了。
26、System.exit(int status)静态方法终止当前正在运行的java虚拟机。其参数status表示
    状态的代码,按照约定,一个非0的状态代码指示了一个非正常的终止。
 
java编程规范
 
1、package的命名
   package的名字由全部小写的字母组成,例如:cn.mypackage
2、class和interface的命名
   class和interface的名字由大写字母开头而其它字母都小写的单词组成,例如:
   Exception、RuntimeException。
3、class变量的命名
   变量的名字用一个小写字母开头,后面的单词用大写字母开头,例如:
   myInfocurrentUser
4class方法的命名
   方法的名字用一个小写字母开头,后面的单词用大写字母开头,例如:
   run()、getInstance()
5、static final常量的命名
   所有字母都大写,并且能表示完整含义。例如:PI
6、参数的命名
   参数的名字和变量的命名规范一致。
7、数组的命名
   数组应该总是用这样的方式命名:byte[] buffer
 
java的常用包
 
1、java.applet:包含一些用于创建java小应用程序的类。
2、java.awt:   包含一些用于编写与平台无关的图形界面(GUI)应用程序的类。
3、java.io:    包含一些用作输入输出(I/O)处理的类。
4、java.lang: 包含一些java语言的基本类与核心类,如String、Math、Integer、System
               和Runtime,提供常用的功能,这个包中的所有类是被隐式导入的。
5、java.net:   包含用于建立网络连接的类,与java.io同时使用完成与网络有关的读写。
6、java.util:包含一些实用工具类和数据结构类。
 
==equals的用法
 
1在java中,boolean、byte、short、int、long、char、float、double这八种是基本数据
   类型,其余的都是引用类型
2==是比较两个变量的值是否相等
    "equals"是比较两个对象变量所代表的对象的内容是否相等
3、当我们声明了一个引用类型变量时,系统只为该变量分配了引用空间,并未创建一个具体的
   对象;当用new为对象分配空间后,将对象的引用赋值给引用变量。
   *可以将java中的引用理解为一个地址,也就是对象的首地址
 
String和StringBuffer
 
1、String str = "abc";
   int i = 3;
   float f = 4.5f;
   char ch = 'a';
   boolean b = true;
   System.out.println(str + i + f + ch + b);
2、针对String的++=,是java中唯一被重载的操作符;在java中,不允许程序员重
   载操作符。
3、String类对象是一个常量对象。(String对象一旦给赋了一个引用之后,它就是一个常量对
   象了)
   String str = "abc";
   str = "def";       //"abc"此时成了垃圾内存,str保存了"def"的引用
4、在处理大量字符串的程序中,我们通常用StringBuffer来替代String。
5、构造一个空的StringBuffer,初始的容量是16个字符。
        StringBuffer()
   超出16个字符,容量会自动增加,这样就不用担心容量不够。
        StringBuffer(int length);
   构造时指定初始容量。
  
   StringBuffer类的一些常用方法:
      int capacity() 返回当前StringBuffer的容量;
      char charAt() 获取一个char;
      StringBuffer delete(int start, int end) 删除StringBuffer中字符串的一个子
                                               串,从开始位置到结束位置。
                                               需要注意的是,删除的结束位置字符通
                                               常是不包括的。可以理解为大于等于起
                                               始位置和小于结束位置。
      StringBuffer reverse()
 
数组
 
1、数组元素是基本数据类型将被初始化为0,是引用类型的将被初始化为NULL
2、当给数组变量赋值为NULL时,相当于把它所保存的引用清除掉了。原来保存的引用的所在的
   对象就成了垃圾对象。所以,如果想让内存成为垃圾内存,可以给保存了对象引用的变量赋
   值为NULL。
3、main方法是由java虚拟机调用的,所以必须是public的。由于java调用main方法时,不需要
   产生任何的对象,所以它要声明为static。不需要返回值,所以声明为void。有一个引用类
   型的数组参数String[] args。
   *args是用来接收命令行参数的,不包括命令行输入的java和java后的类名称。
  
函数的调用
 
1、在java中,传递参数时,都是以传值的方式进行。
2、对于基本数据类型,传递的是数据的拷贝;对于引用类型,传递的是引用的拷贝。
 
 
数组的相关操作
 
1、在java中,所有的数组都有一个缺省的属性length,用于获取数组中元素的个数。
2、数组的复制:System.arraycopy(
                 Object src,
                 int srcPos,
                 Object dest,
                 int destPos,
                 int length)
3、数组的排序:Arrays.sort()。
4、在已排序的数组中查找某个元素:
   Arrays.binarySearch()
5、Arrays类在java.util包中。
6、数组是一种引用类型的变量。
7、Arrays.sort()对于对象排序的要求:数组中的所有元素必须实现了Comparable接口。数组中的所有元素都是可以互相比较的。
   Comparable接口中有一个方法需要被实现:
      public int compareTo(Object o);
      //小于返回负数,等于返回0,大于返回正数。
8、String类本身已经实现了Comparable接口,可以直接调用compareTo进行比较。
 
封装类
 
1、针对八种基本数据类型定义的相应的引用类型--封装类:
  
    基本数据类型    封装类
    boolean     Boolean
    byte            Byte
    short           Short
    int         Integer
    long            Long
    char            Character
    float           Float
    double          Double
2、从Integer中取出int值使用函数intValue();
   从Long中取出long值使用函数longValue()
   从Float中取出float值使用函数floatValue();
3、将Integer转换为字符串类型toString()
4、将String类型转换为Integer可以用Integer.valueOf(String s)静态方法。
5、基本数据类型转换为String可以通过是使用封装类型的toString()方法达到目的。
6、将String类型转换为基本数据类型可以通过调用封装类的parseXXX()静态方法来达到目
   的。例:int n = Integer.parseInt("123");
          float f = Float.parseFloat("12.34");
   注意Boolean类型没有类似的parse用法。
7、所有的封装类都是只读类型没有提供任何方法修改其内容。
 
 
程序、进程和线程
 
1、程序是计算机指令的集合,它以文件的形式存储在磁盘上。
   进程:是一个程序在其自身的地址空间中的一次执行活动。
   *进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申
    请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资
    源。
   线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。
   *线程又成为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在
    于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程
    间的通信远较进程简单。
2、一个进程中至少会有一个线程。
 
java对多线程的支持
 
1、java在语言级提供了对多线程程序设计的支持。
2、实现多线程程序的两种方式:
   (1)从Thread类继承;
   (2)实现Runnable接口。
3、一个Thread对象就代表了进程当中的一个线程。java虚拟机允许一个应用程序可以拥
有多个并发运行的线程。当一个JVM启动的时候,通常由一个单一的非后台线程(典
型的就是调用main方法的线程)
4、可以利用线程类当中的静态方法
   static Thread currentThread()返回当前正在执行的Thread对象的引用,也就是获取
当前线程。
5、可以利用线程类当中的方法
    String getName()获取线程的名字。
   例:Thread.currentThread().getName();
6、让线程可以运行我们的代码需要覆盖其run()方法。
7、让线程运行需要调用线程类中的一个方法start。当我们调用start方法的时候就会导
致这个线程开始执行,然后java的虚拟机就会调用这个线程的run方法。可以把run
方法理解为线程的入口函数。
8、可以把一个线程设置为后台线程,利用线程类中的一个方法:
   void setDaemon(boolean on)标记这个线程为后台线程或者用户线程。
   如果参数设置为真,标记该线程为后台线程。
      *main方法所在的线程是非后台线程。
9、一个正在执行的线程可以放弃它执行的权利让另一个线程运行,使用Thread类中的静态方法 static void yield()导致当前正在执行的thread对象临时暂停允许其它thread执行。
10、java中每一个线程都有一个优先级,可以通过Thread类中的方法int getPriority()
和void setPriority(int newPriority)去得到一个线程的优先级和设置线程的优先级。
    *线程优先级的取值范围(1~10):
     三个常量(MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY)表示线程最大、最小、
默认优先级,它们表示的整数值分别是10、1、5。
    *可以随时去设置线程的优先级,可以在start()前也可以在start()后去修改。
    *java中如果一个线程的优先级较高,那么它将始终获得运行的机会
 
java多线程的支持
 
1、java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行。
2、在java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等CPU时间的进程)。抢占式调度模型就是许多线程处于可以运行状态(等待状态),但实际上只有一个线程在运行。该线程一直运行到它终止进入可运行状态(等待状态),或者另一个具有更高优先级的线程可变成可运行状态。在后一种情况下,低优先级的线程被高优先级的线程抢占,高优先级的线程获得运行的机会。(程序编写中,不要利用高优先级将始终运行这个特点来完成某些功能)
 
3、java线程调度器支持不同优先级线程的抢先方式,但其本身不支持相同优先级线程的
时间片轮转。
4、java运行时系统所在的操作系统支持时间片的轮转,则线程调度器就支持相同优先级线程的时间片轮换。
 
 
实现线程的第二种方式(实现Runnable接口)
 
1、 Thread类其实也实现了Runnable接口
2、 对于一个类来说,如果说它的实例想要被一个线程去执行,就应该实现Runnable接口。该接口只有一个方法run()。
3、 构造Thread的时候可以传递一个实现了Runnable接口的对象:
Thread(Runnable target)作为Thread构造函数的参数。Java虚拟机会调用实现了Runnable接口对象当中的run()方法来执行我们的代码。
 
MyThread mt = new MyThread();
New Thread(mt).start();
4、 通常,如果不需要修改线程类当中除了run()方法之外的其它方法的行为之外,最好都
是要去实现Runnable接口。
5、 实现Runnable接口有两个好处:
*已经继承了其他类无法再继承Thread类时,就实现Runnable接口;
*如果多个线程访问同一种资源的话是很方便的:
6、Thread.sleep(long millis)让当前正在执行的线程睡眠一会。
7、 让一个线程进入一段代码后即使休眠了其它线程也不能进入这段代码,除非它将剩余的代码执行完成之后,其它的线程才能后进入到这段代码之中。可以利用java语言中的同步来完成。
 
 
线程的同步
 
1、在一个程序中,代码段访问了同一个对象从单独的、并发的线程当中,这个代码段就
叫做“临界区”。采用同步的机制对临界区进行保护。
2、同步的两种方式:同步块和同步方法。这两种方式都是通过一个synchronized关键字
来完成的。
A.对于同步块来说,在synchronized后面需要加上一个对象,这个对象是任意的一个
对象。可以定义一个String类型的,也可以定义一个Object类型的对象:
Object obj = new Object();
在synchronized后面加上这个对象:
synchronized(obj)
{
      //保护的代码段
     
}
这样就实现了一个同步。
 
B.*同步方法的实现:
在方法的前面加上synchronized
Public synchronized void method1()
{
}
 
同步的方法可以完成跟同步块一样的结果。同步块需要有一个对象,同步方法只需要
在方法的前面加上一个synchronized关键字。
 
3、同步块的实现机制是怎样完成的呢?java语言中每一个对象都有一个监视器,或者叫
做锁。当我们第一个线程进来的时候首先要判断一下obj这个对象的监视器是否被加
锁,如果没有被加锁,那么它就会将obj的监视器加锁,然后往下执行(遇到sleep
睡眠)如果其它线程执行到Synchronized会判断到obj已经被加锁,那么它们只能
等待。第一个线程执行完受保护的代码后,会将obj的监视器解锁。其它线程就可以
进入到这个同步的代码段中。
 
同步方法的实现机制又是怎样的呢?当我们一个线程进入这个方法的时候,也需要加
上一把锁,同步的方法是给类中的this变量的监视器加锁。当一个线程进入同步方法
的时候,会察看this对象是否加锁,没有加锁则会加锁。然后进入到方法内部,方法
执行完后,会将this解锁,其它线程在this解锁后才可以进入。
4、同步方法利用的是this所代表的对象的锁。
5、因为静态方法只属于类本身,而不属于某个对象。每个类都对应有一个class对象,
步静态方法使用的就是方法所在的类所对应的class对象的监视器。
 
 
线程的死锁
 
1、 哲学家进餐的问题。
2、 线程1锁住了对象A的监视器,等待对象B的监视器,线程2锁住了对象B的监视器,等待对象A的监视器,就造成了死锁。
3、 Thread类中两个废弃的方法就很容易造成死锁,suspend()、resume()
 
Wait、notify、nofityAll方法
 
1、 每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,它的等待队列是空的。
2、我们应该在当前线程锁住对象的锁后,去调用该对象的wait方法。也就是说wait方法只能够在同步方法或者同步块中被调用。但我们调用wait方法的时候,这个线程就进入了这个对象的等待队列当中。
3、 当调用对象的notify方法时,将从该对象的等待队列中删除一个任意选择的线程,这个线程将再次成为可运行的线程。
4、 当调用对象的notifyAll方法时,将从该对象的等待队列中删除所有等待的线程,这些线程将成为可运行的线程。
5、 Wait和notify主要用于producer-consumer这种关系中。
6、 Wait和notify方法必须在一个同步的块或者方法中被调用,并且针对同一对象的等待队列
 
 
线程的状态
 
1、 用new创建一个线程的时候,线程就处于new状态。
当调用start方法的时候,线程处于可运行(Runnable)状态。
一个尚未运行的线程是Runnable状态,一个正在运行的线程也是Runnable状态。
当一个正在运行的线程调用yield方法的时候,线程调度器会选择另外一个线程去运行,调用yield方法的线程仍然处于Runnable状态。
当我们调用sleep、wait、suspend或者I/O阻塞时线程就进入Not Runnable状态。当一个线程sleep结束,或者调用了notify方法、resume方法或者I/O操作完成,线程就会从Not Runnable状态返回Runnable状态。
(resume和suspend这两个函数已经被废弃了,不建议我们再使用)
当一个处于可运行状态的线程它的run方法执行完毕或者调用stop方法,线程就进入了Dead状态终止了。
在Not Runnable状态的时候,调用了stop方法,线程也会终止。
(stop方法是用来停止一个线程的,这个方法也已经废弃了,因为这个方法是不安全的,当调用stop方法时,它会解锁先前锁住的所有的监视器,这样的话,其它的线程就可以去访问被保护的对象,导致对象的状态不一致,结果是不可预料的)
 
↓new thread
                 yield
     start                  sleep wait suspend I/O阻塞
New →→→→→→ Runnable →→→→→→→→→→→→→→→→→→Not Runnable
                          ←←←←←←←←←←←←←←←←←←       
                          Sleep结束、notify resume I/O操作完成     
                                                                  
                                                                 
                                                              
                               ↘ run方法退出               stop方法调用                            
                                 ↘ stop调用                
                                                        
                                                      
                                                    
                                                 
                                              Dead
 
线程的终止(两种方式)
 
1、 设置一个flag变量
2、 interrupt()方法(可以中断一个线程)
 
 
File
 
1、 一个File类的对象,表示了磁盘上的文件或目录。
2、 File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作。
3、 可以通过一个文件名来构造一个File类对象:
File(String pathname)
   也可以通过指定一个File对象,再指定它的文件名:
    File(String parent, String child)去构造一个File对象,这里的parent表示
文件或目录所在的父目录。Child指定文件
名。
4、File类不只可以用来表示一个文件还可以表示一个目录。
5、File类中:
    Boolean canRead() //检测文件是否可读
    Boolean canWrite()//检测文件是否可写
    Boolean createNewFile() 当我们构造一个File对象的时候可以调用
createNewFile()去创建一个新的文件
1、 在我们进行I/O操作的时候,经常会出现一些异常。如:磁盘空间不足、因为磁盘故障不能创建文件。所以在用java.io包中的类进行编程的时候,经常会需要捕获一些异常。为了简单起见,可以在main后throws出异常,让java虚拟机去处理。
import java.io.*;
 
class FileTest
{
public static void main(String[] args) throws Exception
{
    File f = new File("1.txt");
    f.createNewFile();
}
}
2、 File类还可以用来创建目录:
Boolean mkdir(); //用来创建一个目录
例:
    File f = new File("1.txt");
     //f.createNewFile();
     f.mkdir();
3、 利用绝对路径创建一个文件:
File f = new File("D:\\MyWorks\\lessons\\java\\lesson7\\1.txt");
f.createNewFile();
10、File类提供了常量表示目录的分隔符:
    Static String separator //系统独立的分隔符在windows下会被解释为“\”,
//在linux下为/
    Static char separatorChar //也是用来表示分隔符,只不过一个使用String类
//型来表示,一个是用char表示
4、 在当前盘符下直接写一个目录分隔符,也可以表示当前盘符的根目录。
 
 
 
I/O 流概述
 
  输入/输出处理是程序设计中非常重要的一部分,比如从键盘读取数据、从文件中读取数据或向文件中写数据等等。
 
  Java把这些不同类型的输入、输出源抽象为流(stream),用统一接口来表示,从而使程序简单明了。
 
  Jdk 提供了包java.io,其中包括一系列的类来实现输入/输出处理。下面我们对java.io包的内容进行概要的介绍。
 
 I/O流的层次
 
  1.字节流
 
  2.字符流
 
  3.对象流
 
  4.其它
 
---------------------------------
 1.字节流:
 
  从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。
  ◇ InputStream、OutputStream
  ◇ FileInputStream、FileOutputStream
  ◇ PipedInputStream、PipedOutputStream
  ◇ ByteArrayInputStream、ByteArrayOutputStream
  ◇ FilterInputStream、FilterOutputStream
  ◇ DataInputStream、DataOutputStream
  ◇ BufferedInputStream、BufferedOutputStream
 
 2.字符流:
 
  从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位。
  ◇ Reader、Writer
  ◇ InputStreamReader、OutputStreamWriter
  ◇ FileReader、FileWriter
  ◇ CharArrayReader、CharArrayWriter
  ◇ PipedReader、PipedWriter
  ◇ FilterReader、FilterWriter
  ◇ BufferedReader、BufferedWriter
  ◇ StringReader、StringWriter
 
 3.对象流
 
  ◇ ObjectInputStream、ObjectOutputStream
 
 4.其它
 
  ◇ 文件处理:
  File、RandomAccessFile;
 
  ◇ 接口
  DataInput、DataOutput、ObjectInput、ObjectOutput;
 
-----------------------------------
1.InputStream
 
  ◇ 从流中读取数据:
  int read( ); //读取一个字节,返回值为所读的字节
  int read( byte b[ ] ); //读取多个字节,放置到字节数组b中,通常
              //读取的字节数量为b的长度,返回值为实际
              //读取的字节的数量
  int read( byte b[ ], int off, int len ); //读取len个字节,放置
                       //到以下标off开始字节
                       //数组b中,返回值为实
                       //际读取的字节的数量
  int available( );   //返回值为流中尚未读取的字节的数量
  long skip( long n ); //读指针跳过n个字节不读,返回值为实际
             //跳过的字节数量
 
  ◇ 关闭流:
  close( ); //流操作完毕后必须关闭
  
  ◇ 使用输入流中的标记:
  void mark( int readlimit ); //记录当前读指针所在位置,readlimit
                 //表示读指针读出readlimit个字节后
                //所标记的指针位置才失效
  void reset( );     //把读指针重新指向用mark方法所记录的位置
  boolean markSupported( ); //当前的流是否支持读指针的记录功能
 
  有关每个方法的使用,详见java API。
 
 
 2.OutputStream
 
  ◇ 输出数据:
  void write( int b );   //往流中写一个字节b
  void write( byte b[ ] ); //往流中写一个字节数组b
  void write( byte b[ ], int off, int len ); //把字节数组b中从
              //下标off开始,长度为len的字节写入流中
 
  ◇ flush( )       //刷空输出流,并输出所有被缓存的字节
  由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中。
 
  ◇ 关闭流:
   close( );       //流操作完毕后必须关闭
 
-----------------------------------
进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:FileNotFoundException, EOFException, IOException
-----------------------------------
文件的顺序处理
 
  类FileInputStream和FileOutputStream用来进行文件I/O处理,由它们所提供的方法可以打开本地主机上的文件,并进行顺序的读/写。例如,下列的语句段是顺序读取文件名为text.txt的文件里的内容,并显示在控制台上面,直到文件结束为止。
 
例:
    FileInputStream fis;
   try{
    fis = new FileInputStream( "text.txt" );
   System.out.print( "content of text is : ");
     int b;
     while( (b=fis.read())!=-1 ) //顺序读取文件text里的内容并赋值
                    给整型变量b,直到文件结束为止。
     {