上週學習了繼承和多態,知足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一個對象)才行,根據要求來建立對象,實現不一樣的排序方法