201521123069 《Java程序设计》 第4周学习总结
1. 本周学习总结
1.1 尝试使用思维导图总结有关继承的知识点。
1.2 使用常规方法总结其他上课内容。
(1)文档注释(类注释、方法注释、属性注释、通用注释、)
(2)多态性、instanceof运算符(判断引用的对象实例的实际类型)
(3)强制转换(基本类型和引用类型都可以使用强制转换,父类在强制转换成子类之前,最好用instanceof进行判断)
(4)抽象方法必须被重写,抽象方法只能有声明,不能有实现。
(5)控制可见性的访问修饰符:private(在本类中可见)、public(对所有类可见)、protected(对同包和所有子类可见)、默认(对本包可见,不推荐)
(6)Object类(所有类的父类):toString方法(输出对象所属的类名和散列码)、equals方法(判断两个对象是否有相同的引用)、hashCode方法
2. 书面作业
Q1.注释的应用
使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看。(截图)
Q2. 面向对象设计(大作业1,非常重要)
2.1 将在网上商城购物或者在班级博客进行学习这一过程,描述成一个故事。(不得少于50字,参考QQ群中PPT的范例)
2.2 通过这个故事我们能发现谁在用这个系统,系统中包含的类及其属性方法,类与类之间的关系。尝试找到这些类与属性,并使用思维导图描述类、属性、方法及类与类之间的关系。
2.3 尝试使用Java代码实现故事中描述的这一过程(不必很完善),将来要在这个基础上逐渐完善、扩展成一个完整的面向对象的系统。(可选:加分)
参考资料:
UML类图
面向对象案例-借款者姓名地址.zip
2.1
答:周一中午,我在食堂排队的时候接到我妈打来的电话,她让我在网上给我爸买个手机。我在纠结该买哪个牌子的手机,舍友们说华为这个牌子不错,而且挺适合男生用。于是,吃完饭回到宿舍,我就打开电脑,输入京东官网地址,登入自己的账号,在搜索栏输入华为手机,选择屏幕尺寸为5.1-5.5英寸,运行内存为3GB,机身内存为16GB,然后出现满足这些条件的华为手机,我开始查看它的评价及售后保障并对其进行筛选,比较喜欢的就将它添加到购物车,最后在购物车中选择最满意的一款,然后点击结算,填好收货地址及联系电话,然后完成支付。
2.2
2.3
商品类
class Goods {
private double price;
private int nums;
private String type;
public Goods(double price, int nums, String type) {
super();
this.price = price;
this.nums = nums;
this.type = type;
}
public double getPrice() {
return price;
}
public int getNums() {
return nums;
}
public String getType() {
return type;
}
@Override
public String toString() {
return "Goods [price=" + price + ", nums=" + nums + ", type=" + type + "]";
}
public void search(){
...
}
华为手机类
class HW_Phone extends Goods{
private double ScreenSize;
private String RAM;
private String ROM;
private String capacity;
public HW_Phone(double price, int nums, String type, double screenSize,
String rAM, String rOM, String capacity) {
super(price, nums, type);
ScreenSize = screenSize;
RAM = rAM;
ROM = rOM;
this.capacity = capacity;
}
public double getScreenSize() {
return ScreenSize;
}
public String getRAM() {
return RAM;
}
public String getROM() {
return ROM;
}
public void setROM(String rOM) {
ROM = rOM;
}
public String getCapacity() {
return capacity;
}
@Override
public String toString() {
return "HW_Phone "+super.toString()+"[ScreenSize=" + ScreenSize + ", RAM=" + RAM + ", ROM="
+ ROM + ", capacity=" + capacity + "]";
}
}
购物车类
class ShoppingCar{
private Goods goods;
private Users user;
@Override
public String toString() {
return "ShoppingCar [goods=" + goods + ", user=" + user + "]";
}
public void add(){
...
}
public void delete(){
...
}
public double sum(){
...
}
public void find_similar(){
...
}
}
用户类
class Users{
private String pname;
private String adress;
private String tel;
public Users(String pname, String adress, String tel) {
super();
this.pname = pname;
this.adress = adress;
this.tel = tel;
}
@Override
public String toString() {
return "Users [pname=" + pname + ", adress=" + adress + ", tel=" + tel
+ "]";
}
Q3.ManagerTest.zip代码分析
分析ManagerTest.zip中的代码,回答几个问题:
3.1 在本例中哪里体现了使用继承实现代码复用?回答时要具体到哪个方法、哪个属性。
3.2 Employee类及其子类Manager都有getSalary方法,那怎么区分这两个方法呢?
3.3 文件第26行e.getSalary(),到底是调用Manager类的getSalary方法还是Employee类的getSalary方法。
3.4 Manager类的构造函数使用super调用父类的构造函数实现了代码复用,你觉得这样的有什么好处?为什么不把父类构造函数中的相关代码复制粘贴到Manager的构造函数中,这样看起来不是更直观吗?
3.1
答:子类Manager的getSalary方法中复用了父类Employee类的getSalary方法,子类Manager的构造方法中复用了父类Employee类的构造方法。属性name,salary,hireDay也实现了代码复用。
3.2
答:JVM会根据调用该方法的实际对象类型来判断调用哪个方法,即若实际对象类型为Manager,则调用Manager类的getSalary方法,若实际对象类型为Employee,则调用Employee类的getSalary方法。
3.3
答:当e=staff[0]时,调用了Manager类的getSalary方法,当e=staff[1]或e=staff[2]时,调用了Employee类的getSalary方法。
3.4
答:好处:大大提高了软件开发的效率,提高了程序的可维护性。把父类构造函数中的相关代码复制粘贴到Manager的构造函数中,如果对父类构造函数中的相关代码进行了修改,那么同时也要对Manager的构造函数进行修改,而当Manager类的构造函数使用super调用父类的构造函数实现了代码复用时,只需对父类进行修改即可。
Q4.Object类
4.1 编写一个Fruit类及属性String name,如没有extends自任何类。使用System.out.println(new Fruit());是调用Fruit的什么方法呢?该方法的代码是从哪来的?尝试分析这些代码实现了什么功能?
4.2 如果为Fruit类添加了toString()方法,那么使用System.out.println(new Fruit());调用了新增的toString方法。那么其父类中的toString方法的代码就没有了吗?如果同时想要复用其父类的toString方法,要怎么操作?(使用代码演示)
4.3 Fruit类还继承了Object类的eqauls方法。尝试分析其功能?自己编写一个equals方法覆盖父类的相应方法,功能为当两个Fruit对象name相同时(忽略大小写),那么返回true。(使用代码证明你自己覆盖的eqauls方法是正确的)
4.4 在4.3的基础上使用ArrayList<Fruit> fruitList
存储多个fruit
,要求如果fruitList
中已有的fruit
就不再添加,没有的就添加进去。请编写相关测试代码。并分析ArrayList
的contatins
方法是如何实现其功能的?
4.1
答:使用System.out.println(new Fruit());是调用Fruit的toString()方法,Fruit类继承Object类,Object类中有toString方法,Fruit类对Object类的toString方法实现了复用。这些代码返回一个字符串(字符串内容:Class对象所代表的具体对象的名称与该对象哈希码值的16进制形式)。
4.2
答:父类中的toString方法的代码仍然有。
4.3
答:功能:判断当前对象与传入对象是否有相同的引用,如果有返回true,否则返回false.
代码:
class Fruit{
private String name;
public Fruit(String name) {
super();
this.name = name;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
Fruit other=(Fruit) obj;
if((name.compareToIgnoreCase(other.name))==0){
return true;
}
return false;
}
@Override
public String toString() {
return super.toString()+" Fruit [name=" + name + "]";
}
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fruit f1=new Fruit("apple");
Fruit f2=new Fruit("Apple");
System.out.println(f1.equals(f2));
}
}
4.4
import java.util.ArrayList;
import java.util.Scanner;
class Fruit{
private String name;
public Fruit(String name) {
super();
this.name = name;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
Fruit other=(Fruit) obj;
if((name.compareToIgnoreCase(other.name))==0){
return true;
}
return false;
}
@Override
public String toString() {
return "Fruit [name=" + name + "]";
}
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Fruit> fruitList=new ArrayList<>();
Scanner in=new Scanner(System.in);
int n=in.nextInt();
for (int i = 0; i < n; i++) {
String str=in.next();
Fruit f=new Fruit(str);
if(i==0){
fruitList.add(f);
}
else{
if(!fruitList.contains(f)){
fruitList.add(f);
}
}
}
System.out.println(fruitList);
}
}
答:通过遍历elementData数组来判断对象是否在fruitList中,若存在,返回对象在数组中的元素下标,若不存在则返回-1。ArrayList中的contains方法可以通过indexOf(Object)方法的返回值来判断对象是否被包含在fruitList中,若返回值大于等于0,则返回true,否则返回false。
代码阅读:EqualsTest.java(equals与hashCode)
5.1 读懂main函数,将自己推测的出代码运行结果与真正运行结果进行比较。尝试分析原因
5.2 为Employee类的equals函数的每一行加中文注释。
5.3 为Manager类的equals函数的每一行加中文注释。并回答,编写子类的equals函数需要注意什么?
5.4 对Employee的hashCode源代码,加中文注释。并结合数据结构中的知识,你觉得每个类中都有的hashCode方法有什么用?
5.5 查看Manager的hashCode源代码。并回答,编写子类的hashCode方法需要注意什么?
5.1
结果:
分析:注意"=="比较的是引用值,调用equals()方法时,JVM会根据实际对象类型来选择调用哪个方法,只需对方法中的条件进行判断。注意不要漏看"boss.setBonus(5000);"这一句,否则在判断"System.out.println("carl.equals(boss): " + carl.equals(boss));"时就会判断错。
5.2
5.3
答:编写子类的equals函数注意可以复用父类的equals函数。
5.4
public int hashCode() {
int h = hash;//将hash的值赋给h
if (h == 0 && value.length > 0) {//如果h的值为0并且value数组的长度不为0
char val[] = value;//将value数组赋给val数组
for (int i = 0; i < value.length; i++) {//i从0变化到value.length-1时满足循环条件
h = 31 * h + val[i];//h与val[i]一一映射
}
hash = h;//将h的值赋给hash
}
return h;//返回h的值
}
答:返回该对象的哈希码值。每创建一个对象,根据该对象的哈希码值,可将其插入到Hash表中,若不同对象的哈希码值相同,也就是在key位置发生了冲突,那么就在key位置新建一个链表,将相同哈希码的不同对象插入链表。比较两个对象时,首先比较的是它们的哈希码值,若哈希码值不同,则肯定不equal。
Q6.代码阅读:PersonTest.java(abstract、多态)
6.1 画出类的继承关系
6.2 读懂main函数,将自己推测的出代码运行结果与真正运行结果进行比较。尝试分析原因
6.3 子类中里面使用了super构造函数,作用是什么?如果将子类中的super构造函数去掉,行不行?
6.4 PersonTest.java中的代码哪里体现了多态?你觉得多态有什么好处?多态和继承有什么关系吗?
参考文件:PersonTest.java
6.1
6.2
运行结果:
分析:按年龄从小到大对数组peoples进行排序,并根据调用toString()方法的实际对象类型来选择调用哪个方法。例如:peoples[3]实际是Manager类,则调用Manager类的toString()方法,而Manager的toString()方法中又使用了super.toString(),即调用了Employee类的toString()方法,依此类推,Employee类的toString()方法调用了Person类的toString()方法,将Manager的toString()方法输出即可。
6.3
答:调用父类的构造函数,对子类中与父类相同的属性进行初始化。不能将子类中的super构造函数去掉。
6.4
多态体现:
多态的好处:可以增强程序的可扩展性及可维护性,使代码更加简洁。
多态和继承的关系:继承是多态的前提。
3. PTA实验总结及码云上代码提交记录
3.1本周Commit历史截图
3.2 实验总结
实验碰到的问题、思考、收获与解决方案
实验碰到的问题:(1)输出persons2数组(ArrayList容器)中的每个元素,使用for(int i=0;i<persons2.size();i++){System.out.println(persons2[i]);}(2)将"default"打成"dafault".
解决方案:(1)将"System.out.println(persons2[i]);"改成"System.out.println(persons2.get[i]);"(2)当编写的代码测试多次都无法通过,逻辑上的代码又没有错误的时候可以再仔细检查一下单词的拼写问题。
收获:Object类是所有类的父类。擅于使用封装与继承能提高代码编写的效率。