201521123082 《Java程序设计》第5周学习总结
标签(空格分隔): java
1. 本周学习总结
1.1 尝试使用思维导图总结有关多态与接口的知识点。
1.2 可选:使用常规方法总结其他上课内容。
选取上课的PPT中的重点:
1.接口的语法特性:
(1)接口不是类,不能使用new进行实例化;
(2)使用instanceof运算符
if (anObject instanceofComparable){
...}
可以查看该对象是否实现了Comparable接口
(3)接口可以扩展,将共同的行为抽象到父类接口(例子):
public interface Moveable{
void move(double x,double y);
}
public interface Powered extends Moveable{
double milesPerGallon();
double SPEED_LIMIT = 95; //public static final
}
(4)接口中可以包含常量,一个类可以实现多个接口。
2.Comparable与Comparator区别与联系
参考下面的题目3
3.接口与抽象类的区别与联系
(1)相同之处:都代表系统的抽象层,都不能被实例化,都能包含抽象方法。
(2)不同之处:可以实现多个接口,但只能继承一个类。
4.面向接口编程
参考下面的题目5
2. 书面作业
Q1.代码阅读:Child压缩包内源代码
1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误。并分析输出结果。
源代码如下:
package com.parent;
public class Child extends Parent{
public static void main(String[] args){
Parent p = new Parent();
Child c = new Child();
c.getParenti();
c.getParentj();
Other.showParentj(p);
}
public void getParenti(){
System.out.println(i);
}
public void getParentj(){
System.out.println(super.j);
System.out.println(j);
System.out.println(geti());
System.out.println(super.geti());
}
}
class Other{
public static void showParentj(Parent p){
System.out.println(p.j);
System.out.println(p.geti());
}
}
class Parent{
private int i=1;
protected int j=2;
protected int geti(){
return i;
}
public void getj(){
System.out.println(j);
}
}
Answer:
不能通过编译,MyEclipse中出现错误提示:
改正思路和正确输出结果以及分析:
父类Parent的i是private类型的,父类的i域对于子类来说是不可见。所以我们将Parent的i定义为protected类型。得到以下输出结果:
c.getParenti():
因为子类没有重新定义i,所以输出的值还是父类的i,而父类的i在实例化的时候就初始化为1( protected int i=1;);
c.getParentj():
输出的值为父类的j,父类的j,父类的i和父类的i。因为都是在继承父类的方法,j在父类中初始化为2。
Other.showParentj(p):
输出的值父类的j和父类的i,方法用static修饰的,所以直接用类名调用。
1.2 另外一个包中的OutOfParentPackage.java,能否编译通过?提示什么错误?分析原因。如何更改才能使之正常编译?
import com.parent.*;
public class OutOfParentPackage{
public static void showParentj(Parent p){
System.out.println(p.j);
System.out.println(p.geti());
p.getj();
}
}
Answer:
如图:
我们可以看见OutOfParentPackage在parent包外面。
我们现在MyEclipse中编译出现错误The type Parent is not visible。
说明Parent类是不可见的。Parent类加上public。
尝试修改的代码如下:
public class Parent{
piblic int i=1;
protected int j=2;
public int geti(){
return i;
}
public void getj(){
System.out.println(j);
}
}
使用public使包外的类能够访问。
1.3 回答:如果为了访问到protected修饰的属性或方法应该怎么办?###
Answer:
protected都是不可被继承的,访问protected修饰的属性或方法可以在同一个类中调用protected修饰的属性或方法,也可以同一个包中或是子类中调用protected修饰的属性或方法。
Q2.abstract进阶:阅读GuessGame抽象类的设计与使用源代码
package cc.openhome;
import java.util.Scanner;
//改造前
public class Guess {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int number = (int) (Math.random() * 10);
int guess;
do {
System.out.print("猜数字(0 ~ 9):");
guess = scanner.nextInt();
} while (guess != number);
System.out.println("猜中了...XD");
}
}
//改造后
//Guess2.java
package cc.openhome;
public class Guess2 {
public static void main(String[] args) {
GuessGame game = new ConsoleGame();
game.go();
}
}
//GuessGame.java
package cc.openhome;
public abstract class GuessGame {
public void go() {
int number = (int) (Math.random() * 10);
int guess;
do {
print("输入数字:");
guess = nextInt();
} while (guess != number);
println("猜中了");
}
public abstract void print(String text);
public abstract void println(String text);
public abstract int nextInt();
}
//ConsoleGame.java
package cc.openhome;
import java.util.Scanner;
public class ConsoleGame extends GuessGame {
private Scanner scanner = new Scanner(System.in);
@Override
public void print(String text) {
System.out.print(text);
}
@Override
public void println(String text) {
System.out.println(text);
}
@Override
public int nextInt() {
return scanner.nextInt();
}
}
2.1 Guess改造前代码很简单,而改造后的代码使用了抽象类、抽象方法看起来很复杂,那这样的改造到底有什么好处呢?
Answer:
好处:
- 改造前,未使用抽象类,只能控制台输出
- 改造后,使用抽象类,可以在控制台,也可以使用对话框图形界面等输入
由java笔记上抽象方法和抽象类的知识点可知:因为我们不知道代码运行的环境,使用抽象方法和抽象类可以先写出代码,后来根据需求和环境续上代码。
2.2 如果想将该游戏改造成图形界面,应该进行一些什么操作?
Answer:
设计一个游戏图形界面类,重写上面的抽象类中的抽象方法满足图形界面的输入输出要求,然后由游戏界面类继承这个抽象类。
2.3 结合该例子,你觉得什么时候应该使用abstract
?
Answer:
首先我们先了解什么是抽象类和抽象方法:
一个抽象类使用关键字abstract来定义,抽象类可以包含抽象方法,当然也可以不包含抽象的方法。抽象类不能被实例化成对象,但是它可以被继承。一个抽象类可能包含有静态属性,也包含有静态方法。当一个抽象类被继承以后,子类通常要实现其父类中的所有的抽象的方法。然而,如果子类没有实现所有的父类中的抽象的方法,那么这个子类也必须被定义成抽象类。
抽象方法就是不用没有方法体的——也就是没有实现的方法(没有花括号并且后面跟着分号),就像下面这样:
abstract void sum(int a, int b);
其次,我觉得以下情况时考虑用抽象类:
- 你想要在几个关联紧密的类之间共享代码。
- 你想要继承抽象类的那些类有一些公共方法或属性抑或是有修改protected或private属性的权限。这时你也可以考虑使用抽象类。
- 你想要声明非静态或者是非最终执行的属性。你可以获得并且修改这些属性所属的对象的状态。
2.4 重要:在这个例子中,变化的是什么,不变的是什么?尝试结合abstract、继承等概念进行说明。
Answer:
我觉得变化的是代码运行环境,比如常见的文本框、控制台、图形界面等;
不变的是这个抽象类,这个类是通用的,只是根据不同的环境决定不同的输出方式方法。
说明:
抽象类(abstract)可能就像是算法,然后我们要运用它的时候,只有通过各种语言,才能在不同的平台上实现其内容。(虽然这么说可能不是那么准确)。其次,我们编写一个抽象类和抽象方法,我们必须有类继承它,这样才有意义,在具体的类中具体实现方法。
Q3.Comparable与Comparator
3.1 描述Comparable接口的用途。为什么某个类实现了Comparable接口就可以直接使用Arrays.sort对其进行排序?
Answer:
用途:
此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序,类的 compareTo 方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort ( Arrays.sort进行自动排序。
分析:
先贴上JDK查询结果:
使用Comparable接口,可以让待排序对象所在的类实现Comparable接口,并重写Comparable接口中的compareTo()方法,就可以使用Arrays.sort进行排序。
3.2 有了Comparable接口为什么还需要Comparator接口呢?
Answer:
comparable和Comparator 都是用来实现集合中的排序的,只是Comparable是在集合内部定义的方法实现的排序,Comparator是在集合外部实现的排序。
所以,如想实现排序,就需要在集合外定义Comparator接口的方法compare()或在集合内实现Comparable接口的方法compareTo() 。
Comparable是一个对象本身就已经支持自比较所需要实现的接口(如String、Integer自己就可以完成比较大小操作)而Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
3.3 可选:使用匿名内部类、Lambda表达式实现PTA编程5-2。
Answer:
匿名内部类方法:
直接贴上代码:
//按name排序
Comparator<PersonSortable> nameComparator =
new Comparator<PersonSortable>(){
@Override
public int compare(PersonSortable o1, PersonSortable o2) {
return o1.getName().compareTo(o2.getName());
}
};
//按age排序
Comparator<PersonSortable> ageComparator =
new Comparator<PersonSortable>(){
@Override
public int compare(PersonSortable o1, PersonSortable o2) {
if (o1.getAge() > o2.getAge()) {
return 1;
} else if (o1.getAge() < o2.getAge()) {
return -1;
} else {
return 0;
}
}
};
Lambda表达式:
1.Labmda表达式语法:
- 参数 -> 表达式或程序块{ }
- 如果是表达式,则return该表达式的值(无需写return语句)
- 如果是程序块{ },可以包含多条语句
2.实现:
Comparator<PersonSortable> nameComparator =
(PersonSortable o1, PersonSortable o2) -> (o1.getName().compareTo(o2.getName()));
Arrays.sort(personSortables, nameComparator);
Comparator<PersonSortable> ageComparator =
(PersonSortable2 o1, PersonSortable2 o2)
-> {
if (o1.getAge() > o2.getAge()) {
return 1;
} else if (o1.getAge() < o2.getAge()) {
return -1;
} else {
return 0;
}};
Arrays.sort(personSortables, ageComparator);
4.面向接口案例分析
阅读Case-StudentDao.zip案例
4.1 画出类关系图,描述每个类与接口的作用。
Answer:
Student类:包含名字属性,有参构造器,还有getter/setter和toString()方法。
StudentDao接口:编写了三个抽象方法,writeStudent、readStudent、diplayAllStudent。
StudenDaoListImpl类:是对StudentDao接口的操作,存放学生信息采用列表的方式,实现了接口的三个抽象方法,用ArrayList完成操作。
StudentDaoArrayImpl类:对StudentDao接口的操作,实现接口的三个抽象方法。
4.2 StudenDaoListImpl与StudentDaoArrayImpl有何区别?
Answer:
StudenDaoListImpl是用ArrayList实现的,而StudentDaoArrayImpl是用数组实现的。
5.什么是面向接口编程?面向接口编程的好处是什么?
结合题目3与4中的Test.java的代码讨论分析。
Answer:
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。我们在一般实现一个系统的时候,通常是将定义与实现合为一体,不加分离的,而将所有的定义与实现分离就是面向接口编程吧。
我是这么理解上面那段话的,就以题目4为例子,体现了接口来实现多态,我们只要Test类里面,我们只要做的就是面向StudentDao接口,确定数据是以何种数据结构来存放,之后往后台写数据,无需考虑后台是什么(到底是数据库、文件、数组、List)。面向接口编程可以将接口与实现相分离,从而大大提高程序的灵活性。
题目3中,分别调用Comparable和Comparator两个接口,我们可以对我们自己定义的类进行比较,Comparable接口定义一个对象支持自比较,而Comparator接口可以实现比较两个属于某一特定类的专用比较。
关于面向接口编程可以参考:面向接口编程详解
6.结对编程:面向对象设计(大作业2-非常重要)
内容:使用Java代码完成上周做的面向对象设计大作业,需要有初步界面。实现的功能尽量简单,少而精,只包含必要的功能,不要追求高大全。
写出:类图(尽量精简,不用太多子类,两个即可)、系统常用功能描述、关键代码与界面
形式: 两人依托码云合作完成。请在这里贴出你们的学号、姓名与任务分工。
注意: 再过几次课要讲Java图形界面编程,到时候要将该系统升级为图形界面。系统的业务逻辑部分应该变化不大,变化大的是输入与输出部分。所以编码的时候,输入(Scanner)与输出(System.out)的代码,请不要将其与某个业务处理函数绑死。
选做加分: 给出两人在码云上同一项目的提交记录截图,额外加分。注:两个人在码云上新建一个项目。
6.1
学生A[倪兢飞201521123061] | 学生B[黄华林201521123082] | 项目地址 |
---|---|---|
http://www.cnblogs.com/JMUNJF/ | https://home.cnblogs.com/u/moyi-h/ | http://git.oschina.net/smoyi/test |
6.2 常用功能描述框架图
商讨后功能流程图如下:
3. 码云上代码提交记录及PTA实验总结
3.1. 码云代码提交记录
3.2. PTA实验
实验5.1:根据题目要求,Arrays.sort不能对自定义对象进行排序,要对自定义的PersonSortable类的对象,使用Arrays.sort进行排序。实现Comparable接口:实现先对name升序排序,如果name相同则对age进行升序排序,由于难度不大,直接关键代码:
public int compareTo(PersonSortable per) {
int x = this.name.compareTo(per.name);
if(x!=0){
return x;
}
else{
if (this.age>per.age)
return 1;
else if(this.age<per.age)
return -1;
else
return 0;
}
}
}
实验5.2:题目要求编写不同的Comparator来满足多样的排序需求。难度其实也不大,直接贴上NameComparator类和AgeComparator类的代码:
class NameComparator implements Comparator {
@Override
public int compare(Object per1, Object per2) {
PersonSortable2 p1 = (PersonSortable2) per1;
PersonSortable2 p2 = (PersonSortable2) per2;
if (p1.getName().compareTo(p2.getName()) > 0)
return 1;
else if (p1.getName().compareTo(p2.getName()) < 0)
return -1;
else
return 0;
}
}
class AgeComparator implements Comparator {
@Override
public int compare(Object per1, Object per2) {
PersonSortable2 p1 = (PersonSortable2) per1;
PersonSortable2 p2 = (PersonSortable2) per2;
if (p1.getAge() > p2.getAge())
return 1;
else if (p1.getAge() < p2.getAge())
return -1;
else
return 0;
}
}
其实这周的PTA主要是Comparable和Comparator的应用,在上面题目3已经有了较完整的理解表达