Java程序设计基础(第2版) 课件 第4章 继承(第2版)_第1页
Java程序设计基础(第2版) 课件 第4章 继承(第2版)_第2页
Java程序设计基础(第2版) 课件 第4章 继承(第2版)_第3页
Java程序设计基础(第2版) 课件 第4章 继承(第2版)_第4页
Java程序设计基础(第2版) 课件 第4章 继承(第2版)_第5页
已阅读5页,还剩141页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

继承1内容4.1通过继承共享祖先的特征 4.2父类和子类的构造方法 4.3覆盖实例方法和隐藏静态方法4.4上转型和下转型 4.5抽象类和抽象方法 4.6保留字final 4.7接口 4.8多态 4.9源代码的组织和访问控制4.10Object类 4.10.1toString方法4.10.2equals方法 4.10.3hashCode方 4.11枚举 2概念继承描述了类与类之间的“Is-a”关系圆是平面形状(ACircleisaShape.)轿车是机动车。假设类B继承了类A,那么类B是类A的子类(childclass)。也称扩展类(extendedclass)或导出类(derivedclass)反过来,类A是类B的父类(parentclass),也称超类(superclass)或基类(baseclass)。3继承树4继承树在这棵继承树中,具有相同父类(parent)的类称为兄弟类如B、C、D互为兄弟从树的根到某结点路径上的所有类称为该结点的祖先(ancestor)类。类H的祖先类有A、D、F。从树的根到某结点路径称为继承链。以某结点为根的子树上的结点称为该结点的后代类。例如D的后代为F、G、H。5汽车是机动车汽车是由动力驱动,具有四个或四个以上车轮的非轨道承载的车辆机动车(motorvehicle)是以动力装置驱动或者牵引,上道路行驶的供人员乘用或者用于运送物品以及进行工程专项作业的轮式车辆汽车摩托车拖拉机6汽车是机动车汽车类Car机动车类Vehicle任何一辆机动车都有外廓尺寸属性,但不一定有车牌号码;任何一辆机动车都能被查看外廓尺寸(getOverallSize),但不一定能够鸣笛(honk)。7Car.javaVehicle继承继承使得子类自动具有了父类的属性和行为。保留字extends就用于声明类之间的继承关系8ExtendsDemo.java保留字extends保留字extends声明类Car继承了类Vehicle这就使得类Car自动具有了Vehicle的属性外廓尺寸,以及行为查看外廓尺寸getOverallSize()。所以在第4行就能够通过汽车对象的引用c来调用方法getOverallSize(),尽管该方法并没有在Car类中声明。注意:子类不能继承父类的私有成员。9子类实例中的成员10Object类Java中类Object是所有类的父类,Object类是唯一没有父类的类。Object类定义了所有对象都应具备的行为相等比较equals()转换成字符串表示toString()等等。虽然类Vehicle没有显式地声明继承Object类,但Java语言默认已经继承了Object类。11Object类12publicclassVehicleextends

Object{}

publicclassVehicle{}等价于4.2父类和子类的构造方法子类不能继承父类的构造方法因为构造方法的名字与类名相同子类可以调用父类的构造方法super类Car在其构造方法Car(StringlicenceNumber,intlength,intwidth,intheight)中的第一条语句(第11行)通过调用父类的构造方法13Vehicle.javaExtendsDemo.java构造方法如果在类的定义中没有定义任何构造方法,那么Java自动提供一个默认的无参构造方法。但是,一旦在类的定义中定义了构造方法,无论几个,那么Java就不再提供默认的无参构造方法。14ConstructorDemo.javapublicCar(StringlicenceNumber,intlength,intwidth,intheight){super();this.licenceNumber=licenceNumber;}中的构造方法等价于:默认的构造方法行为15注意在子类构造方法中调用通过保留字super调用父类构造方法的语句必须是子类构造方法的首条语句。构造方法至少两个Vehicle类声明了两个构造方法:一个是有参数的Vehicle(intlength,intwidth,intheight)另一个是无参数的Vehicle()16Vehicle.java继承链上的构造方法实例化E时会通过super()自动调用C的无参构造方法C();而在调用C()时,就会通过super()自动调用A的无参构造方法A()17classA{}classCextendsA{}classEextendsC{}classA{A(){super();}}classCextendsA{C(){super();}}classEextendsC{E(){super();}}等价于构造方法链一般而言,实例化子类将会依次调用其继承链上的所有祖先类的构造方法。形成了构造方法链(constructorchaining)由于每次作为第一条语句调用,所以在类继承链上最后类的构造方法最后执行完,最先类的构造方法最早执行完毕18ConstructorChain.java总结从一个类创建对象会激发构造方法链上所有构造方法的执行。当使用子类的构造方法初始化对象时,良好的程序设计实践是在构造方法的第一条语句中使用含参数的super方法初始化父类的实例变量,然后再初始化子类的实例变量。194.3覆盖实例方法和隐藏静态方法子类不仅能够继承和直接使用父类的实例方法,还能够使用原来的方法重新定义,这种现象称为方法的覆盖(override)toString方法是类java.lang.Object中的实例方法,该方法返回对象的字符串表示。20使用默认的toString方法:OverrideDemo.java覆盖toString方法:OverrideToStringDemo.java举例toString方法是类java.lang.Object中的实例方法,该方法返回对象的字符串表示。21classA{ intaMember;}Aa=newA();System.out.println(a.toString());A@9cab16举例类A中重新定义toString方法22classA{ intaMember;

StringtoString(){ return"A[aMember="+aMember+"]"; }}Aa=newA();System.out.println(a.toString());A[aMember=0]注意子类的方法与父类中被覆盖方法的返回值、名字、参数类型序列一致。基本数据类型和void的返回值类型:必须相同引用数据类型的返回值类型:兼容只有那些可继承的实例方法才可以被覆盖。子类中的方法可以保持或提高被覆盖方法的可访问性,但不能降低。可访问性从小到大依次是包私有(默认)protectedpublic覆盖方法所抛出的异常必须和被覆盖方法的所抛出的异常兼容。对象的类型决定了所执行的实例方法的版本;而不是引用变量的类型。23@OverrideJava语言的注解@Override用来提示编译器这是一个覆盖方法,注意检查该方法是否满足方法覆盖的条件24源文件48OverrideAnotationDemo.java访问被覆盖的实例方法使用保留字super可以显式地访问被覆盖的实例方法25源文件

4‑9SuperDemo.java隐藏如果在子类中重新定义了静态方法的方法体,这种现象就称子类中的方法隐藏(hidden)了父类的方法26源文件4-10HiddenDemo.java4.4上转型和下转型上转型指的是按照某类型的祖先类型引用该类型的对象。上转型对象总是允许的,但下转型则需要显式地说明。27CastingDemo.java注意当通过上转型引用子类的对象时,无法访问子类中定义的实例变量和非覆盖方法。第10行试图访问子类对象的实例变量licenceNumber却产生了编译错误:找不到符号licenceNumber。在第11行试图调用子类对象的实例方法honk,但产生编译错误:找不到符号honk但如果在父类Vehicle中增加了实例方法honk()的定义(第56行到第58行)使得父类Vehicle中的honk()方法被覆盖,则第不会在第11行产生编译错误不建议覆盖设计只有一条空语句的方法28CastingDemo.java56Stringhonk(){

57;

58}

59下转型如果沿着继承链从祖先类向子类方向转型,则称为下转型。下转型必须显式地进行。通过在对象引用前使用转型运算符:

(<类型>)例如:Vehiclev=newVehicle();Carc=(Car)v;29下转型这是因为下转型就意味着按照子类型访问父类型的对象,显然存在风险。比如:

Vehiclev=newVehicle();Carc=(Car)v;doublex=c.licenceNumber;

而事实上c所引用的对象中根本就没有实例变量licenceNumber。30下转型为了保证转型成功,程序员必须确保被下转型的对象是子类的实例。一般的做法是在转型之前对被转型的对象进行判定,看看是否是所转类型的实例这就用到了运算符instanceof。31if(vinstanceofCar){

b=(Car)v;

b.honk();

}CastingDemo.java总结把子类的对象上转型为其父类,就相当于按照父类型访问对象,此时可访问父类的实例变量和实例方法,但当实例方法被子类覆盖时,将访问子类的实例方法。在下转型之前要确认被转型的对象是欲转成的类型。如果一个对象是由类C实例化而来,那么这个对象既是类型C的对象,又是其祖先类型的对象。324.5抽象类和抽象方法如果想限制一个类不能实例化对象,那么就是要保留字abstract将其声明为抽象类(abstractclass)。例“机动车”太抽象了,无法定义如何鸣笛需要有一个实例方法,但不想或不能定义方法体就可以把这种方法定义为抽象方法含有抽象方法的类必须声明为抽象类33AbstractDemo.java抽象方法如果一个方法只定义了方法的头部而没有定义方法体,那么这样的方法就称为抽象方法(abstractmethod)实例方法Vehicle类的getOverallSizeVehicle也应设计为抽象方法通过把Vehicle定义为抽象类禁止从该类实例化对象,从而避免调用抽象方法子类应提供所有抽象方法的具体实现如果子类没有全部实现父类中的抽象方法,则子类必须声明为抽象的34机动车的鸣笛行为考虑三个类:机动车(Vehicle)、轿车(Car)和救护车(Ambulance),轿车和救护车都能鸣笛(horn),但是鸣笛的声音不同。机动车具有鸣笛行为,但具体什么样的声音取决于具体的车35机动车的鸣笛行为:初始设计36publicclassVehicle{publicvoidhorn(){;}}publicclassCarextendsVehicle{publicvoidhorn(){System.out.println("嘀嘀");}}publicclassAmbulanceextendsVehicle{publicvoidhorn(){System.out.println("嘀嘟嘀嘟");}}问题如果有客户程序实例化了Vehicle类,那么客户程序就可以调用其horn()方法,而此时的horn()方法仅仅有一条空语句,调用没有产生没有任何效果,会使客户程序感到莫名其妙:

Vehiclev=newVehicle();v.horn();

37改进禁止实例化Vehicle对象,然后调用其上的horn()方法;强迫Vehicle的子类必须提供horn()方法的具体实现。38改进第1条改进可以通过把Vehicle定义为抽象类来实现;第2条改进就需抽象方法来实现。39改进后的版本40publicabstractclassVehicle{

abstractpublicvoidhorn();}注意含有抽象方法的类必须是抽象类,所以Vehicle类同时使用abstract保留字定义为抽象的。当父类中含有抽象方法,子类必须提供该抽象方法的方法体,这称为实现继承的抽象方法41注意类中只要定义了抽象方法,该类就必须声明为抽象类。抽象类中可以不含抽象方法。抽象类只能作为基类,不能被实例化。如果子类没有全部实现父抽象类的抽象方法,则子类必须声明为抽象的。42完整的改进版本43publicabstractclassVehicle{

abstractpublicvoidhorn();

}publicclassCarextendsVehicle{ publicvoidhorn(){ System.out.println("嘀嘀"); }}

publicclassAmbulanceextendsVehicle{publicvoidhorn(){System.out.println("嘀嘟嘀嘟");}}完整的改进版本44publicclassTest{ publicstaticvoidmain(String[]args){ Carc=newCar(); c.horn(); }}问题:计算水箱体积45问题:计算水箱体积46//圆柱形水箱的底classCircle{

doubler;

Circle(doubler){

this.r=r;

}

doublegetArea(){

returnMath.PI*r*r;

}

}

问题:计算水箱体积47//圆柱形水箱classPillar{

Circlebottom;

doubleheight;

Pillar(Circlebottom,doubleheight){

this.bottom=bottom;

this.height=height;

}

doublegetV(){

returnbottom.getArea()*height;

}

}

问题:计算水箱体积48public

classDemoPillar{

public

static

voidmain(String[]args){

Pillarp=newPillar(newCircle(1),1);

System.out.println(p.getV());

}

}问题:计算水箱体积49//还需要方柱形水箱,怎么办?public

classDemoPillar{

public

static

voidmain(String[]args){

Pillarp=newPillar(new

Rectangle(1,1),1);

System.out.println(p.getV());

}

}定义抽象类和抽象方法50abstractShape{//不能从Shape类创建对象

//希望能计算面积;但是,具体算法取决于子类

abstractdoublegetArea();

}方柱体的底51classRectangleextendsShape{

doublewidth;

doubleheight;

Rectangle(doublewidth,doubleheight){

this.width=width;

this.height=height;

}

public

doublegetArea(){

returnwidth*height;

}

}

圆柱体的底52classCircleextendsShape{

doubler;

Circle(doubler){

this.r=r;

}

public

doublegetArea(){

returnMath.PI*r*r;

}

}

柱体53classPillar{

Shapebottom;

doubleheight;

Pillar(Shapebottom,doubleheight){

this.bottom=bottom;

this.height=height;

}

doublegetV(){

returnbottom.getArea()*height;

}

}

计算柱体的体积54public

classDemoPillar{

public

static

voidmain(String[]args){

Pillarp=newPillar(newRectangle(1,1),1);

System.out.println(p.getV());

Pillarq=newPillar(newCircle(1),1);

System.out.println(q.getV());

}

final类 如果想限制某个类不能被任何类所继承,那么就在定义类的时候使用final保留字来修饰55finalclassA{…}4.6保留字final保留字final的含义是“最终的,不可改变的”用来修饰类、方法和变量被final修饰的类不能被继承被final修饰的变量不能被再次赋值,只能初始化时赋值一次被final保留字修饰的类的成员方法不能被子类覆盖56finalclassA{

……}final成员被final修饰的变量称为常量在f()方法体中试图对这三个常量再次赋值,则产生的编译错误。引用类型的成员变量a和INDEX也被final修饰,方法f()对其的修改企图也会产生编译错误注意,是变量a或INDEX的值不能被修改而不是a或INDEX所引用的对象不能被修改类B继承了类A,并试图覆盖方法f(),则出现编译错误因为类A中把方法f声明为final,不允许被覆盖57FinalMemberDemo.java总结如果一个类不允许被子类继承,就使用final修饰如果一个方法不允许被子类覆盖,就用final修饰如果一个成员变量不允许被修改,就用final修饰如果想使用常量,使用final修饰变量如果想使用全局常量,使用publicstaticfinal修饰变量584.7接口 从形式上看,接口是彻底的抽象类所有方法都是抽象方法,而且是public从内容上看,接口是类的客户和该类之间的一组约定(方法的头部,原型)。59例假如一个应用程序想使用汽车对象,要求这个汽车对象提供鸣笛(honk)查看外廓尺寸(getOverallSize)查看车牌号码(getLicenceNumber)开发团队中指派小张负责设计实现小汽车对象,并告诉小张具体这些方法的头部:

StringgetLicenceNumber()StringgetOverallSize()voidhonk()60ICar.java实现接口把接口ICar交给小张后,小张就应该做两件事情:设计接口的实现类测试实现类保留字implements用来建立接口与其实现类直接的实现关系由于接口中的方法的可访问性默认是public,所以其实现类中的相应的方法也必须是public方法61实现接口Car.java测试接口的实现InterfaceDemo.java

单元测试对类的测试称为单元测试。建议使用jUnit测试框架进行单元测试。类Car的测试驱动程序@Before注解setUp方法会在每个@Test注解的方法执行前被调用;@Test注解的方法称为一个测试用例。测试用例由两部分组成:输入预期的输出输入以被测方法的实在参数提供62CarTest.java举例应用栈解决括号匹配问题6364publicclassTest{

publicstaticvoidmain(String[]args){ Strings="A(B,C(D,E(F,G)),H);XY(Z);"; Stackstack=new…;//此处创建一个栈对象 intN=s.length(); for(inti=0;i<N;i++){ if(s.charAt(i)=='(') stack.push('('); if(s.charAt(i)==')'){ if(stack.isEmpty()){ System.out.println("Mismatch!"); return; } stack.pop(); } } if(stack.isEmpty()) System.out.println("Match!"); else System.out.println("Mismatch"); }

}举例在这个客户代码中,希望有一个栈对象,并且可以使用实例方法push、pop、isEmpty等访问这个对象。这一组实例方法就是客户程序与栈的实现之间的一个约定65interface保留字66publicinterfaceIStack{ /** *入栈. *@parame入栈元素. *@return如果栈满,返回false;否则true. */ booleanpush(Objecte);

/** *出栈. *@return如果栈空,返回false;否则true. */ booleanpop();

/** *判断是否栈空. *@return栈空则返回true;否则返回false. */ booleanisEmpty();

}单链表实现的栈67classListNode{publicObjectelement;publicListNodenextNode;

//构造方法publicListNode(Objectelement){this(element,null);}

publicListNode(Objectelement,ListNodenextNode){this.element=element;this.nextNode=nextNode;}

}publicclassListStackimplementsIStack{

privateListNodetopOfStack;

publicListStack(){ topOfStack=null; } publicbooleanpush(Objecte){ if(this.isFull()) returnfalse; else{ topOfStack=newListNode(e,topOfStack); returntrue; } }单链表实现的栈68 publicbooleanpop(){ if(this.isEmpty()) returnfalse; else{ topOfStack=topOfStack.nextNode; returntrue; } } publicbooleanisEmpty(){ returntopOfStack==null; }}数组实现的栈69publicclassArrayStackimplementsIStack{

privateObject[]objectArray; privateinttopOfStack; privatestaticfinalintCAPACITY=128;

publicArrayStack(){ objectArray=newObject[CAPACITY]; topOfStack=-1; } publicbooleanpush(Objecte){ if(this.isFull()) returnfalse; else{ objectArray[++topOfStack]=e; returntrue; } } publicbooleanpop(){ if(this.isEmpty()) returnfalse; else{ topOfStack--; returntrue; } }

publicbooleanisEmpty(){ returntopOfStack==-1; }}测试70publicclassInterfaceTest{

publicstaticvoidmain(String[]args){ Stacks1=newListStack(); s1.push("One"); s1.clear(); Stacks2=newArrayStack(); s2.push("Two"); s2.clear(); }}客户程序71publicclassTest{

publicstaticvoidmain(String[]args){ Strings="A(B,C(D,E(F,G)),H);XY(Z);";

Stackstack=newArrayStack();//此处创建一个栈对象 intN=s.length(); for(inti=0;i<N;i++){ if(s.charAt(i)=='(') stack.push('('); if(s.charAt(i)==')'){ if(stack.isEmpty()){ System.out.println("Mismatch!"); return; } stack.pop(); } } if(stack.isEmpty()) System.out.println("Match!"); else System.out.println("Mismatch"); }

}注意72接口中声明的方法默认是public和abstractpublicinterfaceUA{voiddoSomethingofA();}publicinterfaceUA{

publicabstractvoiddoSomethingofA();}常量73在接口中也可以定义成员变量,这些成员变量默认是public

staticfinalpublicinterfaceUA{ intCAPACITY=128; voiddoSomethingofA();}publicinterfaceUA{

publicstaticfinalintCAPACITY=128; voiddoSomethingofA();}访问接口74访问接口中定义的常量与访问类的静态成员类似,通过“<接口名>.<常量名>”格式访问。接口的多重继承751public

interfaceIA{

2

voidf();

3}

1public

interfaceIB{

2

voidg();

3}1public

interfaceICextendsIA,IB{

2}1public

classTimplementsIC{

2

public

voidf(){

3System.out.println("Dosomethingoff");

4}

5

6

public

voidg(){

7System.out.println("Dosomethingofg");

8}

9}

10实现类与接口76一个接口可以有多个实现类;一个类也可使实现多个接口。一个类实现多个接口77类S同时实现了两个接口IA和IB1public

classSimplementsIA,IB{

2

public

voidf(){

3System.out.println("Dosomethingoff");

4}

5

6

public

voidg(){

7System.out.println("Dosomethingofg");

8}

9}注意实现某个接口意味着实现接口的所有抽象方法和继承接口中所有静态常量。如果不想实现接口中全部抽象方法,则必须把实现类声明为抽象类。可访问性为public的接口与可访问性为public的类一样,其对应的源文件名必须与接口名严格一致78注意接口用以描述服务提供者与服务使用者(客户)之间的契约,所以接口中的成员都是public的。接口仅描述做什么,而不关心如何去做,所以接口中的方法都是抽象的。接口中的方法默认是publicabstract。接口中的变量默认是publicstaticfinal,且必须给出初值。接口不能被实例化。79定义接口和实现接口从以上实例可以总结出定义接口的语法:interface<名字>{ <接口成员>}class<类名>implements<接口1>,…,<接口n>{ //对接口中所有抽象方法的实现

//其他类成员定义}80注意publicinterfaceIA{ voidf();}必须保存为IA.java。81访问接口中的常量<接口名>.<常量名>82publicclassIDDemo{publicstaticvoidmain(String[]args){int[]a=newint[ID.CAPACITY];}}接口中的默认方法publicdefault

返回类型方法名(){}831public

interfaceIE{

2

public

default

voidf(){

3System.out.println("Adefaultmethod.");

4}

5}1public

classEimplementsIE{

2

3}1public

classDefaultDemo{

2

public

static

voidmain(String[]args){

3IEe=newE();

4e.f();

5}

6}接口中使用static保留字声明静态方法84publicinterfaceIF{publicstaticvoidf(){System.out.println("接口中的静态方法");}}publicclassStaticMethodDemo{publicstaticvoidmain(String[]args){IF.f();}}4.8多态 多态是程序在运行时刻展现出的一种现象:相同的消息通过相同类型的引用发送给不同的对象却产生了不同的行为。比如,有A、B、C三辆机动车停在路边。其中A是轿车、B是救护车、C是救火车。现在让每辆机动车都开始鸣笛。那么,这三辆车应当发出不同的鸣笛声。这就是生活中的多态现象。85多态现象86PolyByInheritanceDemo.java虽然变量a、b、c的类型相同、接收的消息相同(a.honk()、b.honk()、c.honk()),但却产生不同的结果多态即相同的消息,由于运行时接收并执行消息对象的类型不同,从而产生不同行为。由于任意类的实例都可以上转型为其任意祖先类的类型,所以在类继承链上任意结点都可以设计多态程序。多态既可以由类继承实现,也可以通过接口及其实现类完成。87PolybyInterfaceDemo.java通过接口实现多态比通过继承实现多态具有更好的灵活性88有的动物只会叫不会飞,比如狗、猫、绵羊;有的动物只会飞不会叫,比如蝴蝶;而有的动物既会飞也会叫,比如喜鹊。就可以通过定义两个接口Speakable和Flyable,通过二者组合在声明实现类。首先声明三个实现类Dog、Cat和Sheep实现Speakable,这三个类定义了能叫的动物。然后声明蝴蝶类Butterfly实现Flyable,最后让喜鹊类Magpie既实现Speakable接口,又实现Flyable接口。源文件436AnimalsDemo.java多态:动态重定位89注意继承来的成员的可访问性只能被提升,而不能下降904.9源代码的组织和访问控制Java应用程序是一些类的集合。当类的数量很大的时候,比如成百上千个,就需要分门别类把一组相关的类型(类、接口等)定义在一起形成一个集体,称为包(package)。这样,一个类的全名(fullyqualifiedname)就形如:<包名>.<类名>91包的作用与命名类名的前面有了包名的限制,就为能够类名冲突。当两个类名字都是Car,那么只需把这两个类声明在不同的包里即可例如某IT公司abc的互联网域名可能是:,那么该公司研发的包就应命名为:.abc。注意包名一律使用小写字母。包名仅仅是一个标识符,其中的“.”也是普通字符,没有其它含义。92例如JDK(JavaDevelopmentKit)包含了丰富的预先写好的类,这些类称为应用程序接口,简称API(ApplicationProgrammingInterfaces)。JDK中的API,也称为标准API组织在不同的包中java.lang包是编写Java程序最基本的包,其中包含了String、Math、System等最常用的类java.util包含了Calendar、Date、Scanner、Stack、Vector、Set和Queue等实用类93自定义包94package.abc;

publicclassA{…}类A就属于包.abc自定义包源文件中的包定义语句约束了本源文件中定义的所有类和接口都属于这个包。本例中类A就属于包.abc。一个源文件中最多有一个包定义语句。如果在源文件中有一个包定义语句,则该语句必须是第1条语句。Java世界中的包与操作系统中的文件夹有映射关系。例如包.abc与文件夹cn\com\abc相对应。包.abc中的类型的源文件都保存在文件夹cn\com\abc中。95访问自定义包两种方式使用包中的类:完整类名导入(import)包的某个成员96全名方式假设包.xyz中的类E偶尔用一次包.abc中的类A,就可以使用类的全名.abc.A:97package.xyz;classE{voidaccessOtherClassInOtherPackage(){.abc.Aa=new.abc.A();……}}方式2:导入(import)包的某个成员98package.xyz;import.abc.A;classE{voidaccessOtherClassInOtherPackage(){Aa=newA();}}默认导入包java.lang中的类,无需使用import语句导入导入包中所有成员importhebtu.cs.dd.oop.*;

意思是导入hebtu.cs.dd.oop包中的所有类但这不是好的程序设计实践,建议逐一导入所需要的类99注意import语句必须出现在包定义和类定义之间100访问控制 访问控制就实施在两个级别上:类级别成员级别一个类可以声明为public,这意味着该类可以被任意类使用。如果在定义类的时候没有给出访问修饰符public,就意味着该类是包私有的(package-private),仅仅能够被同一包中的类使用。101成员访问控制类中的每个成员都可以定义访问控制有四种:公共public保护protected包私有私有private102访问控制103Java应用程序com.abccom.abcedu.csPoop.abccom.xyzNBCAAMpublicprivatepackage-private访问修饰符104同一包中的可访问性类A的成员方法分别是公共的、保护的、包私有的和类私有的这四个成员方法都能被类A中的方法accessInClass访问类B的成员方法accessAbyOtherClass()通过实例化类A的对象,访问其上的四个方法,其中访问私有成员方法会导致编译错误类A的子类C的成员方法accessAbySubClass()直接调用了继承来的类A的成员方法。因为父类的私有成员不能被继承,所以访问类A的私有方法会导致编译错105源文件4-37AccessModifierDemo.java不同包的可访问性在类B中的accessAbyOtherClass()方法中试图访问类A的实例方法,但仅能访问public修饰的实例方法,访问其他实例方法则出现编译错误在子类C中的accessAbySubClass()方法中试图访问继承的成员,但仅能访问public和protected修饰的的实例方法106.abc.A.xyz.B.xyz.C注意继承来的成员的可访问性只能被提升,而不能下降类P中声明了public的成员方法f(),而在第13行其子类C试图覆盖f()并把访问修饰符改成private,这会导致编译错误107源文件441C.java4.10Object类java.lang.Object类是所有类的祖先类。进行类的定义时,即便没有显式地继承Object类,Java也默认继承了Object。即:

publicclassCar{}

等价于:

publicclassCarextendsObject{}108当定义了一个类后,这个类默认继承了Object类的一些方法,这包括toString()clone()equals(Objectobj)hashCode()109toStringtoString方法返回对象的字符串表示。Object提供的对象的默认字符串表示形如“<类名>@<对象哈希码>”。其中,<类名>是实例化该对象时所使用的类;而默认的对象哈希码就是对象所在的内存地址,以十六进制表示。110举例111publicclassA{publicstaticvoidmain(String[]args){Aa=newA();System.out.println(a);}}toString方法通常情况下,类的设计这需要默认覆盖继承的Object的toString方法以较好的可读性设计对象的字符串表示112期望输出Car[licenceNumber=1234,length=4500,width=2300,height=1600]Car.javaequals方法Java中约定使用equals方法用于判断两个对象是否相等。比如下面的代码声明了两个引用类型变量a和b,分别引用两个类A的对象:Aa,b;a=newA();b=newA();113equals方法如果判断变量a引用的对象和变量b引用的对象是否相等,则使用对象上的equals方法:a.equals(b)a==b114同一(identical)和相等(equal)“同一”就是指两个引用类型变量a和b是否引用了同一个对象。比如下面的代码片段就使得引用类型变量a和b引用了同一个对象:

Aa,b;a=newA();b=a;115同一判读两个引用类型变量是否引用同一个对象,只需使用关系运算符“==”即可:

a==b116相等当引用类型变量a和b分别引用各自的对象,这两个对象是否相等则取决于类A如何覆盖equals方法117equals方法两个对象相等的具体判断规则是由类的设计者决定的,并通过覆盖equals方法实现。118equals方法Object类提供的equals方法仅仅进行“同一”判断,其实现代码如下:119publicbooleanequals(Objectobj){return(this==obj)}equals方法此equals方法的语义与“==”运算符相同。一般来说,如果两个对象具有相同的状态,则认为这两个对象相等。120equals方法比如两个Car类的对象,可以认为车牌号相等,那么这两个对象就相等;也可以认为车重量相等,这两个对象就相等。所以,具体如何定义对象相等,取决于程序所解决的实际问题。121122classCar{ privateintweight; privateStringlicenceNumber; publicbooleanequals(Objectobj){ if(this==obj) returntrue; if(obj==null) returnfalse; if(getClass()!=obj.getClass()) returnfalse;

//确保此刻obj引用的是Car类型的对象

Carother=(Car)obj; if(licenceNumber==null){ if(other.licenceNumber!=null) returnfalse; }elseif(!licenceNumber.equals(other.licenceNumber)) returnfalse; if(weight!=other.weight) returnfalse; returntrue; }}首先使用关系运算符“==”比较对象a和b的同一性,如果同一,则返回真;如果b为null则返回假;如果b的类型与a的类型不同,则返回假。获取对象的类型通过从Object类继承的方法getClass完成;把b转型为a的类型。上例中把Object类型转型为Car类型;逐一比较实例变量。检查是否为空,这是为了避免出现NullPointerException异常没有必要对所以实例变量进行比较。当选择的实例变量都相等,则返回真。基本数据类型的实例变量直接使用比较运算符“==”;引用类型的实例变量仍需调用其上的equals方法。覆盖equals方法注意equals方法的形式参数类型是java.lang.Object。一定不要使用其它类型,否则就无法覆盖java.lang.Object,从而导致问题。123标准API中的equals方法JDK中很多类都提供了equals方法比较两个日期124EqualsDemo.javaInteger类中的equals方法125publicbooleanequals(Objectobj){if(objinstanceofInteger){returnvalue==((Integer)obj).intValue();}returnfalse;}

hashCode方法当把对象添加到这些集体对象中去的时侯会调用对象的hashCode()方法来计算在哈希表中的地址。Java语言约定使用hashCode方法返回对象的哈希码。哈希码用来计算哈希表中索引。Object类中提供了hashCode的默认实现:以十六进制返回对象的内存地址。因此类的设计者一般需要覆盖Object类的hashCode方法。126hashCode方法(一)相同对象必须产生相同的哈希码(一致性):如果a.equals(b)为true,那么a.hashCode()和b.hashCode()应该返回相同的整数值。(二)不同对象尽量产生不同的哈希码(扩散性):虽然无法保证完全避免哈希冲突,但一个好的哈希函数应该让不同对象的哈希码分布均匀,以减少冲突的概率。(三)哈希码应该是稳定的:如果对象内容不变,则其哈希码不应改变。即只要对象状态不变,调用其hashCode方法的返回值就不变,无论调用几次。127hashCode方法一种计算哈希码的算法是使用一个素数迭代地与所有实例变量累加和相乘。128classCar{ privateintlength,width; publicinthashCode(){ finalintprime=31; intresult=1; result=prime*result+length; result=prime*result+width; returnresult; }}hashCode方法java.lang.String类提供的hashCode方法:字符串"abc"31*(31*'a')+'b')+'c'129把字符串看作是“31进制数”,其哈希码就是它的“真值”"a".hashCode()97"ab".hashCode()310531*97+98clone()访问对象是通过指向对象的引用类型变量完成的。那么两个引用类型变量间的赋值就不是将一个对象的内容复制到另外一个对象上,而是将一个变量中的引用复制给另外一个变量。这样,在效果上使得这两个变量引用了同一个对象。130clone()java.lang.Object的clone方法函数头部声明如下:

protectedObjectclone()throwsCloneNotSupportedException

131clone方法java.lang.Object的clone方法创建对象的副本并返回该副本的引用,这个副本与原对象具有相同的类型、相同的实例变量以及相同的实例变量值。但是,如果某个实例变量是引用类型的,那么clone

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论