20172301 2017-2018-2 《程序设计与数据结构》第八周学习总结
教材学习内容总结
- 多态:有许多形式,能在不同的时间指向不同类型的对象。
- 多态的体现:父类的引用指向了自己子类的对象。
- 多态的前提:类与类之间要存在继承或者是实现关系,并且存在覆盖。
- 多态的好处:提高代码的复写性。
- 多态的体现:父类的引用指向了自己子类的对象。
- 后绑定(静态绑定):延迟到程序运行时才能执行。
- 有静态绑定就会存在静态绑定。(详细解释)
- 有静态绑定就会存在静态绑定。(详细解释)
- 建立多态方式的两种方式:继承、接口
- 注意:继承方式中,实际将调用的方法版本取决于对象的类型而不是引用对象的类型。
接口方式中,实际调用的方法不是取决于接口引用的类型,而是取决于调用发生时接口引用所指向的对象的类型。 - 同样注意:在使用接口引用变量时,只能调用定义在接口中的方法。即使接口引用变量所指向的对象还有其他的一些方法,也不能调用。
这跟继承多态是不同的。继承多态是可以调用子类的方法。所以,只能在一定意义上说,实现类与所实现的接口的关系,如同子类和父类的关系。
- 注意:继承方式中,实际将调用的方法版本取决于对象的类型而不是引用对象的类型。
- 使用多态性解决的两种问题:排序、搜索
- 排序:
- 选择法排序:扫描数列,找到最小的一个和第一个进行交换。
- 插入法排序:逐渐比较几个数之间的大小,如果有变化,那么将把小的数插入到前面,其他的向后移动。
- 比较:选择法排序和插入法排序实质上有同等的效率,都是n^2算法。但是,选择法排序执行的交换操作的次数更少。因此选择法优于插入法。
- 搜索:
- 线性搜索:从起点开始,一个个进行搜索,最终找到目标。
- 二分搜索:必须是有序的。不断的取中点进行搜索。如果搜索个数是偶数,那么就会有两个中点。取第一个中点为新的中点。
- 比较:算法的选择取决于具体条件。
二分搜索适用于数据排序相对容易或者数据的搜索量非常大。线性搜索的实现相对简单,虽然效率比较低,但是在一些忽略效率的问题上是最佳选择。
- 多态性设计:培养自己的设计敏感性,知道什么问题能够运用多态性解决。提高代码的复写性。不同类型的对象执行相同类型的方法。
教材学习中的问题和解决过程
- 问题1:后绑定(动态绑定)和静态绑定。
- 问题1解决方案:这里先给出一个参考链接:关于多态以及动态绑定
如果对多态的定义和优点还有困惑,这篇博客里面给出了更加形象具体的解释。
多态就是同一事物的多种不同形态,简单点来说就是:“一个接口,多种实现”。
举个例子:体育课上体育老师只要喊一句:“开始活动”,则 打篮球的就开始打篮球,踢足球的就开始踢足球,体育老师不用对打篮球的喊“开始打篮球”,对踢足球的喊“开始踢足球”,即学生是一个“抽象”的事物,只要是学生就具备活动的能力,所以只要喊“开始活动”,则学生就会开始活动,至于活动的内容,则有不同的学生内部自己去实现去决定。
这就使事情变得十分灵活了,即实际上多态让“做什么”和“怎么做”分离了,即体育老师只要发布“做什么”(一个接口),而学生可以去具体做各自的事“怎么做”(多种实现)。这就是多态的优点。所以我们看出只要存在继承,并且父类子类之间存在重写方法,则就存在多态。同样,多态的前提在文中也有提及。
- 现在我们来解释动态绑定和静态绑定。首先我们要清楚他们的定义。
静态绑定(前期绑定):即在程序执行前,即编译的时候已经实现了该方法与所在类的绑定。
动态绑定(后期绑定):运行时根据对象的类型进行绑定,java中的大多数方法都是属于动态绑定,也就是实现多态的基础。
这里所谓的绑定,即一个方法的调用与方法所在的类(方法主体)关联起来。
java中只有static,final,private和构造方法是静态绑定,其他的都属于动态绑定,而private的方法其实也是final方法(隐式),而构造方法其实是一个static方法(隐式)。
所以可以看出把方法声明为final,第一可以让他不被重写,第二也可以关闭它的动态绑定。- 实现动态绑定一个很重要的东西就是在jvm方法区里每一个类都有一个方法表(实质是一个数组),这个方法表里记录了这个类的所有方法(包括继承父类的方法)在内存里的地址。
我们来看个例子:
Father fa=new Son();
fa.say();- 具体过程是,
- 首先由于fa的类型是Father,所以一开始还是会到Father类的方法表里去找say()方法
- 然后获得到say()方法的索引项比如是第N项(即在方法表里的位置),如果此时Father的方法表里找不到say()方法那就直接编译报错了
- 得到say()在Father里的索引项之后,然后根据堆里new的具体实例的类型(这里是Son),去Son里面的第N项取出say()方法在内存里的地址,然后执行。
- 如果想继续了解JVM如何调用的方法。请参考资料:
Java动态绑定机制原理分析
- 首先由于fa的类型是Father,所以一开始还是会到Father类的方法表里去找say()方法
- 结合书上所见,后绑定的效率低于编译阶段的绑定效率。但是,明显的优点就是实现了多态。
- 问题2:对象和引用变量。他们两个之间怎么区别?这个问题,一开始是方艺雯同学问我书上的creature是引用变量吧。当时只是暂时解决了,然后,我回去把这个问题抛给了组员李馨雨同学。结果把刚刚看完10.2的她又给弄懵了。( ̄▽ ̄)~*
- 问题2解决方案:
有这样的一种解释,java中引用类型的变量和对象的区别
对象:是按照“类”这个模板建立的,建立的位置则是内存
例如A是一个类。A X则是创建一个引用变量,X=NEW A()则是在内存中建立一个对象(开辟了1片空间),对象的模板就是A(可以理解为在空间里复制了A类里的变量到空间里去)。
此时就可以使用引用变量X去引用对象中的变量了
- 那么,我们来继续探讨。Java对象及对象引用变量
我们一般创建对象。都是Vehicle veh1 = new Vehicle();
现在把它分成两部分,
Vehicle veh1; veh1 = new Vehicle();
有两个实体:一是对象引用变量,一是对象本身。
Vehicle veh2; veh2 = veh1;
这时候,veh2指向了veh1所指向的对象。复制的是对象引用,而非对象本身。
所以,有以下结论:一个对象引用可以指向0个或1个对象
一个对象可以有N个引用指向它如果还不清楚,我们进一步研究。Java对象和引用变量
存储区域 | 存储内容 | 优点 | 缺点 | 回收 |
---|---|---|---|---|
栈 | 基本类型的变量和对象的引用变量 | 存取速度比堆要快,仅次于寄存器,栈数据可以共享 | 存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量 | 当超过变量的作用域后,Java会自动释放掉该变量,内存空间可以立即被另作他用 |
堆 | 由new等指令创建的对象和数组 | 可以动态地分配内存大小,生存期也不必事先告诉编译器 | 由于要在运行时动态分配内存,存取速度较慢 | 由Java虚拟机的自动垃圾回收器来回收不再使用的数据 |
我们可以观察到,引用变量是存在栈内存中的。
那么我们就可以得出 结论,
引用变量就相当于是为数组或对象起的一个名称,可以在程序中使用栈中的引用变量来访问堆中的数组或对象。
引用变量起到的就是指针的作用,指向堆内存的对象实例。
我们结合上面的例子来总结一下,
Vehicle veh1;
veh1 = new Vehicle();
首先, new Vehicle()在堆内存里面开辟了空间给Vehicle类的对象,这个对象没有名字
然后, Vehicle()随即调用了Vehicle类的构造函数
最后, 把对象的地址在堆内存的地址给引用变量veh1
ヾ(๑╹◡╹)ノ" 终于是懂了。
- 问题3:向上转型和向下转型的区别和有关困惑。这个概念是在视频里面提到了,在周测里面也有涉及。所以研究下。
- 问题3解决方案:
- 我先看见了一个这个问题,java多态向上转型向下转型的问题
为什么不叫做子类引用指向父类对象呢?
我觉得这个问题很有意思,为什么就偏偏叫做父类引用指向子类对象呢?
结合上个问题,我们应该能很容易回答。如果是子类引用指向父类对象 Cat a = new Animal();这显然是不合逻辑的。 - 现在回归正题。区别一下两个用法,
向上转型:只能调用与父类引用中父类相同的方法,++不能调用子类中自己定义的方法++;如果在子类中重写了,则调用的是子类中的方法;
向下转型:可以调用父类中的方法,++也可以调用子类中自己定义的方法++;如果子类中重写了父类的方法,调用的是子类中重写的方法; - 对象间的转型问题:
向上转型:
Fu f = new Zi();
向下转型:
Zi z = (Zi)f;//要求该f必须能够转换为Zi的。
由此我们可见,向上转型是自动的,而向下转型则是强制的。 可以自己编写代码尝试一下。 - 参考资料:
- 我先看见了一个这个问题,java多态向上转型向下转型的问题
代码调试中的问题和解决过程
问题1:在做项目10.5的时候,排序有点问题。
问题1解决方法:实际上呢,是我对排序算法的理解还不够深入。这个应该是对DVDCollection类进行排序,我们应该重新定义这个类,并且重写构造方法。并且实现接口Comparable和重写compareTo方法
代码托管
上周考试错题总结
Which of the following is true regarding Java classes? : A
A . All classes must have 1 parent but may have any number of children (derived or extended) classes
B . All classes must have 1 child (derived or extended) class but may have any number of parent classes
C . All classes must have 1 parent class and may have a single child (derived or extended) class
D . All classes can have any number (0 or more) of parent classes and any number of children (derived or extended) classes
E . All classes can have either 0 or 1 parent class and any number of children (derived or extended) classes
理解:java是单继承,所以肯定只有一个父类。但是不要忘记Object类,所有类间接或者直接都是它的子类。所以每个类必须有一个父类,而子类就可以若干了。这里不要钻牛角尖,说什么Object类的父类是谁。A variable declared to be of one class can later reference an extended class of that class. This variable is known as : D
A . protected
B . derivable
C . cloneable
D . polymorphic (多态)
E . none of the above, a variable declared to be of one class can never reference any other type of class, even an extended class
理解:这里我们首先要清楚polymorphic是多态的意思。结合第十章的知识,我们就可以很好的理解这道题。多态引用变量可以指向不同类型的对象。Abstract methods are used when defining : A
A . interface classes
B . derived classes
C . classes that have no constructor
D . arrays
E . classes that have no methods
理解:抽象方法什么时候被定义?第一种就是在抽象类里面,另一种就是接口里面。这道题我看到E的时候直接就认为没有方法体的方法就是抽象方法。实际上,是因为我英语阅读的错误。这也是追求速度的弊端。没有认真查阅题目。
结对及互评
点评过的同学博客和代码
- 本周结对学习情况
其他
这周的学习很紧张。因为有一个小组任务,四则运算。所以说,第十章的理解并不是足够的全面。在周测的答题时间上我对自己进行了控制,尽量保持一道题在一分钟左右,对于单词比较复杂的题目用时可能较多。学长说,应该少扣概念,而加强对代码的运用编写。这一章的多态要有足够的设计敏感性,要知道什么时候运用多态,更好的解决代码重复问题。这一点,应该有意识的锻炼自己。
学会控制自己的压力,保持良好的心态和动力。不能因为一点挫折而郁郁不振。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 122/122 | 1/1 | 20/20 | |
第二周 | 487/609 | 1/2 | 18/38 | |
第三周 | 482/1091 | 1/3 | 22/60 | |
第四周 | 1357/2448 | 1/4 | 20/80 | |
第五周 | 628/3106 | 1/5 | 20/100 | |
第六周 | 566/3672 | 2/7 | 20/120 | |
第七周 | 934/4606 | 1/8 | 25/145 | |
第八周 | 2407/7013 | 1/9 | 30/175 |