从零开始学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不能同时使用。- 从零开始学java(五)--面向对象(下)
- 从零开始学java(四)--面向对象(上)
- 每天学一点Swift----面向对象下(五)
- Java基础<五>_面向对象(下)
- 从零开始学java:面向过程,面向对象等编程思想个人理解
- 从零开始学java(五)运算符
- Java面向对象(五)
- 从零开始学Java(二)一切都是对象
- 5、从零开始学习JAVA--面向对象
- JAVA学习五:面向对象
- JAVA面向对象(五)
- java面向对象下
- JAVA面向对象下
- Java面向对象(下)
- java面向对象下
- 菜鸟学Java----Java面向对象
- 从零开始学Android(五)
- 从零开始学Makefile(五)
- 编辑原理系列学习:编译器简介及Lexical analyzer
- hdu 4291 A Short problem(矩阵快速幂)
- linux shell脚本基础用法详解
- robotFramework——FOR循环语句
- 数据挖掘
- 从零开始学java(五)--面向对象(下)
- 俄罗斯方块游戏的shell脚本
- 潘鹏整理WPF(14)绑定到非元素对象
- hdu 3231 Box Relations(拓扑排序)
- 知道你的手机是如何确定你的位置的吗
- UGUI学习笔记1——Canvas
- drupal markdown editor for BUEditor
- spring Bean的配置方法笔记
- 将cocos2dX项目工程移植到ecplise中打包为apk