从零开始学java(五)--面向对象(下)

来源:互联网 发布:迅游国际版 mac 编辑:程序博客网 时间:2024/05/22 14:28

1  基本数据类型的包装类

         java包含8中基本类型的数据,不支持面向对象的编程机制,不具备“对象”的特性:无属性、方法可以调用。java提供这8中数据类型是为了照顾程序员传统的习惯。

基本数据类型和包装类的对应关系

基本数据类型

包装类

byte

Byte

short

Short

int

Integer

long

Long

char

Character

float

Float

double

Fouble

boolean

Boolean

 

         JDK提供自动装箱和自动拆箱功能,进行自动装箱和自动拆箱的时候注意类型的匹配。另外,包装类还可以实现基本类型变量和字符串之间的转换,除了Character之外的所有包装类都提供了一个parseXxx(String s)静态方法,用于将一个特定的字符串转换为基本类型变量;除此之外,在String类中也提供了多个重载valueOf()方法,用于将基本类型变量转化为字符串。

2  处理对象

         Java对象都是Object泪的实例,可以直接调用该类中定义的方法,这些方法提供了处理java对象的通用方法。

2.1  打印对象和toString方法

         System.out.println()方法只能在控制台输出字符串,当利用此方法输出一个类对象时,实际上输出的是该对象的toString()方法的返回值。

    所有java类都是Object类的子类,toString()方法是Object类里的一个实例方法。该方法是一个“自我描述”的方法,用于告诉外界该对象具有的状态信息,返回对象的类名+@+hashCode值。如果需要打印用户自己定义的信息,则需要重该方法。

2.2  ==和equals比较运算符

         ①如果2个变量都是基本类型的变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,使用==判断返回true。

         ②对已两个引用类型的变量,必须他们指向同一个对象是,==判断才会返回true。==不可比较类型上没有父子关系的两个对象。

         ③对于只需要判断“值相等的情况”,则需要使用str1.equals(str2)来实现判断。同样可按照用户自定义的标准重写该方法。重写该方法需要注意满足以下条件:

3  类成员

         在java类中只能包含属性、方法、构造器、初始化块、内部类和枚举类6种成员,static除构造器不能修饰外其他5中成员都可修饰。被static修饰的成员就是类成员。类成员既可通过对象来访问,也可以通过类来访问

         对static关键字而言,类成员(包括方法、初始化块、内部类、枚举类)不能访问实例成员(包括属性、方法、初始化块和枚举类)。

4  单例(Singleton)类

         如果一个类始终只能创建一个实例,则这个类被称为单例类。

         应用场景:不允许自由创建该类的对象,而是只允许为该类创建一个对象。要点是:①用private修饰该类的构造函数;②提供一个public方法作为该类的访问点,用于创建该类的对象;③该类缓存已经创建的对象。

class Singleton

{

  //使用一个变量来缓存曾经创建的实例

private static Singleton instance; 

// 用private修饰构造器,隐藏该方法

    private Singleton(){};  

  

    //提供一个public static 方法,用于返回Singleton实例

    public static Singleton getInstance()

    {

        if (instance ==null) //如果instance为null,则表明Singleton对象未创建

        {

            instance= new Singleton();

        }

        return instance;

    }

}

  

public class SingletonTest

{

    public static void main(String[] args)

    {

        Singleton s1 =Singleton.getInstance();

        Singleton s2 =Singleton.getInstance();

        System.out.println(s1== s2);   //这里可以看出确实是同一个对象 

    }

}

5  final修饰符

5.1  final变量

         final可以修饰成员变量(包括实例变量和类变量),也可修饰局部变量、形参。final修饰的变量不可被改变,一旦获取初值之后,该final变量就不能被重新赋值。

5.1.1 final修饰成员变量

         final修饰的成员变量不能被重新赋值,则不可以在普通方法中对成员变量重新赋值。赋值地方:

         ①类属性(即static修饰的成员变量):可在静态初始化块中、声明该属性时指定初始值;

         ②实例属性:可在普通初始化块、声明该属性、构造器中指定初始值。

         如果在上述地方都没有对其初始化,则成员变量的值将是0、’\u0000’、false或null

5.1.2 final修饰局部变量

         系统不会对局部变量初始化,必须有程序员显式初始化。因此用final修饰局部变量时既可在定义时指定默认值,也可以在后续代码中指定。特例:final修饰形参时根据传入的参数完成初始化,不能被赋值。

5.1.3 final修饰基本类型和引用类型变量的区别

         使用final修饰基本类型变量时,不能对其重新赋值,因此基本类型变量不能被改变;但是对于引用类型变量而言,其仅仅保存的是一个引用,final只能保证其所引用的地址不变,但其指向的对象完全可变。

5.2  final方法

         如果不希望子类重新父类的某个方法,则可使用final修饰该方法。

5.3  final类

         final修饰的类不可有子类。

5.4  不可变类

         不可变类的意思是:创建该类的实例后,该实例的属性不可改变。java所提供的8个包装类和java.lang.String都是不可变类。创建不可变类需遵循以下规则:

         ①使用private和final修饰符来修饰该类的属性;

         ②提供带参数构造器,用于根据入参初始化类的属性

         ③仅为该类的属性提供getter方法,不为该类的属性提供setter方法

         ④如有必要,重写Object类中的hashCode和equals方法。

         与可变类相比,不可变类对象的成员变量在整个生命周期中永远处于初始化状态,后续不可更改,控制更为简单。

5.5  缓存实例的不可变类

         不可变类的实例的状态不可改变,可以很方便地被多个对象共享。若程序经常需要使用相同的不可变类实例,则需考虑如何缓存这种不可变类的实例。

         缓存是软件设计中一个非常有用的模式,缓存的实现方式有很多,不同实现方式可能存在较大的性能差别。

6  抽象类

         抽象方法和抽象类必须用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类中可以没有抽象方法。抽象类和抽象方法的设计规则如下:

         ①抽象类和抽象方法都必须用abstract修饰符来修饰,含有抽象方法的类智能被定义成抽象类,抽象类不能有具体的方法体。

         ②抽象类不能被实例化

         ③抽象类可以包含属性、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类、枚举类六种成份。

         ★abstract

(a) abstract修饰的类只能被继承,abstract修饰的方法表明该方法必须由子类提供实现(即重写)

(b) abstract不能用于修饰属性,不能用于修饰局部变量

(c) abstract也不能用于修饰构造器

(d) abstract不能与private同时修饰方法

       ★final

(a) final修饰的类不能被继承,final修饰的方法不能被重写。

(b) abstract与final不能同时被使用

         ★static

       static用于修饰一个方法时,表明这个方法属于当前类,因此satic不能与abstract一起修饰某方法。

7  更彻底的抽象:接口

7.1  接口的定义

         抽象类是从多个类中抽象出来的模板,形成特殊的“抽象类”——接口(interface),体现的是一种规范与实现相分离的设计哲学。接口中不能包含普通的方法,接口中提供的方法都是抽象方法。

         [修饰符]interface 接口名extends 父类接口1,父类接口2…

         {

                   零到多个常量定义…

                   零到多个抽象方法定义…

}

         ①x修饰符可以是public或者省略,如果省略了public访问控制符,则默认采用包权限访问控制符,即只有在相同包结构下才可以访问该接口。

         ②一个接口可以有多个直接父类接口,但接口只能继承接口,不能继承类。

         ③接口定义的是一种规范,不能包含构造器和初始化块。

         ③接口可以包含属性(只能是常量)、方法(只能是抽象方法)、内部类(包括内部接口)和枚举类定义。

         ④对于接口中定义的常量属性而言,系统会自动为这些属性增加static和final两个修饰符。由于无构造器和初始化块,因此只能在定义时指定默认值。

         ⑤对于接口中定义的方法而言,他们只能是抽象方法,系统会自动为其增加abstract修饰符,不允许使用static修饰接口里面的方法。

7.2  接口的继承

         接口支持多继承,可以有多个直接父类接口。子类继承父类接口,将会获得父类接口里定义的抽象方法、常量属性、内部类和枚举类定义。

7.3  接口的使用

         一个类可以实现一个或多个接口,继承使用extends关键字,实现则使用implements关键字。子类继承父类,并实现接口的语法如下:

         [修饰符] class 类名 extends 父类 implements接口1,接口2…

         {

         实体部分

}

实现接口与继承父类相似,一样可以获得所有实现接口里定义的常量属性、抽象方法、内部类和枚举类定义。

一个类实现了一个或者多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些方法),否则,该类将保留从父类那里继承得到的抽象方法,该类也必须定义成抽象类。

7.4  接口和抽象类的对比

         ①相同点

         (a)二者都不能被实例化,他们位于继承树的顶端,用于被其他类实现和继承。

         (b)二者都能包含抽象方法,实现接口或者抽象类的普通子类都必须实现这些抽象方法。

         ②不同点

         (a)设计的目的差异:接口体现的是一种规范,制定了系统中各个模块必须遵循的标准;抽象类作为系统中多个子类的共同父类,体现的是一种模板式设计。

         (b)使用方法的差异

★接口中只能包含抽象方法,不包含已经提供实现的方法;抽象类可以包含普通方法

         ★接口中不能定义静态方法;抽象类可以定义静态方法

★接口中只能定义静态常量属性,不能定义普通属性;抽象类既可以定义普通属性,也可以定义静态常量属性。

★接口不包含构造器;抽象类可以包含构造器,用于让其子类调用这些构造器完成属于抽象类的初始化操作。

★接口里不能包含初始化块,抽象类则可以包含初始化块

★一个类做多只能有一个直接父类,包括抽象类;但是一个类可以直接实现多个接口,通过实现多个接口以弥补java单继承的不足。

8  内部类

         在某些情况下需要将一个类放在另外一个类中定义,这个定义在其他类内部的类就被称为内部类(或嵌套类),包含内部类的类也被称为外部类(或宿主类)。内部类有如下作用:

         ①提供更好的封装,将内部类隐藏在外部类之类,不允许一个包中的其他类访问该类;

         ②内部类成员可以直接访问外部类的私有数据,但外部类不能访问内部类的实现细节,如内部类的属性;

         ③匿名内部类适合用于创建那些仅需要一次使用的类。

8.1  非静态内部类

         定义内部类非常简单,可以放在类中的任何位置,甚至可以放在方法中(称为局部内部类),定义语法格式如下:

         publicclass OuterClass

         {

                   //此处可定义内部类

}

成员内部类是一种与属性、方法、构造器和初始化块相似的类成员,局部内部类和匿名内部类则不是类成员。

成员内部类分为两种:静态内部类(使用static修饰)和非静态内部类。

内部类作为其外部类的成员,可以使用任意的访问控制符,如:private、protected和public等.

外部类的上一级程序单元是包,所以它只有2个作用域:同一个包和任何位置。因此只需要两种访问权限:包访问权限和公开访问权限。正好对应省略访问控制符(省略访问控制符是包访问权限,同一个包中的其他类可以访问省略访问控制符的成员)和public访问控制符。如果一个外部类不使用任何访问控制符修饰,则只能被同一个包中的其它类访问。而内部类的上一级程序单元是外部类,它具有4个作用域:同一个类、同一个包、父子类和任何位置,因此可以使用4中访问控制权限。

         编译含内部类的文件,会自动生成处外部类外的class文件OuterClass$InnerClass.class.

         非静态内部类的方法访问某个变量查找的顺序:先在该方法内部查找,再在该方法所在的内部类中查找,最后在该类所在的外部内中查找。示例代码如下:

class OuterClass

{

     public StringAttrOuter = "外部类属性";

    

     OuterClass() /*外部类构造函数*/

     {

         System.out.println("外部类构造函数");

         System.out.println("外部类构造函数"+AttrOuter);

         //System.out.println("外部类构造函数"+InnerClass.this.AttrInner); //NO

         System.out.println("外部类构造函数"+new InnerClass().AttrInner);

     }

    

     {

         System.out.println("外部类初始化块");

         System.out.println("外部类初始化块"+AttrOuter);

         //System.out.println("外部类初始化块"+InnerClass.this.AttrInner); //NO

         System.out.println("外部类初始化块"+new InnerClass().AttrInner);

     }

    

     public void test()

     {

         System.out.println("外部类方法");

         InnerClass in = new InnerClass();

         in.PrintAttr();

     }

    

     public class InnerClass

     {

         public StringAttrInner = "内部类属性";

        

         InnerClass()/*内部类构造函数*/

         {

              System.out.println("内部类构造函数");

              System.out.println("内部类构造函数"+OuterClass.this.AttrOuter);

              System.out.println("内部类构造函数"+AttrInner);

         }

        

         {

              System.out.println("内部类初始化块");

              System.out.println("内部类初始化块"+OuterClass.this.AttrOuter);

              System.out.println("内部类初始化块"+AttrInner);

         }

        

         public void PrintAttr()

         {

              String ArrtLocal = "局部变量";

              System.out.println("内部类方法"+OuterClass.this.AttrOuter);

              System.out.println("内部类方法"+AttrInner);

              System.out.println("内部类方法"+ArrtLocal);

         }

     }

};

 

public class HelloWorld

{   

     public static voidmain(String[] args)

     {   

         new OuterClass().test();

     }

}

         总结:

非静态内部类的成员可以访问外部类的所有成员(包括private成员),反过来不成立。非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员,则必须显式创建非静态内部类对象来访问其实例成员。

         ②根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类(包括不能使用非静态内部类定义变量,创建实例等)。

         ③java不允许非静态内部类里定义静态成员,不能有静态方法、静态属性、静态初始化块。

         ④注意:初始化块在如果要初始化实例属性,实例属性一定要在其之前定义!

8.2  静态内部类

         使用static来修饰一个内部类,则这个内部类属于整个外部类,不单独属于外部类的某个对象。实例代码如下:

class OuterClass

{

     public StringAttrOuter = "外部类非static属性";

     static public String AttrOuter_S ="外部类static属性";

    

     {

         System.out.println("外部类非static初始化块");

         System.out.println("外部类非static初始化块"+AttrOuter);

         System.out.println("外部类非static初始化块"+AttrOuter_S);

         //System.out.println("外部类非static方法"+InnerClass.ArrtInner);//NO

         System.out.println("外部类非static方法"+InnerClass.ArrtInner_S);

     }

    

     static {

         System.out.println("外部类static初始化块");

         //System.out.println("外部类非static初始化块"+AttrOuter);//NO

         System.out.println("外部类非static初始化块"+AttrOuter_S);

         //System.out.println("外部类非static方法"+InnerClass.ArrtInner);//NO

         System.out.println("外部类非static方法"+InnerClass.ArrtInner_S);

     }

    

     OuterClass()

     {

         System.out.println("外部类构造函数");

         System.out.println("外部类构造函数"+AttrOuter);

         System.out.println("外部类构造函数"+AttrOuter_S);

         //System.out.println("外部类构造函数"+InnerClass.ArrtInner);//NO

         System.out.println("外部类构造函数"+InnerClass.ArrtInner_S);  

     }

    

     static class InnerClass

     {

         public StringArrtInner = "静态内部类非static属性";

         static public String ArrtInner_S ="静态内部类static属性";

        

         {

              System.out.println("内部类非static初始化块");

              //System.out.println("内部类非static初始化块"+OuterClass.AttrOuter);  //NO

              System.out.println("内部类非static初始化块"+OuterClass.AttrOuter_S);

              System.out.println("内部类非static初始化块"+ArrtInner);

              System.out.println("内部类非static初始化块"+ArrtInner_S);

         }

        

         static {

              System.out.println("内部类static初始化块");

              //System.out.println("内部类非static初始化块"+OuterClass.AttrOuter);  //NO

              System.out.println("内部类非static初始化块"+OuterClass.AttrOuter_S);

              //System.out.println("内部类非static初始化块"+ArrtInner);  //NO

              System.out.println("内部类非static初始化块"+ArrtInner_S);

         }

        

         InnerClass()

         {

              System.out.println("内部类构造函数");

              //System.out.println("外部类构造函数"+OuterClass.AttrOuter);  //NO

              System.out.println("外部类构造函数"+OuterClass.AttrOuter_S);

              System.out.println("外部类构造函数"+ArrtInner);

              System.out.println("外部类构造函数"+ArrtInner_S);

         }

        

         public void PrintInner()

         {

              //System.out.println("静态内部类非static方法"+OuterClass.AttrOuter);  //NO

              System.out.println("静态内部类非static方法"+OuterClass.AttrOuter_S);

              System.out.println("静态内部类非static方法"+ArrtInner);

              System.out.println("静态内部类非static方法"+ArrtInner_S); 

         }

        

         static public voidPrintInnerS()

         {

              //System.out.println("静态内部类static方法"+OuterClass.AttrOuter);//NO

              System.out.println("静态内部类static方法"+OuterClass.AttrOuter_S);

              //System.out.println("静态内部类static方法"+ArrtInner);  //NO

              System.out.println("静态内部类static方法"+ArrtInner_S);

         }

     }

    

     public void PrintOuter()

     {

         System.out.println("外部类非static方法"+AttrOuter);

         System.out.println("外部类非static方法"+AttrOuter_S);

         //System.out.println("外部类非static方法"+InnerClass.ArrtInner);//NO

         System.out.println("外部类非static方法"+InnerClass.ArrtInner_S);  

         new InnerClass().PrintInner();

         InnerClass.PrintInnerS();

     }

    

     static public voidPrintOuterS()

     {

         //System.out.println("外部类非static方法"+AttrOuter);//NO

         System.out.println("外部类非static方法"+AttrOuter_S);

         //System.out.println("外部类非static方法"+InnerClass.ArrtInner);//NO

         System.out.println("外部类非static方法"+InnerClass.ArrtInner_S);

         new InnerClass().PrintInner();

         InnerClass.PrintInnerS();

     }

};

 

public class HelloWorld

{   

     public static voidmain(String[] args)

     {   

         OuterClass.PrintOuterS();

         new OuterClass().PrintOuter();

     }

}

总结:(假设外部类和内部类的属性均为public)

外部类方法访问外部类属性及内部类属性的权限

 

外部类实例属性

外部类属性

内部类实例属性

内部类属性

内部类实例方法

内部类方法

构造函数

直接访问

直接访问

×

内部类名.属性名

×

×

初始化块

直接访问

直接访问

×

内部类名.属性名

×

×

静态初始化块

×

直接访问

×

内部类名.属性名

×

×

实例方法

直接访问

直接访问

×

内部类名.属性名

内部类对象.实例方法

内部类对象.实例方法

类方法

×

直接访问

×

内部类名.属性名

内部类名.类方法

内部类名.类方法

 

内部类方法访问外部类属性及内部类属性的权限

 

外部实例属性

外部类属性

内部实例属性

内部类属性

构造函数

×

外部类名.属性名

直接访问

直接访问

初始化块

×

外部类名.属性名

直接访问

直接访问

静态初始化块

×

外部类名.属性名

×

直接访问

实例方法

×

外部类名.属性名

直接访问

直接访问

类方法

×

外部类名.属性名

×

直接访问

 

①java允许在接口里定义内部类,接口中定义的内部类默认使用public static修饰。

②接口里定义内部接口是接口的成员,因此系统默认添加public static两个修饰符。

③静态内部类是外部类的一个静态成员,因此外部类的静态方法、静态初始化块可以使用静态内部类来定义变量、创建对象等。

8.3  内部类的使用

8.3.1 在外部类以外使用非静态内部类

         如果希望在外部类以外的地方访问内部类(包括静态类和非静态类),则内部类不能使用private访问控制权限。访问权限列表如下:

非静态内部类被访问权限

 

public

protected

private

省略访问权限

外部类

外部类以外

可以与外部类处于同一个包中的其它类和外部类的子类访问。

 

只能被与外部类处于同一个包中的其他类访问

         注意:不能在外部类的静态成员(包括静态方法和静态初始化块)中使用非静态内部类,因为静态成员不能访问非静态成员。

         在外部类以外的地方来定义内部类(包括静态和非静态)变量,因为非静态内部类的对象必须寄存在外部类的对象里,因此创建非静态内部类对象之前必须先创建其外部类对象,语法格式如下:

         OuterClass.InnerClassverName = new OuterClass.new InnerClass();

8.3.2 在外部类以外使用静态内部类

静态内部类被访问权限

 

public

protected

private

省略访问权限

外部类

外部类以外

待归纳总结

待归纳总结

待归纳总结

待归纳总结

         静态内部类是外部类相关的,因此创建内部类对象无须创建外部类对象,格式如下:

         OuterClass.StaticInClassin = new OuterClass.StaticInClass();

8.4  局部内部类

         如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。局部内部类不能使用访问控制符和static修饰符修饰。

8.5  匿名内部类

         匿名内部类适合创建那种只需要一次使用的类。格式如下:

         new父类构造器(实参列表) | 实现接口()

         {

                   //匿名内部类的类体部分

}

从上面定义可见,匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。

匿名内部类不能是抽象类,且不能定义构造函数(但是可以定义实例初始化块)。

8.6  闭包和回调

         闭包(Closure)是一种内被调用的对象,它保存了创建它的作用域的信息。

         回调就是某个方法一旦获得了内部对象的引用后,就可以在合适的时候反过来调用外部类实例的方法。实例代码如下:

interface teache   //定义一个接口类

{

     void work();

}

 

class programme   //定义基类

{

     public programme() //缺省构造函数

     {

     }

    

     public programme(String name)  //带参构造函数

     {

         this.name = name;

     }

    

     public void work()

     {

         System.out.println(name +"programmer is coding...");

     }

    

     public String GetName()  //给外部提供获取基类属性接口

     {

         returnname;

     }

     private Stringname;

}

 

class TeachProgramextends programme

{   

     public TeachProgram()  //缺省构造函数

     {

     }

    

     public TeachProgram(String name)  //带参构造函数

     {

         super(name);

     }

    

     private void teach()

     {

         System.out.println(GetName()+"teacher is teaching...");

     }

    

     private class teacher implements teache  //实现接口

     {

         public void work()

         {

              teach();

         }

     }

    

     public teache GetCallBackFun()

     {

         return new teacher();

     }

}

 

public class HelloWorld

{   

     public static voidmain(String[] args)

     {   

         TeachProgram tp =new TeachProgram("张三");

         tp.work(); //调用TeachProgram. programme  的work()方法

         tp.GetCallBackFun().work();  //调用teacher的work()方法,该方法实际上调用了外部类的teach()方法

     }

}

打印结果:

张三programmer is coding...

张三teacher is teaching...

9  枚举类

         应用场景:某些情况下一个类的对象是有限且固定的,如季节、星期、月份等。这种实例有限而且固定的类,在java中被称为枚举类。

9.1  手动实现枚举类

         设计方式:

         ①通过private将构造器隐藏起来;

         ②将这个类所有可能实例都使用publicstatic final属性来保存。

         ③如果有必要,提供一些static方法,允许其它程序根据特性的参数来获取与之匹配的实例。

class Season

{

     private final String name;

     private final String desc;

    

     private Season(String name,String desc)

     {

         this.name = name;

         this.desc = desc;

     }

     public static finalSeason SPRING=newSeason("","踏春");

     public static finalSeason SUMMER=newSeason("","冲浪");

     public static finalSeason AUTOMN=newSeason("","收获");

     public static finalSeason WINTER=newSeason("","赏雪");

    

     public static Season getSeason(int SeasonNum)

     {

         switch(SeasonNum)

         {

         case 1:

              returnSPRING;

         case 2:

              returnSUMMER;

         case 3:

              returnAUTOMN;

         case 4:

              returnWINTER;

         default:

              return null;

         }

     }

    

     public String getName()

     {

         returnname;

     }

    

     public String getDesc()

     {

         returndesc;

     }

}

9.2  枚举类入门

         枚举类是一种特殊的类,J2SE1.5新增一个enum关键字用以定义枚举类。枚举类一样可以有自己的方法和属性,可以实现一个或多个接口,也可以定义自己的构造函数。与普通类的区别如下:

         ①枚举类实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是继承Object类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable接口。

         ②枚举类的构造器只能使用private访问控制符来修饰,省略则默认也为此权限。

         ③枚举类的所有实例必须显式列出,否则这个枚举类将永远不能产生实例。列出这些实例时,那个会自动添加public static final修饰。

         ④所有的枚举类都提供了一个values方法,可以遍历所有的枚举值。

         举例如下:

         publicenum SeasonEnum

         {

                   SPRING,SUMMER,AUTUMN,WINTER;

         }

         publicclass TestEnum

         {

                   publicvoid judge(SeasonEnum s)

                   {

                            switch(s)

                            {

                                     caseSPRING:

                                               System.out.println("spring");

                                               break;

}

}

public static void main(String[] args)

{

         newTestEnum().judge(SeasonEnum.SPRING);

}

}

         enum关键字和class、interface关键字的作用大致相似,定义枚举类时,需要显式列出所有枚举值,所有枚举值之间以英文逗号“,”隔开,最终以英文分号“;”结束。

9.3  枚举类的属性、方法和构造器

         枚举类通常应该设计成不可变类,也就是说它的属性值不应该允许改变,这样更安全,代码更简洁。因此我们将枚举类的属性都是用private final来修饰(用其他修饰符修饰亦可,只是可能会被修改),这种情况下的枚举类要显式定义带参构造函数。一旦显式定义了带参的构造器,则列举枚举值时必须对应地传入参数,如:

         publicenum Gender

         {

                   MALE(“男”),FEMALE(“女”);

                   privatefinal String name;

                  

                   privateGender(String name)

                   {

                            this.name= name;

}

}

         前面列举枚举值时无需传入参数,甚至无需使用括号,是因为前面的枚举类包含无参构造器。

9.4  实现接口的枚举类

         枚举类也可以实现一个或多个接口,具体方法和要求与普通类实现一个或多个接口完全一样。

         如果有枚举类来实现接口里的方法,则每个枚举值在调用该方法时,都有相同的行为方式。如果需要每个枚举值在调用方法时呈现不同的行为,则可以让每个枚举值分别来实现该方法,实例如下:

interface GeneralInterface

{

     public void fun();

}

 

enum EnumClassimplements GeneralInterface

{

     MALE("")

     {

         public void fun()

         {

              System.out.println("MALE interface overwrite");

         }

     },

     FEMALE("")

     {

         public void fun()

         {

              System.out.println("FEMALE interface overwrite");

         }

     };

    

     private final String name;

     private EnumClass(String name)

     {

         this.name = name;

     }

}

         编译上述文件,会生成EnumClass.class、EnumClass$1.class、EnumClass$2.class三个文件。

9.5  包含抽象方法的枚举类

enum Operation

{

     PLUS,MINUS,TIMES,DIVIDE;

     double eval(double x,double y)

     {

         switch(this)

         {

         casePLUS: return(x+y);

         caseMINUS: return(x-y);

         caseTIMES: return(x*y);

         caseDIVIDE: return(x/y);

         default:return 0;//实际上这句不会出现,但是没有这句编译不过。

         }

     }

}

public class HelloWorld

{   

     public static voidmain(String[] args)

     {   

         System.out.println(Operation.PLUS.eval(1, 2));

         System.out.println(Operation.MINUS.eval(1, 2));

         System.out.println(Operation.TIMES.eval(1, 2));

         System.out.println(Operation.DIVIDE.eval(1, 2));

     }

}

         现在利用抽象方法实现上述代码如下:

enum Operation

{

     PLUS

     {

         public double eval(doublex,doubley)

         {

         return (x+y);

         }

     },

     MINUS

     {

         public double eval(doublex,doubley)

         {

         return (x-y);

         }

     },

     TIMES

     {

         public double eval(doublex,doubley)

         {

         return (x*y);

         }

     },

     DIVIDE

     {

         public double eval(doublex,doubley)

         {

         return (x/y);

         }

     };

     public abstract doubleeval(doublex,doubley);

}

 

public class HelloWorld

{   

     public static voidmain(String[] args)

     {   

         System.out.println(Operation.PLUS.eval(1, 2));

         System.out.println(Operation.MINUS.eval(1, 2));

         System.out.println(Operation.TIMES.eval(1, 2));

         System.out.println(Operation.DIVIDE.eval(1, 2));

     }

}

10 对象与垃圾回收

10.1  对象在堆内存中的状态

         ①激活状态:当一个对象被创建后,有一个以上的引用变量引用它。

         ②去活状态:程序中某个对象不再有任何引用变量引用它。在回收该对象之前,系统会调用所有去活状态对象的finalize方法进行资源清理,如果系统在调用finalize方法重新让一个引用变量引用该对象,则这个对象再次变为激活状态,否则该对象将进入死亡状态。

         ③死亡状态:对象与所有引用变量的关联都被切断,且系统已经调用所有对象的finalize方法依然没有使该方法变成激活状态,则这个将会变成死亡状态,被系统所回收。

10.2  强制垃圾回收

         通知系统进行垃圾回收,但系统是否进行垃圾回收依然不确定。两种方法如下:

         ①调用System类的gc()静态方法:System.gc()

         ②调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()

10.3  finalize方法

         java提供了默认机制来清理该对象的资源,使用定义在Object类的实例方法:finalize方法。原型为:protected void finalize() throws Throwable

         此方法可以被重写。具有如下四个特点:

         ①永远不要主动调用某个对象的finalize方法,由垃圾回收机制调用;

         ②finalize方法何时被调用具有不确定性;

         ③当JVM执行去活对象的finalize方法时,可能是该对象或系统中其他对象重新变成激活状态;

         ④当JVM执行finalize方法时出现异常,垃圾回收机制不会抛出异常,程序继续执行。

10.4  对象的软、弱和虚引用

         对大部分对象而言,程序里会有一个引用变量引用该对象,这是最常见的引用方式。java.lang.ref提供三个类:SoftReference、PhantomReference和WeakReference,分别代表三种引用方式:软引用、虚引用和弱引用。

         ①强引用(StrongReference)

         程序创建一个对象,并把这个对象赋给一个引用变量。

         ②软引用(SoftReference)

         常用于对内存敏感的程序中。

         ③弱引用(WeakReference)

         弱引用的引用级别比软引用更低

         ④虚引用(PhantomReference)

         主要用于跟踪对象垃圾回收的状态,不能单独使用,和引用队列(ReferenceQueue)联合使用。

11 jar命令使用归纳

         jar:java archivefile,java归档文件。

         应用场景:提供JAR文件给别人使用时,用户只需在CLASSPATH环境变量中添加这个JAR文件,java虚拟机则可以在内存中自动解压这个jar包。

         ①创建JAR文件:jar cftest.jar test

         ②创建JAR文件并显示压缩过程:jarcvf test.jar test

         ③不使用清单文件:jar cvfMtest.jar test

         生成的test.jar中没有包含META-INF/MANIFEST文件

         ④自定义清单文件内容:jarcvfm test.jar manifest test

         ⑤查看jar包内容:jar tftest.jar

         ⑥查看jar包详细内容:jar tvftest.jar

         ⑦解压缩:jar xf test.jar

         ⑧带提示信息的解压缩:解压缩:jar xvf test.jar

         ⑨更新jar文件: jar uf test.jarHello.class

         更新test.jar 中的Hello.class

         ⑩更新jar文件时显示详细信息: jaruvf test.jar Hello.class

         ⑪创建可执行的JAR包

         (a)使用平台的编译器生成平台相关的可执行文件。

         (b)为整个应用编辑一个批处理文件

         (c)将一个应用程序制作成可执行的jar包,通过jar包进行发布。

12  总结

 

顶层类/接口

成员属性

方法

构造器

初始化块

成员内部类

局部成员

public

 

 

protected

 

 

 

包访问控制符

 

 

private

 

 

 

abstract

 

 

 

 

final

 

 

static

 

 

 

strictfp

 

 

 

 

synchronized

 

 

 

 

 

 

native

 

 

 

 

 

 

transient

 

 

 

 

 

volatile

 

 

 

 

 

 

         包访问控制符是一个特殊修饰符,不用任何访问控制符就是包访问控制。

         strictfp关键字的含义是FP-strict,即精确浮点的意思。如果使用了strictfp关键字修饰类、接口或者方法时,则其所修饰的访问将完全依照规范IEEE-754执行。

         native关键字主要用于修饰一个方法,native方法通常采用C语言来实现。

         访问控制符是互斥的,最多只能出现其中之一,另外abstract和final不能同时使用,abstract和static不能同时使用,abstract和private不能同时使用。
0 0