上周学习了继承和多态,知足is-a条件,可是发现会致使继承的滥用,若是只是但以的想拥有某种行为或变量,不须要必定要继承才能实现,可使用接口html
接口与抽象类
抽象类表示这个类是什么,接口类表示这个类能作什么
抽象类和接口都不能直接实例化
抽象类能够有具体的方法 和属性,接口只能有抽象方法和不可变常量
一个类只能继承一个抽象类,而一个类却能够实现多个接口
接口和抽象类区别java
1.1 com.parent包中Child.java文件可否编译经过?哪句会出现错误?试改正该错误。并分析输出结果。git
在Child类中 public void getParenti(){ System.out.println(i);//此处报错:i不可见 } 分析:在Child的类中没有i这个属性,则morning会调用父类的i,可是i被private修饰,只容许本类访问,可改成protected,这样就能够容许子类访问了 输出结果: 1 2 2 1 1 2 1 分析结果: 因为子类Child类中没有i,j属性,那么就会使用父类的属性,因此那些输出结果都是用父类的i和j
1.2 另一个包中的OutOfParentPackage.java,可否编译经过?提示什么错误?分析缘由。如何更改才能使之正常编译?算法
public class OutOfParentPackage{ public static void showParentj(Parent p){ System.out.println(p.j); //报错 System.out.println(p.geti());//报错 p.getj(); //报错 } }
答:不能经过编译,根据eclipse提示能够在Parent类中用getter和setter方法,或者将j的属性改成public修饰的,可是不大安全就是了,同理,也将geti和getj方法改成public的编程
2.1 Guess改造前代码很简单,而改造后的代码使用了抽象类、抽象方法看起来很复杂,那这样的改造到底有什么好处呢?数组
改造前: 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"); } } 改造以后: 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(); }
分析:改造前的代码比较中规中矩,但只能在控制台输入输出,该造后,用abstract修饰输出输入的方法,使其抽象化,能够在控制台,图形界面或者以其余方式进行安全
2.2 若是想将该游戏改形成图形界面,应该进行一些什么操做?框架
答:首先确定是要导入工具包,由于输入输出,还有获取输入都是用抽象方法,具体实现的内容是由继承这些类的子类来重写这些方法来实现
2.3 结合该例子,你以为何时应该使用abstract?dom
答: 当一个类中没有充足的信息来描述一个具体的对象时,能够用abstract,以不变应万变
2.4 重要:在这个例子中,变化的是什么,不变的是什么?尝试结合abstract、继承等概念进行说明。eclipse
答:能够变化的是继承GuessGame的子类中复写父类的方法,即输入输出的方式;不变的是父类抽象类方法的定义,这些类不须要有具体的内容,毕竟不知道要干啥,能够随机应变,由于任何继承这个抽象类的子类都必须复写父类的抽象方法,这样想作什么就让子类来作就行了
3.1 描述Comparable接口的用途。为何某个类实现了Comparable接口就能够直接使用Arrays.sort对其进行排序?
在API中查找的结果:
public static void sort(Object[] a)根据元素的天然顺序对指定对象数组按升序进行排序。数组中的全部元素都必须实现 Comparable 接口。此外,数组中的全部元素都必须是可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,e1.compareTo(e2) 不得抛出 ClassCastException)。 保证此排序是稳定的:不会因调用 sort 方法而对相等的元素进行从新排序。 该排序算法是一个通过修改的合并排序算法(其中,若是低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n*log(n) 性能。 参数: a - 要排序的数组 抛出: ClassCastException - 若是数组包含不可相互比较的 的元素(例如,字符串和整数)。
简要分析:comparable接口当中含有compareTo比较具体方法,可是只能按一种方式比较
3.2 有了Comparable接口为何还须要Comparator接口呢?
Arrays.sort(T[] a, Comparator<? super T> c) 根据指定比较器产生的顺序对指定对象数组进行排序。 API文档中查找的结果: sort public static <T> void sort(T[] a, Comparator<? super T> c)根据指定比较器产生的顺序对指定对象数组进行排序。数组中的全部元素都必须是经过指定比较器可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,c.compare(e1, e2) 不得抛出 ClassCastException)。 保证此排序是稳定的:不会因调用 sort 方法而对相等的元素进行从新排序。 该排序算法是一个通过修改的合并排序算法(其中,若是低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n*log(n) 性能。 参数: a - 要排序的数组 c - 肯定数组顺序的比较器。null 值指示应该使用元素的天然顺序。 抛出: ClassCastException - 若是数组包含使用指定的比较器不可相互比较的 的元素。
简要分析:有了Comparable接口,Arrays.sort实现比较算法进行排序,可是形式比较单一,有了Comparator接口,在集合外定义compare()的方法,能够重写compare方法。传入了两个参数,就能够根据不一样的排序要求做出排序,比较灵活,在书上284页也有相应的例子
3.3 可选:使用匿名内部类、Lambda表达式实现PTA编程5-2。
匿名内部类:(主要代码) Comparator<PersonSortable2> n1 = new Comparator<PersonSortable2>() { //按年龄升序,定义了匿名内部类 public int compare(PersonSortable2 o1, PersonSortable2 o2) { return o1.getAge() - o2.getAge(); } }; //注意此处的分号 Arrays.sort(p, n1); System.out.println("NameComparator:sort"); for (int i = 0; i < n; i++) { System.out.println(p[i]); } Comparator<PersonSortable2> n2 = new Comparator<PersonSortable2>() { //按姓名升序排序 public int compare(PersonSortable2 o1, PersonSortable2 o2) { return o1.getName().compareTo(o2.getName()); } }; Arrays.sort(p, n2); System.out.println("AgeComparator:sort"); for (int i = 0; i < n; i++) { System.out.println(p[i]); } System.out.println(Arrays.toString(n1.getClass().getInterfaces())); System.out.println(Arrays.toString(n2.getClass().getInterfaces()));
Lambda表达式: Comparator<PersonSortable2> n1 = (PersonSortable2 o1, PersonSortable2 o2) -> (o1.getName().compareTo(o2.getName())); Comparator<PersonSortable2> n2 = (PersonSortable2 o1, PersonSortable2 o2) -> (o1.getAge() - o2.getAge()); 补充格式: 参数 -> 表达式或程序块{ } 若是是表达式,则return该表达式的值(无需写return语句) 若是是程序块{ },能够包含多条语句
截图:
阅读Case-StudentDao.zip案例
4.1 画出类关系图,描述每一个类与接口的做用。
Student类当中只有name这个属性,有有参的构造函数,还有其对应的setter和getter方法
StudentDao接口定义了读写学生信息和显示所有学生信息的抽象方法,
StudenDaoListImpl类实现了StudentDao接口,用列表来存储Student类的对象,readStudent方法是经过遍历列表找到目标,writeStudent是直接经过add添加新的对象
StudentDaoArrayImpl类也实现了StudentDao接口,不过是默认存储Student对象数组大小为80,与StudenDaoListImpl类有点不一样的是读入信息是判断数组元素是否为空,才存入数组,其余大同小异
Test类就是含有入口函数,测试用的
4.2 StudenDaoListImpl与StudentDaoArrayImpl有何区别?
答:顾名思义,前者是用List列表来存储对象,后者是用数组来存储对象,只是实现方式不同,结果是同样的
结合题目3与4中的Test.java的代码讨论分析。不要百度原封不动照搬!
答;面向接口编程就是在面向对象的前提下,因为各个对象之间有可能存在协做关系,因此能够采用接口来实现交互,题目3中的Comparable和Comparator接口一样都是用来比较的,可是后者是能够比较一个类生成的两个对象之间属性的比较,同为比较,可是实现的方式不一样,题目4的StudenDaoListImpl与StudentDaoArrayImpl一样实现的结果是同样的,面向接口编程,就是在实现的方式不清楚的状况下,定义的一个接口,让其余类实现这个接口,再根据状况来写具体的内容,有了接口可变性比较强,可以解决需求变化。在书上202页第一段就有提到:写程序要有弹性,要有可维护性。
6.1内容:使用Java代码完成上周作的面向对象设计大做业,须要有初步界面。实现的功能尽可能简单,少而精,只包含必要的功能,不要追求高大全。
写出:类图(尽可能精简,不用太多子类,两个便可)、系统经常使用功能描述、关键代码与界面
形式: 两人依托码云合做完成。请在这里贴出大家的学号、姓名与任务分工。
注意: 再过几回课要讲Java图形界面编程,到时候要将该系统升级为图形界面。系统的业务逻辑部分应该变化不大,变化大的是输入与输出部分。因此编码的时候,输入(Scanner)与输出(System.out)的代码,请不要将其与某个业务处理函数绑死。
选作加分: 给出两人在码云上同一项目的提交记录截图,额外加分。注:两我的在码云上新建一个项目。
参考资料:
结对编程参考资料
可使用Processon画图
参考书面做业第三、4题的作法,使输入输出抽象化
类图:
学生L | 学生null | 项目地址 |
---|---|---|
https://q.cnblogs.com/u/lyq063/ | https://git.oschina.net/jmulyq/ShoppingCart.git |
6.2 经常使用功能描述框架图
6.3 关键代码
输入输出接口: public interface shop { //输入输出方式抽象化 public void print(String text); public abstract void println(String text); public abstract int nextInt(); public abstract Double nextDouble(); public abstract String next(); } 菜单类: public class Menu implements shop{ private Scanner scan = new Scanner(System.in); int k=0; public void showmenu(Cart cart){ println("**********欢迎光临**********"); println(" 1.浏览商品"); println(" 2.查找商品"); println(" 3.加入购物车"); println(" 4.个人购物车"); println(" 0.退出"); println("请选择:"); int choice=nextInt(); Iterm[] booklist=Iterm.allproduct(); switch(choice){ case 1:{ for(Iterm i:booklist){ println(i.toString2()); } break; } case 2:{ boolean flag=false; String prudoct=next(); for(k=0;k<booklist.length;k++){ if(booklist[k].getName().equals(prudoct)){ println(booklist[k].toString2()); flag=true; break; } } if(!flag){ println("您所查找的商品未找到,请从新输入"); k=-1; }else break; } case 3:{ if(k>=0){ println("请输入数量:"); int num=nextInt(); booklist[k].setNumber(num); cart.addproduct(booklist[k]); cart.cartmenu(booklist[k]); } else{ println("错误操做,还未选择商品!"); } break; } case 4:{ cart.cartmenu(booklist[k]); break; } case 0:return; } showmenu(cart); } @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 scan.nextInt(); } @Override public Double nextDouble() { return scan.nextDouble(); } @Override public String next() { return scan.next(); } } 商品类: public class Iterm{ private String name; private double price; public int number; ...一堆setter、getter、toString方法(含有两种格式,一种是不须要输出数量的) } 购物车类: public class Cart implements shop { ArrayList<Iterm> iterm = new ArrayList<Iterm>(); private Scanner scan = new Scanner(System.in); public void cartmenu(Iterm i) { println("1.删除商品"); println("2.结算所有商品"); println("3.清空购物车"); println("4.显示购物车中全部商品"); println("0.返回菜单"); println("请选择:"); int c = nextInt(); switch (c) { case 1: { deleteproduct(i); break; } case 2: { System.out.println(allmoney()); break; } case 3: { iterm.clear(); break; } case 4:{ for(Iterm i1:iterm){ System.out.println(i1.toString()); break; } } case 0: { return; } } } public void addproduct(Iterm i) { if(iterm.contains(i)){ iterm.get(iterm.indexOf(i)).number+=i.number; } else iterm.add(i); } public void deleteproduct(Iterm i) { iterm.remove(i); } public double allmoney() { double sum = 0; for (Iterm i : iterm) { sum += i.getPrice() * i.getNumber(); } return sum; } public void showcartproduct() { for (Iterm i : iterm) { println(i.toString()); } } ...还有复写接口输入输出的方法 } 测试类: public class PersonTest { public static void main(String[] args) { Menu menu=new Menu(); Cart cart=new Cart(); menu.showmenu(); } }
6.4 运行界面
主菜单及全部商品:
在书列表中找不到的状况:
加入购物车并结算:
删除当前商品:
题目集:jmu-Java-04-面向对象2-进阶-多态接口内部类
必定要有实验总结
5-1
这题编写了PersonSortable类,实现了Comparable接口,根据题意来重写compareTo和toString方法
比较简单,注意Comparable
5-2
这题用的是比较器,须要import java.util.Comparator;,应为这题要求是分别对姓名和年龄排序,因此能够重写compare方法,传入两个对象进行属性之间的比较 注意最后排序时候要Arrays.sort(p,new一个对象)才行,根据要求来建立对象,实现不一样的排序方法