java 基础。。。。。

1、JAVA CLASSPATH
    CLASSPATH一般设置为.;%JAVA_HOME%/lib;这样JAVA解释器首先在当前目录寻找类,如果未找到则到lib目录寻找。
    这样如果当前目录
    如果类如Good.java在E:下,这里在CMD中切换到E:编译及解释都通过,但切换到D:则会提示找不到类Good.这时可在CMD中输入命令SET CLASSPATH=E:
    这样JAVA解释器执行时会从CLASSPATH所定的目录开始寻找,这时会发现即使命令提示符在D:输入JAVA Good仍可执行。
    按此思路如果此时我输入命令:SET CLASSPATH=D:/,而Good.java文件仍在E:根目录下,此时我在CMD中切换到E:,执行JAVA Good会发现找不到类Good.
    这还是因为寻找的路径是按SET CLASSPATH来的,所以在这里你会发现虽然明明E:下有这个文件,但切换到这个目录反而执行不了。。
    要想解决这个问题,需要修改CLASSPATH,如SET CLASSPATH=D:/;.;这样如果在D下面寻找不到所需的类,会再到当前目录寻找。这里要注意的是这个"当前"是指的CMD中你所切换的目录,如果此时不在E:而在F:下执行命令,也会提示找不到类的。
     
2、JAVA数据类型
    JAVA数据类型分数值数据类型和布尔数据类型(boolean),数值数据类型分字符类型char,整型(short,int,long),实型(float,double)型。
    boolean和byte为1个字节,char,short为两个字节,int,float为四个字节,long,double为八个字节。
   
            关于基本数据类型运算时转换时的几点说明:
                1、运算时总是将小的类型转换为运算式中最大的类型再进行运算;
                2、byte,char,short不会互相转换,它们会先转换成int类型再运算;
                3、整型默认为int类型,实型默认为double类型。这条很重要,很多下面的问题都可从这里得到解释。如
               
                        (1) 注意:byte类型参与运算的时候会自动转为int型。。
                        byte b=2;      //特殊点:JAVA中允许将int类型直接声明给byte,char,short类型,即byte b=2; 中2为int类型;char c=12;但要注意不能超过它们各自的范围。如byte最大为128则不能byte b=129;
                        b=b*3;                //这里运算时,将b看作int类型,3为int类型。所以要转换。
                        这里应使用强制类型转换:b=(byte)(b*3);
                        但是注意了:
                        long L1=123;      //没错
                        long L1=L1+23;   //没错
                        (2) 实型:
                        float f=3.2;
                        这个定义编译时会出错。原因是系统会将3.2当作double型来看,所以这里改为:
                        float f=3.2f;
                        (3)注意各类型变量的默认值,boolean型默认为true,值只有true和false.
    (4)数组:不能象c语言一样定义:int a[3];
        JAVA中定义数组应为:int[] a = new int[3];
    也要注意:int[] num={1,2,3};这是对的,但下面却会提示错误。
        int[] num1;
        num1={1,2,3,4};//error
    还要注意:int[] num1=new int[]{1,2,3};//right
        int[] num2=new int[3]{1,2,3};//error,如果在后面已列出值就不要再加3这一数据元素个数了。
    另一种数组的定义和赋值方式:
        int[] num=new int[3];
        num[0]=2;num[1]=4;num[2]=322;
    (5)字符的赋值:可以给字符赋整数如:char c=97;

3、for语句
    for(int i=0;i<10;i++)
        {
            System.out.println("sf");
        }
        System.out.println(i);//error*/
    要注意,java是for语句中定义的i,只在for语句范围内有效。

4、位运算
    位运算有&(按位与)、|(按位或)、^(按位异或)、~取反,<<左移运算符,>>右移运算符。
    按位与:
        一般用于清零,即找一个与其相反的数相与结果为0.如:00101011与10010100按位与结果为00000000
        按位与另一用途为保留整数的高位或低位字节.如将:00101100 10101100与0000000011111111或1111111100000000相按位与操作结果使其只保留低位字节和高位字节.
    按位或:
        常用于将低八位或高八位全置为1.如a:00101100 10101100 与o(0377)即二进制的00000000 11111111相或,置低八位为1.
    按位异或:
        按位异或,即同则0异则1.如a:00111001^00101100=00010101
        常用于使特定位翻转,即想使哪几位由1变为0,只需将其与1异或即可.
        与0相异或,保留原值.
        异或还用做交换两个值,不用临时变量...                 
            fn(int x,int y)
            {
                x=x+y;
                y=x-y;
                x=x-y;
            }
        如a=3,b=4想将a,b的值互换只需:a=a^b,b=b^a,a=a^b;
            如:   a=011
               (^)b=100
            _____________
              a=a^b=111=7  (异或之后:a=7)
                (^)b=100
            _____________
              b=b^a=011=3  (异或之后:b=3)
                              a=111=7
                        ______________
                          a=a^b=100=4  (异或之后:a=4)
            最终完成了a与b的互换.这可用于排序中交换值,而不用声明temp变量.
        推导:b=b^a,而a=a^b,有b=b^(a^b)=a^b^b,b^b=0,所以:b=a^0,而上面说过与0异或保留值.故b=a;
             a=a^b,而a=a^b,b=b^a=b^(a^b),所以,a=a^b^(b^(a^b))=a^a^b^b^b=b;即a=b;
    按位取反:各位均取反。
    左移运算符:二进制位整体向左移,右补0,如:3=00000011,向左移两位,右补0得:00001100=12,由此可知,左移相当于乘2,左移两位3*4=12;
        左移运算比乘法快很多,有些C编译程序自动将乘2的运算用左移一位来实现,将乘2(n)的幂运算处理为左移n位。
        但要注意的是:如c语言中unsign int 为2字节,取值范围为0-255,所以64(01000000)左移一位时溢出为0,乘2,128,如果再左移一位,则溢出1,得到结果为0.
    右移运算符:右移n位相当于除以2的n次方。
        右移需要注意符号位的问题,如果符号位为0,即为正,则移入0.如果符号位为1即负数,则右移之后,左边是补0还是补1取决于所用的计算机系统。
        左边补0的称为逻辑右移,即简单右移;
        左边补1的称为算术右移。
    上述为c语言中的右移表述,
        在java及javascript语法中
        注意>>(Signed right shift)表示带符号右移,即右移后左补1;
        >>>(Unsigned right shift)表示无符号右移,即右移后左补0;
    如: a            x                 x<<2              x>>2                  x>>>2
         17       00010001           00|01000100        00000100|01            00000100|01
        -17       11101111 (补码)    11|10111100        11111011|11(补码)      00111011|11
        如:a(113755)   1001011111101101  a>>1:0100101111110110(逻辑左移),a>>1:1100101111110110(算术右移)
    用操作系统上的计算机由10进制到二进制的转换得到的就是补码值.

5、求一负数的补码。(正数的补码与原码是一样的,所以如果给出补码符号位为0则表示正数,补码即原码)
    如题:(1)将其转换成十进制数,取它的绝对值(2)将它的绝对值的二进制行式取反(3)取反后加1、
        如-6.求6的二进制为:00000110,取反得:11111001,加1:11111010,-6的补码即为:11111010.
        上面方法也可以理解为:负数的符号位不变,其它各位取反再加1.即-6:10000110, 取反:11111001,加1:11111010.

6、已知一个负数的补码,求这个负数的值的步骤。
    如题:(1)将各位取反。(2)将其转换成十进制数(3)加上负号再减1.
        如:x的补码为:11111010,求x=?  采用以上方法得:取反:00000101,得5,加上负号再减1,-5-1=-6.
            x=-6.
        如上面例4中-17经过右移后得:11111011求这个值。取反:00000100,十进制4,加负号再减1得-5.
          (2)也可以先依靠补码求出原码,再求值.方法就是对该补码再求补码
            如:x的补码为:11111010,求x的原码.由于最高位为1即负数,所以符号位不变其余各位取反得10000101,再加1得10000110即-6

7、在JAVA中BIN目录中JAVAP为反编译工具,通过JAVAP Student可以查看到Student.java中的有关成员变量和方法的定义。

8、构造函数:当你自己新创建了一构造函数时即进行了构造函数的重载时,还应该声明默认的构造函数,因为当你创建了新的构造函数时系统不会自动创建默认构造函数
    所以当你要创建一个不带参数的对象时,编译器会提示没有相应的构造函数与之对应。但当你创建对象是传了参数则不会提示出错。

9、this关键字的使用:
    (1)、当成员变量中的变量名与成员函数也包括构造函数中的形参名相同时,可在函数内使用this.x=x来引用成员数据并为成员变量赋值。
    (2)、需明确使用当前对象的句柄,this返回当前对象的引用。
        例如:public class Leaf {
              private int i = 0;
              Leaf increment() {
                i++;
                return this;
              }
              void print() {
                System.out.println("i = " + i);
              }
              public static void main(String[] args) {
                Leaf x = new Leaf();
                x.increment().increment().increment().print();
              }
            }
    (3)、在构建器里调用构建器:注意的是应该放在构造函数的最前面。
        例如:public class Flower {
              private int petalCount = 0;
              private String s = new String("null");
              Flower(int petals) {
                petalCount = petals;
                System.out.println(
                  "Constructor w/ int arg only, petalCount= "
                  + petalCount);
              }
              Flower(String ss) {
                System.out.println(
                  "Constructor w/ String arg only, s=" + ss);
                s = ss;
              }
              Flower(String s, int petals) {
                this(petals);
            //!    this(s); // Can't call two!
                this.s = s; // Another use of "this"
                System.out.println("String & int args");
              }
              Flower() {
                this("hi", 47);
                System.out.println(
                  "default constructor (no args)");
              }
              void print() {
            //!    this(11); // Not inside non-constructor!
                System.out.println(
                  "petalCount = " + petalCount + " s = "+ s);
              }
              public static void main(String[] args) {
                Flower x = new Flower();
                x.print();
              }
            }
        尽管可用this调用一个构建器,但不可调用两个   

10、static关键字的使用:
    Static关键字:
    通常只有创建了对象才能分配内存,才能够使用类中的方法.假如我要一段代码保存数据的内存或我要一个不从属任何对象的方法,则通过Static关键字实现.
     当你声明某种东西是static的时候,你的意思是这项数据或方法没有被连到任何一个类的实例.因此即使不创建这个类 的实例也可以使用这个static数据或方法.
     但是static的方法不能直接访问非static的成员或方法.
    static数据及方法的访问:
    class StaticTest
    {
        static int i=23;
    }
    (1)可以用两种方法使用变量i,
    一种使用类的对象StaticTest st1=new StaticTest();st1.i++;
    一种是直接使用类名.StaticTest.i++;
    注意:如果使用类的多个对象使用变量i时,改变其中一个另一个跟着改变,因为他们使用的是同一段内存.
    StaticTest st1=new StaticTest();
    StaticTest st2=new StaticTest();
    st1.i++;
    st2.i++;
   
     (2)特别注意:
    public class Point
    {
        int x;
        void output()
        {}
        static void output(int x)
        {
            this.x=x;//这里static声明的成员函数是不能访问非static的成员变量的。除非将x声明成:static int x;
        }
    }


    (3)将static变量也称为类变量,其他变量则可称为实例变量。同样有类方法,实例方法。
    要注意的是:在非static方法中是可以调用static方法和成员变量的。
    如main函数中的方法.
    public static void main(String[] args){
       System.out.println("slfsfsfsf");
    }
    因为out是System类中声明为static类型的对象
    另外main方法也是定义成static的,这是因为当类加载时并没有创建实例,而JAVA中都是以类为单元的,所以这里定义为static,便于不同类加载它。

11、final
    final int a=3;
    或final int a;
      Point()
      {
             //this(1,1);注意:this(1,1)一定要放在构造函数最前面。
             a=3;
      }
      Point(int x,int y)
      {
        a=3; //注意:如果final类型的常量在定义时没有初始化,那么在构造函数中初始化时需要注意,即所有构造函数中都要有初始化语句a=3;
      }
     即final声明一个常量并初始化,或先声明然后在构造函数中初始化。
     但是要注意的是:
        常量一般声明为static,即static final int a=3;这里因为声明的是static的不属于任何实例的,所以这时一定要在常量声明时初始化,不能在构造函数中初始化了。

12、继承性
    JAVA不允许类的多继承。C++当中是允许多继承的。当子类与超类中存在相同的方法时,超类的方法被隐藏,即超类对象调用超类中的方法,子类对象调用子类的方法。
    如:class Animal
        {
            int height ,weight;
            void sleep()
            {
                System.out.println(" Animal sleep");
            }
            void eat()
            {
                System.out.println(" Animal eate");
            }
        }

        class Fish extends Animal
        {
            void eat()
            {
                System.out.println(" Fish eate");
            }
        }

        class Integeration
        {
            public static void main(String[] args)
            {
                Animal an= new Animal();
                Fish fh = new Fish();
                an.eat();
                fh.eat();
            }
           
        }
        结果为: Animal eate
             Fish eate

13、super的使用
    super用于在子类中对父类的访问
            可以利用super来访问父类被子类隐藏的变量或方法。也就是说当父类与子类都有某一方法的定义时,如果我想在子类中调用父类中的这个方法,那么使用super来实现。
            如:class Cleanser {
                  private String s = new String("Cleanser");
                   public void scrub() { append(" scrub()"); }
                  public void print() { System.out.println(s); }
                  }
       
                public class Detergent extends Cleanser {
                  public void scrub() {
                    append(" Detergent.scrub()");
                    super.scrub(); // Call base-class version
                  }
                 
                  public static void main(String[] args) {
                    Detergent x = new Detergent();
                    x.scrub();
                    x.print();
                   }
                }
       
                   

14、继承的执行顺序及构造函数的调用过程:
    程序如下:
            class act1
            {
                act1(){
                System.out.println("act1 constructor");}
            }
       
            class act2 extends act1
            {
                act2(){
                System.out.println("act2 constructor");}
            }
       
            public class act3 extends act2
            {
                act3(){
                System.out.println("act3 constructor");}
                public static void main(String[] args)
                {
                    act3 x=new act3();
                }
            }
       
       
            结果如下:
            C:/java>java act3
            act1 constructor
            act2 constructor
            act3 constructor
    说明:在衍生类的构建器中,Java会自动插入对基础类构建器的调用。这里正是super关键字的用处所在:即在子类中隐藏了语句super。父类构造函数名()。

15、以下示例用带参数的构造函数来说明super在继承中调用构造函数时所起的作用。
                class act11
                {
                    act11(int i){
                    System.out.println("act11 constructor");}
                }
           
                class act12 extends act11
                {
                    act12(int i){
                        super(i);
                    System.out.println("act12 constructor");}
                }
           
                public class act13 extends act12
                {
                    act13(){
                        super(13);
                    System.out.println("act13 constructor");}
                    public static void main(String[] args)
                    {
                        act13 x=new act13();
                    }
                }
           
                结果为:
                C:/java>java act13
                act11 constructor
                act12 constructor
                act13 constructor
    说明:
    含有自变量的构建器
    例14中有自己默认的构建器;也就是说,它们不含任何自变量。编译器可以很容易地调用它们,因为不存在具体传递什么自变量的问题。
    如果类没有默认的自变量,或者想调用含有一个自变量的某个基础类构建器,必须明确地编写对基础类的调用代码。这是用super关键字以及适当的自变量列表实现的。
    注意区别super与this的使用,this用于在同一类中某一构造函数中调用另一构造函数;而super则不只限于构造函数,用于在继承类中调用父类中的具有相同特性的函数。
    super用来调用基类的带参数的构造函数时应该注意的地方:
            看下面两段代码:一个是在继承类中有super(i)调用基类带参数构造函数,另一个则没有,注意看他们的输出值。
                public class Test {
                    public static int i ;
                    public static void main(String[] args) {
                        TT t = new TT(23);
                        }
                    }   
                class T{
                    protected float j=2.0f;
                    public T(){
                        System.out.println("fater class constuctor");
                    }   
                    public T(int i){
                        System.out.println("fater class constuctor tt="+i);
                    }
                }
                class TT extends T{
                    public TT(){
                        System.out.println("child class contructor");
                    }   
                    public TT(int i){
                        super(i);
                        System.out.print("chiled="+i);
                    }
                       
                }
                输出结果为:
                fater class constuctor tt=23
                chiled=23
                再看:
                public class Test {
                    public static int i ;
                    public static void main(String[] args) {
                        TT t = new TT(23);
                        }
                    }   
                class T{
                    protected float j=2.0f;
                    public T(){
                        System.out.println("fater class constuctor");       //当没用用super(i)显式调用基类的构造方法的时候,JAVA虚拟机会自动找基类的无参构造函数。
                    }   
                    public T(int i){
                        System.out.println("fater class constuctor tt="+i);
                    }
                }
                class TT extends T{
                    public TT(){
                        System.out.println("child class contructor");
                    }   
                    public TT(int i){
                        //super(i);                           //作了注释
                        System.out.print("chiled="+i);
                    }
                       
                }
                输出结果为:
                fater class constuctor
                chiled=23
                无super(i)调用时,自动调用基类无参的构造方法,再执行自身的构造方法
               
                下面我把基类的无参构造方法注释掉:
                public class Test {
                    public static int i ;
                    public static void main(String[] args) {
                        TT t = new TT(23);
                        }
                    }   
                class T{
                    protected float j=2.0f;
                    /*
                    public T(){
                        System.out.println("fater class constuctor");
                    }   
                    */
                    public T(int i){
                        System.out.println("fater class constuctor tt="+i);
                    }
                }
                class TT extends T{
                    public TT(){
                        System.out.println("child class contructor");
                    }   
                    public TT(int i){
                        //super(i);
                        System.out.print("chiled="+i);
                    }
                       
                }
                提示报错:
                    Test.java:19: 找不到符号
                    符号: 构造函数 T()
                    位置: 类 T
                            public TT(){
                                      
   
16、java中文件名及public类名关系
            (1) 每个编译单元(文件)都只能有一个public类。每个编译单元有一个公共接口的概念是由那个公共类表达出来的。根据自己的需要,它可拥有任意多个提供支撑的“友好”类。但若在一个编译单元里使用了多个public类,编译器就会向我们提示一条出错消息。
            (2) public类的名字必须与包含了编译单元的那个文件的名字完全相符,甚至包括它的大小写形式。所以对于Widget来说,文件的名字必须是Widget.java,而不应是widget.java或者WIDGET.java。同样地,如果出现不符,就会报告一个编译期错误。
            (3) 可能(但并常见)有一个编译单元根本没有任何公共类。此时,可按自己的意愿任意指定文件名,不过应注意,在通过java命令执行的时候,后面应该跟:具有main方法的类名。

17、多态性
        动态绑定:指执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际的类型调用相应方法。
                首先:多态性是通过覆盖父类的方法来实现的,在运行时通过传递的对象引用来调用相应的方法。多态性与方法的重载和覆盖是密不可分的。
                class Animal
                {
                    int height ,weight;
                    void sleep()
                    {
                        System.out.println(" Animal sleep");
                    }
                    void eat()
                    {
                        System.out.println(" Animal eate");
                    }
                }
           
                class Fish extends Animal
                {
                    void eat()
                    {
                        System.out.println(" Fish eate");
                    }
                }
           
                class Integeration
                {
                    static void fn(Animal an)
                    {
                        an.eat();
                    }
                    public static void main(String[] args)
                    {
                        Animal an;
                        Fish fh=new Fish();
                        an=fh;
                        Integeration.fn(an);
                    }   
                }
                结果为:Fish eate.
               
                类中通过eat方法的覆盖,及将Fish引用赋给Animal引用,当调用静态方法fn时,虽然参数类型为Animal,但实际传过来的是Fish的引用,调用的是子类Fish类中的eate方法;
                java利用其多态性输出结果为:Fish eate.
        在这里注意,假如Fish类中没有eate方法,那么结果将是输出Animal eate.
           
                java中:重载也称为编译时多态,覆盖称为运行时多态。
               
                >>>  对象的转型
                    规则:
                    1、一个基类的引用可以指向其子类的对象。 如:Animal a = new Dog();
                    2、一个基类的引用不可访问子类新增的成员变量或方法。
                                派生类新增的功能基类肯定看不到。。
                    3、可使用(引用变量 instanceof 类名)来判断该引用变量所"指向"的对象是否属于该类或该类的子类。
                    4、子类的对象可以当作基类来使用称向上转型upcasting,反之称为向下转型downcasting.
                        如下:Animal类,Dog类为子类
                            public class TestIns{
                                public static void main(String[] args){
                                    Dog d = new Dog("xiaohei","black");
                                    d.print();
                                    d.swim();
                                    Animal a = new Dog("xiaobai","white");
                                    a.print();
                                //    a.swim();                   //Animal a只认Dog类中从基类中继承出来的方法或成员,对swim()这一子类中新增的方法不可见。
                                }
                            }
                           
                            class Animal{
                                String name;
                                public Animal(String name){
                                    this.name = name;
                                }
                                    public void print(){
                                        System.out.println("name="+name);
                                }
                            }
                           
                            class Dog extends Animal{
                                String furColor;
                                public Dog(String name,String furColor){
                                    super(name);
                                    this.furColor = furColor;
                                }
                               
                                public void swim(){
                                    System.out.println("Dog swimming");
                                }
                                public void print(){
                                    System.out.println("name="+name+", furColor="+furColor);
                                }
                            }
                            输出结果:
                            name=xiaohei, furColor=black
                            Dog swimming
                            name=xiaobai, furColor=white
                           
                            父类引用指向子类对象
                            public class TestIns{
                            public static void main(String[] args){
                                Dog d = new Dog("xiaohei","black");
                                d.print();
                                d.swim();
                                System.out.println(a.furColor);
                                Animal a = new Dog("xiaobai","white");            //这里使用父类引用指向子类对象,但此时引用只把该对象当作普通的animal,即看不到dog的其他特性。
                                a.print();
                                //System.out.println(a.furColor);                //a无法访问子类的新成员。
                                //    a.swim();
                                Dog d1 = (Dog)a;
                                d1.swim();
                               
                                System.out.println(d instanceof Dog);
                                System.out.println(d instanceof Animal);
                                System.out.println(a instanceof Dog);
                                System.out.println(a instanceof Animal);
                               
                            }
                        }
                       
                        class Animal{
                            String name;
                            public Animal(String name){
                                this.name = name;
                            }
                                public void print(){
                                    System.out.println("name="+name);
                            }
                        }
                       
                        class Dog extends Animal{
                            String furColor;
                            public Dog(String name,String furColor){
                                super(name);
                                this.furColor = furColor;
                            }
                           
                            public void swim(){
                                System.out.println("Dog swimming");
                            }
                            public void print(){
                                System.out.println("name="+name+", furColor="+furColor);
                            }
                        }
                       
                        可以在方法的参数里面使用父类的引用,但传入一个子类的对象。这样不管多少个子类对象都可以得到执行。
                       
                >>>    再看下例:
                   
                            class Animal{
                                String name;
                                Animal(String name){
                                    this.name=name;
                                }
                                public void enjoy(){
                                    System.out.println("动物叫。。。。");
                                }   
                            }
                           
                            class Cat extends Animal{
                                String furColor;
                                Cat(String name,String furColor){
                                    super(name);
                                    this.furColor = furColor;
                                }
                                public void enjoy(){
                                    System.out.println("猫叫。。。。。");
                                }
                            }
                           
                            class Dog extends Animal{
                                String DurColor;
                                Dog(String name,String DurColor){
                                    super(name);
                                    this.DurColor = DurColor;
                                }
                                public void enjoy(){
                                    System.out.println("狗叫。。。。");
                                }
                            }
                           
                            class Laddy{
                                String name;
                                Animal pet;
                                Laddy(String name,Animal pet){
                                    this.name = name ;
                                    this.pet = pet;
                                }
                                public void mypetEnjoy(){
                                    pet.enjoy();
                                }
                            }
                           
                            public class TestDuotai{
                                public static void main(String[] args){
                                    Cat c = new Cat("cat","blue");
                                    Dog d = new Dog("dog","black");
                                    Laddy l1= new Laddy("limei",c);
                                    Laddy l2 = new Laddy("zhanli",d);
                                    l1.mypetEnjoy();
                                    l2.mypetEnjoy();
                                }
                            }
                            输出结果为:
                            猫叫。。。。。
                            狗叫。。。。
                           
                            由上例子可以看出实现多态要有三个条件:
                            要有继承
                            要有重写
                            要有父类引用指向子类对象。
           
            >>> 接口引用指向对象的时候也发生了多态。如下:
                        interface Singer{
                            public void sing();
                            public void sleep();
                        }
                        class Student implements Singer{
                            public void sing(){
                                System.out.println("student singer");
                            }
                            public void sleep(){
                                System.out.println("student sleep");
                            }
                            public void study(){
                                System.out.println("student study");
                            }
                        }
                       
                        public class TestInterface{
                            public static void main(String[] args){
                            Student s = new Student();
                            s.sing();
                            s.sleep();
                            s.study();
                           
                            Singer s1 = new Student();
                            s1.sing();
                            s1.sleep();
                            //s1.study();   跟类的继承时父类的引用指向子类对象一样,看不到子类中的新的方法。
                            //这里把s1只当作Singer只看得到sing()和sleep();
                        }
                        }

18、instanceof判断引用是否为类的实例。
                class Animal
                {
                    int height ,weight;
                    void sleep()
                    {
                        System.out.println(" Animal sleep");
                    }
                    void eat()
                    {
                        System.out.println(" Animal eate");
                    }
                }
           
                class Fish extends Animal
                {
                   
                }
           
                class Integeration
                {
                    static void fn(Animal an)
                    {
                        an.eat();
                    }
                    public static void main(String[] args)
                    {
                        Animal an=new Animal();
                        Fish fh=new Fish();
                        //an=fh;                             //(1)
                        if(fh instanceof Animal)
                            System.out.println("fh is instance of animal");
                        else
                            System.out.println("fh is not instance of animal");
                        if(an instanceof Fish)
                            System.out.println("an is instance of fish");
                        else
                            System.out.println("an is not instance of fish");
                           
                    }   
                }
                结果为:
                fh is instance of animal
                an is not instance of fish
                取消注释(1)得结果:
                fh is instance of animal
                an is instance of fish
19、包
            源码:
            package com.mybook;
            public class Book
            {
                public static void main(String[] args)
                {
                    System.out.println("java package");
                }
            }
            JAVA的包与文件系统中的目录结构要求对应:
            那么也就是说com.mybook我要在对应的目录中创建com和mybook文件夹。可利用命令javac -d . Book.java,表示在Book.java所在目录进行编译,同时将编译的结果,即生成的Book.class文件置于com文件夹下的mybook文件夹下。
            当然也可以将class文件生成在其它目录中:javac -d d:/  Book.java,即将在d:/com/mybook下生成Book.class文件。
20、类、变量、方法的修饰符
                   (1) 类的修饰符:
                    表示类的访问权限(public,private,default package  注意:类没有protected修饰符)和一些其他特性(abstract,final等)。
                如果类没有声明任何表访问权限的修饰符则为默认包权限。即同一包中的类可以互相访问。如果从另一包中访问这个包中的类,则此类需声明为public的。如果类声明为private的,则只有类的创建者才有权限使用,
                我们一般不这样声明,如果想别的类不能访问此类,大可将此类的构造函数声明为private的。
                    final类:final类表示此类为最终类,即此类不能被派生或覆盖。如java.lang.String类即为final类。
                如:编写类Ex1.java
                    import java.lang.*;
                    public class Ex1 extends String
                    {
                        public static void main(String[] args)
                        {
                            System.out.println("sf");
                        }
                    }
                    运行结果为:
                    Ex1.java:2: 无法从最终 java.lang.String 进行继承
                    public class Ex1 extends String                   
                    1 错误
                    (2) 方法的修饰符
                    方法声明格式为:[<修饰符>]<返回类型><方法名>([<参数>])[throws <异常类>]{}
                        如:public static final int Book(int x,int y) throws IOException{...}
                    访问权限(public,protected,private,default),方法的其它修饰符(static, final,abstract,native,synchronized)
                    图示访问权限:
                        public        protected       default       private
                    同类      Y                Y              Y            Y
                    同包      Y                Y              Y            N
                    子类      Y                Y              N            N
                    不同包非继承      Y           N          N           N
                关于方法的访问权限修饰符21中仍有说明。
                    方法的其它修饰符:
                    1、static关注第10个学习点。
                    2、final方法:
                        final方法是为确保方法在继承的过程中保持不变,即不能被子类改变(覆盖)。
                        类中所有private和static方法自然成为final方法。
                    3、抽象方法与抽象类:
                        (1)在类中没有方法体的方法即为抽象方法,含有抽象方法的类即为抽象类;
                            package com.my;
                            public abstract class My //有抽象方法的类为抽象类
                            {
                                public abstract  void fn();//抽象方法;
                                public static void main(String[] args)
                                {
                                    System.out.println("my ");
                                }
                            }
                        (2)如果一个子类没有实现抽象基类中的任何抽象方法,则子类也为抽象类。
                            父类:
                            package com.my;
                            public abstract class My
                            {
                                public abstract  void fn();
                                public static void main(String[] args)
                                {
                                    System.out.println("my ");
                                }
                            }
                            子类:
                            package com.my;
                            public class Msun extends My
                            {
                               
                                public static void main(String[] args)
                                {
                                    System.out.println("msun ");
                                }
                            }
                            编译:javac -d . My.java
                                  javac -d . Msun.java
                                  java com.my.My
                                  java com.my.Msun     //出错提示:msun.java:2: com.my.Msun 不是抽象的,并且未覆盖 com.my.My 中的抽象方法 fn()
                                  即:如果父类为抽象类,则子类要么声明为抽象类,要么覆盖父类的抽象方法。
                                  修改子类如下:
                            子类:
                            package com.my;
                            public abstract class Msun extends My
                            {
                               
                                public static void main(String[] args)
                                {
                                    System.out.println("msun ");
                                }
                            }
                            或
                            package com.my;
                            public class Msun extends My
                            {   
                                public void fn()
                                {System.out.println("overrite ");}
                               
                                public static void main(String[] args)
                                {    Msun ms = new Msun();
                                    ms.fn();
                                    System.out.println("msun ");
                                }
                            }
                        (3)我们可以将没有包括任何抽象方法的类声明为抽象类,以避免由这个类产生的任何对象。
                    4、native方法
                        JNI:java native interface
                        使用sun网站上下载的tutorial,目录下有native 1.1,打开index.html
                        指南里有具体的写一个java native 方法的步骤。
                        HelloWorld.java->HelloWorld.class->(javah -jni HelloWorld)HelloWorld.h+stdio.h具体操作见文档及孙鑫视频教程lesson3f.swf
                        static
                        {
                            System.out.println("sf");
                        }
                        //静态代码块。

21、关于protected访问控制符的说明
                    可访问性:    public > protected > package >private
                    1.protected 访问控制符既能被用于方法又能用于成员变量。(不用于类)
                    2.声明为protected的方法和成员变量能被同一个包里的所有类所访问。
                    3.声明为protected的方法和成员变量能被该类的子类所访问,子类和父类可以不在一个包中。
                    4.不在同一个包中的子类要访问父类的方法或成员变量有2种方式.  
                       (1) 直接访问父类的protected方法或成员变量。
                          // 定义父类;
                          package packfather;
               
                          public class Father(){
                                  protected int var;
                          }
               
                          // 定义子类一;
                          package packsun;
                          import packfather.Father;
                          public calss Sun1 extends Father{
                                public void set(int varsun1){
                                        // 可以直接访问父类protected变量;
                                        var = varsun1;
                                  }
                          }
                       
                          (2) 通过子类的对象访问父类的protect方法或成员变量。
                          // 定义子类二
                          package packsun;
                          import packfather.Father;
                          public calss Sun2 extends Father{
                                  pbulic void set(int varsun2){
                                          Sun2 sun2 = new Sun2;
                                        //子类的对象访问父类的protected变量
                                          sun2.var = varsun2;
                            //在子类中利用父类对象访问父类的protected变量是不行的。
                              Father fh = new Father();
                              fh.var=20;(编译会报错)
                                  }
                          }
                     注:子类中用父类对象和其它子类的对象都不能访问父类中的protected变量;
                     当你想让一个类中的某个方法或成员变量在包中都可见,而且其子类也能访问(子类有可能和父类不在同一个包中)但又不想让所有类都可以访问该类时,就可以用protected修饰符。

22、垃圾回收garbage collecter
                    java.lang.Object.finalize();
                    java.lang.System.gc();
                    当内存空间不足时,系统会自动调用垃圾回收器将不再使用的对象进行回收。系统会调用java.lang.System.gc();方法,然而在此之前还会调用java.lang.Object.finalize().
                    因为所有内都是继承自Object类,所以我们可以通过覆盖finalize方法来演示java系统进行垃圾回收的过程。
                    class Garbage
                    {
                        int index;
                        static int count;
                        Garbage()
                        {
                            count++;
                            System.out.println("object "+count+" constructed");
                            setID(count);
                        }
                        void setID(int id)
                        {
                            index=id;
                        }
                        protected void finalize()
                        {
                            System.out.println("object "+index+" reclaimed");
                        }
                        public static void main(String[] args)
                        {
                            new Garbage();//创建第一个对象,但没有引用,按理是要回收的,但JAVA不会立即回收,所以自己通过覆盖finalize方法和调用gc方法手动测试回收的过程。
                            System.gc();
                            new Garbage();
                            new Garbage();
                            System.gc();
               
               
                        }
               
               
                    }
                    运行结果为:
                        object 1 constructed
                        object 1 reclaimed
                        object 2 constructed
                        object 3 constructed
                        object 3 reclaimed
                        object 2 reclaimed

23、interface接口
   
                    (1)类可以实现一个或多个接口,需要注意的是:如果类要实现一个接口的话,必须要实现此接口中所有的方法。
                    interface Sport
                    {
                        void jump();
                        void run();
                    }
                    interface Eate
                    {
                        void eate();
                       
                    }
                    class Athlete implements Sport,Eate
                    {
                        public void jump()
                        {
                            System.out.println("jump");
                        }
                        /*
                        public void run()
                        {
                            System.out.println("run");
                        }
                        */
                        public void eate()
                        {
                            System.out.println("eate");
                        }
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Athlete ah = new Athlete();
                            ah.jump();
                        //    ah.run();         
                        //对方法加注释后,会报错提示:Athlete.java:11: Athlete 不是抽象的,并且未覆盖 Sport 中的抽象方法 run(),即应该要实现接口中所有的方法才行。
                            ah.eate();
                        }
                    }
                    (2)接口中的方法都是public和abstract抽象的。接口中方法不能声明为:native、static、final、synchronized、private、protected等修饰符。
                        需要注意的是在类中实现方法的时候权限都要用public,现在设为默认权限试试:
                    interface Sport
                    {
                        void jump();//接口隐藏了修饰符:public abstract
                        void run();
                    }
                    interface Eate
                    {
                        void eate();
                       
                    }
                    class Athlete implements Sport,Eate
                    {
                         void jump()       //在上例的基础上将该方法设为默认权限
                        {
                            System.out.println("jump");
                        }
               
                        public void run()
                        {
                            System.out.println("run");
                        }
               
                        public void eate()
                        {
                            System.out.println("eate");
                        }
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Athlete ah = new Athlete();
                            ah.jump();
                            ah.run();
                            ah.eate();
                        }
                    }
                    编译时出错提示:Athlete.java:13: Athlete 中的 jump() 无法实现 Sport 中的 jump();正在尝试指定更低的访问权限;应为 public void jump()
                    为什么这里一定要用public呢?
                    这是因为:接口的的方法都是默认为public权限并且一定是抽象的方法。即interface Sport中的方法如jump(),应为:public abstract void jump();
                    这里因为接口中的方法权限为public的,所以在类中具体实现接口的方法的权限至少不能比public低。
                    (3)和public类一样,public接口必须放在与接口同名的文件名中。
                    (4)接口中可以有数据成员,但数据成员默认都是为:public static final类型的。
                        如例:CountArea.java
                        interface Math
                        {
                            double PI=3.1415926;//隐藏了修饰符:public static final
                        }
                        class Area implements Math
                        {
                            double roundArea(int round)
                            {
                                return PI*round*round;
                            }
                        }
                        class  CountArea
                        {
                            public static void main(String[] args)
                            {
                                Area ar = new Area();
                                System.out.println(ar.roundArea(3));
                                System.out.println(ar.PI);     //通过对象实例访问
                                System.out.println(Math.PI);   //通过接口名访问
                                System.out.println(Area.PI);   //通过实现接口的类名访问接口中的成员
                            }
                        }
                        在上例中通过实例和接口都可访问PI,证明实际声明的时候为static类型的。
               
                    (5)示例说明一下接口的含义:
                        接口:程序开发的时候模块与模块之间可能有不能的团队在做,那么就需要一方定义接口并实现接口,而另一方只需调用接口中的方法就可以了。
                            接口一定是一方实现它,另一方调用它。
                下面通过四个java文件来说明显卡与主板之间通过接口来通信
       
                        一、接口类:VidoCard.java
                        //接口:显卡与主板能通过接口连在一起。
                        interface VidoCard
                        {
                            void display();
                            String getName();
                        }
                        二、显卡类:Dmeng.java
                        //帝盟为显卡的制造商,他实现了接口VidoCard
                        class Dmeng implements VidoCard
                        {
                            String name;
                            public void setName(String name)
                            {
                                this.name=name;
                            }
                            public String getName()
                            {
                                return name;
                            }
                            public Dmeng()
                            {
                                name="Dmeng name's vidodisplay";
                                System.out.println(name);
                            }
                            public void display()
                            {
                                System.out.println("vidocard display is running");
                            }
                           
                        }
                        三、主板类:Mainboard.java
                        //主板类,在此类中安装cpu和显卡。
                        class Mainboard
                        {
                            String strCPU;
                            VidoCard vc;//注意这里并没有实例化对象,只是引用了接口。
                            public void setCPU(String strCPU)
                            {
                                this.strCPU=strCPU;
                            }
                            public void setVidoCard(VidoCard vc)
                            {
                                this.vc=vc;
                            }
                            void run()
                            {
                                System.out.println(strCPU);
                                vc.display();
                                System.out.println("Mainboard is running");
                            }
                           
                        }
                        四、通过cpu,显卡,主板组装成的电脑类:Computer.java
                        class Computer
                        {
               
                            public static void main(String[] args)
                            {
                                Dmeng dm = new Dmeng();
                                Mainboard mb = new Mainboard();
                                mb.setCPU("Intel's cpu");
                                mb.setVidoCard(dm);
                                mb.run();
                            }
                        }
                        运行结果:
                        Dmeng name's vidodisplay
                        Intel's cpu
                        vidocard display is running
                        Mainboard is running
               
                        上面四个文件,显卡制造商实现了显卡的功能,主板通过接口VidoCard显示,最后组装的电脑运行证明通过接口使设备能顺利运行。

                    (6)java中不允许类的多继承,但允许接口的多继承,即一个接口可继承自多个接口,且一个类可继承多个接口。
                        如下例:
                        接口类Good.java
                        interface Sitable
                        {
                            void site();
                        }
                        interface Sleep
                        {
                            void sleep();
                        }
                        public interface Good extends Sleep,Sitable
                        {
                            void goodbye();
                        }
                        实现接口的类GGood.java
                        public class  GGood implements Good
                        {
                            public void site()
                            {
                                System.out.println("site");
                            }
                            public void sleep()
                            {
                                System.out.println("sleep");
                            }
                                public void goodbye()
                            {
                                System.out.println("goodbye");
                            }
                            public static void main(String[] args)
                            {
                                System.out.println("Hello World!");
                            }
                        }
                    (7) 接口的嵌套
                    如类:Sports.java
                    interface A
                    {
                        interface B
                        {
                            int f();
                            void fn();
                        }
                        void fm();
                       
                    }
                    class Sports implements A
                    {
                       
                        public void fm()    {    }
                       
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.fm();
                        }
                    }
                    编译通过。也就是说当接口有嵌套时,实现哪个接口就实现该接口的方法,可以不管内层的接口。
                    再看下例:实现内层的接口
                    interface A
                    {
                        interface B
                        {
                            int f();
                            void fn();
                        }
                        void fm();
                       
                    }
                    class Sports implements A.B            //实现内层接口
                    {
                        public int f()
                        {
                            System.out.println("implements A.f()");
                            return 0;
               
                        }
                        public void fn()    {    }
                        //public void fm()    {    }          //这里实现的是内层的接口,外层接口的方法可以不实现。
                       
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.f();
                        }
                    }
               
                    下面实现外部类实现接口A.B,内部类实现接口A.
                    class InterTest         //在类里面也可以声明嵌套的接口
                    {
                        interface A
                        {
                            interface B
                            {
                                int f();
                                void fn();
                            }
                            void fm();
                           
                        }
                    }
               
                    class Sports implements InterTest.A.B
                    {
                        static class InnerSports implements InterTest.A      //private static class InnerSports implements InterTest.A       这里还可声明为private噢,在外部类可就不可以噢。
                        //因为我在外部类的main方法中创建了内部类的对象,这里需要声明为static的,因为main是static的。
                        {
                            public void fm()
                            {
                                System.out.println("在内部类中实现内层接口A.B");
                            }
               
                        }
               
                        public int f()
                        {
                            System.out.println("在外部类中实现接口A");
                            return 0;
               
                        }
                        public void fn()    {    }
                        //public void fm()    {    }
                       
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.f();
                            InnerSports InS = new InnerSports();
                            InS.fm();
                        }
                    }
                    输出结果为:
                    Hello World!
                    在外部类中实现接口A
                    在内部类中实现内层接口A.B
                   
                    下例在外部类的非main方法中创建内部类的对象,所以内部类不用声明为static的。
                    class InterTest
                    {
                        interface A
                        {
                            interface B
                            {
                                int f();
                                void fn();
                            }
                            void fm();
                           
                        }
                    }
               
                    class Sports implements InterTest.A.B
                    {
                         class InnerSports implements InterTest.A           //因为我在外部类中的getInnerObject方法创建了内部类的对象,所以不声明为static
                        {
                            public void fm()
                            {
                                System.out.println("在内部类中实现内层接口A.B");
                            }
               
                        }
               
                        public int f()
                        {
                            System.out.println("在外部类中实现接口A");
                            return 0;
               
                        }
                        public void fn()    {    }
                        //public void fm()    {    }
               
                        public void getInnerObject()
                        {
                            InnerSports InS = new InnerSports();
                            InS.fm();
                        }
                       
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.f();
                            s.getInnerObject();
                           
                        }
                    }
               
                    下面看一下接口声明为private的情况
                    class InterTest
                    {
                        private interface A
                        {
                            interface B
                            {
                                void fn();
                            }
                            void fm();
                           
                        }
               
                        public class InnerTest implements A       //与私有接口在同一类中,可以访问
                        {
                            public void fm()
                            {
               
                            }
                        }
                    }
               
                    class Sports implements InterTest.A.B      //与私有接口不在同一类中,不可访问
                    {         
                        public void fn()    {    }
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.f();
                        }
                    }
                    输出提示:
                    Sports.java:22: InterTest.A 可以在 InterTest 中访问 private
                        class Sports implements InterTest.A.B      //与私有接口不在同一类中,不可访问   ^
                        Sports.java:22: 此处需要接口
                        class Sports implements InterTest.A.B      //与私有接口不在同一类中,不可访问                                          ^
                        Sports.java:29: 找不到符号
                        符号: 方法 f()
                        位置: 类 Sports
                                    s.f();
                                     ^
                    这里其实很容易理解,接口的权限跟类相似,这里在类中如果用private定义接口,那么只有在本类中有访问权限。
                    再看一下,将内层接口声明为private的情况
                    class InterTest
                    {
                         interface A
                        {
                            private interface B            //声明为private,提示出错
                            {
                                void fn();
                            }
                            void fm();
                           
                        }
               
                        public class InnerTest implements A       //与私有接口在同一类中,可以访问
                        {
                            public void fm()
                            {
               
                            }
                        }
                    }
               
                    class Sports implements InterTest.A.B      //与私有接口不在同一类中,不可访问
                    {         
                        public void fn()   
                        {   
                            System.out.println("in fn");
                        }
                        public static void main(String[] args)
                        {
                            System.out.println("Hello World!");
                            Sports s = new Sports();
                            s.fn();
                        }
                    }
                    输出结果为:
                    Sports.java:5: 非法的修饰符组合:public 和 private
                                        private interface B
                    这里因为Interace里面默认为public,而对内层接口声明的却是private所以提示非法组合。
               
                关于接口更多问题的测试:
                一、接口继承时的问题:接口C继承了接口A,B,但A,B中都有一个同名的方法action()
                        package com.lwf;
       
                        public class Test {
                       
                            public static void main(String[] args) {
                                D c = new D();
                                c.action();
                            }
                       
                        }
                       
                        interface A{
                            public void action();
                        }
                        interface B{
                            public void action();
                        }
                        interface C extends A,B{
                           
                        }
                        class D implements C{
                       
                            public void action() {
                                System.out.println("action");
                            }
                           
                        }
                        运行正常输出结果为action
                二、类D实现两个接口,两个接口中都有一同名方法action
                        package com.lwf;

                        public class Test {
                       
                            public static void main(String[] args) {
                                D c = new D();
                                c.action();
                            }
                       
                        }
                       
                        interface A{
                            public void action();
                        }
                        interface B{
                            public void action();
                        }
                       
                        class D implements A,B{
                       
                            public void action() {
                                System.out.println("action");
                            }
                           
                        }
                        运行正常输出action
                三、类D继承类B,并且实现接口A,但类B和接口A中都有同名方法action
                        package com.lwf;

                        public class Test {
                       
                            public static void main(String[] args) {
                                D c = new D();
                                c.action();
                            }
                       
                        }
                       
                        interface A{
                            public void action();
                        }
                        class B{
                            public void action(){
                                System.out.println("actionb");
                            }
                        }
                       
                        class D extends B implements A{
                       
                            public void action() {
                                System.out.println("action");
                            }
                           
                        }
                        运行正常,输出action


24、内部类
    在一个类的里面定义另一个类,这样在内里面定义的类叫内部类。
    (1)内部类中可以访问外部类的私有成员。当然也指的是所有成员。
        class Outer
        {
            private int index=100;
            class Inner
            {
                void print()
                {
                    System.out.println(index);
                }
            }
            void print()
            {
                Inner in = new Inner();
                in.print();
            }
           
        }
         
        public class Test
        {
            public static void main(String[] args)
            {
                Outer ou = new Outer();
                ou.print();
            }
        }
    运行结果为:100
    这说明Inner类中可以访问Outer类中的私有成员Index,实事上当在外部类里创建内部类后,在内存单元中将内部类通过外部类.this与外部类关联起来,即Outer.this。
    即然内部内可以访问外部类的private成员,那么肯定可以访问其它成员,实际上内部类可以访问外部类的所有成员。
     (2)当内部类和外部类中有相同的成员时,内部类怎样访问这些成员呢?
        class Outer
        {
            private int index=100;
            class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                }
            }
            void print()
            {
                Inner in = new Inner();
                in.print();
            }
           
        }
         
        public class Test
        {
            public static void main(String[] args)
            {
                Outer ou = new Outer();
                ou.print();
            }
        }
    运行结果为:30,因为print方法中有局部变量index=30;
    那么在内部类的成员与外部类的成员名相同时,怎样访问内部类本身的成员和外部类的成员呢?
    System.out.println(this.index);           //this 返回当前对象的引用
    System.out.println(Outer.this.index);   //Outer.this实际就是指向Outer类引用
            class Outer
        {
            private int index=100;
            class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
            void print()
            {
                Inner in = new Inner();
                in.print();
            }
           
        }
         
        public class Test
        {
            public static void main(String[] args)
            {
                Outer ou = new Outer();
                ou.print();
            }
        }
        运行结果:
        30
        50
        100
                           
    (3)那么我想在其它类中实例化一个内部类的对象,应该怎么做呢?
        public class Test
        {
            public static void main(String[] args)
            {
                Outer ou = new Outer();
                ou.print();
                Inner in1 = new Inner();//这样是否可以呢?
                in1.print();
            }
        }
    看上面在Test类中实例化一个内部类的对象,编译会错,提示找不到该类。
    这时候有两个方法:
        1、需要在Outer类中添加函数,返回值为Inner类的引用。然后引用in1实例。
        2、在其它类中直接实例化In2实例,详细看下面示例。
        class Outer
        {
            private int index=100;
            class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
            void print()
            {
                    System.out.println("outer print");
                Inner in = new Inner();
                in.print();
           
            }
            Inner getInner()//返回Inner类的引用,然后在Test类中通过Outer类的实例调用该方法
            {
                return new Inner();
            }
           
        }
         
        public class Test
        {
            public static void main(String[] args)
            {
                Outer ou = new Outer();
                ou.print();
                Outer.Inner in1 = ou.getInner();//调用Outer类中的方法getInner,注意内部类的引用是用Outer.Inner类定义的。
                in1.print();
                //Outer.Inner in1 =new Inner();
                //不能直接产生一个Inner类的对象,这是因为内部类的对象可以随意的访问外部类的成员,要产生内部类的对象必先产生一个外部类的对象。
                //所以在其它类中实例化内部类的另一种方法是:Outer.Inner in2 = ou.new Inner();
                Outer.Inner in2 = ou.new Inner();
                in2.print();
            }
        }
        结果输出:
        30
        50
        100
        30
        50
        100
        30
        50
        100
     
      (4) 在外部类中直接引用内部类
          class Outer
        {
            private int index=100;
            class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
            void print()
            {
                System.out.println("outer print");
                Inner in = new Inner();
                in.print();
           
            }
            Inner getInner()
            {
                return new Inner();
            }
            public static void main(String[] args)
            {
                Inner in1= new Inner();//在main中实例化Inner类,看提示什么?
                in1.print();           
            }
           
        }
        在上面的几个例子中Outer类的print方法中实例化了Inner类的实例,那么在Outer类的main方法中能否实例化Inner类呢?
        如果直接在Outer类中创建Inner类的对象,那么编译提示出错:Test.java:28: 无法从静态上下文中引用非静态 变量 this:  Inner in1= new Inner();
    那么在外部类中怎么访问内部类呢?
        类似其它类中引用内部类Inner的方法,在外部类中同样有两种方法:
        1.将Outer类中的main()方法改为:
        public static void main(String[] args)
        {
            Outer ou = new Outer();   //先创建一Outer类的对象
            Inner in = ou.getInner();//利用Outer类的对象引用调用函数使Inner类获得引用in
            in.print();
        }
        即同(3)中一样,通过外部类的函数返回内部类的引用
         2.在外部类中利用外部类的引用创建内部类的对象,将main方法改为:
        public static void main(String[] args)
        {
           
            Outer ou = new Outer();
            Inner in1 =ou.new Inner();
            in1.print();
        }
        由(3)、(4)可见要想在别的类中(包括外部类和其它类)引用内部类,先要创建一个外部类的对象ou.再能过外部类与内部类的关系引用内部类中的成员及函数。
       
    (5) 类可以放在方法、if语句中、句语块中。
        如下:编译无错误
        class Outer
        {
            private int index=100;
            void fn()
            {
                if(true)
                {
                    class Midlle
                    {
                        class Inner
                        {
                            int index=50;
                            void print()
                            {
                                int index=30;
                                System.out.println(index);
                                System.out.println(this.index);
                                System.out.println(Outer.this.index);
                            }
                        }
                    }
                }
            }
               
        }
    在方法fn()中定义一局部变量,并在Inner类中的print方法中输出代码如下:
         class Outer
        {
            private int index=100;
            void fn(int a)
            {    int b;
                if(true)
                {
                    class Midlle
                    {
                        class Inner
                        {
                            int index=50;
                            void print()
                            {
                                int index=30;
                                System.out.println(index);
                                System.out.println(this.index);
                                System.out.println(Outer.this.index);
                                b = 5;
                                System.out.println(b);
                            }
                        }
                    }
                }
            }
                   
        }
    编译出错提示:Outer.java:19: 从内部类中访问局部变量 b;需要被声明为最终类型    ^ b = 5;
    即当类放在方法内部而且需要在内部类中访问方法中定义的局部变量时,该变量必须声明为final类型。
    所以以上方法fn应改为:void fn(final int a){final int b=0;....}
        因为b声明为final类,所以print()中不能用b=5;
   
       (6)可以把内部类当作外部内的一个方法来理解。
          我们知道类的访问权限没有protected,方法才有,在这里内部类可以声明为protected.
         class Outer
        {
            private int index=100;
            protected class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
           
        }
    以上将类Inner声明为protected,编译无错误。
    下面看一下内部类声明为protected后的权限:
         class Outer
        {
            private int index=100;
            protected class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
           
        }
        class Test
        {
            Outer ou = new Outer();
            Outer.Inner in = ou.new Inner();
        }
    编译无错误:说明同一包中的类访问protected内部类是没问题的。当然在外面类Outer中访问更没有问题。
    下面测试一下从别的包访问声明为protected的内部类。
     类:Outer 在com.god包中;
        package com.god;
        public class Outer
        {
            private int index=100;
            protected class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
           
        }
    类:Good 在com.good包中;
    package com.g;
        import com.god.*;
        class Good
        {
            Outer ou = new Outer();
            Outer.Inner in = ou.new Inner();
        }

    编译:E:/>javac -d . *.java
    出错提示:
    Good.java:6: com.god.Outer.Inner 可以在 com.god.Outer 中访问 protected
    出错地方:Outer.Inner in = ou.new Inner();
    可见在其他包中是不能够访问protected的内部类。
   
    现将Inner类声明为private:
         class Outer
        {
            private int index=100;
            private class Inner
            {
                int index=50;
                void print()
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);
                    System.out.println(Outer.this.index);
                }
            }
           
        }
        class Test
        {
            Outer ou = new Outer();
            Outer.Inner in = ou.new Inner();
        }
    出错提示为:Outer.java:20: Outer.Inner 可以在 Outer 中访问 private
                    Outer.Inner in = ou.new Inner();
                         ^
    说明声明为private后,只有在外部类才可访问内部类,在同一包中的其他类也是没有权限访问的。
   
    同理可以声明内部类为abstract,那么此类就不能在外部类和其他类中创建对象,要使用他,可以在其它类中继承内部类,并实现其中的方法。
        声明内部类为final,即希望内部类不能被派生。
    嵌套类:声明为static的内部类,则在内部类与外部类之间就构成实际的嵌套关系。
        声明为static类,则不需要在其它类中通过创建内部类的对象来访问他,只需通过类名来引用就可以了。不过因为内部类是static修饰的,它不能访问外部类的非static成员。
        注意:非static内部类中不能有static的声明。即在内部类中不能声明static的方法或成员。
        例如:
        class Outer
        {
            private int index=100;
            class Inner                //非static内部类
            {
                int index=50;
                static void print()//声明为static
                {
                    int index=30;
                    System.out.println(index);
                    System.out.println(this.index);//不能访问非static成员
                    System.out.println(Outer.this.index);
                }
            }
           
        }
        class Test
        {
            Outer ou = new Outer();
            Outer.Inner in = ou.new Inner();
        }
    出错提示:
        Outer.java:11: 无法从静态上下文中引用非静态 变量 this
                                System.out.println(this.index);
                                                       ^
        Outer.java:12: 无法从静态上下文中引用非静态 变量 this
                                System.out.println(Outer.this.index);
                                                        ^
        Outer.java:7: 内部类不能有静态声明
                                static void print()
                                            ^
    在第三个错误中提示了:内部类不能有静态声明!!(前提是非static类中)
   
    在static内部类中是可以声明static方法的:
         class Outer
        {
            private int index=100;
            static class Inner   //声明为static内部类
            {
                int index=50;
                static void print()
                {
                    int index=30;
                    System.out.println(index);
                    //System.out.println(this.index);
                    //System.out.println(Outer.this.index);
                }
            }
           
        }
       
    (7)继承内部类
    示例:
        class Outer
        {
            class Inner
            {
            }
           
        }
        class Test extends Outer.Inner
        {
            public static void main(String[] args)
            {
                Test te = new Test();
            }
        }
    出错提示:Outer.java:8: 需要包含 Outer.Inner 的封闭实例
          class Test extends Outer.Inner
    我们知道创建派生类的实例时会调用基类的构造函数,这里要调用内部类的构造函数必须要有一个从外部类到内部类的引用,注意这里与从其他类继承嵌套接口不同。
    通过内部类与外部类的关系我们知道,要定义一下内部类的实例必须先要有一外部类的实例
    这里修改如下:
        class Outer
        {
            class Inner
            {
            }
           
        }
        class Test extends Outer.Inner
        {
            Test(Outer ou)
            {
                ou.super();//通过super的特殊应用,来建立内部类对象到外部类对象的引用关系。   
            }
            public static void main(String[] args)
            {   
                Outer out = new Outer();      //先实例化外部类对象
                Test te = new Test(out);    //传递外部类的引用作为参数
            }
        }
    编译无错误。

    (8)内部类实现接口
        例:Test.java
        interface Animal
        {
            void eate();
            void sleep();
        }
        class Zoo
        {
            class Tiger implements Animal       //内部类实现接口
            {
                public void eate()
                {
                    System.out.println("eate");
                }
                public void sleep()
                {
                    System.out.println("sleep");
                }
            }

            Animal getAnimal()                     
            {
                return new Tiger();                 //返回对象引用。这里因为类Tiger实现了接口的方法,所以可以直接用Animal getAnimal().之前我们用Tiger getTiger().
            }
        }
        class Test
        {
            public static void main(String[] args)
            {
                System.out.println("main");
                Zoo z = new Zoo();
                Animal an = z.getAnimal();
                an.eate();
                an.sleep();
            }
        }
        结果为:
            main
            eate
            sleep

     (9) 匿名内部类
       
        在(8)中通过
            Animal getAnimal()                     
            {
                return new Tiger();                 //返回对象引用。这里因为类Tiger实现了接口的方法,所以可以直接用Animal getAnimal().之前我们用Tiger getTiger().
            }
            方法实现。
            那么可否这样呢?如下:
            Animal getAnimal()
            {
                return new Animal();
            }
            我们知道接口是不能够直接实例化一个对象的,所以在这里用,return new Animal()原则上是不行的。那么我们可以在这个语句结束之前先实现接口中的方法,那么就可以了。
            我们在return new Animal()后加上{},并在{}中加上实现的方法。
        代码如下:
        interface Animal
        {
            void eate();
            void sleep();
        }
        class Zoo
        {
            /*
            class Tiger implements Animal
            {
                public void eate()
                {
                    System.out.println("eate");
                }
                public void sleep()
                {
                    System.out.println("sleep");
                }
            }
            */
            //在下面用匿名内部类实现
            Animal getAnimal()
            {
                return new Animal()
                    {
                        public void eate()
                        {
                            System.out.println("niming eate");
                        }
                        public void sleep()
                        {
                            System.out.println("niming sleep");
                        }
                    };
            }
        }
        class Test
        {
            public static void main(String[] args)
            {
                System.out.println("main");
                Zoo z = new Zoo();
                Animal an = z.getAnimal();
                an.eate();
                an.sleep();
            }
        }
        结果为:
        main
        niming eate
        niming sleep
        在代码中:
        return new Animal()
            {
                public void eate()
                {
                    System.out.println("niming eate");
                }
                public void sleep()
                {
                    System.out.println("niming sleep");
                }   
            };
        实际上为一匿名内部类。最后分号不能少。
        上面的这段代码的具体实现是:
        class MyAnimal implements Animal
        {
            public void eate()
                {
                    System.out.println("niming eate");
                }
                public void sleep()
                {
                    System.out.println("niming sleep");
                }
        }
        return new MyAnimal;
        于是可以把上例程序改写为,思路会更清晰一些:
        interface Animal
        {
            void eate();
            void sleep();
        }
        class Zoo
        {
            Animal getAnimal()
            {
                class MyAnimal implements Animal
                {
                    public void eate()
                        {
                            System.out.println("niming eate");
                        }
                        public void sleep()
                        {
                            System.out.println("niming sleep");
                        }
                }
                return new MyAnimal();
            }
        }
        class Test
        {
            public static void main(String[] args)
            {
                System.out.println("main");
                Zoo z = new Zoo();
                Animal an = z.getAnimal();
                an.eate();
                an.sleep();
            }
        }
        输出结果为:
        main
        niming eate
        niming sleep

    回答:在什么情况下要使用匿名内部类?
        要在类中通过方法Animal getAnimal()返回接口的一个对象如return new Animal();,那么我必须要让编译知道我已经实现了接口中的方法,所以在方法的分号之前加入{}块。{}中为实现接口的代码。
          这段{}的代码就是匿名内部类的实现。从上面具体实现我们知道,其实是在方法中定义一个内部类,类中实现接口中的方法,然后再返回这个内部类的引用。匿名内部类只是它的缩写而以。

    (10)为什么要使用内部类
        1.内部类中可以随意的访问外部类的成员,可以更好的组织管理代码,增强代码的可读性。
        2。解决类的多重继承问题。
        每个内部类可以独立的继承一个类,当一个类想要继承多个类的时候怎么办呢,显然只有外部类继承一个类是不够的,
            我可以在这个类里定义多个内部类来实现。另外我可以在类中定义多个内部类来实现同一接口,但实现的方式不同。
            我们说一个类实现两个接口可采用下面两种方法(1)是直接实现两个接口,(2)是实现一个接口,再利用匿名内部类返回另一接口的对象。
            如:
            interface A{}
            interface B{}
            (1) class X implements A,B  {}      //是直接实现两个接口,
            (2) class X implements A{           //实现一个接口,再利用匿名内部类返回另一接口的对象
                B MakB(){
                    return new B()
                    {
                    };
                }
            }
        2.内部类可以用于创建适配器,适配器是可以实现接口的类,使用内部类来实现接口可以更好的定位与接口关联的方法在代码中的位置。
        3.内部类的更多方法:
             当一个类即要继承一个类,又要实现一个接口,但是所继承的父类及接口中有同名但内容不同的方法,这时应该使用内部类。
            如:
            interface Machine
            {
                void run();
            }
            class Person
            {
                void run()
                    {
                        System.out.println("heart run");
                    }
            }
            class Robot extends Person
            {
                class MachineHeart implements Machine
                {
                    public void run()
                    {
                        System.out.println("run");
                    }
                }
                Machine getMachine()
                {
                    return new MachineHeart();
                }
            }

            class Test
            {
                public static void main(String [] args)
                {
                    Robot ro = new Robot();
                    Machine ma = ro.getMachine();
                    ma.run();
                    ro.run();
                }
            }
            结果为:
            run
            heart run
           
            当一个类要继承多个类时:特别是其中有抽象类时
            class A
            {
                void f1()
                {
                    System.out.println("f1");
                }
            }
            abstract class B
            {
                abstract void f2();
            }

            class C extends A
            {
                B getB()
                {
                    return new B()
                    {
                        void f2(){System.out.println("f2");};
                    };
                }
            }

            class Test
            {
                static void m1(A a)
                {
                    a.f1();
                }
                static void m2(B b)
                {
                    b.f2();
                }
                public static void main(String[] args)
                {
                    C c = new C();
                    m1(c);
                    m2(c.getB());
                }
            }
            输出:
            f1
            f2   


25、异常处理
    1、概念
    JAVA程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给JAVA运行时系统,这个过程称为抛出throw异常。
    当JAVA运行时系统接收到异常对象时,会寻找能处理这一异常的代码,并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
    如果JAVA运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的JAVA程序也将退出。
    try/catch/finally
    将有可能引发异常的语句放在try{}中,在catch语句中的捕获异常并进行处理。
    需要注意的是:try语句块中一旦异常产生了,则此语句后面的语句不再执行。即当异常发生立刻跳转到catch中进行处理。
    例如:
    class Exce
    {
        public int division(int a,int b)
        {
            return a/b;
        }
    }
    class ExcepTest
    {
        public static void main(String[] args)
        {
            Exce ex = new Exce();
            try
            {
                ex.division(5,0);                    //调用函数,但分母为0,显然会出错,将可能出错的语句放在try块中。
                System.out.println("trow");          //注意运行结果:并没有输出thow,因为上面的一条语句产生了异常,立刻转到catch块中处理。
            }
            catch (Exception e)
            {
                System.out.println(e.getMessage());           //为exception类从thowrable继承而来的方法,可以查找api中的java.lang.exception类。
                System.out.println(e.toString());
            }
            finally
            {
                System.out.println("good");     //可以看到,不管异常是否发生都会输出good.
            }
        }
    }

    输出结果:
    / by zero                                    //被0除
    java.lang.ArithmeticException: / by zero
    good
    如果想知道异常所发生的位置可在catch块中调用方法e.printStackTrace();
    catch (Exception e)
        {
            System.out.println(e.getMessage());
            System.out.println(e.toString());
            e.printStackTrace();         //打印出错信息的位置。因为printStackTrace方法本身有向标准错误输出打印信息的功能,所以不用System.out.println();
        }
    输出结果为:
    / by zero
    java.lang.ArithmeticException: / by zero
    java.lang.ArithmeticException: / by zero
        at Exce.division(ExceTest.java:5)
        at ExcepTest.main(ExceTest.java:15)
    good

        2、查看exception类的api说明可以看到exception类有许多子类,上例中具体的出错信息是ArithmeticException子类的内容,那么这里也可以修改异常参数
        即将catch (Exception e)改为catch (ArithmeticException e),输出结果与上例一样。
        3、异常的捕获也可放在方法中,如上例中可把异常捕获放在division方法中。
        如:
        class Exce
        {
            public int division(int a,int b)
            {
                try
                {
                    return a/b;
                    //ex.division(5,0);
                   
                }
                catch (ArithmeticException e)
                {
                    e.printStackTrace();
                    return 0;              //需要注意的是这里增加了返回语句,因为上面return a/b实际上先执行a/b就出现异常了,转到catch块,而函数又要求返回int类型值,所以必须要增加返回语句。
                }
                finally
                {
                    System.out.println("good");
                }
               
            }
        }
   
        4、抛出异常,
            I。可以在可以产生异常的函数中抛出异常,它将向上一级调用语句抛出此异常,要求上一级调用语句中要有捕获异常的动作。
            class Exce
            {
                public int division(int a,int b) throws Exception         //向调用它的语句抛出异常
                {
                   
                        return a/b;
                       
                }
            }
            class ExcepTest
            {
                public static void main(String[] args)
                {
                    Exce ex = new Exce();
                    ex.division(5,0);           //该处没有捕获和处理。
                   
                }
            }
            输出结果:
                jasmine.jar
                ExceTest.java:15: 未报告的异常 java.lang.Exception;必须对其进行捕捉或声明以便抛出
                ex.division(5,0);
                       ^
            II。另一个需要注意的地方是:抛出的异常类型要与捕获的异常类型一致。如下:
            class Exce
            {
                public int division(int a,int b) throws Exception         //抛出异常Exception
                {
                   
                        return a/b;
                       
                }
            }
            class ExcepTest
            {
                public static void main(String[] args)
                {
                        Exce ex = new Exce();
                        try
                        {
                            ex.division(5,0);                   
                        }
                        catch (ArithmeticException e)         //捕获时是另一个异常  
                        {
                            System.out.println(e.getMessage());        
                           
                        }
                        finally
                        {
                            System.out.println("good");   
                        }
                }
            }
            输出结果提示未报告的异常,这里抛出异常的类型应与捕获时一致。
            这里也可以采用多个catch块来捕获如:
            try
                {
                    ex.division(5,0);                    //调用函数,但分母为0,显然会出错,将可能出错的语句放在try块中。
                    System.out.println("trow");          //注意运行结果:并没有输出thow,因为上面的一条语句产生了异常,立刻转到catch块中处理。
                }
                catch (ArithmeticException e)
                {
                   
                    System.out.println(e.toString());
                }
                catch (Exception e)
                {
                    System.out.println(e.getMessage());           //为exception类从thowrable继承而来的方法,可以查找api中的java.lang.exception类。
                   
                }
                finally
                {
                    System.out.println("good");     //可以看到,不管异常是否发生都会输出good.
                }
            但是针对这个示例需要注意了,如果我把两个catch块换个位置,如下
            catch (Exception e)
                {
                    System.out.println(e.getMessage());           //为exception类从thowrable继承而来的方法,可以查找api中的java.lang.exception类。
                   
                }
                catch (ArithmeticException e)
                {
                   
                    System.out.println(e.toString());
                }
            这样输出会提示:异常已经被捕获,这是因为所有异常类型都是Exception派生出来的。只要产生异常catch (Exception e)都能捕获,那么后面的捕获语句将不会执行。
            所以写多个catch语句的时候注意,先将具体的异常放在前面,最后才放catch (Exception e)。
               
            III。抛出异常,但不提示需要捕获的情况
                class Exce
                {
                    public int division(int a,int b) throws ArithmeticException
                    {                   
                            return a/b;
                    }
                }
                class ExcepTest
                {
                    public static void main(String[] args)
                    {
                            Exce ex = new Exce();
                    }
                }
                这里抛出了ArithmeticException,但并没有提示出错信息,而在上面I中,抛出Exception异常时,系统会提示一定要捕获,这是为什么呢?
                在api中查找ArithmeticException,不难发现它是继承自java.lang.RuntimeException,JAVA中RuntimeException异常一般是程序员自己因为水平不高而产生的异常,也就是说这一类
                异常系统会自已进行处理。所以以后由RuntimeException派生的异常抛出的时候,不会要求一定要进行捕获!!
            IIII.对子类抛出异常的限定:
            如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常。(构造方法除外,因为构造方法是不能继承的)。
           
           
            !!!几个重要的异常机制及问题
           
                1>  try{return;}finally问题
               
                            public class TEST{
                                public static void main(String[] args){
                                try{
                                    return;
                                    }catch(Exception e){
                                        }finally{
                                            System.out.println("finally");
                                            }
                                        }
                            }
                            运行结果:finally
                            但再问finally是在return前执行还是在return后执行?
                            Finally在return前执行,设计测试代码如下:
                            public class TestChart1 {
                                public static void main(String[] argc){
                                    System.out.println("start:");
                                    try{
                                        System.out.println("before return:");
                                        return ;
                            //            System.out.println("after return:");
                                    }finally{
                                        System.out.println("end:");
                                    }
                            //        System.out.println("last:");
                                }
                            }
                            上面程序在注释的两句均会提示不能到达的区域。如果是先return再执行finally那么last肯定是可以输出的,但这里居然说这个没办法到达,说明是先就执行了finally,再执行return退出。
                   
              2>  Exception
                   
                                                                Throwable
                                                    |                    |        |
                                                |                        |           |
                                        Error           Exception          RuntimeException       
                                       
                                        Error系统错误,处理不了
                                        Exception 可处理也必须处理的异常
                                        RuntimeException 经常性出现的异常,太多。。可以catch也可以不catch。如数组越界,除零等
                            抛出异常:throws Exception
                            当方法本身无法处理异常时,可以抛出异常,供调用该方法的代码块处理异常,如果调用他的代码块还不能处理可继续抛出。
                            如:
                            import java.io.*;
                                    public class TestTry{
                                        public static void main(String[] args) {//throws Exception {
                                            Cat c = new Cat();
                                            //c.fun();      //调用方法:要么catch异常,要么在main方法中抛出异常throws Exception,但最好自己catch进行处理。
                                            try{
                                            }catch(Exception e){
                                                e.printStackTrace();
                                            }
                                        }
                                    }
                                   
                                    class Cat{
                                        public void fun() throws Exception{        //抛出异常
                                            File name = new File("good.txt");
                                            System.out.println("Exception");
                                        }
                                    }
                           
                3> 关于接口与实现类中的异常处理
                           
                                public class TestTry{
                                    public static void main(String[] args) {//throws Exception {
                                        Cat c = new Cat();
                                        c.fun();
                                    }
                                }
                                interface CatInterface{
                                    void fun() throws Exception;
                                    void fun2();
                                }
                                class Cat implements CatInterface{
                                    public void fun(){
                                        System.out.println("fun");
                                    }   
                                    //接口中抛出了异常,在实现类中可以不抛出或catch异常,但如果在实现类中相应方法头部抛出了异常,则在调用该方法的地方要catch异常或在main()后抛出异常。
                                    //public void fun() throws Exception{
                                    //    System.out.println("fun");
                                    //}   
                                     
                                    //public void fun2() throws Exception{
                                    //}
                                    //接口中此方法没有抛出异常,编译提示:未实现方法fun2();
                                    //说明当接口中没有抛出异常时,想要实现接口,则实现类中该方法也不能在方法头部抛出异常。
                                    public void fun2(){
                               
                                    }
                                }
                               
                               
                            >>>    //得出结论:接口抛,实现可抛可不抛,接口不抛,实现一定不抛
                    4> 用于继承或实现接口中重写方法的规定:
                                    实现接口或从父类继承重写方法需要抛出与原方法所抛出异常类型一致异常或不抛出异常.

26、java的常用包
            java.applet:包含一些用于创建JAVA小应用程序的类。
            java.awt:包含一些用于编写与平台无关的图形界面(GUI)应用程序的类。
            java.io:包含一些用于输入输出I/O处理的类。
            java.lang:包含一些JAVA语言的基本类与核心类,如String、Math、Integer、System和Runtime提供常用的功能,这个包被隐式导入。
            java.net:包含用于建立网络连接的类,与JAVA。IO同时使用完成与网络有关的读写。
            java.util:包含一些实用工具和数据结构类。

27、==与equals的区别
                ==主要用来比较两个变量的值;
            equals比较两个对象变量所代表的对象的内容是否相等
            JAVA中除8种基本类型外其它均为引用类型。
            当我们声明一个引用类型变量时,系统只为该变量分配了引用空间,并未创建具体的对象,当用new为对象分配空间后将对象的引用赋值给引用变量。
            引用变量可比拟为电视机的遥控器,而具体的对象则可比拟为电视机。
            class  StringCompare
            {
       
                public static void main(String[] args)
                {
                    String str1 = new String("abc");
                    String str2 = new String("abc");
                    if(str1==str2)
                        System.out.println("str1==str2");
                    else
                        System.out.println("str1!=str2");
                }
            }
            输出结果为:str1!=str2,
            在这里==比较的是str1和str2两个变量的值。String str1;此语句会在栈内存空间中分配空间给变量str1,两个变量的值肯定是不一样的。但两个变量所指的值是一样的。
            class  StringCompare
            {
       
                public static void main(String[] args)
                {
                    String str1 = new String("abc");
                    String str2 = new String("abc");
                    if(str1==str2)
                        System.out.println("str1==str2");
                    else
                        System.out.println("str1!=str2");
                    if(str1.equals(str2))
                        System.out.println("str1==str2");
                    else
                        System.out.println("str1!=str2");
                }
            }
            输出内容为:str1!=str2
                    str1==str2
          
28、在JAVA中系统重载了+和+=运算符,但不允许程序员重载操作符。JAVA中String类型可与其它任何类型进行+,+=操作。
                String 类代表字符串,为常量,声明为public final class String,是不可修改的。
                在处理大量字符串时常用StringBuffer来代替String,通常用StringBuffer类的append方法和toString方法来实现String中的+操作以及向String的转换。
                class  StringCompare
                {
           
                    public static void main(String[] args)
                    {
                        String str1 = new String("abc");
                        System.out.println(str1+1+1.0+'a'+true);
                        StringBuffer str2 = new StringBuffer();
                        System.out.println(str2.append(str1).append(1).append(1.0).append('a').append(true).toString());
                    }
                }
                输出结果:
                    abc11.0atrue
                    abc11.0atrue
                    说明使用String的+与StringBuffer中采用append方法效果是一样的。StringBuffer的初始容易为16个字符,但如果需要他会自动增加。
                    StringBuffer中有很多方法可以使用,具体查api文档。如delete,insert等
                    如:
                    class  StringCompare
                    {
           
                        public static void main(String[] args)
                        {
                            String str1 = new String("abc");
                            System.out.println(str1+1+1.0+'a'+true);
                            StringBuffer str2 = new StringBuffer();
                            str2.append(str1).append(1).append(1.0).append('a').append(true);
                            System.out.println(str2);
                            str2.delete(2,4);
                            System.out.println(str2);
                        }
                    }
                    输出结果为:
                    abc11.0atrue
                    abc11.0atrue
                    ab1.0atrue
                    注意查api中delete方法为:public StringBuffer delete(int start,int end)
                    start从0开始:如上例中:abc11.0atrue,delete(2,4)指删除原字符串中从第二个开始到第四个字符,注意是包括第二个,但不包括第四个。
                    即2,4    指2<=x<4之间的字符。

29、main方法的详细讲解
            public static void main(String[] args)
            因为main方法是由jvm调用的。不需要产生任何对象所以声明为static的,又由于没有返回值,所以声明为void;
            String[] args为一字符串数组,用于接收命令行输入的参数。
            class Test
            {
                public static void main(String[] args)
                {
                    System.out.println("Hello World!");
                    System.out.println(args[0]);
                }
            }
            运行结果出错提示:
                Hello World!
                Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0  at Test.main(Test.java:6)
                即字符串数组并没有值。
                参数args用于接收命令行输入的参数,但并不是java Test
                而是后面跟的字符,如执行字节码文件Test.class时,使用如下命令,得结果为:
                    E:/JAVA TEST>java Test afafaf
                    Hello World!
                    afafaf
                由此可知args接收了参数afafaf,从而经System.out.println(args[0]);输出结果为:afafaf
                同理可利用数组接收多个参数,然后在main函数中输出。

30、参数传递
            基本数据类型在参数传递的时候传递的是值;引用类型在参数传递的时候传递的是引用,引用相当于首地址。

31、对象克隆
            I.为获得一份对象的拷贝,可利用Object类的clone().
            II。在派生类中覆盖基类的clone方法并声明为public.
            III。在派生类中通过super.clone()调用基类的clone方法。抛出异常或捕获异常CloneNotSupportedException
            IIII。在派生类中实现cloneable接口。
            下面Student类覆盖基类的clone方法,并调用super.clone();方法调用基类方法,另外此类还实现了cloneable接口。
            class Student implements Cloneable
            {
                String name;
                int age;
                Student(String name,int age)
                {
                    this.name= name;
                    this.age = age;
                }
                public Object clone()
                {
                    Object o = null;
                    try
                    {
                        o=super.clone();
       
                    }
                    catch (CloneNotSupportedException e)
                    {
                        System.out.println(e.toString());
                       
                    }
                    return o;
                   
                }
               
            }
            public class Teacher
            {
                public static void main(String[] args)
                {
                Student s1 = new Student("zhang shan ",19);
                Student s2 =(Student)s1.clone();
                s2.name="likai";
                s2.age=20;
                System.out.println("name="+s1.name+",age=" + s1.age);
                System.out.println("name="+s2.name+",age=" + s2.age);
                }
            }
            输出结果为:
            name=zhang shan ,age=19
            name=likai,age=20
            这说明发生了克隆,创建了对象的副本。

32、数组的相关操作(视频4下,Lesson4G)
            JAVA中数组都有一属性length,用来获取数组中元素的个数。(注意数组中有length属性,而String有length()方法。
            数组的复制:System.arraycopy();
            数组的排序:Arrays.sort();
            在已排序的数组中查找某个元素:Arrays.binarySearch();
            I.数组复制
            class ArrayTest
            {
                public static void main(String[] args)
                {
                    int[] num1 = new int[]{1,2,3};
                    int[] num2 = new int[3];
                    System.arraycopy(num1,0,num2,0,num1.length);
                    for(int i=0;i<num1.length;i++)
                    {
                        System.out.println(num2[i]);
                    }
                }
            }
       
            输出结果:1
                  2
                  3
            说明:public static void arraycopy(Object src,
                                     int srcPos,
                                     Object dest,
                                     int destPos,
                                     int length)
                参数:
                    src - 源数组。
                    srcPos - 源数组中的起始位置。
                    dest - 目标数组。
                    destPos - 目标数据中的起始位置。
                    length - 要复制的数组元素的数量。
                抛出:
                    IndexOutOfBoundsException - 如果复制会导致对数组范围以外的数据的访问。
                    ArrayStoreException - 如果因为类型不匹配而使得无法将 src 数组中的元素存储到 dest 数组中。
                    NullPointerException - 如果 src 或 dest 为 null。
       
            II。数组的排序及排序后搜索指定字符
                java.util.Arrays.sort();
                类:ArrayTest
                import java.util.Arrays;
                class ArrayTest
                {
                    public static void main(String[] args)
                    {
                        int[] num1 = new int[]{3,2,1};
                        Arrays.sort(num1);
                        for(int i=0;i<num1.length;i++)
                        {
                            System.out.println(num1[i]);
                        }
                        int index=Arrays.binarySearch(num1,2);           //这里要搜索的值为2,返回所在数组的索引位置。这里2的索引为1.
                        System.out.println("index= "+index);
                        System.out.println("element= "+ num[index]);
                    }
                }
                输出结果:
                1
                2
                3
                index=1
                element= 2
                说明:
                public static int binarySearch(int[] a,int key)
                参数:
                    a - 要搜索的数组。
                    key - 要搜索的值。
               
                注意对象数组的排序:
                例如:
                import java.util.Arrays;
                class ArrayTest
                {
                    public static void main(String[] args)
                    {
                        Student[] st1 = new Student[]{
                            new Student(1,23),
                            new Student(2,24),
                            new Student(3,25)
                        };
                            Arrays.sort(st1);
                            for(int i=0;i<st1.length;i++)
                            {
                                System.out.println(st1[i]);
                            }
                    }
                }
       
                class Student
                {
                    int num;
                    int age;
                    Student(int num,int age)
                    {
                        this.num=num;
                        this.age=age;
                   
                    }
                    public String toString()
                    {
                        return "num="+num+","+"age="+age;
                    }
                }
                输出结果为:
                Exception in thread "main" java.lang.ClassCastException: Student
                at java.util.Arrays.mergeSort(Arrays.java:1156)
                at java.util.Arrays.sort(Arrays.java:1080)
                at ArrayTest.main(ArrayTest.java:11)
                详细看一下sort针对对象类型的方法:
       
                public static void sort(Object[] a)根据元素的自然顺序,对指定对象数组按升序进行排序。
                数组中的所有元素都必须实现 Comparable 接口。此外,数组中的所有元素都必须是可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,e1.compareTo(e2) 不得抛出 ClassCastException)。
                Comparable接口在java.lang包中。可以查看api知道String类也实现了这个接口,所以String类型数组是可以排序的。
                int compareTo(T o)比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
                修改代码,实现接口如下:
                import java.util.Arrays;
                class ArrayTest
                {
                    public static void main(String[] args)
                    {
                        Student[] st1 = new Student[]{
                            new Student(4,"zhangshan"),
                            new Student(2,"lisi"),
                            new Student(2,"eisi"),
                            new Student(3,"wangwu")
                        };
                            Arrays.sort(st1);
                            for(int i=0;i<st1.length;i++)
                            {
                                System.out.println(st1[i]);
                            }
                    }
                }
       
                class Student implements Comparable        //实现接口
                {
                    int num;
                    String name;
                    Student(int num,String name)
                    {
                        this.num=num;
                        this.name=name;
                   
                    }
                    public String toString()
                    {
                        return "num:="+num+","+"name:="+name;
                    }
                    public int compareTo(Object o)            //覆盖方法
                    {
                        Student s=(Student)o;
                        return num>s.num? 1 : (num==s.num? 0 :-1); //制定自己的比较方法,按学号进行排序
                    }
                }
       
                输出结果为:
                    num:=2,name:=lisi
                    num:=2,name:=eisi
                    num:=3,name:=wangwu
                    num:=4,name:=zhangshan
                    即得到排序后的输出结果。
                输出的结果当学号一致的时候没有按名字进行排序,那么下例实现这个效果:
                import java.util.Arrays;
                class ArrayTest
                {
                    public static void main(String[] args)
                    {
                        Student[] st1 = new Student[]{
                            new Student(4,"zhangshan"),
                            new Student(2,"lisi"),
                            new Student(2,"eisi"),
                            new Student(3,"wangwu")
                        };
                            Arrays.sort(st1);
                            for(int i=0;i<st1.length;i++)
                            {
                                System.out.println(st1[i]);
                            }
                    }
                }
       
                class Student implements Comparable        //实现接口
                {
                    int num;
                    String name;
                    Student(int num,String name)
                    {
                        this.num=num;
                        this.name=name;
                   
                    }
                    public String toString()
                    {
                        return "num:="+num+","+"name:="+name;
                    }
                    public int compareTo(Object o)            //覆盖方法
                    {
                        Student s=(Student)o;
                        int result = num>s.num? 1 : (num==s.num? 0 :-1); //制定自己的比较方法,按学号进行排序
                        if(result == 0)
                        {
                            result = name.compareTo(s.name); //调用String类的compareTo方法
                        }
                        return result;
                    }
                }
                输出结果:
                num:=2,name:=eisi
                num:=2,name:=lisi
                num:=3,name:=wangwu
                num:=4,name:=zhangshan
           
33、基本数据类型与封装类
            基本数据类型与封装类是一一对应的如:int 对应Integer类。那么他们之间怎么转换呢?
                例如:
                class Test
                {
                    public static void main(String[] args)
                    {
                        int i=3;
                        Integer in = new Integer(i);         //转换成Integer类型。
                        int j= in.intValue();               //转换成int
                        System.out.println(j);
                    }
                }
                其他类型与封装类都有类似的方法进行转型。
                那么String类型与Integer类型有什么转换呢。
                class Test
                {
                    public static void main(String[] args)
                    {
                       
                        Integer num = new Integer(1000);
                        int num1 = num.intValue();
                        System.out.println("Integer->int:"+num+"->"+num1);    //Integer对象转化为int.
       
                        float num2 = num.floatValue();
                        System.out.println("Integer->float:"+num+"->"+num2); //Integer对象类型转化为float
                       
                        String str1 = new String("123");
                        int an = Integer.parseInt(str1);
                        System.out.println("String->int:"+str1+"->"+an);              //String类型转化为int
       
                        int itoString = 23;
                        String st1 = Integer.toString(itoString);
                        System.out.println("int->String:"+itoString+"->"+st1);        //int类型转化为String
       
                        String str2 = new String("1234");
                        Integer in1 = Integer.valueOf(str2);
                        System.out.println("String->Integer:"+str2+"->"+in1);        //String类转化为Integer
       
                        Integer in2 = new Integer(200);
                        String st2 = in2.toString();//st2为类的实例,直接调用方法就可。
                        System.out.println("Integer->String:"+in2+"->"+st2);          //Integer类转化为String
                    }
                }
       
                输出结果为:
                    Integer->int:1000->1000
                    Integer->float:1000->1000.0
                    String->int:123->123
                    int->String:23->23
                    String->Integer:1234->1234
                    Integer->String:200->200
                方法说明:
                (1)public int intValue()以 int 类型返回该 Integer 的值。
                (2)public float floatValue()以 float 类型返回该 Integer 的值。
                (3)public static int parseInt(String s)
                            throws NumberFormatException将字符串参数作为有符号的十进制整数进行分析
                    参数:
                        s - 包含要分析的 int 表示形式的 String。
                    返回:
                        用十进制参数表示的整数值。
                (4)public static String toString(int i)返回一个表示指定整数的 String 对象。将该参数转换为有符号的十进制表示形式,以字符串形式返回它
                (5)public static Integer valueOf(String s)
                               throws NumberFormatException返回保持指定的 String 的值的 Integer 对象。将该参数解释为表示一个有符号的十进制整数, 就好像将该参数赋予 parseInt(java.lang.String) 方法一样。结果是一个表示字符串指定的整数值的 Integer 对象。
                (6)public String toString()返回一个表示该 Integer 值的 String 对象。
               
34、CLASS类
            在JAVA中,每个class都有一个相应的Class对象。我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
            获取Class实例的三种方式:
                (1)利用对象调用getClass()方法获取该对象的Class实例;
                (2)使用Class类的静态方法forName(),用类的名字获取一个Class实例。
                (3)运用。class的方式来获取Class实例,对于基本数据类型的封装类,还可采用.TYPE来获取相对应的基本数据类型的Class实例。
                Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
                以下示例使用 Class 对象来显示对象的类名:
                    void printClassName(Object obj) {
                        System.out.println("The class of " + obj +
                            " is " + obj.getClass().getName());
                    }
                还可以使用一个类字面值(JLS Section 15.8.2)来获得命名类型(或 void)的 Class 对象。例如:
                    System.out.println("The name of class Foo is: "+Foo.class.getName());
               
                示例:
                class Test
                {
                    public static void main(String[] args)
                    {
                       
                        Point pt = new Point();
                        Class c1 = pt.getClass();
                        System.out.println(c1.getName());
                        try
                        {
                            Class c2 = Class.forName("Point");
                            System.out.println(c2.getName());
                   
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                       
                        Class c3 = Point.class;
                        System.out.println(c3.getName());
       
                        Class c4 = int.class;
                        System.out.println(c4.getName());
       
                        Class c5 = Integer.TYPE;
                        System.out.println(c5.getName());
       
       
                    }
                }
                class Point
                {
                    int x,y;
                }
                输出结果为:
                Point
                Point
                Point
                int
                int
        视频4下j,k

35、ArrayList和Vector的区别,HashMap和Hashtable的区别
            答:就ArrayList与Vector主要从二方面来说.
            一.同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程不安全的,不是同步的,ArrayList效率高。要使用线程安全的同步列表使用:Collection.synchronizedList
            二.数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半
            就HashMap与HashTable主要从三方面来说。
            一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
            二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
            三.值:只有HashMap可以让你将空值作为一个表的条目的key或value
   
36、    程序、进程、线程
            程序是计算机指令的集合
            进程是资源申请、调度和独立运行的单位。进程使用系统中的运行资源,程序不能申请系统资源。
            线程是进程中一个单一的连续控制流程,一个进程可以拥有多个线程。线程没有独立的存储空间,而是和同属一个进程的线程共享一个存储空间。
            JAVA在语言级支持多线程:
                继承thread类:java.lang.thread,该类重写thread类的run方法
                实现Runable接口
                同步:有同步方法和同步块。
               
                1、线程可理解为程序里不同的执行路径。声明一个Thread的实例即创建了一个线程,run方法中的内容为线程的执行内容。
                        要想实现多线程,即同时有其它线程与主线程并行执行,则要声明一个Thread类的实例。
                        其实实现Runnable接口后也要声明Thread的实例
                        一般先使用实现接口的方法,再考虑是否继承Thread类。
                                public class TestRunnable {
                                        public static void main(String[] args) {
                                            Runner r = new Runner();
                                            Thread t = new Thread(r);   //构造方法Thread t = new Thread(Runnable r);
                                            t.start();                                    //new Thread(r).start();代替
                                            for(int i=0;i<100;i++){
                                                System.out.println("Thread main: "+i);
                                            }
                                        }
                                   
                                    }
                                    class Runner implements Runnable{
                                        public void run(){                              //注意如果不异常不能在这里使用public void run throws Exception,因为run是重写了Thread类的方法。
                                            for(int i=0;i<100;i++){
                                            System.out.println("Thread Runner: "+i);
                                            }
                                        }
                                    }
                                   
                2、理解主线程与其它线程执行步骤:
                                import java.util.Date;
                   
                                        public class TestRunnable {
                                            public static void main(String[] args) {
                                                Runner r = new Runner();
                                                r.start();                   //主线程与子线程并行执行开始
                                                try {
                                                    Thread.sleep(1000);        //主线程睡眠
                                                } catch (InterruptedException e) {
                                                    e.printStackTrace();
                                                }
                                                r.interrupt();               //打断子线程,使子线程中断,return
                                                System.out.println("main");  //现在只有主线程执行。
                                            }
                                       
                                        }
                                        class Runner extends Thread{
                                            public void run(){
                                            while(true){
                                                System.out.println(new Date());
                                                try {
                                                    sleep(1000);
                                                } catch (InterruptedException e) {
                                                    e.printStackTrace();
                                                    return;
                                                }
                                                }
                                               
                                            }
                                        }
                                       
                                       
                                        主线程执行
                                                |
                                                |        子线程执行
                                                |------|
                                                |sleep(1000) |
                                                |                         |sleep(1000)
                                                |调用        |
                                                |r.interrupt |
                                                |    打断子线程 |return子线程打断   
                                                |主线程打印main
                                   
                3、join方法
                    public final void join()
                        throws InterruptedException等待该线程终止
                        在主线程中调用JOIN方法,即主线程先等待该线程执行完,再执行主线程。相当于将两个并行执行的线程变为一个线程。
            4、yield方法
                        public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
                       
                5、线程互斥:
                        多个线程访问同一个资源的时候,要考虑同步的问题。如
                        银行取钱的问题:你和你朋友(你拿折,朋友拿卡)去取钱,同一个账号,
                                                                    3000
                                                                    |
                                                                |    |
                                                            |         |
                                                    你取2000         朋友拿卡取2000       
                                                如果不采用同步将共享的3000块锁定,那么你朋友取走2000块后你也取了2000块,那银行不亏死。。       
                        可以将取钱的方法放在同步方法或同步块中,锁定共用的资源。当一线程执行时将共用的资源锁定,此时只有该线程有权执行,执行完后其它线程才执行。
                        锁定可采用同步的方法或同步块。指执行该方法的时候锁定了当前的对象。synchronized(this){}当执行这个块的时候锁定当前对象。
                       
                6、多线程程序在执行过程中会发生死锁:
                            注意理解死锁是在多线程的基础上发生的。。。
                                死锁理解为两个或多个线程相互锁定了对方所需求的资源。。。(如两个线程都分别需要两个资源才能进行,但各自都只有一个资源,另一个资源
                                被对方锁定了,这个时候就发生死锁。。
                                著名的哲学家就餐问题就是这样(多个线程死锁)。。两根筷子,自己有一根另一根在别人那里,大家都只有一根筷子最后死锁,都吃不了。。
                                如程序示例:
                                        public class TestLock implements Runnable{
                                                public int flag=1;     //flag用于控制两个线程在run中执行的不同的块。
                                                static Object o1 = new Object(), o2 = new Object();
                                                public void run(){
                                                    System.out.println("flag:"+flag);
                                                    if(flag==1){
                                                        synchronized(o1){                //在这个块里包括另一个块,表示两个资源,必须都满足的时候才执行
                                                            try{
                                                                Thread.sleep(500);
                                                            }catch(Exception e){
                                                                e.printStackTrace();
                                                            }
                                                       
                                                            synchronized(o2){
                                                                System.out.println("1");
                                                            }
                                                        }
                                                    }
                                                   
                                                    if(flag==0){
                                                        synchronized(o2){
                                                            try{
                                                                Thread.sleep(500);
                                                            }catch(Exception e){
                                                                e.printStackTrace();
                                                            }
                                                       
                                                            synchronized(o1){
                                                                System.out.println("0");
                                                            }
                                                        }
                                                    }
                                                }
                                                public static void main(String[] args) {
                                                    TestLock t1 = new TestLock();         
                                                    TestLock t2 = new TestLock();
                                                    t1.flag=1;      //t1执行flag=1的块
                                                    t2.flag=0;      //t2执行flag=0的块
                                                    Thread th1 = new Thread(t1);     //两个线程的创建
                                                    Thread th2 = new Thread(t2);
                                                    th1.start();
                                                    th2.start();
                                                   
                                                   
                                                }
                                           
                                            }
                                输出结果为:
                                flag:1
                                flag:0
                                后来就没反应了。。即发生了死锁。
                           
                    7、线程同步:
                                    同步指一个线程执行过程中要等待另一线程的执行。
                       
                    下面的例子中Producer和Consumer两个线程共享了Query的资源。
           
                    生产者与消费者问题?
                        Producer为生产者类,Consumer为消费者类,Query队列类
                        public class TestThreads {
                                   
                                        public static void main(String[] args) {
                                            Query q = new Query();
                                            Producer p = new Producer(q);          //生产者与消费者两个线程使用的一定是同一个对象q.
                                            Consumer c = new Consumer(q);                     //生产者与消费者两个线程使用的一定是同一个对象q.
                                            p.start();
                                            c.start();
                                        }
                                   
                                    }
                                    class Producer extends Thread{
                                        Query q;
                                        Producer(Query q){
                                            this.q=q;
                                        }
                                        public void run(){
                                            for(int i=0;i<10;i++){
                                                q.put(i);
                                                System.out.println("producer:"+i);           //打印出生产的东西。
                                            }
                                        }
                                    }
                                    class Consumer extends Thread{
                                        Query q;
                                        Consumer(Query q){
                                            this.q=q;
                                        }
                                        public void run(){
                                            while(true){
                                                System.out.println("consumer"+q.get());       //打印出消费的东西。
                                            }
                                        }
                                    }
                                    class Query{
                                        int value;
                                        boolean bfull=false;                                //判断队列是否已满
                                        public synchronized void  put(int value){                        //两个线程访问同一对象的资源,一定要用synchronized方法进行互斥。
                                           
                                            if(!bfull){
                                                this.value=value;
                                                bfull=true;
                                                notify();
                                            }
                                            try {
                                                wait();
                                            } catch (InterruptedException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                        public synchronized int get(){
                                            if(!bfull){
                                                try {
                                                    wait();
                                                } catch (InterruptedException e) {
                                                    e.printStackTrace();
                                                }
                                            }
                                            bfull=false;
                                            notify();
                                            return value;
                                        }
                                    }
                                   
                生产者与消费者另一实例:
                           
                            public class ProducerConsumer {
                                public static void main(String[] args) {
                                    SyncStack ss = new SyncStack();
                                    Producer p = new Producer(ss);
                                    Consumer c = new Consumer(ss);
                                    new Thread(p).start();
                                    new Thread(p).start();
                                    new Thread(p).start();
                                    new Thread(c).start();
                                }
                            }
                           
                            class WoTou {
                                int id;
                                WoTou(int id) {
                                    this.id = id;
                                }
                                public String toString() {
                                    return "WoTou : " + id;
                                }
                            }
                           
                            class SyncStack {
                                int index = 0;
                                WoTou[] arrWT = new WoTou[6];
                               
                                public synchronized void push(WoTou wt) {
                                    while(index == arrWT.length) {
                                        try {
                                            this.wait();
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                    this.notifyAll();       
                                    arrWT[index] = wt;
                                    index ++;
                                }
                               
                                public synchronized WoTou pop() {
                                    while(index == 0) {
                                        try {
                                            this.wait();
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                    this.notifyAll();
                                    index--;
                                    return arrWT[index];
                                }
                            }
                           
                            class Producer implements Runnable {
                                SyncStack ss = null;
                                Producer(SyncStack ss) {
                                    this.ss = ss;
                                }
                               
                                public void run() {
                                    for(int i=0; i<20; i++) {
                                        WoTou wt = new WoTou(i);
                                        ss.push(wt);
                            System.out.println("生产了:" + wt);
                                        try {
                                            Thread.sleep((int)(Math.random() * 200));
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }           
                                    }
                                }
                            }
                           
                            class Consumer implements Runnable {
                                SyncStack ss = null;
                                Consumer(SyncStack ss) {
                                    this.ss = ss;
                                }
                               
                                public void run() {
                                    for(int i=0; i<20; i++) {
                                        WoTou wt = ss.pop();
                            System.out.println("消费了: " + wt);
                                        try {
                                            Thread.sleep((int)(Math.random() * 1000));
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }           
                                    }
                                }
                            }
   

37、集合
                java容器当中不能存放基本类型的数据,而只能存放内置类型的数据。
                list 、set接口继承自Collection接口;
                set不可重复,不包含重复的元素,SortedSet是一个按照升序排序元素的set.
                list是一个有序的集合,但并不是排序的。。可包含重复元素。提供按索引访问的方式。(重复是指两个对象互相equals)
                Map包含了KEY-VALUE对,MAP不能包含重复的KEY,SortedMap是一个按照升序排列key的map.
                1、ArrayList:
                    看作是一个能够自动增长容量的数组。
                    利用ArrayList的toArray()返回一个数组
                    Arrays.asList()返回一个列表。
                2、迭代器(Iterator)给我们提供了一种通用的方式访问集合中的元素。
                    Iterator调用remove()前先调用next().
                3、类collections类
                    sort()方法用于对列表进行排序。
                    但类必须实现comparable接口跟Arrays类中的sort()方法一样。。
                1、例:ArrayListTest.java
                    import java.util.*;
                    class ArrayListTest
                    {
                        public static void main(String[] args)
                        {
                       
                            ArrayList<String> al = new ArrayList<String>();//注意:ArrayList<E>,这里如果仅用ArrayList al = new ArrayList();编译会提示使用了未经检查或不安全的操作。
                            al.add("adfsf");
                            al.add("dfe");
                            System.out.println(al);//two print method
                            for(int i=0;i<al.size();i++)
                            {
                                System.out.println(al.get(i));
                            }
                           
                        }
                    }
           
                例:ArrayListTest.java
                此例表示在ArrayList中添加自定义类型的对象,并通过覆盖toString()方法打印出来
                    import java.util.*;
                    class ArrayListTest
                    {
                        public static void main(String[] args)
                        {
                       
                            ArrayList<Point> al = new ArrayList<Point>();//注意类型改为<point>
                            al.add(new Point(23,45));                    //添加对象类型
                            System.out.println(al);//two print method
                            for(int i=0;i<al.size();i++)
                            {
                                System.out.println(al.get(i));
                            }
                       
                        }
                    }
           
                    class Point
                    {
                        int x,y;
                        Point(int x,int y)
                        {
                            this.x=x;
                            this.y=y;
                           
                        }
                        public String toString()
                        {
                            return "x="+x+";y="+y;
                       
                        }
                    }
                在上例中加入toArray方法从列表中返回元素到数组中
                例:ArrayListTest.java
                    import java.util.*;
                    class ArrayListTest
                    {
                        public static void main(String[] args)
                        {
                       
                            ArrayList<Point> al = new ArrayList<Point>();
                            al.add(new Point(23,45));
                            al.add(new Point(232,434));
                            System.out.println(al);//two print method
                            for(int i=0;i<al.size();i++)
                            {
                                System.out.println(al.get(i));
                            }
                            Object[] o =al.toArray();              //调用ArrayList类中的toArray();
                            for(int i=0;i<o.length;i++)
                            {
                                System.out.println(o[i]);
                            }
                       
                        }
                    }
           
                    class Point
                    {
                        int x,y;
                        Point(int x,int y)
                        {
                            this.x=x;
                            this.y=y;
                           
                        }
                        public String toString()
                        {
                            return "x="+x+";y="+y;
                       
                        }
                    }
                使用Arrays.asList();从数组返回一个固定长度的列表
                    import java.util.*;
                    class ArrayListTest
                    {
                        public static void main(String[] args)
                        {
                       
                            ArrayList<Point> al = new ArrayList<Point>();
                            al.add(new Point(23,45));
                            al.add(new Point(232,434));
                            System.out.println(al);//two print method
                            for(int i=0;i<al.size();i++)
                            {
                                System.out.println(al.get(i));
                            }
                            Object[] o =al.toArray();
                            for(int i=0;i<o.length;i++)
                            {
                                System.out.println(o[i]);
                            }
                            List<Object> l = Arrays.asList(o);          //数组到列表
                            System.out.println(l);
                        }
                    }
           
                    class Point
                    {
                        int x,y;
                        Point(int x,int y)
                        {
                            this.x=x;
                            this.y=y;
                           
                        }
                        public String toString()
                        {
                            return "x="+x+";y="+y;
                       
                        }
                    }
               
                2、迭代器
                创建单独的方法用于输出集合中的元素
                import java.util.*;
           
                    public class Test1 {
                        public static void main(String[] args)
                        {
                            List an = new ArrayList();
                            an.add("dfdf");
                            an.add("wewe");
                    //        Iterator in = an.iterator();
                    //        while(in.hasNext())
                    //        {
                    //            System.out.println(in.next());
                    //        }
                    //        在main中使用迭代器
                            printElement( an);//调用函数使用迭代器
                        }
                        public static void printElement(Collection c)
                        {
                            Iterator i = c.iterator();
                            while(i.hasNext())
                            {
                                System.out.println(i.next());
                            }
                        }
                    }
                   
                    还有remove方法,可调用i.remove(),但注意在这里面不能使用c.remove(),因为迭代器管理元素时将锁定,只有自己可以操作.
           
                3、Collections类
                Collections类为List提供了对List的相关操作
                    注意与数组的操作System.arrayCopy(),Arrays.sort()和Arrays.binarySearch()相比较。
                    排序:Collections.sort();
                    (1)自然排序
                                import java.util.*;
                                        public class TestList{
                                                public static void main(String[] args){
                                                   
                                                    List l = new LinkedList();
                                                    for(int i=0;i<=5;i++){
                                                        l.add("a"+i);
                                                    }
                                                    System.out.println(l);
                                                    Collections.shuffle(l);       //随机排序
                                                    System.out.println(l);
                                                    Collections.reverse(l);             //反序
                                                    System.out.println(l);
                                                    Collections.sort(l);                    //排序
                                                    System.out.println(l);
                                                    System.out.println(Collections.binarySearch(l,"a5"));   //折半查找
                                                   
                                            }
                                        }
                                    输出结果:
                                    [a0, a1, a2, a3, a4, a5]
                                    [a4, a5, a2, a1, a3, a0]
                                    [a0, a3, a1, a2, a5, a4]
                                    [a0, a1, a2, a3, a4, a5]
                                    5
                                    任何要实现排序的类都要实现Comparable接口,这里String类实现了这个接口
                    (2)实现比较器Comparable接口
                    取最大和最小元素:Collections.max(),Collections.min();
                    在已排序的List中搜索指定的元素:Collections.binarySearch();
           
                    例:CollectionsTest。java
                   
                    import java.util.*;
                    public class CollectionsTest
                    {
                        public static void main(String[] args)
                        {
                           
                            Student s1 = new Student(2,"lmew");
                            Student s2 = new Student(3,"mfsf");
                            Student s3 = new Student(4,"bfee");
                            ArrayList al = new ArrayList();
                            al.add(s2);
                            al.add(s1);
                            al.add(s3);
                            printElement(al);      //打印排序之前的序列
                            Collections.sort(al);
                            printElement(al);        //打印排序之后的序列
                            System.out.println("Hello World!");
                        }
                        public static void printElement(Collection c)  //定义静态方法方便打印
                        {
                            Iterator i = c.iterator();
                            while(i.hasNext())
                            {
                                System.out.println(i.next());
                            }
                        }
                    }
                    class Student implements Comparable        //实现Comparable接口,这个与Arrays.sort()方法一样,也要实现接口和覆盖compareTo方法。
                    {
                        int num;
                        String name;
                        Student(int num,String name)
                        {
                            this.num=num;
                            this.name=name;
                        }
                        public int compareTo(Object o)
                        {
                            Student s = (Student)o;
                            return num>s.num ? 1 : (num==s.num ? 0 :-1);        //对集合中的元素按num即学号排序
                        }
                        public String toString()
                        {
                            return "num:"+num+",name:"+name;
                        }
                    }
                如果我想按别的方式排序怎么办?
                实现另一接口:Comparator接口和覆盖compare(Object o,Object o)方法。得用静态内部类实现Comparator接口并覆盖方法compare
                import java.util.*;
                public class CollectionsTest
                {
                    public static void main(String[] args)
                    {
                       
                        Student s1 = new Student(2,"lmew");
                        Student s2 = new Student(3,"mfsf");
                        Student s3 = new Student(4,"bfee");
                        Student s4 = new Student(4,"adsdsd");
                       
                        ArrayList al = new ArrayList();
                        al.add(s1);
                        al.add(s2);
                        al.add(s3);
                        al.add(s4);
                        System.out.println("按添加的顺序输出");
                        printElement(al);
                        System.out.println("调用sort输出");
                        Collections.sort(al);
                        printElement(al);
                        System.out.println("调用sort输出并实现了比较器");
                        Collections.sort(al,new Student.StudentComparator());
                        // Collections类还提供reverseOrder方法用于反序输出。
                        //Collections.sort(al,Collections.reverseOrder());
                        printElement(al);
                       
                    }
                    public static void printElement(Collection c)
                    {
                        Iterator i = c.iterator();
                        while(i.hasNext())
                        {
                            System.out.println(i.next());              //next()返回的是Object类型.
                        }
                    }
                }
                class Student implements Comparable
                {
                    int num;
                    String name;
                    static class StudentComparator implements Comparator //内部类实现比较器,注意Comparator接口有两个方法compare和equals方法,按理都要覆盖实现,但equals方法从object类继承而来,所以其它类默认继承了此方法。
                    {
                        public int compare(Object o1,Object o2)
                        {
                            Student s1 =(Student)o1;
                            Student s2 =(Student)o2;
                            int result=s1.num>s2.num ? 1 : (s1.num==s2.num ? 0 : -1);
                            if(result==0)
                            {
                                result= s1.name.compareTo(s2.name); //当学号相同的时候比较名字
                            }
                            return result;
                           
                           
                        }
                    }
                    Student(int num,String name)
                    {
                        this.num=num;
                        this.name=name;
                    }
                    public int compareTo(Object o)
                    {
                        Student s = (Student)o;
                        return num>s.num ? 1 : (num==s.num ? 0 :-1);
                    }
                    public String toString()
                    {
                        return "num:"+num+",name:"+name;
                    }
                }


38、JAVA数据结构
                LinkedList
                import java.util.*;
                        public class TestList{
                                public static void main(String[] args){
                                   
                                    List l = new LinkedList();
                                    for(int i=0;i<=5;i++){
                                        l.add("a"+i);
                                    }
                                    System.out.println(l);
                                    l.add(3,"a100");
                                    System.out.println(l);
                                    l.set(3,"a101");  //返回原位置的对象
                                    System.out.println(l);
                                    System.out.println((String)l.get(3));
                                    System.out.println(l.indexOf("a4"));
                                    l.remove(3);
                                    System.out.println(l);
                            }
                        }
                    输出结果为:
                    [a0, a1, a2, a3, a4, a5]
                    [a0, a1, a2, a100, a3, a4, a5]
                    [a0, a1, a2, a101, a3, a4, a5]
                    a101
                    5
                    [a0, a1, a2, a3, a4, a5]
               
                实现栈:Mystack.java
                import java.util.*;
                class Mystack
                {
                    private LinkedList<Object> ll = new LinkedList<Object>();
                    public void push(Object o)              //入栈,即在栈顶添加元素
                    {
                        ll.addFirst(o);
                    }
                    public Object pop()                   //出栈,删除栈顶元素并返回值
                    {
                        return ll.removeFirst();
                    }
                    public Object peek()                      //获得栈顶元素值
                    {
                        return ll.getFirst();
                    }
                    public boolean empty()                  //栈是否为空
                    {
                        return ll.isEmpty();
                    }
                    public static void main(String[] args)
                    {
                        Mystack ms = new Mystack();
                        ms.push("one");
                        ms.push("two");
                        ms.push("three");
           
                        System.out.println(ms.pop());
                        System.out.println(ms.peek());
                        System.out.println(ms.pop());
                        System.out.println(ms.empty());
                    }
                }
                输出结果为:
                three
                two
                two
                false
                下例:MyQueue.java
                实现队列
                import java.util.*;
                class MyQueue
                {
                    private LinkedList<Object> ll = new  LinkedList<Object>();
                    public void put(Object o)
                    {
                        ll.addLast(o);
                    }
           
                    public Object get()
                    {
                        return ll.removeFirst();
                    }
           
                    public boolean empty()
                    {
                        return ll.isEmpty();
                    }
                    public static void main(String[] args)
                    {
                        MyQueue my = new MyQueue();
                        my.put("one");
                        my.put("two");
                        my.put("three");
           
                        System.out.println(my.get());
                        System.out.println(my.get());
                        System.out.println(my.get());
                        System.out.println(my.empty());
                    }
                }
                输出结果为:
                one
                two
                three
                true
           
                ArrayList与LinkedList
                ArrayList底层采用数组完成,而LinkedList则是以一般双向链表完成,其内每个对象除了数据本身外还有两个引用,分别指向前一个元素和后一个元素。
                如果经常在List开始处增加元素,或在List中进行插入和删除操作,应该使用LinkedList,否则使用ArrayList.

39、HashSet

               
                import java.util.*;
                            public class TestHashSet{
                                    public static void main(String[] args){
                                        Set s1 = new HashSet();
                                        Set s2 = new HashSet();
                                        s1.add("a");
                                        s1.add("b");
                                        s1.add("c");
                                       
                                        s2.add("a");
                                        s2.add("b");
                                        s2.add("d");
                                       
                                        Set sn = new HashSet(s1);
                                        sn.retainAll(s2);        //取交集
                                       
                                        Set su = new HashSet(s1);
                                        su.addAll(s2);            //取并集,但非重复
                                       
                                        System.out.println(sn);
                                        System.out.println(su);
                                       
                                }
                            }
                            结果为:
                            [a, b]
                            [d, a, c, b]
               
                HashSet 中没有获得元素的方法,只能通过迭代器
                import java.util.*;
                class HashSetTest
                {
                    public static void main(String[] args)
                    {
                        HashSet<String> ha = new HashSet<String>();
                        ha.add("one");
                        ha.add("two");
                        ha.add("two");
                        Iterator it = ha.iterator();
                        while(it.hasNext())
                        {
                            System.out.println(it.next());
                        }
                    }
                }
                HashSet不包括重复对象。
                如上例运行结果是:
                one
                two
               
                注意:程序因为String类覆盖了HashCode方法和equals方法,所以才认为两个two是重复的,如果在容器中添加的是自己定义的类对象,而又没有覆盖方法才认为非同一对象,如下例:
               
                看下面对学生类对象的应用情况
                import java.util.*;
                class HashSetTest
                {
                    public static void main(String[] args)
                    {
                        HashSet<Student> ha = new HashSet<Student>();
                        ha.add(new Student(1,"zhangsan"));
                        ha.add(new Student(2,"sfewe"));
                        ha.add(new Student(3,"sfsfsf"));
                        ha.add(new Student(2,"sfewe"));
                        Iterator it = ha.iterator();
                        while(it.hasNext())
                        {
                            System.out.println(it.next());
                        }
                    }
                }
           
                class Student
                {
                    int num;
                    String name;
                    Student(int num,String name)
                    {
                        this.num = num;
                        this.name = name;
                    }
                    public String toString()
                    {
                        return "num:"+num+",name:"+name;
                    }
                }
                结果:
                num:2,name:sfewe
                num:3,name:sfsfsf
                num:1,name:zhangsan
                num:2,name:sfewe
                会发现输出中输出的顺序与添加的顺序不一样。另外有两行一样的:num:2,name:sfewe,我们认为这两行是一样的,但HashSet认为这是两个新的对象,是不同的。
                为什么呢?
                主要是HashSet在存储元素的时候要根据散列码来计算他的存储位置,而他是利用Object中的HashCode计算出来的,而HashCode是通过对象的内存地址来得到散列码的,
                在这里用的是new ..即是两个对象,即他们的内存也不一样的。即他们的HashCode不一样。
                所以对于要存储的类,每个元素应该重写HashCode方法和equals方法。如String类也覆盖了HashCode方法和equals方法
                如对学生类覆盖方法HashCode和equals方法之后打印出来将不再出现重复。
                import java.util.*;
                class HashSetTest
                {
                    public static void main(String[] args)
                    {
                        HashSet<Student> ha = new HashSet<Student>();
                        ha.add(new Student(1,"zhangsan"));
                        ha.add(new Student(2,"sfewe"));
                        ha.add(new Student(3,"sfsfsf"));
                        ha.add(new Student(2,"sfewe"));
                        Iterator it = ha.iterator();
                        while(it.hasNext())
                        {
                            System.out.println(it.next());
                        }
                    }
                }
           
                class Student
                {
                    int num;
                    String name;
                    Student(int num,String name)
                    {
                        this.num = num;
                        this.name = name;
                    }
                    public String toString()
                    {
                        return "num:"+num+",name:"+name;
                    }
                    public int hashCode()
                    {
                        return num*name.hashCode();           //name.hashCode();即String.hashCode()
                    }
           
                    public boolean equals(Object o)
                    {
                        Student s = (Student)o;
                        return num==s.num && name==s.name ? true : false;
                    }
                }
                输出结果为:
                num:2,name:sfewe
                num:3,name:sfsfsf
                num:1,name:zhangsan

40、TreeSet
                TreeSet是实现SortedSet接口类。依靠HashMap来实现。
                TreeSet是一个有序的集合,按升序排序,缺省的时候按自然顺序进行排列,意味着TreeSet来实现Comparable接口
                可在构造TreeSet对象的时候,传递实现Comparable的比较器。即:public TreeSet()和public TreeSet(Comparator<? super E> c)一个是自然排列一个是按比较器排序
                import java.util.*;
                class TreeSetTest
                {
                    public static void main(String[] args)
                    {
                        //TreeSet<Student> tr = new TreeSet<Student>();
                        TreeSet tr = new TreeSet(new Student.StudentComparator());
                        Student s1 = new Student(2,"lmew");
                        Student s2 = new Student(3,"mfsf");
                        Student s3 = new Student(4,"bfee");
                        Student s4 = new Student(4,"adsdsd");
                        tr.add(s1);
                        tr.add(s2);
                        tr.add(s3);
                        tr.add(s4);
                        Iterator it = tr.iterator();
                        while(it.hasNext())
                        {
                            System.out.println(it.next());
                        }
                       
                    }
           
                }
           
                class Student implements Comparable
                {
                    int num;
                    String name;
                    static class StudentComparator implements Comparator //内部类实现比较器,注意Comparator接口有两个方法compartTo和equals方法,按理都要覆盖实现,但equals方法从object类继承而来,所以其它类默认继承了此方法。
                        {
                            public int compare(Object o1,Object o2)
                            {
                                Student s1 =(Student)o1;
                                Student s2 =(Student)o2;
                                int result=s1.num>s2.num ? 1 : (s1.num==s2.num ? 0 : -1);
                                if(result==0)
                                {
                                    result= s1.name.compareTo(s2.name); //当学号相同的时候比较名字
                                }
                                return result;
                               
                               
                            }
                        }
                    Student(int num,String name)
                    {
                        this.num = num;
                        this.name = name;
                    }
                    public int compareTo(Object o)
                    {
                        Student s = (Student)o;
                        return num>s.num ? 1 : (num==s.num ? 0 : -1);
                    }
                    public String toString()
                    {
                        return "num:"+num+",name:"+name;
                    }
           
                }
                一般使用HashSet,只有当需要排序的时候使用TreeSet.

41、HashMap
            通过put和get方法放置值和获得值。
            或通过keySet方法返回key,通过values方法返回value
            import java.util.*;
            class HashMapTest
            {
                public static void printElement(Collection c)
                {
                    Iterator i = c.iterator();
                    while(i.hasNext())
                    {
                        System.out.println(i.next());
                    }
                }
                public static void main(String[] args)
                {
                    System.out.println("Hello World!");
                    HashMap<String,String> hs = new HashMap<String,String>();
                    hs.put("one","zhangsan");
                    hs.put("two","lisi");
                    hs.put("three","wangwu");
       
                    System.out.println(hs.get("one"));
                    System.out.println(hs.get("two"));
                    System.out.println(hs.get("three"));
       
                    Set keys = hs.keySet();          //JAVA API 文档,返回key
                    System.out.println("key:");
                    printElement(keys);
       
                    Collection values = hs.values(); //返回value
                    System.out.println("values:");
                    printElement(values);
       
       
                }
            }
            输出结果:
            Hello World!
            zhangsan
            lisi
            wangwu
            key:
            one
            two
            three
            values:
            zhangsan
            lisi
            wangwu
       
            另一种方法获得KEY-VALUES
            import java.util.*;
            class HashMapTest
            {
                public static void printElement(Collection c)
                {
                    Iterator i = c.iterator();
                    while(i.hasNext())
                    {
                        System.out.println(i.next());
                    }
                }
                public static void main(String[] args)
                {
                    System.out.println("Hello World!");
                    HashMap<String,String> hs = new HashMap<String,String>();
                    hs.put("one","zhangsan");
                    hs.put("two","lisi");
                    hs.put("three","wangwu");
       
                    System.out.println(hs.get("one"));
                    System.out.println(hs.get("two"));
                    System.out.println(hs.get("three"));
       
                    Set keys = hs.keySet();
                    System.out.println("key:");
                    printElement(keys);
       
                    Collection values = hs.values();
                    System.out.println("values:");
                    printElement(values);
                   
                    Set entry = hs.entrySet();
                    //entrySet返回此映射所包含的映射关系的 collection 视图。在返回的集合中,每个元素都是一个 Map.Entry。
                    printElement(entry);        //打印结果形式为:one=zhangsan
                    //下面通过其它方法打印:
                    Iterator it = entry.iterator();
                    while(it.hasNext())
                    {
                        Map.Entry me= (Map.Entry)it.next();
                        System.out.println(me.getKey()+":"+me.getValue());    //通过此方法输出将变成:one:zhangsan形式
                    }
       
       
                }
            }
           
            TreeMap按KEY进行排序,实现了SortedMap接口
            HashMap通常比TreeMap快只有在使用排序的时候才使用TreeMap。
           
42、集合类说明
                JAVA 1.0/1.1 使用前后对比见35小节
                前                              后
                Vector                     ArrayList
                HashTable                     HashMap
                Stack                       LinkList
                Properties
                示例:获得系统属性
                import java.util.Properties;
           
                public class PropTest {
           
                    /**
                     * @param args
                     */
                    public static void main(String[] args) {
                        // TODO Auto-generated method stub
                        Properties p = System.getProperties();
                        p.list(System.out);
           
                    }
           
                }
           
                以下示例从配置文件中读取键值对
                winsun.ini里面内容为:compamy=sunxin
                        author=luweifeng
                        copyright=2003-2004
                import java.util.Enumeration;
                import java.util.Properties;
                import java.io.*;
                public class PropTest {
           
                    /**
                     * @param args
                     */
                    public static void main(String[] args) {
                        // TODO Auto-generated method stub
                        Properties p = new Properties();
                        try
                        {
                            p.load(new FileInputStream("E://JAVA TEST//winsun.ini"));       
                            Enumeration e = p.propertyNames();
                            while(e.hasMoreElements())
                            {
                                String strKey = (String)e.nextElement();
                                String strValues = p.getProperty(strKey);
                                System.out.println(strKey+":"+strValues);
                            }
                        }
                        catch(Exception e)
                        {
                            e.printStackTrace();
                        }
                       
           
                    }
           
                }
                输出结果:
                copyright:2003-2004
                author:luweifeng
                compamy:sunxin

43、java.io
    输入输出操作
    1、File类:
    表示磁盘上的文件或目录,它提供了与平台无关的方法来对磁盘上文件和目录进行操作。
       (1)可先创建File类的对象,然后能过createFile()和mkdir()方法创建文件和目录,但注意这两个不能同时创建:
        如:FileTest.java
        import java.io.*;
        class FileTest
        {
            public static void main(String[] args)  throws Exception
            {
                File f = new File("java lesson");    
                //调用构造函数:File(String pathname)  通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。
                //创建文件可把文件名设为1.txt,1.doc运行后会在类文件所在目录创建相应的文件
                //File f = new File("1.txt");    在类文件所在目录创建文本文件1.txt
                //File f = new File("E://JAVA TEST//1.txt");    指定目录创建文本文件,注意分隔符要使用//而不是/因为/JAVA当作转意字符。
                boolean w =f.createNewFile();
                boolean m =f.mkdir();
                System.out.println("w:"+w);
                System.out.println("m:"+m);
            }
        }
        结果:
        w:true
        m:false
        结果表明:文件创建成功,目录并没有创建,运行也没有报错
        现在把创建目录放在前面
        import java.io.*;
        class FileTest
        {
            public static void main(String[] args)  throws Exception
            {
                File f = new File("java lesson");
                boolean m =f.mkdir();
                boolean w =f.createNewFile();
                System.out.println("w:"+w);
                System.out.println("m:"+m);
            }
        }
        运行时出错:
        Exception in thread "main" java.io.IOException: 拒绝访问。
        at java.io.WinNTFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(File.java:850)
        at FileTest.main(FileTest.java:9)
        表示不能创建文件,但查看程序目录可发现创建了java lesson目录,说明boolean m =f.mkdir();执行成功的,
        那为什么创建文件与创建目录不能用同一个对象进行呢??
        其实很简单:你一个JAVA LESSON系统不可能即认为是目录又认为文件,所以按先到先创建的方式进行。。


       (2)在Windows下和Linux由于目录分隔符不同,那么怎么使用一套程序做到都可以适用呢?
            使用File类的separator属性,即产生一个分隔符,如在Linux下值为:/,而在windows下值为/。
            看下例:
                使用了File类的构造函数:File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
            import java.io.*;
            class FileTest
            {
                public static void main(String[] args)  throws Exception
                {
                    File f = new File(File.separator);   //先用构造函数File(String pathname)创建一个对象,内容在Linux下为/,在windows下默认为当前类文件所在的盘符根目录,如FileTest.java在E盘,那么File.separator所得内容为E:/.注意:如果在字符串中则File.separator值为/,如下语句:
                    String fname ="JAVA TEST"+File.separator+"lesson"+File.separator+"1.txt";       //实际目录为:JAVA TEST/lesson/1.txt
                    File fn = new File(f,fname);         //File(File parent, String child) :即在目录创建文件,目录为:E:/JAVA TEST/lesson/1.txt
                    fn.createNewFile();
                    //可打印值测试如下:
                    //System.out.println(File.separator); //值为:/                 注:程序在windows下运行。

                }
            }
           

       (3)删除文件命令:delete()删除此抽象路径名表示的文件或目录。
              deleteOnExit()方法:在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
              如:
              import java.io.*;
            class FileTest
            {
                public static void main(String[] args)  throws Exception
                {
                    File f = new File(File.separator);
                    String fname ="JAVA TEST"+File.separator+"lesson"+File.separator+"1.txt";
                    File fn = new File(f,fname);
                    fn.createNewFile();
                    fn.delete();         //删除对象fn创建的文件1.txt
                }
            }

       (4)deleteOnExit()的用法:
            import java.io.*;
            class FileTest
            {
                public static void main(String[] args)  throws Exception
                {
                    File f = new File(File.separator);
                    String fname ="JAVA TEST"+File.separator+"lesson"+File.separator+"1.txt";
                    File fn = new File(f,fname);
                    fn.createNewFile();
                    //fn.delete();
                    fn.deleteOnExit();
                    Thread.sleep(3000);//为了看清楚变化过程,先使用线程睡眠,调用java FileTest 可看到1.txt先创建,过了3000ms后自动删除。如果不使线程睡眠,则看不到这个过程,因为删除时间很短,我们看不到。
                }
            }
           
        deleteOnExit方法可用于先产生一些临时文件,程序运行完后删除。
            java提供了产生临时文件的方法:
                createTempFile(String prefix, String suffix) 在默认临时文件目录中创建一个空文件
                注意:Windows默认临时文件夹,可查看环境变量Temp所指路径,我本机路径为:C:/Documents and Settings/zqwf/Local Settings/Temp
                看以下程序:
                import java.io.*;
                class FileTest
                {
                    public static void main(String[] args)  throws Exception
                    {
                       
                        for(int i=0;i<5;i++)
                        {
                            File.createTempFile("winsun",".txt");     //为静态方法直接采用类名调用      
                            //static File createTempFile(String prefix, String suffix) 在默认临时文件目录中创建一个空文件
                            //prefix - 用于生成文件名的前缀字符串;至少必须是三个字符长
                            //suffix - 用于生成文件名的后缀字符串;可能是 null,在这种情况下,将使用后缀 ".tmp"

                        }
                    }
                }
                运行结果:
                会在C:/Documents and Settings/zqwf/Local Settings/Temp产生以winsun为前缀然后加上随机数字及后缀组成的文件。
                如本例在目录下产生文件:winsum6562.txt,winsum6563.txt,winsum6564.txt,winsum6565.txt,winsum6566.txt

                下面结合deleteOnExit()一起用:
                import java.io.*;
                class FileTest
                {
                    public static void main(String[] args)  throws Exception
                    {
                       
                        for(int i=0;i<5;i++)
                        {
                            File f =File.createTempFile("winsun",".txt");    //因为要调用deleteOnExit方法,所以先保存引用f      
                            //createTempFile(String prefix, String suffix) 在默认临时文件目录中创建一个空文件
                            f.deleteOnExit();
                            Thread.sleep(3000);
                        }
                       
                    }
                }
                临时文件创建后,再删除
        list()返回目录下的文件名或目录名:
            public String[] list()返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。

            import java.io.*;
            class FileTest
            {
                public static void main(String[] args)  throws Exception
                {
                    File f = new File(File.separator);
                    String strMl = "JAVA TEST"+File.separator+"lesson";
                    File fn = new File(f,strMl);
                    String[] a =fn.list();
                    for(int i=0;i<a.length;i++)
                    {
                        System.out.println(a[i]);
                    }
                }
            }

            输出结果为:
            1.txt
            erer
            FileTest.class
            FileTest.java
            FileTest.java.bak
            即在目录:E:/JAVA TEST/lesson目录下有以上文件或目录。
            那么要想进一步了解这个名字到底是文件还是目录可调用public boolean isDirectory()测试此抽象路径名表示的文件是否是一个目录。返回为true则为目录。否则为文件。
       
        使用过滤器列出以某条件限定的文件名。
        刚上面列出来的文件是目录下全部的文件或目录,那么我现在只想列出以.java为后缀名的文件应该采取什么方法呢?
        看方法:
            public String[] list(FilenameFilter filter)
            返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。
            此方法的行为与 list() 方法相同,除了所返回数组中的字符串必须满足过滤器。如果给定 filter 为 null,则接受所有名称。否则,
            当且仅当在此抽象路径名和它所表示的目录中的文件名或目录名上调用过滤器的 FilenameFilter.accept(java.io.File, java.lang.String) 方法返回 true 时,该名称才满足过滤器。
            另外因为参数FilenameFilter为一个接口,所以应该实现方法accept.
            在上例的基础上改写代码如下:
            import java.io.*;
            class FileTest
            {
                public static void main(String[] args)  throws Exception
                {
                    File f = new File(File.separator);
                    String strMl = "JAVA TEST"+File.separator+"lesson";
                    File fn = new File(f,strMl);
                    String[] a =fn.list(new FilenameFilter()
                        {
                            public boolean accept(File dir,String name) //注意要用abstract接口中方法默认权限为public
                            {
                                return name.indexOf(".java")!=-1;      //public int indexOf(String str)返回第一次出现的指定子字符串在此字符串中的索引。
                                                      //如果字符串参数作为一个子字符串在此对象中出现,则返回第一个这样的子字符串的第一个字符的索引;如果它不作为一个子字符串出现,则返回 -1
                            }
                        }
                    );
                    //这里因为方法public String[] list(FilenameFilter filter)的参数为一接口,那么如果声明为String[] a =fn.list(new FilenameFilter());因为接口不能实例化,
                    //所以这里采用匿名内部类返回接口的一个对象,如在匿名内部类中有代码:
                            /*
                                return new Animal()
                                {
                                    public void eate()
                                    {
                                        System.out.println("niming eate");
                                    }
                                    public void sleep()
                                    {
                                        System.out.println("niming sleep");
                                    }   
                                };
                            */
                    //原意是想return new Animal();,此时需要注意:";"分号为这一语句的语句结束符,跟JAVA中其他语句结束符是一样的意思,在本例程序中,因为FilenameFilter filter为参数名,故不存在语句结束符
                    //所以将代码:new FilenameFilter()写成匿名内部类实现的方式即可;在new FilenameFilter()后加入语句块{}里面实现接口FilenameFilter的accept方法即可。
                       
                    for(int i=0;i<a.length;i++)
                    {
                        System.out.println(a[i]);
                    }
                }
            }

            输出结果为:
            FileTest.java
            FileTest.java.bak
            即为所有以.java为后缀的文件名

    2、读取数据、写数据相关操作
        流式I/O
            (1)流(Stream)是字节的源或目的。
            (2)两种基本的流是:输入流InputStream和输出流OutputStream.可从中读出一系列字节的对象称为输入流,而能向其中写入一系列字节的对象称为输出流。
        流的分类:分为节点流:从特定的地方读写的流类,如从磁盘或一块内存区域。
                  过滤流:使用节点流进行输入与输出,过滤流是使用一个已经存在的输入流或输出流连接创建的。
           

        (1)InputStream输入流
            public abstract class InputStream extends Object implements Closeable 此抽象类是表示字节输入流的所有类的超类。
            需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法。
            public abstract int read()
                     throws IOException从输入流读取下一个数据字节。返回 0 到 255 范围内的 int 字节值。
                 如果因已到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流的末尾或者抛出异常前,此方法一直阻塞。
       
            InputStream类层次
                        |    AudioInputStream       !                                   
                        |    ByteArrayInputStream                      
                        |    FileInputStream                          
                InputStream ----|    FilterInputStream------------------------------------------|        BufferedInputStream
                        |    InputStream(org.omg.CORBA.portable.InputStream)           |        CheckedInputStream
                        |    ObjectInputStream                       |        CipherInputStream
                        |    PipedInputStream                       |        DataInputStream
                        |    SequenceInputStream    !                   |        DigestInputStream
                        |    StringBufferInputStream    !                   |        InflaterInputStream          !
                                                           |        LineNumberInputStream      !
                                                           |        ProgressMonitorInputStream    !
                                                           |        PushbackInputStream           !
                !表示OutputStream所没有的子类。
        (2)OutputStream输出流
            相关写方法查看api
            OutputStream类层次
                        |      ByteArrayOutputStream                |    BufferedOutputStream
                        |      FileOutputStream                    |    CheckedOutputStream
                        |      FilterOutputStream-----------------------------    |    CipherOutputStream
                OutputStream----|                                  |    DataOutputStream
                        |      ObjectOutputStream                |    DeflaterOutputStream
                        |      OutputStream                    |    DigestOutputStream
                        |      PipedOutputStream                |    PrintStream
                                           
                                                       
            PrintStream   
                查看System.out.println();中的out
                在java.lang.System类中:
                    public static final PrintStream out
            示例使用标准输入与标准输出
                class StreamTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        int data;
                        while((data=System.in.read())!=-1)
                        {
                            System.out.write(data);
                           
                        }
                    }
                }

        (3) 基本的流类
            1.FileInputStream与FileOutputStream(文件存在则覆盖文件)
                FileInputStream 从文件系统中的某个文件中获取输入字节。哪些文件可用取决于主机环境。
                FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
                文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
                FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter。
                           
                FileInputStream与FileOutputStream
                import java.io.*;
                class StreamTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        FileInputStream f = new FileInputStream(new File("E://JAVA TEST//lesson//1.txt")); //创建字节输入流对象
                        FileOutputStream fo = new FileOutputStream(new File("E://JAVA TEST//lesson//2.txt"));//创建字节输出流对象
                        int data;
                        while((data=f.read())!=-1)
                        {
                            fo.write(data);
                        }

                    }
                }

                如下例:
                import java.io.*;
                class StreamTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        FileOutputStream fo = new FileOutputStream("E://JAVA TEST//lesson//1.txt");
                        fo.write("www.163.com".getBytes());          //public byte[] getBytes()使用平台默认的字符集将此 String 解码为字节序列,并将结果存储到一个新的字节数组中。
                        fo.close();
                       
                        FileInputStream fin = new FileInputStream("E://JAVA TEST//lesson//1.txt");
                        byte[] b = new byte[100];
                        int len =fin.read(b);
                            //public int read(byte[] b)
                             //  throws IOException从此输入流中将最多 b.length 个字节的数据读入一个字节数组中。在某些输入可用之前,此方法将阻塞。
                             //返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
                        System.out.println(new String(b,0,len));
                            //public String(byte[] bytes, int offset,int length)构造一个新的 String,方法是使用指定的字符集解码字节的指定子数组。新的 String 的长度是一个字符集函数,因此不能等于该子数组的长度。
                        fin.close();
                       

                    }
                }
                先寻找E:/JAVA TEST/lesson/1.txt文件,如果没有则创建文件,将www.163.com写入1.txt,然后通过FileInputStream的read方法从文件中读入字节流到字节数组b中,

            2、BufferedInputStream与BufferedOutputStream
                是过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。
                它们从过滤流父类继承而来,继承了他们的方法。BufferedOutputStream必须要有一个输出流的对象进行构造
                    public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的基础输出流。
                对上例做些修改:
                import java.io.*;
                class StreamTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        FileOutputStream fo = new FileOutputStream("E://JAVA TEST//lesson//1.txt");
                        BufferedOutputStream bo = new BufferedOutputStream(fo);
                        bo.write("www.153.com".getBytes());//先写入缓冲区中,如果不调用flush方法,则要等到缓冲区满后才输出到文件中。当然也可以调用close方法关闭流,也可以输出。
                        bo.flush();
                        bo.close();//这里注意了:因为我们上面有两个流fo,bo那么只需关闭bo流其他流也关闭了,因为bo流是采用fo的对象产生的。

                        FileInputStream fin = new FileInputStream("E://JAVA TEST//lesson//1.txt");
                        BufferedInputStream bin = new BufferedInputStream(fin);           //将内容读入缓冲区先
                        byte[] b= new byte[100];
                        int len = bin.read(b);
                        System.out.println(new String(b,0,len));
                        bin.close();
                       

                    }
                }
                先将内容写入到缓冲区,当调用flush或close方法时内容才写到1.txt中;输入流先将文件的内容读入到缓冲区中,再输出到控制台

               
            3、DataIutputStream与DataOutputStream
                是过滤流,需要使用已经存在的节点流来构造,提供了读写JAVA中基本数据类型的功能。
                public DataOutputStream(OutputStream out)创建一个新的数据输出流,将数据写入指定基础输出流。计数器 written 被设置为零。
                看下例:
                import java.io.*;
                class StreamTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        FileOutputStream fo = new FileOutputStream("E://JAVA TEST//lesson//1.txt");
                        BufferedOutputStream bo = new BufferedOutputStream(fo);                   //拥有了写入缓冲区的功能
                        DataOutputStream doc =new DataOutputStream(bo);                                //即拥有写入缓冲区的功能也拥有了写入基本数据类型的功能,如果不需要写入缓冲区功能直接:DataOutputStream do =new DataOutputStream(fo);
                        int a = 5;
                        byte b = 6;
                        char c ='w';
                        float f1 = 1.2f;
                        doc.writeInt(a);        //写入基本数据类型
                        doc.writeByte(b);
                        doc.writeChar(c);
                        doc.writeFloat(f1);
                        doc.flush();
                        doc.close();
                       

                        FileInputStream fin = new FileInputStream("E://JAVA TEST//lesson//1.txt");
                        BufferedInputStream bin = new BufferedInputStream(fin);           //将内容读入缓冲区先
                        DataInputStream din = new DataInputStream(bin);
                        System.out.println(din.readInt());                //读取基本类型数据
                        System.out.println(din.readByte());
                        System.out.println(din.readChar());
                        System.out.println(din.readFloat());
                        din.close();
                    }
                }
                可看到E:/JAVA TEST/lesson/1.txt写入了内容   w?櫃 ,需用ultraedit打开查看对应内容,因为看到的是二进制数据。
                再屏幕打印输出:
                5
                6
                w
                1.2

            4、PipedIutputStream与PipedOutputStream
                管道流,用于线程间的通信。一个线程的PipedIutputStream从另一线程的PipedOutputStream对象读取输入。要使管道流有用,必须同时构造管道输入流和管道输出流。
                public PipedInputStream(PipedOutputStream src)
                    throws IOException创建 PipedInputStream,以使其连接到传送输出流 src。写入 src 的数据字节稍后将用作此流的输入
                public PipedOutputStream(PipedInputStream snk)
                    throws IOException创建连接到指定传送输入流的传送输出流。写入此流的数据字节稍后将用作 snk 的输入。
               
                import java.io.*;
                class PipTest
                {
                    public static void main(String[] args)
                    {
                        PipedOutputStream pos = new PipedOutputStream();
                        PipedInputStream pis = new PipedInputStream();
                        try
                        {
                            pis.connect(pos);
                            new Producer(pos).start();
                            new Consumer(pis).start();
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                        System.out.println("Hello World!");
                    }
                }

                class Producer extends Thread       //继承多线程类
                {
                    private PipedOutputStream pos;
                    public Producer(PipedOutputStream pos)
                    {
                        this.pos = pos;
                    }
                    public void run()         //实现run方法
                    {
                        try
                        {
                            pos.write("hello !".getBytes());        //写入
                            pos.close();

                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }

                class Consumer extends Thread
                {
                    private PipedInputStream pis;
                    public Consumer(PipedInputStream pis)
                    {
                        this.pis = pis;
                    }
                    public void run()
                    {
                        try
                        {
                            byte[] buf = new byte[100];
                            int len = pis.read(buf);
                            System.out.println(new String(buf,0,len));
                            pis.close();
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }

                输出结果为:
                Hello World!
                hello !
                这里就利用了管道的输入与输出流在两个线程之间进行通信。
        (4)JAVA I/O的设计原则
            链接机制:可以将一个流与另一流首尾相接这是JAVA模式Decorator的应用。
                通过流的链接可以动态的增加流的功能
            看一下链:
            Input Stream Chain
                从文件中获取输入字节              增加了缓冲的功能          增加了读取JAVA基本数据类型的功能
            文件 ---> FileInputStream----------->BufferedInputStream---------------->DataInputStream------------------------>数据
           

            Output Stream Chain
                可以往输出流中写入基本数据类型      提供数据写入缓冲区的功能                   将数据写入到文件
            数据-------->DataOutputStream---------------->BufferedOutputStream------------------>FileOutputStream------------------------>文件


        (5)字符流
            Reader类与Writer类
                java中使用UNICODE来表示字符串和字符。
                这两个类主要用来读取字符。
                public abstract class Readerextends Objectimplements Readable, Closeable用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
                       
                        |    BufferedReader          ----------     LinNumberReader
                        |    CharArrayReader
                Reader----------|    FilterReader        ----------    PushbackReader
                        |    InputStreamReader    ----------    FileReader
                        |    PiedReader
                        |    StringReader

            InputStreamReader:
                InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
                每次调用 InputStreamReader 中的一个 read() 方法都会导致从基础输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从基础流读取更多的字节,使其超过满足当前读取操作所需的字节。
                为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
                 BufferedReader in
                   = new BufferedReader(new InputStreamReader(System.in));
           
                   
                        |    BufferedWriter         
                        |    CharArrayWriter
                Writer----------|    FilterWriter       
                        |    OutputStreamWriter    ----------    FileWriter
                        |    PiedWriter
                        |       PrintWriter
                        |    StringWriter

            OutputStreamWriter:
                OutputStreamWriter 是字符流通向字节流的桥梁:使用指定的 charset 将要向其写入的字符编码为字节。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。
                        为了达到最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中以避免频繁调用转换器。例如:

                 Writer out
                   = new BufferedWriter(new OutputStreamWriter(System.out));
                 

                示例:演示将字符写入文件和从文件中读出
                import java.io.*;
                class ReaderTest
                {

                    public static void main(String[] args) throws Exception
                    {
                        FileOutputStream f = new FileOutputStream("1.txt");
                        OutputStreamWriter ou = new OutputStreamWriter(f);          //发挥桥的作用
                        BufferedWriter r = new BufferedWriter(ou);
                        r.write("www.12323.com");
                        r.close();

                        FileInputStream fin = new FileInputStream("1.txt");
                        InputStreamReader in = new InputStreamReader(fin);
                        BufferedReader bin = new BufferedReader(in);
                        System.out.println(bin.read());         //返回值为int,读取字符
                        System.out.println(bin.readLine());     //读取一行字符
                        bin.close();
                    }

                }
                输出值为:
                119
                ww.12323.com
               
                下例演示从标准输入设备读取
                import java.io.*;
                class ReaderTest
                {
                    public static void main(String[] args) throws Exception
                    {
                   
                        BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
                        String strLine ;
                        while((strLine=bin.readLine())!=null)
                            System.out.println(strLine);
                        bin.close();
                    }
                }
                运行即在命令行输入什么即输出什么。
        (6)字符集
            查看JAVA可用的字符集
            import java.util.*;
            import java.nio.charset.Charset;
            class CharsetTest
            {
                public static void main(String[] args)
                {
                    Map m = Charset.availableCharsets();       //InputStreamReader中使用指定的charset读取字节并将其解码为字符。

                    Set name = m.keySet();
                    Iterator i = name.iterator();
                    while (i.hasNext())
                    {
                        System.out.println(i.next());
                    }
                   
                }
            }
            输出结果:
            Big5
            Big5-HKSCS
            EUC-JP
            EUC-KR
            GB18030
            GB2312
            GBK
            。。。。。。
            IBM918
            ISO-2022-CN
            ISO-2022-JP
            ISO-2022-KR
            ISO-8859-1
            ISO-8859-13
            ISO-8859-15
            ISO-8859-2
            ISO-8859-3
            ISO-8859-4
            ISO-8859-5
            ISO-8859-6
            ISO-8859-7
            ISO-8859-8
            ISO-8859-9
            JIS_X0201
            JIS_X0212-1990
            KOI8-R
            Shift_JIS
            TIS-620
            US-ASCII
            UTF-16
            UTF-16BE
            UTF-16LE
            UTF-8
            。。。。。。
            x-windows-950
       
        (7)JAVA中的字符编码及转换
            System类、Property类中的重要方法
            import java.util.*;
            import java.nio.charset.Charset;
            class CharsetTest
            {
                public static void main(String[] args)
                {
                    Properties p = System.getProperties();
                    p.list(System.out);
                }
            }
            输出
            file.encoding=GB18030                            //字符编码
            java.specification.version=1.5
            user.name=zqwf
            。。。。。。
            在JAVA中获得一个UNICODE即由字节->字符叫解码,将字符转换为字节叫编码。
            那么要明白一点的是:
                标准输入采用的字符集是依赖于本地系统所用的字符集,如我们所使用的中文windows 系统一般是中文的GBK;即从标准输入读入的数据(汉字)为GBK的码值。
                而JAVA 虚拟机内部采用的是file.encoding属性的编码如:我现在所使用的是file.encoding=GB18030   如上例所打印出。。
                那么我们常在标准输入中输入汉字后经过程序打印输出,看到的却是乱码,这是为什么呢?
                看下例:
                import java.util.*;
                import java.nio.charset.Charset;
                class CharsetTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        Properties p = System.getProperties();
                        //p.put("file.encoding","ISO-8859-1");
                        int data;
                        byte[] b = new byte[100];
                        int i=0;
                        while((data=System.in.read())!='q')
                        {
                            b[i]=(byte)data;
                            i++;
                        }
                        String str = new String(b,0,i);
                        System.out.println(str);
                    }
                }
                输入汉字,输出为?号。。为什么。

                对上例做修改如下,请看注释:
                import java.util.*;
                import java.nio.charset.Charset;
                class CharsetTest
                {
                    public static void main(String[] args) throws Exception
                    {
                        Properties p = System.getProperties();
                        p.put("file.encoding","ISO-8859-1");                 //设置JAVA虚拟机字符编码方式为ISO-8859-1
                        int data;
                        byte[] b = new byte[100];                          //数组存放的是从标准输入读入数据的GBK码值。
                        int i=0;
                        while((data=System.in.read())!='q')              //注意Systm.in.read()读入的是字节流:即从标准输入读入字符转换成字节:  编码   <1>
                        {                        //public static final InputStream in“标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
                            b[i]=(byte)data;                     
                            i++;
                        }
                        String str = new String(b,0,i);               //从字节数组中返回0到i个字符:这里字节数组按虚拟机的ISO-8859-1解码得相应字符:   解码   过程    <2>
                        String outStr = new String(str.getBytes("ISO-8859-1"),"GBK");     
                            //按ISO-8859-1进行编码回字节数组。    <3>
                            //注意:因为有的本地系统使用的是GBK编码集,那么从标准输入读入了GBK编码,读入后存放在字节数组中,然后采用字节到字符串的转换。
                           
                        System.out.println(outStr);           //打印的时候采用GBK进行解码:  解码  过程   <4>
                    }
                }
                //那么可以看到从以上<1><2><3><4>可以看出本地系统的字符集与JAVA 虚拟机所采用的字符集是有区别的。
                这个在JSP页面中获取客户端提交的信息也有相应的处理:
                String str = request.getParameter("girl");        //客户输入可能含有字符串信息
                byte[] b =str.getBytes("ISO-8859-1");            //从字符串到字节的轮换,即使用ISO-8859-1进行编码
                str = new String(b);                            //将数组转化为字符串对象

       
        (8)RandomAccessFile类
            public class RandomAccessFileextends Objectimplements DataOutput, DataInput, Closeable
            同时实现了数据DataOutput,DataInput接口,实现了对文件的随机存储功能,利用这个类可在文件中任何位置进行读和写操作。
            提供了"文件指针"用来指向下一个要操作的位置。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置
            构造函数:public RandomAccessFile(File file,String mode)
                  public RandomAccessFile(String name,String mode)
                  mode:mode 参数指定用以打开文件的访问模式。
                    含意              值
                     "r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 
                    "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 
                    "rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到基础存储设备。 
                    "rwd"   打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到基础存储设备。

            下例利用RandomAccessFile类进行读取和写入操作
            import java.io.*;
            class RandomAccessFileTest
            {
                public static void main(String[] args) throws Exception
                {
                    Student s1 = new Student(23,"zhang",60.4);
                    Student s2 = new Student(34,"dsd",56.4);
                    Student s3 = new Student(45,"wrtt",68.4);
                    RandomAccessFile raf = new RandomAccessFile("Student.txt","rw");
                    s1.writenStudent(raf);
                    s2.writenStudent(raf);
                    s3.writenStudent(raf);       //写完后,文件指针已经最后。。
                    //注意使用RandomAccessFile类时指针会随着你写入和读取而动。所以写完后如果你想进行读取,则要将指针移到文件开头

                    Student s = new Student();
                    raf.seek(0); //将指针移到文件开头
                    for(long i=0;i<raf.length();i=raf.getFilePointer())       //raf.length返回为long型;i=raf.getFilePointer获取当前指针偏移量
                    {
                        s.readStudent(raf);
                        System.out.println(s.num+","+s.name+","+s.score);
                    }

                    raf.close();
                   
                }
            }


            class Student
            {
                int num;
                String name;
                double score;
                public Student()
                {}
                public Student(int num,String name,double score)
                {
                    this.num=num;
                    this.name=name;
                    this.score=score;
                }

                public void writenStudent(RandomAccessFile raf) throws IOException
                {
                    raf.writeInt(num);
                    raf.writeUTF(name);
                    raf.writeDouble(score);
                }
               
                public void readStudent(RandomAccessFile raf) throws IOException
                {
                    num = raf.readInt();
                    name = raf.readUTF();
                    score = raf.readDouble();
                }

            }
            输出结果:
            23,zhang,60.4
            34,dsd,56.4
            45,wrtt,68.4

                       
        (9)对象序列化
       
            将对象转化成字节流保存起来,并且在日后还原这个对象,这个机制叫做对象的序列化。
            将一个对象保存到永久存储设备上称为持续性。
            一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。
                public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
            利用ObjectOutputStream,这个类实现了DataOutput接口
            ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过使用流中的文件可以实现对象的持久存储。
           
            实例:
            import java.io.*;
            class Test
            {
                public static void main(String[] args) throws Exception
                {
                    Employee e1 = new Employee("zhang",18,200.3);
                    Employee e2 = new Employee("lian",18,343.3);
                    Employee e3 = new Employee("yangu",29,566.3);

                    FileOutputStream fos = new FileOutputStream("Employee.txt");
                    ObjectOutputStream oos = new ObjectOutputStream(fos);
                    oos.writeObject(e1);
                    oos.writeObject(e2);
                    oos.writeObject(e3);       //将对象信息写入到文件中。
                    oos.close();

                    FileInputStream fin = new FileInputStream("Employee.txt");
                    ObjectInputStream iis = new ObjectInputStream(fin);
                    Employee e;
                        for(int i=0;i<3;i++)
                        {
                            e=(Employee)iis.readObject();                //反序列化时不会调用对象的任何构造函数,它只会将保存的对象状态信息来还原对象。
                            System.out.println(e.name+":"+e.age+":"+e.salary);
                        }

                }
            }
            class Employee implements Serializable
            {
                String name;
                int age;
                double salary;
                //transient Thread t = new Thread();
                public Employee(String name,int age,double salary)
                {
                    this.name = name;
                    this.age =age;
                    this.salary = salary;
                }
            }
            输出结果为:
            zhang:18:200.3
            lian:18:343.3
            yangu:29:566.3


            1.当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
            2.如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
            3.如果一个可序列化的对象包含对某个不可序列化的对象的引用,那个整个序列化的操作将会失败,并且抛出一个NotSerializableException.我们可以将这个引用标记为transient.那么这个对象还可以序列化。
            transient Thread t = new Thread();

            在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:
             private void writeObject(java.io.ObjectOutputStream out)
                 throws IOException
             private void readObject(java.io.ObjectInputStream in)
                 throws IOException, ClassNotFoundException;
                这两个特殊的方法都声明为private但是他们在类的外部是可以调用的。
                如下例:在上例的基础上的Employee类中增加两个方法
                import java.io.*;
                class Test
                {
                    public static void main(String[] args) throws Exception
                    {
                        Employee e1 = new Employee("zhang",18,200.3);
                        Employee e2 = new Employee("lian",18,343.3);
                        Employee e3 = new Employee("yangu",29,566.3);

                        FileOutputStream fos = new FileOutputStream("Employee.txt");
                        ObjectOutputStream oos = new ObjectOutputStream(fos);
                        oos.writeObject(e1);
                        oos.writeObject(e2);
                        oos.writeObject(e3);
                        oos.close();

                        FileInputStream fin = new FileInputStream("Employee.txt");
                        ObjectInputStream iis = new ObjectInputStream(fin);
                        Employee e;
                            for(int i=0;i<3;i++)
                            {
                                e=(Employee)iis.readObject();
                                System.out.println(e.name+":"+e.age+":"+e.salary);
                            }

                    }
                }
                class Employee implements Serializable
                {
                    String name;
                    int age;
                    double salary;
                    public Employee(String name,int age,double salary)
                    {
                        this.name = name;
                        this.age =age;
                        this.salary = salary;
                    }
                    private void writeObject(java.io.ObjectOutputStream out)  throws IOException
                    {
                        out.writeInt(age);
                        out.writeUTF(name);
                        System.out.println("Write Object");
                    }
                    private void readObject(java.io.ObjectInputStream in)   throws IOException
                    {
                        age = in.readInt();
                        name = in.readUTF();
                        System.out.println("Read Object");
                       
                    }
                }
                输出结果:
                Write Object
                Write Object
                Write Object
                Read Object
                zhang:18:0.0
                Read Object
                lian:18:0.0
                Read Object
                yangu:29:0.0
                从结果可以发现程序自动调用了这两个新增的方法先是将对像序列化,然后再反序列化,可以看到因为没有对salary成员进行序列化,所以不会打印出相应的值。


44、网络编程
    C/S系统即socket编程
    服务器端:ServerSocket此类实现服务器套接字,通过public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字
        再调用accept()方法进行侦听客户端请求。
    客户端:public Socket(String host,int port) throws UnknownHostException,IOException创建一个流套接字并将其连接到指定主机上的指定端口号。
        注意InetAddress 中的getHostName() 获取此 IP 地址的主机名。
    服务器端程序的编写:
    (1)调用ServerSocket(int port)创建一个服务器端套接字,并绑定在指定端口上;
    (2)调用accept()监听连接请求,如果有客户端请求连接,则接受连接,返回通信套接字。
    (3)调用Socket类的getOutputSream()和getInputStream()获取输出和输入流,开始网络数据的发送和接收。
    (4)关闭通信套接字。
    客户端程序的编写:
    (1)调用Socket()创建一个流套接字,并连接到服务器。
    (2)调用Socket类的getOutputSream()和getInputStream获取输出流和输入流,开始数据的发送和接收。
    (3)关闭通信套接字。
    下面在一个类中写server和client方法
    执行的时候打开两个CMD一个执行时输入一个参数,另一个则不带参数执行
    本例没有采用多线程。
        import java.net.*;
        import java.io.*;
        public class Lesson
        {
            public static void main(String[] args)
            {
                if(args.length>0)
                server();
                else
                client();
            }
           
            public static void server()
            {
                try
                {
                    ServerSocket s = new ServerSocket(6000);
                    Socket ss =s.accept();
                    OutputStream o = ss.getOutputStream();
                    InputStream i = ss.getInputStream();
                    o.write("hello".getBytes());
                    byte[] b = new byte[100];
                    int len = i.read(b);
                    System.out.println(new String(b,0,len));
                    o.close();
                    i.close();
                    ss.close();
                    s.close();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
           
            public static void client()
            {
                try
                {
                    Socket s = new Socket(InetAddress.getByName("localhost"),6000);
                    OutputStream o = s.getOutputStream();
                    InputStream i = s.getInputStream();
                    byte[] b = new byte[100];
                    int len = i.read(b);
                    System.out.println(new String(b,0,len));
                    o.write("hello this".getBytes());
                    o.close();
                    i.close();
                    s.close();           
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
           
        }
        E:/JAVA TEST>java Lesson sfsf
        等待客户端连接

        E:/JAVA TEST>java Lesson
        输出结果:hello

        服务器端输出:hello this
       
        另一种写法分成两个类:
        类TCPServer:
            import java.net.*;
            import java.io.*;
            public class TCPServer{
                    public static void main(String[] args) {
                        try{
                            ServerSocket ss = new ServerSocket(6666);  //监听
                            while(true){
                                Socket s = ss.accept();  //接收连接
                                System.out.println("A client server");
                                DataInputStream dis = new DataInputStream(s.getInputStream());
                                System.out.println(dis.readUTF());
                           
                                DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                                dos.writeUTF("hello client 地址: "+s.getInetAddress()+" 端口: "+s.getPort());
                                dos.close();
                                dis.close();
                                s.close();
                                //ss.close();
                                }
                        }catch(IOException e){
                            e.printStackTrace();
                            System.out.println("程序出错");
                        }
                           
                    }
            }
           
            类TCPClient:
                    import java.net.*;
                    import java.io.*;
                    public class TCPClient{
                            public static void main(String[] args) {
                                try{
                                    Socket s = new Socket("127.0.0.1",6666);     //申请连接
                                    OutputStream os = s.getOutputStream();
                                    DataOutputStream dos = new DataOutputStream(os);
                                    dos.writeUTF("hello server");
                                    dos.flush();
                               
                                   
                                    DataInputStream dis = new DataInputStream(s.getInputStream());
                                    System.out.println(dis.readUTF());
                                    dis.close();
                                    dos.close();
                                    s.close();
                                }catch(IOException e){
                                    e.printStackTrace();
                                }
                               
                            }
                    }

    基于udp程序的编写
        接收端Server                                       发送端(Client)
        DatagramSocket(int port)                             DatagramSocket()
 
               DatagramPacket(byte[] buf,int length)               DatagramPacket(byte[] buf,int length,InetAddress address,int port)

        DatagramSocket.receive(DatagramPacket p)            DatagramSocket.send(DatagramPacket p)
       
        接收端程序:
        (1)调用DatagramSocket(int port)创建一个数据报套接字,并绑定一指定端口上;
        (2)调用DatagramPacket(byte[] buf,int length),创建一个字节数组以接收UDP包。
        (3)调用DatagramSocket类的receive(),接收UDP包
        (4)最后关闭数据报套接字
        发送端程序编写:
        (1)调用DatagramSocket()创建一个数据报套接字;
        (2)调用DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port),建立要发送的UDP包。
        (3)调用DatagramSocket类的send(),发送udp包。
        (4)最后关闭数据报套接字。
       
        UPDServer类:
       
                import java.net.*;
                public class UDPServer {
               
                    public static void main(String[] args) {
                        try{
                            byte buf[] = new byte[1024];
                            DatagramSocket ds = new DatagramSocket(4563);     //服务器端端口
                            DatagramPacket dp = new DatagramPacket(buf,buf.length); //包接收的地方
                            while(true){
                                ds.receive(dp);       //将收到的放入包中
                                System.out.println(new String(buf,0,dp.getLength()));   //打印收到的内容
                                System.out.println("I already received!");
                            }
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                       
                    }
               
                }
               
        UPDClient类:
           
                import java.net.*;
                public class UDPClient {
               
                    public static void main(String[] args) {
                        try{
                            byte buf[] = (new String("hello")).getBytes();//将字符串写入字节数组
                           
                            DatagramSocket ds = new DatagramSocket(4444);     //注意此端口号为客户端自己占用的端口号
                            DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",4563)); //此端口为与服务器对应的端口号。
                            ds.send(dp);
                            ds.close();
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
               
                }
               
                在客户端发送long类型的数据,在服务端接收long类型数据
               
                    import java.net.*;
                    import java.io.*;
                    public class UDPServer {
                   
                        public static void main(String[] args) {
                            try{
                                byte buf[] = new byte[1024];
                                DatagramSocket ds = new DatagramSocket(4563);     //服务器端端口
                                DatagramPacket dp = new DatagramPacket(buf,buf.length); //包接收的地方
                                while(true){
                                    ds.receive(dp);       //将收到的放入包中
                                    ByteArrayInputStream bais = new ByteArrayInputStream(buf);
                                    DataInputStream bis = new DataInputStream(bais);
                                    System.out.println(bis.readlong());
                                    //System.out.println(new String(buf,0,dp.getLength()));   //打印收到的内容
                                    System.out.println("I already received!");
                                }
                            }catch(Exception e){
                                e.printStackTrace();
                            }
                           
                        }
                   
                    }
                   
                                       
                        import java.net.*;
                        import java.io.*;
                        public class UDPClient {
                       
                            public static void main(String[] args) {
                                try{
                                    //byte buf[] = (new String("hello")).getBytes();
                                    int long=1000L;
                                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                    DataOutputStream dos = new DataOutputStream(baos);
                                    dos.writelong(n);
                                   
                                    byte[] buf =baos.toByteArray();
                                    DatagramSocket ds = new DatagramSocket(4444);     //注意此端口号为客户端自己占用的端口号
                                    DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",4563)); //此端口为与服务器对应的端口号。
                                    ds.send(dp);
                                    ds.close();
                                }catch(Exception e){
                                    e.printStackTrace();
                                }
                            }
                       
                        }

           


URL与URI
    URI通过资源标识符

45、DataSource用于替代DriverManager
    RowSet 比 ResultSet功能更强,支持断开的处理。
   
   
   
46、JAVA图形开发
        GUI(Graphics user Interface)
        AWT(Abstract window Toolkit)
        Swing
                       
                                                Component             MenuComponent
                                                    |
                                                    |
                                -------------------------
                                |                         |
                Button,TextArea,Label,List..       Container
                                                                                    |
                                                                                    |
                                                                                    |
                                                    -----------------------------------
                                                    |                                                                |
                                                    window                                               Panel
                                                    |                                                                |
                                        ------------                                                Applet
                                        |                        |
                                        frame       dialog     (model:此窗口不关,主窗口没法动,modellist:主窗口能运行       
               
                Container指容器,能容纳其它Component.  Container是一种Component
               
                Color类:定义了常用的颜色
               
                Frame类是Window的一个子类,由Frame或其子类创建的对象为一个窗体。
                Frame常用构造方法Frame(),Frame(String s)创建标题为s的窗体。
                frame 的默认布局为 BorderLayout。
                setBounds(int x,int y,int width,int height)
                    设置窗体位置和大小,x,y是左上角坐标,width,height为宽度和高度。
                setSize(int width,int height)
                    设置窗体位置和大小,x,y是左上角坐标
                setLocation(int x,int y)
                    设置窗体出现的时候默认所在左上角坐标的位置
                setBackGround(Color c)
                    设置背景颜色
                setVisible(boolean b)
                    设置是否可见。
                setTitle(String name)String getTitle()
                setResizable(boolean b)设置是否可以调整大小。
                 Frame f= new Frame();
                 Panel p = new Panel(null);
                 f.add(p);
                 Panel要放在Frame中显示。Panel也有与Frame类似的方法。
                
                 Awt提供了5种布局管理器类:setLayout()设置。
                 FlowLayout:Panel类的默认布局管理器。默认对齐方式是居中。
                 BorderLayout:是Frame类的默认布局管理器。将整个容器的布局分布东西南北中。可使用f.add(bn,BorderLayout.North); bn为Button对象。
                 GridLayout:划分成表格。f.setLayout(new GridLayout(3,2)); f.add(b1);  f.pack();
                 CardLayout
                 GridBagLayout
                
                 事件监听:
                 事件监听机制:
                     基本方法:在frame中添加事件监听方法如:addActionListener();在方法体中传入具体的对象new Monitor()
                     Monitor类实现ActionListener接口.并实现接口中的方法.
                     一般API提供了实现了接口的adapter类,所以可以继承adapter类.如WindowAdapter类实现了WindowListener接口
                    
                
                     import java.awt.*;
                    import java.awt.event.*;
                    public class TestButton{
                        public static void main(String[] args){
                            Frame f = new Frame("Test");
                            f.setSize(100,150);
                            f.setLocation(30,50);
                            f.setResizable(false);
                            Button b = new Button("button");
                            b.setSize(30,40);
                            Monitor m = new Monitor();
                            b.addActionListener(m);
                            b.setActionCommand("game over");
                           
                            f.add(b,BorderLayout.CENTER);
                            f.setVisible(true);
                           
                        }
                    }
                   
                    class Monitor implements ActionListener{
                        public void actionPerformed(ActionEvent e){
                            System.out.println("action listener info"+e.getActionCommand());
                        }
                    }
                   
                   
                    import java.awt.*;
                    import java.awt.event.*;
                    public class TestButton{
                        public static void main(String[] args){
                            new TFframe();
                        }
                    }
                   
                    class TFframe extends Frame{
                         TFframe(){
                             TextField tf = new TextField();   
                             add(tf);
                             tf.addActionListener(new Monitor());
                             tf.setEchoChar('*');
                             pack();
                             setVisible(true);
                        }
                    }
                   
                   
                    class Monitor implements ActionListener{
                        public void actionPerformed(ActionEvent e){
                            TextField tf =(TextField)e.getSource();
                            System.out.println(tf.getText());
                        }
                    }
                   
                    学习持有对方引用
                    Button监听事件,但在事件监听器里要获得文本的内容.
                            import java.awt.*;
                            import java.awt.event.*;
                            public class TestAdd{
                                public static void main(String[] args){
                                    Myframe myframe = new Myframe();
                                    myframe.getFrame();
                                }
                            }
                           
                            class Myframe extends Frame{
                                TextField num1,num2,num3;
                                public void getFrame(){
                                     num1 = new TextField(5);
                                     num2 = new TextField(5);
                                     num3 = new TextField(5);
                                   
                                    Label L1 = new Label("+");
                                    Button b = new Button("=");
                                    b.addActionListener(new MyListener(this));
                                    add(num1);
                                    add(L1);
                                    add(num2);
                                    add(b);
                                    add(num3);
                                   
                                   
                                    setLayout(new FlowLayout());
                                    setSize(200,300);
                                    setVisible(true);
                                }
                            }
                           
                            class MyListener implements ActionListener{//这里因为在Button的事件中要获得其他文本对象的属性,所以声明Myframe类的引用
                                Myframe mf =null;     //持有对方的引用
                                public MyListener(Myframe mf){
                                    this.mf = mf;
                                }
                                public void actionPerformed(ActionEvent e){
                                    int n1 = Integer.parseInt(mf.num1.getText());       //Myframe mf的引用指向其成员
                                    int n2 = Integer.parseInt(mf.num2.getText());
                                    int n3 = n1+n2;
                                    mf.num3.setText(""+n3);
                                   
                                }
                            }
                     在上面的程序中我们使用持有对方引用获得类中的成员.但有更简单的方法,我们知道内部类可以访问外部类的所有成员(包括私有成员),
                     下面使用内部类来实现:
                             import java.awt.*;
                            import java.awt.event.*;
                            public class TestAdd{
                                public static void main(String[] args){
                                    Myframe myframe = new Myframe();
                                    myframe.getFrame();
                                }
                            }
                           
                            class Myframe extends Frame{
                                TextField num1,num2,num3;
                                public void getFrame(){
                                     num1 = new TextField(5);
                                     num2 = new TextField(5);
                                     num3 = new TextField(5);
                                   
                                    Label L1 = new Label("+");
                                    Button b = new Button("=");
                                    b.addActionListener(new MyListener());
                                    add(num1);
                                    add(L1);
                                    add(num2);
                                    add(b);
                                    add(num3);
                                   
                                   
                                    setLayout(new FlowLayout());
                                    setSize(200,300);
                                    setVisible(true);
                                }
                               
                                class MyListener implements ActionListener{//这里因为在Button的事件中要获得其他文本对象的属性,所以声明Myframe类的引用
                                    public void actionPerformed(ActionEvent e){
                                        int n1 = Integer.parseInt(num1.getText());        //直接访问外部类的成员
                                        int n2 = Integer.parseInt(num2.getText());
                                        int n3 = n1+n2;
                                        num3.setText(""+n3);
                                   
                                }
                            }
                            }
                画图类:Graphics类
                Fram类继承了Contianer类的paint方法:创建Fram后会自动调用:具体是在每次需要重画时自动调用.
                        import java.awt.*;
                        public class TestAdd{
                            public static void main(String[] args){
                                new MyFrame().lanchFrame();
                            }
                        }
                       
                        class MyFrame extends Frame{
                            public void lanchFrame(){
                                setBounds(200,200,640,480);
                                setVisible(true);
                            }
                           
                            public void paint(Graphics g){      //重写paint方法,画一个椭圆和一矩形,此方法会自动调用
                                Color c = g.getColor();
                                g.setColor(Color.red);
                                g.fillOval(50,50,30,30);
                                g.setColor(Color.green);
                                g.fillRect(80,80,40,40);
                                g.setColor(c);
                               
                               
                            }
                        }
                       
                鼠标事件:事件类:MouseListener,MouseListener类中有四个方法,如果实现这个类,显然要把四个方法全部重写,J2SE里已经有一个实现了
                MouseListener的类MouseAdapter,所以一般用鼠标事件的时候继承MouseAdapter类
        下例在程序界面上按下鼠标就画一个圆点:
                    import java.awt.*;
                    import java.awt.event.*;
                    import java.util.*;
                    import java.awt.Point;
                   
                    public class MyMouseAdapter{
                        public static void main(String[] args){
                            new Myframe("draw...");
                        }
                    }
                   
                    class Myframe extends Frame{
                        ArrayList<Point> points = null;
                        Myframe(String s){
                            super(s);
                            points = new ArrayList<Point>();
                            setLayout(null);
                            setBounds(300,400,300,400);
                            setBackground(new Color(204,204,255));
                            setVisible(true);
                            addMouseListener(new Monitor());
                        }
                       
                        public void paint(Graphics g){
                            Iterator i = points.iterator();
                            while(i.hasNext()){
                                Point p = (Point)i.next();
                                g.setColor(Color.BLUE);
                                g.fillOval(p.x,p.y,10,10);
                            }
                        }
                       
                        public void addPoint(Point p){
                            points.add(p);
                        }
                    }
                   
                    class Monitor extends MouseAdapter{
                        public void mousePressed(MouseEvent e){
                            Myframe f = (Myframe)e.getSource();
                            f.addPoint(new Point(e.getX(),e.getY()));
                            f.repaint();  //重画
                        }
                    }
                   
                    运行:
                    在frame上面点鼠标左键,画出一个个小圆点
                   
                    下面通过两种方式添加窗口的关闭事件,关闭窗口
                    import java.awt.*;
                    import java.awt.event.*;
                    import java.util.*;
                    import java.awt.Point;
                   
                    public class MyMouseAdapter{
                        public static void main(String[] args){
                            new Myframe("draw...");
                        }
                    }
                   
                    class Myframe extends Frame{
                        ArrayList<Point> points = null;
                        Myframe(String s){
                            super(s);
                            points = new ArrayList<Point>();
                            setLayout(null);
                            setBounds(300,400,300,400);
                            setBackground(new Color(204,204,255));
                            setVisible(true);
                            addMouseListener(new Monitor());
                            addWindowListener(new WindowAdapter(){
                                    public void windowClosing(WindowEvent e){
                                    setVisible(false);
                                    System.exit(0);
                                    }
                                }
                            );
                        }
                       
                        public void paint(Graphics g){
                            Iterator i = points.iterator();
                            while(i.hasNext()){
                                Point p = (Point)i.next();
                                g.setColor(Color.BLUE);
                                g.fillOval(p.x,p.y,10,10);
                            }
                        }
                       
                        public void addPoint(Point p){
                            points.add(p);
                        }
                    }
                   
                    class Monitor extends MouseAdapter{
                        public void mousePressed(MouseEvent e){
                            Myframe f = (Myframe)e.getSource();
                            f.addPoint(new Point(e.getX(),e.getY()));
                            f.repaint();  //重画
                        }
                    }
                    /*
                    class MyWindowListener extends WindowAdapter{
                        public void windowClosing(WindowEvent e){
                            //setVisible(false);
                            System.exit(0);
                        }
                    }
                */
               
               
47、
        toString()
       
        public class TesttoString{
                public static void main(String[] args){
                    Dog d = new Dog();
                    System.out.println(d);
                    System.out.println(d.toString());
                }
            }
           
            class Dog{
                public String toString(){
                    return "sfsf";
                }
               
            }
            输出:
            sfsf
            sfsf
            这里类Dog覆盖了Object类的方法toString()如果不覆盖则输出:
            public class TesttoString{
                public static void main(String[] args){
                    Dog d = new Dog();
                    System.out.println(d);
                    System.out.println(d.toString());
                }
            }
           
            class Dog{
                           
            }
            输出:
            Dog@192d342
            Dog@192d342
            原理是Object里返回的是当前的类名+@号再加上对象的hashCode()的16进制值。
            api:getClass().getName() + '@' + Integer.toHexString(hashCode())

48、
        equals
                public boolean equals(Object obj)指示某个其他对象是否与此对象“相等”。
                equals 方法在非空对象引用上实现相等关系:
               
                自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
                对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
                传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
                一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
                对于任何非空引用值 x,x.equals(null) 都应返回 false。
                Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
               
                注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
               
                看以下程序:
                public class TestEquals{
                        public static void main(String[] args){
                            Dog d1 = new Dog("zhan","sf");
                            Dog d2 = new Dog("zhan","sf");
                            System.out.println(d1==d2);
                            System.out.println(d1.equals(d2));
                            Cat c1 = new Cat();
                            Cat c2 = new Cat();
                            System.out.println(c1==c2);
                            System.out.println(c1.equals(c2));
                        }
                    }
                   
                    class Dog{
                        String golor;
                        String name;
                        public Dog(String golor,String name){
                            this.golor = golor ;
                            this.name = name ;
                        }
                注意:
                程序输出结果:
                false
                false
                false
                false
               
                即java中的Object类提供的equals方法默认比较的就是x==y; x,y 分别为对象的引用。
                所以在上面的程序中不论是判断c1==c2,c1.equals(c2)结果是一样,均为false.
                但看下面的程序:
                public class TestEquals{
                    public static void main(String[] args){
                        String s1 = new String("sf");
                        String s2 = new String("sf");
                       
                        System.out.println(s1==s2);
                        System.out.println(s1.equals(s2));
                    }
                }
                注意了:
                输出结果为:
                false
                true
                综合两个例子,这是为什么呢?
                查看String类的api原来String类重写了equals()方法。
                    看API的方法如下:
                      public boolean equals(Object anObject) {
                                if (this == anObject) {
                                    return true;
                                }
                                if (anObject instanceof String) {
                                    String anotherString = (String)anObject;
                                    int n = count;
                                    if (n == anotherString.count) {
                                    char v1[] = value;
                                    char v2[] = anotherString.value;
                                    int i = offset;
                                    int j = anotherString.offset;
                                    while (n-- != 0) {
                                        if (v1[i++] != v2[j++])
                                        return false;
                                    }
                                    return true;
                                    }
                                }
                                return false;
                                }
                    API解释为:
                    public boolean equals(Object anObject)比较此字符串与指定的对象。当且仅当该参数不为 null,并且是表示与此对象相同的字符序列的 String 对象时,结果才为 true
                   
                    所以equals方法不是对每个类比较的结果都是false,你自己可以重写equals方法达到自己想要的结果。
                    如下:重写Cat方法,将与前例产生不同的结果:
                    public class TestEquals{
                            public static void main(String[] args){
                                Cat c1 = new Cat(23,24);
                                Cat c2 = new Cat(23,24);
                                System.out.println(c1==c2);
                                System.out.println(c1.equals(c2));
                            }
                        }
                       
                        class Cat{
                            int height;
                            int weight;
                            Cat(int height,int weight){
                                this.height = height;
                                this.weight = weight;
                            }
                            public boolean equals(Object obj){
                                if(obj == null)
                                    return false;
                                else{
                                    if(obj instanceof Cat){
                                        Cat c = (Cat)obj;
                                        if(c.height == this.height && c.weight == this.weight){
                                            return true;
                                        }
                                    }
                                    return false;
                                }
                            }
                        }
                        输出结果为:
                        false
                        true
                       
49    常用类
                        String 类

                        public class TestString{
                           
                            public static void main(String[] args){
                                    String s = "abcDe";
                                    s = s.substring(2,4);
                                    System.out.println(s);
                                   
                                    int j = 2323;
                                    String s1 = String.valueOf(j);
                                    System.out.println(s1);
                                   
                                    String s2 ="m,d,y";
                                    String[] str = s2.split(",");
                                    for(int i=0;i<str.length;i++){
                                        System.out.println(str[i]);
                                    }
                                   
                                    String s4 ="sfsAweDSFsioweoiwDFKKVLO1234_sfw9989l";//找出大写小写及非字母的个数
                                    int lCount =0,uCount=0,oCount=0;
                                    for(int i=0;i<s4.length();i++){
                                        char c = s4.charAt(i);
                                        if(c>='a' && c<='z'){
                                            lCount++;
                                        }else if(c>='A' && c<='Z'){
                                            uCount++;
                                    }else{
                                        oCount++;
                                        }
                                    }
                                    System.out.println(lCount+","+uCount+","+oCount);
                                   
                                   
                                    String s5 = "javasfweiwoifjavalfweiwofjavaoweuwoefjava";//找出出现java字符串的次数.
                                    String stoFind="java";
                                    int count=0;
                                    int index=-1;
                                    while((index = s5.indexOf(stoFind)) !=-1){
                                        s5 =s5.substring(index+stoFind.length());
                                        count++;
                                    }
                                    System.out.println(count);
                                   
                                   
                                   
                                }
                        }
           
                StringBuffer类:可变的字符序列
                与String只是增加新字符串的时候不同.如
                String s="sfsf";
                s+="sfsf";
                实际过程创建了一个StringBuffer对象.
               
               
                    基本数据类型包装类:
                                public class TestInt{
                                    public static void main(String[] args){
                                    Integer i = new Integer(100);
                                    int j = Integer.intValue(i);
                                    int n = Integer.pareInt("123"); //字符串->整数
                                    double d1 = Double.pareDouble("12.4"); //字符串->实数
                                    Double d = Double.valueOf("14.54");  //字符串->实型
                                    double r = Double.valueOf("12.3").doubleValue();   //字符串-实型-取实数 
                                }
                            }
                           
                            public class TestInt{
                                    public static void main(String[] args){
                                        double d[][];
                                        String s = "1,2;3,4,5;6,7,8"; //将字符串拆分,然后解析成一二维数组
                                        String[] sFirst = s.split(";");         //按;拆分
                                        d = new double[sFirst.length][];       
                                        for(int i=0;i<sFirst.length;i++){
                                            String[] sSecond = sFirst[i].split(","); //按,拆分
                                            d[i] = new double[sSecond.length];
                                            for(int j=0;j<sSecond.length;j++){
                                                d[i][j] = Double.parseDouble(sSecond[j]);
                                                System.out.println(sSecond[j]);
                                            }
                                        }
                                       
                                        for(int i=0;i<d.length;i++){
                                            for(int j=0;j<d[i].length;j++){
                                                System.out.println(d[i][j]);
                                            }
                                        }
                                    }
                                }
                               
                    File类
                    使用递规方法列出目录下面的文件及目录
                    import java.io.*;
                            public class TestFile{
                                public static void main(String[] args){
                                    File f = new File("E:/STUDY");
                                    tree(f,0);
                                }
                               
                                public static void tree(File f,int level){
                                    String strPre ="";
                                    for(int i=0;i<level;i++){
                                        strPre+="     ";
                                    }
                                    File[] childs = f.listFiles();
                                    for(int i=0;i<childs.length;i++){
                                        System.out.println(strPre+childs[i]);
                                        if(childs[i].isDirectory()){
                                            tree(childs[i],level++);
                                        }
                                    }
                                }
                            }
                           
                    枚举类型:
                        public class TestEnum{
                                public enum MyColor {red,blue,black};
                                public static void main(String[] args){
                                    MyColor m = MyColor.red;
                                    switch(m){
                                        case red :
                                            System.out.println("red");
                                            break;
                                        case blue :
                                            System.out.println("blue");
                                            break;
                                        default :
                                            System.out.println("default");
                                    }
                                }
                            }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值