资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,Java,教程第,5,章 抽象类、接口与内部类,5.1,抽象类,5.2,接口,5.3,内部类,5.4,包,第,5,章 抽象类、接口与内部类,5.1,抽象类,(1),在继承的层次关系中,从子类到父类,类就变的更一般、更通用。类的设计应该保证父类包含子类的共同特征,也就是父类应该是子类的良好的抽象。,有时我们将一个父类设计的非常非常的抽象,以至于它都没有具体的实例,这样的类我们称之为,抽象类,(,abstract class,),.,当需要一个类作为一个更通用的接口来控制一系列的相关类的时候,我就要创建一个抽象类来实现这个功能,5.1,抽象类,(2),抽象类,:用,abstract,关键字来修饰一个类时,该类叫做抽象类;,抽象类,必须被继承,。,抽象类,不能被直接实例化,。它只能作为其它类的超类,这一点与最终类(,final,类)正好相反。,抽象方法,:用,abstract,来修饰一个方法时,该方法叫做抽象方法。,抽象方法,必须被重写,抽象方法,只有声明,不能有实现,。,定义了抽象方法的类必须是抽象类,。,abstract,returnType,abstractMethod,(,paramlist,);,两个类,Circle,和,Rectangle,public class Rectangle,public float width,height;,Rectangle(float width,float height),this.width =width;,this.height=height;,public double area(),return width*height;,public class Circle,public float r;,Circle(float r),this.r=r;,public double area(),return 3.14*r*r;,5.1,抽象类,(3),假设有若干个,Circle,,以及若干个,Rectangle,,希望计算它们的总面积,直截了当的做法是将它们分别放到两个数组中,用两个循环,加上一个加法,这种做法是不漂亮的。,如果还有其它形状:,Triangle,等,上述方法显得“累赘”。我们希望有一种统一的表示,例如用一个数组,shape,,接受所有的形状,然后用:,for(i=0;ishape.length;i+),area_total+=shapei.area();,5.1,抽象类,(4),abstract class Shape,abstract double area();,class Rectangle extends Shape,public float width,height;,Rectangle(float w,float h),this.width =width;,this.height=height;,public double area(),return width*height;,class Circle extends Shape,public float radius;,Circle(float radius),this.radius=radius;,public double area(),return 3.14*radius*radius;,5.1,抽象类,(5),5.1,抽象类,(6),通过上面的例子我们可以看出,抽象类,Shape,是,Circle,和,Rectangle,的统一的接口。使利用,Circle,和,Rectangle,的对象变的更加方便。在例子中抽象类,Shape,被,Circle,和,Rectangle,继承,抽象类必须在被继承并其继承它的类不再是抽象类的时候才能被实例化,抽象方法必须被重写。,5.2,接口,5.2.1,接口的定义与实现,5.2.2,用接口实现,Java,中的多重继承,5.2.3,接口的扩展,5.2.4,接口的嵌套,接口(,interface,)就是,方法定义和常量值的集合,。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有方法的实现。,通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。,通过接口可以指明多个类需要实现的方法。,通过接口可以了解对象的交互界面,而不需了解对象所对应的类。,5.2,接口,用,implements,子句来表示一个类使用某个接口。,在类体中可以使用接口中定义的常量,而且必须,实现接口中定义的所有方法,。,利用接口可实现,多重 继承,,即一个类可以实现多个接口,在,implements,子句中用逗号分隔。,接口的作用和抽象类相似,只定义原型,不直接定义方法的内容。,接口中的方法和变量,必须是,public,的,。,5.2.1,接口的定义与实现,5.2.1,接口的定义与实现,Java,中的接口声明的语法为:,interface interfaceName/,接口体,/,常量域声明,域类型 域名,=,常量值;,/,抽象方法声明,返回值 方法名(参数列表);,例如:,interface myinterface,void f();,int g();,5.2.1,接口的定义与实现,接口实现用关键字,implements,,实现的具体形式:,class ClassName implements interfaceName,接口(,interface,)作为特殊形式的抽象类,和类(,class,)在使用上具有类似的约束。,与类继承不同,一个接口可以继承多个父接口,一个,public,接口只能定义在同名的,.java,文件中,程序,5.4,5.2.2,用接口实现,Java,中的多重继承,类允许实现多个接口。,一个类可以看起来像多个接口。,类通过实现多个接口间接的实现,java,中的多重继承。,类可以转型为多个接口的类型进行访问。,程序,5.5,5.2.3,接口的扩展,通过继承可以对一个或多个接口进行组合并扩展,并可以在扩展的接口中添加新的方法,使接口更加丰富。,5.2.3,接口的扩展(例),interface I1,void f1();,interface I2,void f2();,interface Ie1 extends I2,void fe1();,interface Ie2 extends Ie1,I1 /,只有在接口的情况下才能继承多个接口。,void fe2();,5.2.4,接口的嵌套,类嵌套接口,接口嵌套接口,5.2.4,接口的嵌套(,类嵌套接口,),class A,interface B,void method();,private interface B,void method();,5.2.4,接口的嵌套(,接口嵌套接口,),interface A,interface B,void f();,public interface C,void f();,5.3,内部类,5.3.1,内部类的基本语法,5.3.2,局部内部类,5.3.3,静态内部类,5.3.4,匿名内部类,5.3.5,内部类的继承,5.3,内部类,嵌套在类里面的类就被称为内部类。内部类允许一个类定义被放到另一个类定义里。内部类是一个有用的特征,因为它们允许将逻辑上同属性的类组合到一起,并在另一个类中控制一个类的可视性。,5.3.1,内部类的基本语法,class OuterClass,class InnerClass,上面代码就是典型的内部类的代码,正如我前面说的把类,InnerClass,放在类,OuterClass,的内部,5.3.2,局部内部类,局部内部类基本的内部类形式上没什么区别,唯一不同的就是作用域不同。比如上面内部类的作用域范围是整个外层类。,如果将这个类放在某个方法内,此时他的作用域范围只是该方法内部,那么这个方法以外是不能创建该内部类对象的。如果在某个块中,那么他的作用域范围就只在这个块以内。,5.3.2,局部内部类(,2,),public,Interface,InnerMethod2(),/,创建一个局部内部类,继承自,Interface,接口,class,InnerLocal,implements,Interface,public void getInfo(),System.out.println(localClass);,/*,在方法类创建该类的对象,并调用其方法。这个是被允许的*,/,Interface,local,=,new,InnerLocal();,local.getInfo();,return,local;,5.3.2,局部内部类(,3,),public,Interface,showLocalClass(final,boolean,flag),if(flag),class,InnerLocal,implements,Interface,public,void,getInfo(),System.out.println(localClass,+,flag);,Interface,local,=,new,InnerLocal();,local.getInfo();,return,local;,else,class,InnerLocal,implements,Interface,public,void,getInfo(),System.out.println(localClass,+,flag);,Interface,local,=,new,InnerLocal();,local.getInfo();,return,local;,5.3.3,静态内部类,静态内部类又被称为嵌套类,在内部类前面加上,static,关键字,就表示该内部类是一个静态内部类。,静态内部类是不能放在方法或者块中。,静态内部类没有了指向外层类的引用。,5.3.3,静态内部类(,2,),public class StaticInnerClass,private static class InnerClass,void getInfo(),System.out.println(InnerClass);,5.3.4,匿名内部类,匿名内部类也是一种内部类,他区别于一般的内部类是它本身是没有任何名字的。因此被称为匿名,使用匿名内部类能让我们的代码看起来更简洁,很好的避开耦合性。,你可以在任何创建某个对象的地方使用匿名内部类,然后重写这个类的方法来解决特定的问题。,匿名内部类是不可能有命名的构造器,这个原因也很简单,因为它本身没有名字。,5.3.4,匿名内部类(,1,),abstract class AnonymousClass,abstract public String value();,public class AnonymousClassDemo,public AnonymousClass makeac(),return new AnonymousClass(),string,str=AnonymousClass;,public String value(),return str;,;,5.3.4,匿名内部类(,2,),return new AnonymousClass(),string,str=AnonymousClass;,public String value(),return str;,;,class MyAnonymousClass implements AnonymousClass,string,str=AnonymousClass;,public String value(),return str;,5.3.4,匿名内部类(,3,),在需要参数的情况:,public class AnonymousClassDemo2,public AnonymousClass makeac(int x),return new AnonymousClass(x),public int value(),return super.value()*10;,;,5.3.4,匿名内部类(,4,),对内部类中定义的字段进行初始化(必须将参数设为,final,),public class AnonymousClassDemo3,public AnonymousClass makeac(,final,String str1),return new AnonymousClass(),private String str=str1,;,public String value(),return str;,;,5.3.5,内部类的继承,非静态内部类本身隐藏了一个指向外层类的引用。,如果我们需要一个外部类来直接继承内部类,那么这里就会产生一个问题。因为外部类并不包含这个外层类对象的引用,那么默认调用超类的构造器就会产生问题,因此连编译时都无法通过。,5.3.5,内部类的继承,class OuterClass,class InnerClass,public class InheritInnerClass extends OuterClass.InnerClass,/InheritInnerClass();,不能被编译。,public InheritInnerClass(OuterClass outer),outer.super();,5.4,包,5.4.1,创建并命名自己的包,5.4.2,包的引用,5.4,包,提供了把相关的程序段组织成一个单元的机制,在包中定义的类必须通过他们的包名来访问。这样,包就提供了一种命名类的集合的途径。,参与了,Java,的访问控制机制,包中定义的类可以声明为包所私有的,使包外的代码无法访问。这样包为类提供了一种能够被封装的方式。,5.4.1,创建并命名自己的包,建立一个包,把你的类和接口放到里面。这需要把,package,语句放到源文件的顶部。,package com.myPackage;,public class TestPackage,public static void main(String rgs),new Test().print();,class Test,public void print(),System.out.println(test of using package!);,5.4.1,创建并命名自己的包,上面的例子把,TestPackage,放到,com,下的,myPackage,包内。注意:必须把,package,语句放到你所定义的类文件的第一句。,package,语句的作用范围是整个源文件。,全世界的,java,程序员都在利用,java,编写类和接口,怎样使他们编写的相同名字的类和接口不发生冲突呢,这就是包的作用之一,我们把具有相同名字的类和接口放在不同的包下面,这样就不会发生冲突。,按照惯例,包名是创建者的,Internet,域名的反序,如果你按照惯例,你的,package,名称是独一无二的,因为你的,Internet,域名是独一无二的,所以也就不会出现什么名称冲突的问题了。,5.4.2,包的引用,用成员的全称来访问它,(包含路径和包名),com.myPackageA.A myA=new com.myPackageA.A();,导入包的成员,import com.myPackageA.A,;,A myA=new A();,
展开阅读全文