20155314 2016-2017-2 《Java程序设计》第4周学习总结
20155314 2016-2017-2 《Java程序设计》第4周学习总结
教材学习内容总结
- 理解封装、继承、多态的关系
- 理解抽象类与接口的区别
- 掌握S.O.L.I.D原则
- 了解模式和设计模式
- 能正确覆盖方法
- 了解垃圾回收机制
- 掌握Object类
- 掌握enum
get到的重点
第六章 继承与多态
- 相关概念:
- 继承:避免多个类间重复定义共同行为
- 子类与父类:
- 父类:
- 对有着共同特性的多类事物,进行再抽象成一个类,这个类就是多类事物的父类
- 父类的意义在于可以抽取多类事物的共性
- 子类既可以是一个子类,也可以是一个父类;父类既可以是一个父类,也可以是一个子类
- 在Java中只有单一继承,即子类只能继承一个父类
- 子类与父类间会有is-a的关系(子类 is a 父类)
- 父类:
- is-a
- 多态:
- 继承可以复用代码,更大的用处是实现「多态」
- 封装是继承的基础,继承是多态的基础
- 「用父类声明对象引用,用子类生成对象」就有了多态
- 覆盖:子类中有和父类中可访问(可继承到子类)的同名同返回类型同参数表的方法,就会覆盖从父类继承来的方法
- 抽象方法、抽象类:
- Java中有抽象方法的类一定是抽象类,但抽象类中的方法不一定都是抽象方法
- 抽象类不能使用
new
生成对象
- 关键字:
-
extends
:- 继承父类的行为,再扩充父类原本没有的行为
- 继承时使用
extends
关键字,private
成员也会被继承,但子类无法直接存取,必须通过父类提供的方法来存取(父类愿意提供访问方法的话)
-
权限关键字:
-
public
:权限最大 -
protected
:被声明为protected
的成员,相同包中的类可以直接存取,不同包中的类可以在继承后的子类直接存取 -
private
:权限最小但实际上有四个权限范围(未定义权限关键字时默认为包范围):
|关键字 | 类内部| 相同包类|不同包类|
| -------- | :----------------😐:----------------😐:---------------: |
| public | 可存取 | 可存取 | 可存取 |
| protected | 可存取 | 可存取 | 子类可存取 |
| 无 | 可存取 | 可存取 | 不可存取 |
| private | 可存取 | 不可存取 |不可存取|
设计时使用权限需根据经验或团队讨论而定,通常先使用private
,以后视需求再放开权限。
-
-
super
:- 取得父类中的方法定义
- 执行父类中某构造函数
- 与
this
只能择一调用,而且一定要在构造函数第一行执行
-
final
:- 定义类:表示这个类是最后一个,不会再有子类,不能被继承
- 定义方法:表示最后一次定义方法,子类不可以重新定义
final
方法
-
abstract
:如果某方法区块中没有任何程序代码操作,可以用abstract
标示该方法为抽象方法,该方法不用写{}
区块,直接;
结束即可
-
教材学习中的问题和解决过程
问题一:关于println与printf函数参数问题
问题二:关于关键词abstract的使用
课后习题
所谓“实践是检验认识真理性的唯一标准”,我在IntelliJ IDEA上把教材第三章课后练习题又敲了一遍,给出了自己的答案,并加上了一些自己的分析,通过逐题进行代码调试实践的方式来深入对java类与对象的理解。小白在此恳请大家积极指出错误的地方(>_<)
6.4.1 选择题
-
C 分析:
class Some641 { void doService() { System.out.println("some service"); } } class Other641 extends Some641 { @Override void doService() { System.out.println("other service"); } } public class Exercise641 { public static void main(String[] args) { Other641 other=new Other641(); other.doService(); } }
-
C 分析:
class Some6412 { void doService() { System.out.println("some service"); } } class Other6412 extends Some6412 { @Override void doService() { System.out.println("other service"); } } public class Exercise6412 { public static void main(String[] args) { Some6412 some6412=new Other6412(); some6412.doService(); } }
-
B 分析:
class Some6413 { String ToString() { return "Some instance"; } } public class Exercise6413 { public static void main(String[] args) { Some6413 some6413=new Some6413(); System.out.println(some6413); } }
-
D 分析:
class Some6414 { int hashCode() { return 99; } } public class Exercise6414 { public static void main(String[] args) { Some6414 some6414=new Some6414(); System.out.println(some6414.hashCode()); } }
-
D 分析:
class Some6415 { @Override String ToString() { return "Some instance"; } } public class Exercise6415 { public static void main(String[] args) { Some6415 some6415=new Some6415(); System.out.println(some6415); } }
-
A 分析:
class Some6416 { abstract void doService(); } class Other6416 extends Some6416 { @Override void doService() { System.out.println("other service"); } } public class Exercise6416 { public static void main(String[] args) { Some6416 some6416=new Other6416(); some6416.doService(); } }
-
D
class Some6417 { protected int x; Some6417(int x) { this.x=x; } } class Other6417 extends Some6417 { Other6417(int x) { this.x=x; } }
-
D
public class IterableString extends String { public IterableString(String original) { super(original); } public void iterate() { //... } }
-
AC 分析:
class Some6419 { Some6419() { this(10); System.out.println("Some()"); } Some6419(int x) { System.out.println("Some(int x)"); } } class Other6419 extends Some6419 { Other6419() { super(10); System.out.println("Other()"); } Other6419(int y) { System.out.println("Other(int y)"); } } public class Exercise6419 { public static void main(String[] args) { new Other6419(); new Other6419(10); new Some6419(); } }
-
D
class Some64110 { Some64110() { System.out.println("Some()"); this(10); } Some64110(int x) { System.out.println("Some(int x)"); } } class Other64110 extends Some64110 { Other64110() { super(10); System.out.println("Other()"); } Other64110(int y) { System.out.println("Other(int y)"); } } public class Exercise64110 { public static void main(String[] args) { new Other64110(); } }
代码调试中的问题和解决过程
关于课本P86和P185伪随机数(根本不随机)的问题
哼只需要改一个小小的地方就行啦(>_<)
代码托管
- 运行statistics:
上周考试错题总结
- Java中,=与==并没有在基本类型和类类型的不同。(OK)
- 两个Integer对象比较大小,可以使用(comareTo())方法。
- “30”转化为byte类型的30的语句是(Byte.parseByte(“30”);)。
- public void someMethod(int i)和public int someMethod()是方法重载。(OK)
- Java中方法内可以定义类。(OK)
学习心得
别睡懒觉啦,快去蹭Java课啦
偶然听43班一哥们说我们系江智宇学霸经常来他们班蹭Java课(震惊!!这么好的利用教学资源的机会我怎么没想到!),自学有困难的我也立刻萌生了前去蹭课的想法,顺便感受一下43班的小班教学嘿嘿~于是适逢双周一天没课的这周四下午,为了蹭课干脆不睡午觉的我早早地潜伏在617教室后排,终于顺利地蹭了人生第一节课(还是Java课(>_<))
由于43班用的教材跟我们不一样,关于Java知识体系的叙述顺序不同,我也事先没有弄清他们班的教学进度,可以说真的是毫无准备地蹭课:(好在老师这节课重点讲解类和对象的使用、方法重载,恰好是我看教材五六两章最搞不懂犯迷糊的地方,带着问题去听,认真做好笔记,因此一节课听下来还是有不少收获的( ̀⌄ ́)
关于对象的清除
由于周四那会儿还没看到教材第六章垃圾收集机制呢,这段内容当时其实听得一知半解,但在周六看完书之后,特别是将课上做的笔记与书上的图结合起来看一对照就恍然大悟啦~
- 蹭课所得:
Java运行时系统通过垃圾收集器周期性地释放无用对象所使用的内存,完成对象的清除。当不存在对一个对象的引用时,该对象成为一个无用对象。Java的垃圾收集器自动扫描对象的动态内存区,对被引用的对象加标记,然后把没有引用的对象作为垃圾收集起来并释放。垃圾收集器作为一个线程运行,当系统的内存用尽或程序中调用
System.gc()
要求进行垃圾收集时,垃圾收集线程与系统同步运行,否则垃圾收集器在系统空闲是异步地执行。在对象作为垃圾被收集器释放前,Java运行时系统会自动调用对象的方法finalize()
(老师PPT上竟打错成finialize,噗),使它清除自己所使用的资源。在类的定义中,除了必须定义创建类实例等方法外,还可以在定义中提供用于对象清除的方法
finalize()
,它的格式如下:
protected void finalize() throws Throwable { //撤销对象 }
finalize()
方法是类java.long.Object
中最基本的方法。前面已经讲过,Java提供自动内存垃圾收集和处理程序,然而,在某些情况下,当一个类被破坏后,需要亲自执行一些垃圾收集器不能处理的特殊清理工作。
- 结合教材:
说到Java的垃圾回收机制,就不得不说到让很多人头疼的Android手机越用越卡的问题。众所周知,Android手机上的程序都是在JVM上跑的,而JVM即使具有垃圾回收机制也无法避免内存泄露的问题,就会不断产生垃圾、消耗内存,Android手机会随着安装的APP越多,cpu能耗越大,从而越来越卡,且时间一长,这种卡顿体验会越来越明显(>_<)TOO BAD:(而最新推出的Android7.0据说通过优化精简代码来改进运行效率,极大提升了软件运行速度和应用安装速度,可谓是Android阵营的福音~据说基于Android7.0的华为P10快要发售了哟嘻嘻~
关于方法重载
老师举的几个例子非常恰当,看完代码就差不多就明白怎么回事了~
- 蹭课所得:
重载:一个方法的不同版本
-
关于成员方法重载的例子:
//DemoOverload.java class Demo2 { int a,b; int method(){ //成员方法一 return a+b; } int method(int c){ //成员方法二 return a+b+c; } int method(int c,int d){ //成员方法三 return a+b+c+d; } Demo2(int a,int b){ //构造方法 this.a=a; this.b=b; } } public class DemoOverload { public static void main(String args[]) { Demo2 aDemo2=new Demo2(1,2); //实例化 int a=aDemo2.method(); //调用成员方法一 System.out.println(a); int b=aDemo2.method(3); //调用成员方法二 System.out.println(b); int c=aDemo2.method(3,4); //调用成员方法三 System.out.println(c); } }
其实在敲老师给的代码的过程中,我发现了这样一个问题:
-
关于实例方法和类方法
-
蹭课所得:
实例方法可以对当前对象的实例变量进行操作,也可以对类变量进行操作,但类方法不能访问实例变量。实例方法必须由实例对象来调用,而类方法除了可由实例对象调用外,还可以由类名直接调用。
关于类方法对使用,有如下一些限制:
(1)在类方法中不能引用对象变量;
(2)在类方法中不能使用
super
、this
关键字;(3)类方法不能调用类中的对象方法。
如果违反这些限制,程序就会导致编译错误。
与类方法相比,实例方法几乎没有什么限制:
(1)实例方法可以引用对象变量(这是显然的),也可以引用类变量;
(2)实例方法中可以使用
super
、this
关键字;(3)实例方法中可以调用类方法。
翻出尘封已久的C语言书,现在...封印解除~!
上了几周的数据结构课,张岩老师已经将六大排序算法用C语言定义顺序表的实现方式全部讲完了,老实说光听下来自己不动手实践对这门课十分无感,对排序算法更是吃不消。回寝室,从破旧的书柜中扒出了尘封已久的C语言书,望着满是尘埃早已泛黄的让人失望的记忆,感慨万千,无限伤感……
不过一翻开这本再熟悉不过的C语言书时我的脑海中突然闪过“敲代码”这个冲动,便立即联系起java课上娄老师传授给我们的“做中学”理论,有了继续接触C的动力。
于是这周上完数据结构课后我马上跑去图书馆,带着C语言教材,慢慢地想、慢慢地写,不断地调试,花了一个下午加一个晚上的时间终于将除了基数排序之外的排序算法(冒泡、选择、插入、快速、堆、归并、计数)全部用C语言数组(链表实在是太难了:(还没搞懂)分别写进多个函数的形式实现了一遍(数组下标什么的最讨厌了)~在没有考虑优化和防止非法输入的情况下不知不觉又写了近300行(>_<):
#include <stdio.h>
#include <stdlib.h>
#define N 5
void BubbleSort(int a[]);
void SelectionSort(int a[]);
void InsertionSort(int a[]);
void QSort(int a[],int s,int t);
int Partition(int R[],int low,int high);
void CountingSort(int a[],int k);
int max(int a[]);
void HeapSort(int a[]);
void MaxHeapify(int a[],int s,int m);
void BuildMaxHeap(int a[]);
void MergeSort(int a[],int s,int t);
void Merge(int a[],int i,int m,int n);
void main()
{
int i,j,temp;
int a[N],b[N];
printf("请输入%d个整数:",N);
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
BubbleSort(a); //冒泡排序
/*for(i=0;i<N;i++) //冒泡排序
{
for(j=0;j<N;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}*///冒泡排序
SelectionSort(a);
//InsertionSort(a); //插入排序
/*for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始
{
b[j]=a[i];
}
QSort(b,1,N);
for(i=1;i<N+1;i++)
{
printf("%d ",b[i]);
}*/ //快速排序
//CountingSort(a,max(a)); //计数排序
//HeapSort(a); //堆排序
/*for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始
{
b[j]=a[i];
}
MergeSort(b,1,N);
for(i=1,j=0;i<N+1,j<N;i++,j++) //将数组下标还原为从0开始
{
a[j]=b[i];
}*/ //归并排序
for(i=0;i<N;i++)
{
printf("%d ",a[i]);
}
}
void BubbleSort(int a[]) //冒泡排序
{
int i,j,temp;
for(i=0;i<N-1;i++)
{
for(j=i+1;j<N;j++)
{
if(a[i]>a[j])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
}
void SelectionSort(int a[]) //选择排序
{
int i,j,k,temp;
for(i=0;i<N-1;i++)
{
k=i; //从下标为0处开始记录
for(j=i+1;j<N;j++)
{
if(a[j]<a[k])
{
k=j; //记录最小数下标位置
}
}
if(k!=i) //优化处理:若最小数所在的下标位置不在下标位置i,则交换
{
temp=a[k];
a[k]=a[i];
a[i]=temp;
}
}
}
void InsertionSort(int a[]) //插入排序
{
int i,j,b[N];
for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始,便于设置监视哨a[0]
{
b[j]=a[i];
}
for(i=2;i<=N;i++)
{
if(b[i]<b[i-1])
{
b[0]=b[i]; //复制为监视哨
for(j=i-1;b[0]<b[j];j--)
{
b[j+1]=b[j];
}
b[j+1]=b[0];
}
}
for(i=1,j=0;i<N+1,j<N;i++,j++) //将数组下标还原为从0开始
{
a[j]=b[i];
}
}
void QSort(int a[],int s,int t) //快速排序
{
int pivotloc;
if(s<t-1) //长度大于1
{
pivotloc=Partition(a,s,t); //对a[]进行一次划分
QSort(a,s,pivotloc-1); //对左子序列递归排序,pivotloc是轴位置
QSort(a,pivotloc+1,t); //对右子序列递归排序
}
}
int Partition(int R[],int low,int high)
{
int pivotkey;
R[0]=R[low];
pivotkey=R[low]; //"轴"
while (low<high)
{
while (low<high&&R[high]>=pivotkey)
high--;
R[low]=R[high];
while (low<high&&R[low]<=pivotkey)
++low;
R[high]=R[low];
}
R[low]=R[0];
return low;
}
void CountingSort(int a[],int k) //计数排序
{
int i,j;
int C[N]; //引入索引数组C
int R[N]; //新建存储数组R
for(i=0;i<=k;i++)
{
C[i]=0; //初始化数组c
}
for(i=0;i<N;i++)
{
C[a[i]]++; //c[i]中存值等于i的元素个数
}
for(i=1;i<=k;i++)
{
C[i]=C[i]+C[i-1]; //c[i]中存值小于等于i的元素个数
}
for(j=N-1;j>=0;j--)
{
R[C[a[j]]]=a[j];
C[a[j]]--; //下一个值为a[j]的元素被放到a[j]的前一个位置
}
for(i=0;i<N;i++)
{
a[i]=R[i+1];
}
}
int max(int a[])
{
int i;
int max;
max = a[0];
for(i=1;i<N;i++)
{
if (max<a[i])
max=a[i];
}
return max;
}
void HeapSort(int a[]) //堆排序
{
int temp,i;
BuildMaxHeap(a); //建大顶堆
for(i=N;i>1;i--)
{
temp=a[0]; //将堆顶元素和当前未经排序子序列a[0...i-1]中最后一个元素交换
a[0]=a[i-1];
a[i-1]=temp;
MaxHeapify(a,0,i-2); //调整a[0...i-2]使其成为大顶堆
}
}
void MaxHeapify(int a[],int s,int m) //维护堆的性质
{
int rc,j;
rc=a[s]; //暂存a[s]
for(j=2*s;j<=m;j*=2)
{
if(j<m&&a[j]<a[j+1]) j++; //左右"孩子"之间先进行相互比较,令j指示较大的关键字所在位置
if(rc>=a[j]) break; //再作"根"和"孩子"之间比较,若">="成立,则说明已找到rc的插入位置s,不需继续向下调整
a[s]=a[j];
s=j; //否则关键字上移,仍需继续向下调整
}
a[s]=rc; //将调整前的堆顶插入到s位置
}
void BuildMaxHeap(int a[]) //建堆
{
int i;
for(i=N/2-1;i>=0;i--)
{
MaxHeapify(a,i,N); //建大顶堆
}
}
void MergeSort(int a[],int s,int t) //归并排序
{
int m;
if(s<t)
{
m=(s+t)/2; //分解
MergeSort(a,s,m); //解决
MergeSort(a,m+1,t);
Merge(a,s,m,t); //合并
}
}
void Merge(int a[],int i,int m,int n) //归并有序序列a[i...m]和a[m+1...n]
{
int j,k,p,q;
int R[N];
for(j=i;j<=n;j++)
{
R[j]=a[j]; //复制
}
for(j=m+1,k=i;i<=m&&j<=n;k++)
{
if(R[i]<=R[j]) a[k]=R[i++];
else a[k]=R[j++];
}
if(i<=m)
{
for(p=i,q=k;p<=m,q<=n;p++,q++)
{
a[q]=R[p];
}
}
if(j<=n)
{
for(p=j,q=k;p<=n,q<=n;p++,q++)
{
a[q]=R[p];
}
}
}
一提到防止非法输入,就不得不提到我比较熟练运用的C语言实现,说到C语言实现,那就一定要安(xuan)利(yao)一下加入了防止非法输入功能的比较完备的具有独立知识产权的中国剩余定理的C语言实现~不说废话直接上图~哼谁敢欺负我我就拿代码砸死你(。・ω・。)
(下周更)
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 20篇 | 300小时 | |
第一周 | 34/34 | 1/4 | 12/12 | |
第二周 | 360/394 | 1/5 | 16/28 | |
第三周 | 701/1018 | 1/6 | 19/ 47 | 代码量激增( ̀⌄ ́) |
第四周 | 608/1375 | 1/7 | 18/55 | ①蹭了一节张健毅老师的Java课;②自己将数据结构课上所学的排序算法除了基数排序之外全部用C语言实现了一遍(`_´)ゞ;③本次博客史无前例的长:) |
感想具体见上一条「学习心得」
任何学习都是没有捷径的。
这周高估了自己的理解能力,不说回看第五章理解得如何,没想到光看第六章就耗费了我大量的时间和精力,只得马马虎虎地把第七章简单翻了一遍,合上书就啥也不知道了:(导致这周考试没考好还是有些遗憾的:(不过自己通过动手实践加深了对数据结构这门课的理解,也算是一大收获吧嗯!
有学霸学长学姐建议我说不要把过多时间浪费在写博客上,我一想确实自己每周每天都要花很多时间来完善我的博客而不去真正搞懂Java中的有些问题,的确有失偏颇,在这里感谢学长学姐的批评指正!但其实我认为,这几周下来,我已经将写博客全然当成了一种发朋友圈、发说说一类的日常习惯,随时记录自己的学习情况、随时markdown自己的感想,我觉得自己将写博客从任务到习惯的蜕变,也可以算是一种进步吧( ̀⌄ ́)
这周老师开创性地采用了「蓝墨云班课」的教学方式,令人耳目一新。其中老师回复盛照宗同学说我们Java课采用「翻转课堂」的方式,可以根据自己的学习进度来安排学习任务,这也一定程度上启发了我。实际上老师的教学方式确实是比较灵活的,提问和答疑的方式也变得越来越便捷和高效,所以,每个人可以根据自己的程度完全量身定做自己的学习方式,哪里不懂就学哪里吧!
-
计划学习时间:20小时
-
实际学习时间:18小时