201521123082 《Java程序设计》第5周学习总结

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);

其次,我觉得以下情况时考虑用抽象类:

  1. 你想要在几个关联紧密的类之间共享代码。
  2. 你想要继承抽象类的那些类有一些公共方法或属性抑或是有修改protected或private属性的权限。这时你也可以考虑使用抽象类。
  3. 你想要声明非静态或者是非最终执行的属性。你可以获得并且修改这些属性所属的对象的状态。

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已经有了较完整的理解表达

posted @ 2017-03-25 18:16  末日驿站  Views(706)  Comments(0Edit  收藏  举报