《接口和抽象》PPT课件.ppt

上传人:牧羊曲112 文档编号:5516358 上传时间:2023-07-15 格式:PPT 页数:40 大小:225.99KB
返回 下载 相关 举报
《接口和抽象》PPT课件.ppt_第1页
第1页 / 共40页
《接口和抽象》PPT课件.ppt_第2页
第2页 / 共40页
《接口和抽象》PPT课件.ppt_第3页
第3页 / 共40页
《接口和抽象》PPT课件.ppt_第4页
第4页 / 共40页
《接口和抽象》PPT课件.ppt_第5页
第5页 / 共40页
点击查看更多>>
资源描述

《《接口和抽象》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《接口和抽象》PPT课件.ppt(40页珍藏版)》请在三一办公上搜索。

1、第7章 接口和抽象,本章要点:接口的本质接口的声明及实现接口的多重实现接口的继承克隆浅拷贝与深拷贝内部类、局部内部类、静态内部类抽象类抽象类与接口的区别,7.1 接口,7.1.1 接口的产生那么究竟什么是接口呢?在阐述接口的概念以前,我们先举个例子,在日常生活中,我们都会用到插头及插座,一个插座无论是两相的还是三相的,也无论生产插座的厂家是哪里的,都会执行相同的规范,因此当用户购买到插座以后都可以使用。在这里我们关心的是制造插座的规范,并不关心这个插座是用来接电视机或台灯;作为生产插座的厂家关心的也只是制造这个插座过程中所执行的规范,他们只要按照规范生产出来的插座,用户就一定可以正常使用。,7

2、.1.2 接口的概念接口是只说明类应该做什么,但并不指定如何做的方法,一个类可以实现一个或多个接口。在这里再强调一次,接口只是声明应该做,但不关心如何做。,7.1.3 接口的声明接口在Java中是用关键字interface来声明的。所以说接口并不是一个类,而是对符合接口需求的类的一套规范。接下来,我们就看一看接口是如何声明的,还是以我们设计的学生类为例。我们思考这样一个问题,所有的学生再进一步的抽象,那就是人,也就是说所有的学生都是人,作为一个人有其共有的属性,如姓名、性别、出生年月、籍贯等,如果说作为学生,除了上述的属性外还有学号、专业等特有的属性,如果是工人,那就有工号、级别等特有的属性。

3、所以我们在此可以设计一个关于人的接口,由于人的姓名、性别、出生年月等是不可以再改变的,所以我们只提供一个访问器,而地址不仅提供访问器同时也提供设置器。,7.1.4 接口的实现实现一个接口是指类实现一个接口,基本上类似于类的继承,但接口的实现是通过关键字implements来实现的。实现接口的类,必须要实现接口中的所有方法。,7.1.5 接口的多重实现在前面我们提到过,一个类可以实现多个接口,正如一个工厂可以生产多种产品,执行不同的生产规范一样的道理。如果一个类实现多个接口,也是用关键字implements来实现的,多个接口之间用逗号“,”来分隔。我们就以一个具体的例子来探讨一下接口的多重实现,

4、并学习如何利用Java公开库中的接口。假设一个班级中有50个学生,我们想实现学生间按照学号进行排序。在Arrays类中有一个静态的方法:public static void sort(Object a)现在我们就想利用这个方法来实现对象类型的比较。现在我们看一下关于这个方法的API文档,有这样一句话:All elements in the array must implement the Comparable interface.文档告诉我们,如果想利用数组中对象的排序方法,数组中的每一个元素必须要实现Comparable接口。,7.1.6 接口的属性接口不是一个类,因此永远不能用关键字new

5、来生成一个接口的实例。x=new Comparable();/这是错误的虽然我们不可以实例化一个接口,但可以声明一个接口的变量:Comparable x;/这是完全可以的既然是变量总要指向一个对象,那接口变量应该指向什么对象呢?接口变量必须指向一个实现了该接口的类的对象。也就是必须用接口的实现类来代替接口的实例。如在例7-2中,我们可以用Person x=new Student();也可以用Comparable x=new Student();至于在程序中究竟该用哪一个接口来作为形式类型,那要根据具体情况具体分析。,7.1.7 接口的继承既然接口具有类的某些属性,那我们也可以像类一样,从一个接

6、口中派生出另一个或几个接口,这是一个从通用性到专门性的扩展过程。接口的继承和类的继承一样也是用关键字extends来实现的。例如,由于每一个人年满18岁就会拥有一张具有惟一编号的身份证号码,所以我们再从Person接口派生出一个成人(AdultPerson)的接口,它又追加两个方法声明,代码如下:public interface AdultPerson extends PersonString getIdentityCardNumber();void setIdentityCardNumber(String strNumber);这样的话,如果是小学生就可以实现Person接口,而大学生就可以

7、实现AdultPerson接口了。由于实现了不同的接口,所以设计出的学生类也就不同了。,7.1.8 接口的意义所以说接口实际上不仅是一种规范,更是一种思想的体现,它也是Java编程语言的横向扩展的必然需要。,7.2 克隆,7.2.1 浅拷贝如果你想拷贝一个新对象,而该对象的初始状态同源值是相同的,但可以独立变化,不会因为一个变量的操作,而影响到另外一个变量,那就需要用到clone(克隆)方法。这个方法属于Object类,它返回的是一个Object对象,所以如果想获得正确的类型需要进行类型的转换。例如:Student tom=new Student(Tom,20021024);Student t

8、omCopy=(Student)tom.clone();tomCopy.setAddress(American);此时再输出两个对象的信息就会发现不同,不会因为操纵tomCopy而导致tom的改变。这正是由于克隆了源对象的一个新的拷贝,这个拷贝是一个对象的整体的拷贝,而不仅仅是对象地址的拷贝。,克隆,7.2.2 深拷贝我们再回过头去看一下Object类中关于clone方法的实现,由于该方法对于对象一无所知(因为它是空的,没有做任何有意义的工作),因此它只能按照字段逐一拷贝,如果所有的数据字段是数字或是其他的基本类型,那拷贝这些字段是没有问题的(这些工作的完成是由解释器自动完成的),因为这个字段

9、拷贝的过程是按值传递的。但如果这些字段是对象类型的,我们拷贝的仍然是一个对象地址。,深拷贝,7.3 内部类,所谓内部类,故名思义就是定义在一个类内部的类。创建一个内部类很简单,如:class Student class Course我们在学生类Student内部又定义了一个课程类Course。内部类具有以下特点:(1)一个内部类的对象能够访问创建它的对象的实现,包括私有数据;(2)对于同一外包中的其他类来说,内部类是不可见的;(3)匿名内部类可以很方便地定义回调;(4)使用内部类可以非常方便地编写事件驱动的程序。,7.3.1 使用内部类来访问对象状态虽然创建一个内部类很简单,但真正将内部类运用

10、好,也是一件十分不容易的事情,因为在设计一些类时,并没有明显的特征使我们会立刻想到运用内部类。为了更好地理解内部类,我们先设计一个示例。因为每一个学生都有主修的课程,我们希望在设定学生的时候,同时也可以设定该学生的相关的课程,在这里,我们尝试用一个内部类去实现学生有关课程的设置。如下:class Courseprivate String strCourse;/学生课程的数组public Course(String strCourse)this.strCourse=strCourse;,通过设定一个字符串数组,容纳学生的课程,然后再对这个数组进行相关的操作,如果说把这个类作为一个单独的类,并没有

11、什么奇特的地方,但如果把它放到学生类的里面,由此会产生很多微妙的变化,我们会在学生类中增加一个设置课程的方法,课程类我们也加上了访问控制符。代码如下:class Studentprivate String strName;private String strNumber;,public Student(String name,String number)strName=name;strNumber=number;public Course setStudentCourse(String strCourse)return new Course(strCourse);private class C

12、ourseprivate String strCourse;public Course(String course)strCourse=course;,也许有的读者会问,类的访问控制符不是只有public与default吗?是的,作为一个单独的类,只能有这两种控制符,也就是说一个类最小的可见度是包内可见,但只有内部类可以是private,也就是说只有包含它的类中的方法才可以访问它。由此可以看出,虽然内部类Course包含在Student类内部,但并不意味着每个Student的实例都有一个Course类的实例。当然我们也需要构造内部类的对象,但这个对象只是属于外部类的方法中的局部变量。Cours

13、e类是Student类的私有内部类,这是Java的一种安全机制,这样只有setStudentCourse方法能够生成Course类的实例,我们也不用担心封装被破坏。,内部类Course有一个构造器,可以每次设定学生所学习的课程,当然在内部类的里面根据需要将会添加一些方法,以便做一些更加具体的事情,代码如下:private class Courseprivate String strCourse;/学生课程的数组private int courseNumber;public Course(String course)strCourse=course;courseNumber=course.len

14、gth;getDescription();,private void getCourse()for(int i=0;i courseNumber;i+)System.out.print(t+strCoursei);private void getDescription()System.out.println(学生:+strName+学号是:+strNumber+。一共选了+courseNumber+门课,分别是:);getCourse();,在这里,我们仔细分析一下上面的代码。在Course类中能够访问它本身的实例字段,即字符串数组,但在Course类中并没有定义strName与strNumb

15、er字段,而是指向了创建Course类实例的Student对象的strName与strNumber字段,就像是访问它本身的数据一样,虽然strName与strNumber字段是私有的,但作为内部类仍然是可以访问的。实际上在内部类中也有一个隐含的指向外部类的引用,这个引用对于内部类的定义来说是不可见的,如第6章中讲到的this关键字一样,this关键字隐含的指向本身的引用,例如:class Studentprivate String strName;public void setStudentName(String strName)this.strName=strName;,关于这方面知识的详细

16、情况,如果读者不熟悉,请参阅第6章相关的内容。那作为内部类又是如何去实现这个隐含的引用呢?难道还是通过this关键字吗?虽然内部类并不是通过关键字this来实现引用的,但也与this有一定的关系,因为this关键字暗含的是类本身的引用,那么作为外部类来讲,我们可以采用外部类名与this相结合,实现这种隐藏的引用。格式如下:,例如在Course类中,我们引用strName与strNumber字段时,可以这样写:private void getDescription()System.out.println(学生:+Student.this.strName+学号是:+Student.this.str

17、Number+。一共选了+courseNumber+门课,分别是:);getCourse();现在我们通过先写一个完整的程序,再接着探讨另外一个问题。例7-5程序清单 Student.java,当然读者也可以将getDescription方法改成如下的格式:private void getDescription()System.out.println(学生:+strName+学号是:+strNumber+。一共选了+courseNumber+门课,分别是:);getCourse();结果是一样的。那接下来,我们再探讨一个内部类的外部引用的问题,细心的读者可能发现了一个问题:为什么这一次我们的m

18、ain方法是写在Student类内部呢?而不是像以前一样,单独写一个测试方法呢?现在我们将上面的代码修改成如下的代码:例7-6程序清单 StudentTest.java(略),这段代码编译是不能通过的。输出结果:StudentTest.java:10:Student.Course has private access in Student Student.Course cou=one.setStudentCourse(course);通过错误提示信息,我们可以看到由于Course类是private的,所以不能在Sutdent类外面进行访问。如果想使这段程序编译通过,只要将Course类的访问控

19、制符由private改为public即可。我在这里想重点讲的就是main方法中关于内部类对象句柄的问题:Student.Course cou=one.setStudentCourse(course);,通过这行代码,Student类的实例调用setStudentCourse方法,得到了Course类的句柄,那么在外部我们是通过Student.Course来引用的。这就是外部类引用内部句柄的格式:外部类类名.内部类名这两个类名的联合形式就是内部类的类型,这同一个字符串String类型是一样的,在使用的过程中同使用String或者Student类型是一样的。既然我们可以通过“外部类名.内部类名”的

20、形式指定内部类的类型,那我们是否可以直接调用内部类的构造器,而不调用Student类的setStudentCourse方法呢?,public class StudentTestpublic static void main(String args)String course=计算机原理,编译方法,数据结构;Student one=new Student(Tom,20021024);Student.Course cou=new Student.Course(course);cou.getDescription();实际上这样做是可以的。但我们应当尽量避免这样的操作,所以从封装的完整性来说,内部类

21、一般情况下只能是private。,7.3.2 局部内部类在例7-5中,我们可以看到在实际的使用中,我们只是用了一次Course类的名字,那我们也可以将Student类的setStudentCourse方法改成如下的形式:public void setStudentCourse(String strCourse)class Courseprivate String strCourse;private int courseNumber;public Course(String course)strCourse=course;courseNumber=course.length;getDescrip

22、tion();,private void getCourse()for(int i=0;i courseNumber;i+)System.out.print(t+strCoursei);private void getDescription()System.out.println(学生:+strName+学号是:+strNumber+“。一共选了”+courseNumber+“门课,分别 是:);getCourse();new Course(strCourse);,这样的话Course类就变成局部内部类了,局部内部类不必使用访问控制符,因为局部内部类的范围总是限定在声明它的方法内部。作为局部内

23、部类,有一个非常重要的优点,那就是它的可见性更加的隐蔽了,除了在声明它的方法内是可见的,其他的任何地方都是不可见的,就像是方法的局部变量一样。局部内部类,它不仅可以访问外部类的私有字段及相应的方法,相对于内部类来讲,局部内部类还有一个重要的优点,它可以访问方法内的局部变量,既然如此,那我们在上面的代码中就可以直接使用setStudentCourse方法中的字符串数组strCourse了,再不必通过局部类的构造器来构建对象了,然而这些局部变量必须声明为final才可以,因为final类型的变量不能被修改,这就保证了局部变量与局部类所建立的拷贝总有相同的值。,上面的代码经过修改如下:public

24、void setStudentCourse(final String strCourse)class Courseprivate int courseNumber=strCourse.length;private void getCourse()for(int i=0;i courseNumber;i+)System.out.print(t+strCoursei);public void getDescription()System.out.println(学生:+strName+学号是:+strNumber+。一共选了+courseNumber+门课,分别是:);,getCourse();C

25、ourse course=new Course();course.getDescription();请读者仔细将这两部分代码比较一下,在经过简化的局部内部类中,我们已经不再需要构造器了,而是在类内直接去访问外部类的形式参数。我们曾经见过将final用于修饰常量,实际上,关键字final可以修饰任意的局部变量、实例变量和静态变量等,在这些情况中,它的含义是完全一样的,在这些变量被赋值完成后,就不能再修改它的值。,7.3.3 静态内部类虽然有些时候需要通过内部类来把一个类隐藏在另一个类中,但在内部类中并不需要访问外部类的任何字段,这时候可以把内部类声明为static,去掉外部类自动生成的引用。只有

26、内部类才可以声明为static,从这个意义上来讲,我们可以把内部类看作与类的实例变量、方法同等级别的内容。,7.3.4 匿名内部类有些时候我们只是需要一个内部类的对象,所以我们可以不必要非要给内部类起一个名字,我们称这种类为匿名内部类,在这一点上与匿名数组有一点类似。这一部分的内容我们将在图形编程的事件处理部分再详细说明。,7.4 抽象行为,在前面主要学习了Java的第二个核心概念接口,下面我们开始学习另外一个核心概念抽象。谈到抽象这个词,可以作为名词也可以作为动词。也许有的读者可能认为这个词很接近于哲学中抽象的概念,其实这是有点类似的。在哲学中抽象是将现实上升到理论,也就是有点类似于我们平常

27、所说的总结。但在Java程序设计中,抽象是一种具体的行为,它将对象的行为进一步向通用化靠拢,以设计出一个更普通、更通用的类,这个过程称为类的抽象的过程。,7.5 抽象类,什么是抽象类呢?使用关键字abstract修饰的类我们称为抽象类。根据一个类的继承层次图,在最上层的类也变得越来越通用,也越来越抽象,不能很好地描述对象的属性。那为什么还需要抽象呢?比如说人,都有几个重要的属性,如姓名等,我们可以把getName方法放到继承层次图的最高层,而在子类中就不再需要写这个方法了。接下来我们再添加一个方法:getDescription(),用以返回对工人、学生、商人等的描述,有点类似于学生类的toSt

28、ring方法。例如:the worker with the salary of¥1000the student majoring in computer sciencethe trader is very rich,7.6 抽象与接口的区别,通过上面的讲述,读者可能感觉到抽象与接口在很多方面是类似的。比如:(1)都不能产生实例,都不能用关键字new来生成实例;(2)可以声明变量,但必须指向子类或实现类的对象等等;(3)在接口中我们可以声明一个标记接口,在抽象类中我们也可以声明一个没有抽象方法的类作为抽象类。但两者有重要的区别:(1)关于继承,Java语言不支持多重继承,也就是说一个子类只能有一

29、个父类,但一个子类可以实现多个接口;(2)接口比抽象类具有更广泛的应用,也提供了更多的灵活性;(3)接口内不能有实例字段,但抽象类中可以有实例字段及实现了的方法;(4)接口内的方法自动为public型,但在抽象类中的抽象方法必须手动声明其访问标识符。,7.7 小结,在本章中,重点讨论了接口的概念,接口的声明、接口的实现、接口的属性、继承及意义,在接口的基础之间,讨论了Comparable及Cloneable接口,并深入探讨了克隆的一些特点,分析了深拷贝的本质。通过本章的学习读者应该深入了解接口的实质,为进一步的学习打下深厚的基础。本章看起来比较简单,主要介绍了抽象行为,抽象在Java面向对象编程思想中的重要体现,并学习了抽象类,最后我们总结了抽象类与接口的区别。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号