201521123091 《Java程序设计》第4周学习总结
Java 第二周總結(jié)
第四周的作業(yè)。
目錄
1.本章學(xué)習(xí)總結(jié)
2.Java Q&A
3.使用碼云管理Java代碼
4.PTA實(shí)驗(yàn)
1.本章學(xué)習(xí)總結(jié)
1.1 嘗試使用思維導(dǎo)圖總結(jié)有關(guān)繼承的知識(shí)點(diǎn)。
1.2 使用常規(guī)方法總結(jié)其他上課內(nèi)容。
多態(tài)在這邊介紹一下:
- 多態(tài)就是相同的形態(tài),不同的行為。這樣去理解,在面向?qū)ο蟮木幊陶Z言中,多態(tài)就是不同類型的對(duì)象通過相同的接口去實(shí)現(xiàn)不同的方法。那么我們可以通過類繼承機(jī)制或者是接口來實(shí)現(xiàn)動(dòng)態(tài)綁定,進(jìn)而實(shí)現(xiàn)多態(tài)。
- instanceof 測(cè)試一個(gè)對(duì)象是否是某個(gè)類的實(shí)例,即使左邊是右邊類的子類的實(shí)例對(duì)象,也會(huì)返回true。
- 我們可以通過使用類型指派來完成子類所特有的某些方法。但是不能隨便進(jìn)行類型指派,否則會(huì)出現(xiàn)ClassCastException異常。要謹(jǐn)慎使用類型指派,所以經(jīng)常會(huì)通過instanceof來檢查。
2.Java Q&A
1.注釋的應(yīng)用:使用類的注釋與方法的注釋為前面編寫的類與方法進(jìn)行注釋,并在Eclipse中查看。(截圖)
首先上我們的注釋過后的類的文檔:
package ex3;/*** 照著String的文檔,寫一點(diǎn)點(diǎn),英語不好,權(quán)且用中文吧。這個(gè)類呢,大概是用來描述公司里面的一個(gè)雇員。* 下面就不一一介紹這些成員變量了,因?yàn)橐馑己芮逦?#xff0c;我沒有隨便命名變量。* 為了穩(wěn)妥起見,我指定程序代碼最早使用的版本為JDK5.0。主要沒有好好研究下,是不是里面用了一些新版本的新特性。* <p>下面只是簡(jiǎn)單地試一些標(biāo)簽* <p>“@see”這個(gè)標(biāo)簽可以允許我們引用其他類的文檔,生成HTML文件會(huì)生成超鏈接* <p>“@author”這個(gè)標(biāo)簽就是指明作者,LJL36就是我了* <p>“@return”用來描述返回值的含義* <p>“@param”用來描述參數(shù)列表中的標(biāo)識(shí)符* @see java.lang.Object#toString()* @see java.lang.String* @author LJL36* @since JDK5.0*/class Person {private String name;private boolean gender;private int age;private int id;/*** 這是一個(gè)無參構(gòu)造器,會(huì)輸出一個(gè)語句,然后將未初始化的默認(rèn)成員變量值打印出來*/public Person() {// TODO Auto-generated constructor stubSystem.out.println("This is constructor");System.out.println(name + "," + age + "," + gender + "," + id);}/*** 這是一個(gè)最常見的有參的構(gòu)造器,就是把傳進(jìn)來的參數(shù)來初始化對(duì)象,* 不過這邊沒有初始化id這個(gè)變量,所以會(huì)默認(rèn)是0* @param name* 名字* * @param age* 年齡* * @param gender* 性別*/public Person(String name, int age, boolean gender) {this.name = name;this.gender = gender;this.age = age;}/*** 這邊重寫了一個(gè)toString方法,是用eclipse自動(dòng)生成的* @return Person類的字符串表示*/@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Person [name=" + name + ", age=" + age + ", gender=" + gender + ", id=" + id + "]";}public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean isGender() {return gender;}public void setGender(boolean gender) {this.gender = gender;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public int getId() {return id;}public void setId(int id) {this.id = id;} } 類的注釋是用中文寫的,因?yàn)橛⒄Z不大好,用中文會(huì)流暢很多。類文檔一上來應(yīng)該簡(jiǎn)要的概括一下這個(gè)類。我測(cè)試的這個(gè)類非常的簡(jiǎn)單orz。所以也沒什么太多的話說。所以我嘗試加入一些參數(shù)的使用,具體的意思上面也都說了。最常用的幾個(gè)就像@see,@author,@since這些了。
有參構(gòu)造器的注釋:
無參構(gòu)造器的注釋:
toString方法的注釋:
(當(dāng)然一般在輸出一個(gè)類的時(shí)候,如果已經(jīng)寫好了toString方法的話,就不需要顯示加上,這邊只是為了看看toString方法的注釋而已)
2.面向?qū)ο笤O(shè)計(jì)(大作業(yè)1,非常重要)
2.1 將在網(wǎng)上商城購(gòu)物或者在班級(jí)博客進(jìn)行學(xué)習(xí)這一過程,描述成一個(gè)故事。(不得少于50字)
實(shí)變函數(shù)學(xué)十遍、學(xué)習(xí)泛函心犯寒
最近要學(xué)習(xí)一下復(fù)變分析,據(jù)說Elias M. Stein寫的Complex Analysis寫的不錯(cuò)。于是先輸入賬戶,密碼和驗(yàn)證碼登錄了某購(gòu)物網(wǎng)站:
顯示登陸成功!
然后在搜索框中輸入我要買的這本書“Complex Analysis”:
下面出現(xiàn)了很多搜索結(jié)果,第一本就是我要的
進(jìn)入看詳細(xì)信息,除了外面就可以看到的書名,價(jià)格,里面還可以看到:
點(diǎn)擊加入購(gòu)物車
我可以不止買一本,可以兩本、三本,十幾本……
那去結(jié)算咯!再看一下價(jià)格,900+??,把我賣了都買不起啊,妥妥刪了,隨便去down個(gè)PDF下來吧。
(上面都是我瞎扯的,沒有時(shí)間學(xué))
2.2 通過這個(gè)故事我們能發(fā)現(xiàn)誰在用這個(gè)系統(tǒng),系統(tǒng)中包含的類及其屬性方法,類與類之間的關(guān)系。嘗試找到這些類與屬性,并使用思維導(dǎo)圖描述類、屬性、方法及類與類之間的關(guān)系。
2.3 嘗試使用Java代碼實(shí)現(xiàn)故事中描述的這一過程(不必很完善),將來要在這個(gè)基礎(chǔ)上逐漸完善、擴(kuò)展成一個(gè)完整的面向?qū)ο蟮南到y(tǒng)。(可選:加分)
兩題合在一起做了
1.首先需要有一個(gè)啟動(dòng)類:啟動(dòng)購(gòu)物系統(tǒng),主要就是main方法在這個(gè)里面,主要就是要調(diào)用其他的類。
2.然后需要一個(gè)商品類Goods:最主要的屬性就是商品名和價(jià)格
package shopping;public class Goods {private String name;private double price; }PS:然后下面會(huì)繼承其他的許多類,我這邊寫了些,比如圖書,服裝。主要是一個(gè)網(wǎng)上商城肯定有分類,而且這樣易于搜索。然后還會(huì)有一個(gè)AllGoods類,按理來說數(shù)據(jù)操作都是在后臺(tái)數(shù)據(jù)庫(kù)完成的?這邊就暫且加一個(gè)吧。
3.搜索類:這樣想的,凡是根據(jù)滿足關(guān)鍵字條件的商品都加入列表中,并且顯示出來,所以暫時(shí)先只要:
4.菜單類,主要是和用戶的交互,比如查看訂單,查看個(gè)人消息,查看購(gòu)物車,搜索之類的雜七雜八的:
package shopping;public class Menu {public void startSearch() {Search search = new Search();}public void showMyself(User user) {}public void showShoppingCart(ShoppingCart shoppingCart) {} }5.用戶類,里面放了一些用戶需要的屬性,方法沒怎么加。同樣加了個(gè)AllUsers存放所有用戶的信息。
package shopping;public class User {String userName;String password;String address;}6.購(gòu)物車類,非常核心的一個(gè)類,不過同樣地我也沒怎么寫東西,這邊用到了組合,因?yàn)樯唐房梢杂袛?shù)量。
package shopping;import java.util.ArrayList; import java.util.concurrent.BlockingDeque;public class ShoppingCart {class Item {private Goods goods;private int num;}private ArrayList<Item> items = new ArrayList<Item>();private double totalPrice;public void add() {}public void delete() {}public void purchase() {}public void clear() {} }7.登錄類:主要就是把登錄這個(gè)功能單獨(dú)細(xì)分出來,然后因?yàn)橛猩婕暗津?yàn)證碼,所以這邊有加了個(gè)驗(yàn)證碼的類,不知道真正的實(shí)現(xiàn),隨便寫了個(gè)。
//Code.java package shopping;import java.io.File;public class Code {File picture;String codeString; }//Login.java package shopping;public class Login {void showCode() {}boolean verify(String userName, String passWord, String code) {return true;}Code code; } 差不多就這樣了,然后貼一下UML類圖,大致現(xiàn)在的關(guān)系就是這樣,因?yàn)楹芏鄬傩詻]有考慮到,而且方法還沒有具體實(shí)現(xiàn),所以比較EZ:
3.分析ManagerTest.zip中的代碼,回答幾個(gè)問題:
3.1 在本例中哪里體現(xiàn)了使用繼承實(shí)現(xiàn)代碼復(fù)用?回答時(shí)要具體到哪個(gè)方法、哪個(gè)屬性。
首先,這邊貼一下維基對(duì)于代碼復(fù)用的定義:
Code reuse, also called software reuse, is the use of existing software, or software knowledge, to build new software,following the reusability principles.
簡(jiǎn)言之,就是對(duì)曾經(jīng)使用過的代碼一部分甚至全部重新加以利用。那我們就記住這句話,然后來看看在ManagerTest.java中到底哪些地方體現(xiàn)了代碼的復(fù)用。
- 構(gòu)造器
這邊出現(xiàn)了super關(guān)鍵字,這是面向過程語言中一個(gè)重要的關(guān)鍵字,在構(gòu)造器當(dāng)中,我們上回提到了this這個(gè)關(guān)鍵字表示的是當(dāng)前對(duì)象的引用。而相似地,我們也經(jīng)常會(huì)通過super這個(gè)關(guān)鍵字去調(diào)用父類的構(gòu)造器或者是父類的方法。這邊我們就是在調(diào)用父類的構(gòu)造器來完成子類對(duì)象的初始化。
關(guān)于構(gòu)造器這邊還有要說的點(diǎn)
Note: If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
如果子類的構(gòu)造器沒有顯式調(diào)用父類的構(gòu)造器,那么Java的編譯器就會(huì)自己加一個(gè)父類的無參構(gòu)造器,如果父類沒有無參構(gòu)造器,那么就會(huì)編譯出錯(cuò),這是什么情況呢,就是在父類寫了個(gè)有參的構(gòu)造器,然后子類的構(gòu)造器沒有顯式調(diào)用這個(gè)有參的構(gòu)造器,那么編譯就會(huì)出錯(cuò)。就加入我們現(xiàn)在把這第一行刪掉,就會(huì)發(fā)出“Implicit super constructor Employee() is undefined. Must explicitly invoke another constructor”的編譯錯(cuò)誤。
- 成員變量
這邊就是name(String)、salary(double)和hireDay(Date)
代碼當(dāng)中并沒有很明顯體現(xiàn)出哪里是復(fù)用了父類的成員,其實(shí)在上面我們?cè)诮榻B構(gòu)造器的時(shí)候,大家就可以發(fā)現(xiàn),我們?cè)贛anager類中并沒有定義任何成員變量,但是都沒有出現(xiàn)編譯出錯(cuò)的信息,究其原因就是子類復(fù)用了定義父類成員變量的代碼,所以就不用再重復(fù)了。
- 成員方法
這邊是調(diào)用父類的方法。從這段代碼我們更可以看出添加super關(guān)鍵字的重要性,如果將super去掉,那么就會(huì)產(chǎn)生我們并不希望看到的遞歸。主要這個(gè)函數(shù)還沒有基準(zhǔn)條件(Base Case)那么就會(huì)一直向下遞歸,直到簿記空間全部被塞滿為止,然后電腦就跑崩了。
說完繼承之后,Java表示權(quán)限的四大關(guān)鍵字就已經(jīng)全部出現(xiàn)了,下面分列它們各自的訪問權(quán)限范圍。
(PS:發(fā)現(xiàn)了博客園的第?個(gè)不支持:表格,這邊把我用md語法實(shí)現(xiàn)的表格截下來)
3.2 Employee類及其子類Manager都有g(shù)etSalary方法,那怎么區(qū)分這兩個(gè)方法呢?
區(qū)分兩個(gè)同名方法?
那大概想讓編譯器能夠區(qū)分吧。
首先,我們?cè)谏匣靥岬?#xff0c;如何在一個(gè)類當(dāng)中去區(qū)分同名方法,我們的解決辦法是使用不同的參數(shù)列表,這個(gè)不同的范圍非常大,即使我們使用了相同的參數(shù),只要順序不同,編譯器都可以區(qū)分出來。
那么,怎么去區(qū)分父類和子類的兩個(gè)方法。其實(shí)上面我們也說過了,就是我們使用super關(guān)鍵字來表示父類,那么假如這個(gè)例子super.getSalary()就表示父類的getSalary()方法。因?yàn)槲覀儠?huì)有遞歸啊,所以在方法內(nèi)部出現(xiàn)了同名的方法,完全可以認(rèn)為是遞歸,所以必須得用super來區(qū)分。
3.3 文件第26行e.getSalary(),到底是調(diào)用Manager類的getSalary方法還是Employee類的getSalary方法。
貼圖解決
e都已經(jīng)說明是Employee類的了,肯定調(diào)用Employee類的方法啊,而且調(diào)用子類的方法,聽上去不是有點(diǎn)怪怪的嗎,雖然查了下似乎是可以的,以一種曲線救國(guó)的方法,不過應(yīng)該沒什么必要,這邊貼個(gè)鏈接,學(xué)到后面了回頭再看。傳說中的父類調(diào)用子類方法
不好意思,上面是錯(cuò)誤的示范。留在這邊,當(dāng)個(gè)反例。趕得太急了,也沒有檢查。這里面也是多態(tài)的體現(xiàn)。就是我們下面會(huì)說到的動(dòng)態(tài)綁定,編譯器無法得知到底是什么類的對(duì)象在調(diào)用這個(gè)方法,只有在運(yùn)行的時(shí)候,才能夠根據(jù)e的類型來確定。這邊只是通過父類給所有的繼承它的子類都提供同名方法的統(tǒng)一接口而已。(感謝老師指出錯(cuò)誤)
3.4 Manager類的構(gòu)造函數(shù)使用super調(diào)用父類的構(gòu)造函數(shù)實(shí)現(xiàn)了代碼復(fù)用,你覺得這樣的有什么好處?為什么不把父類構(gòu)造函數(shù)中的相關(guān)代碼復(fù)制粘貼到Manager的構(gòu)造函數(shù)中,這樣看起來不是更直觀嗎?
好處就是少寫了一些代碼。
是很直觀,但是犯了Don't repeat yourself.的錯(cuò)誤。
使用父類的構(gòu)造器super()來幫助子類進(jìn)行初始化,已經(jīng)是一種約定俗成的方法,所以在代碼的可讀性方面并不輸直接復(fù)制粘貼代碼,而且還縮減了代碼量,所以肯定是直接用super調(diào)用父類的構(gòu)造器更好。(而且這樣顯得比較高大上,復(fù)制粘貼代碼看上去很蠢。)
這邊又要提到上文我們說的代碼復(fù)用的問題
再引用一下wiki
Code reuse aims to save time and resources and reduce redundancy by taking advantage of assets that have already been created in some form within the software product development process.
......
These are some of the main goals behind the invention of object-oriented programming,which became one of the most common forms of formalized reuse.Code reuse
代碼復(fù)用就是為了要節(jié)省時(shí)間和資源,還要減少冗余。造成冗余的易讀性是沒有必要的。而且wiki還說了OOP就是為了更規(guī)范地復(fù)用代碼而生的,然后如果還傻乎乎的復(fù)制粘貼,無話可說。
4.Object類
4.1 編寫一個(gè)Fruit類及屬性String name,如沒有extends自任何類。使用System.out.println(new Fruit());是調(diào)用Fruit的什么方法呢?該方法的代碼是從哪來的?嘗試分析這些代碼實(shí)現(xiàn)了什么功能?
class Fruit {private String name; }public class Main {public static void main(String[] args) {System.out.println(new Fruit());} }運(yùn)行結(jié)果:Fruit@15db9742
在之前的博文中,包括在上面我也有提到,當(dāng)我們直接輸出某個(gè)對(duì)象的時(shí)候,就會(huì)調(diào)用toString()方法。
看一下println()的實(shí)現(xiàn)
思想就是要將對(duì)象用字符串的形式表示出來,然后輸出(使用print()方法),并且加個(gè)回車符(newLine()方法)。
valueOf()方法是用來return the string representation of the {@code Object} argument.它的實(shí)現(xiàn)就是
正如我們所說的,歸根結(jié)底還是調(diào)用了toString()方法。在本例中,我們并沒有重寫toString()方法,從運(yùn)行結(jié)果我們可以看出本例中就是使用Object的toString()方法,即類名加上16進(jìn)制的哈希碼。這邊就引出了一個(gè)很重要的點(diǎn):
當(dāng)創(chuàng)建一個(gè)類時(shí),總是在繼承,因此,除非已明確指出要從其他類中繼承,否則就是隱式地從Java的標(biāo)準(zhǔn)根類Object進(jìn)行繼承。
——《Java編程思想》
Object的源代碼文檔中也如是提到
Class {@code Object} is the root of the class hierarchy.Every class has {@code Object} as a superclass. All objects, including arrays, implement the methods of this class.
4.2 如果為Fruit類添加了toString()方法,那么使用System.out.println(new Fruit());調(diào)用了新增的toString方法。那么其父類中的toString方法的代碼就沒有了嗎?如果同時(shí)想要復(fù)用其父類的toString方法,要怎么操作?(使用代碼演示)
原來父類的toString()方法并不會(huì)沒有啊。一個(gè)爸爸可以有好幾個(gè)兒子,就因?yàn)檫@個(gè)兒子重寫了某個(gè)方法,導(dǎo)致其他兒子都得自己重寫?顯然是不可能的。只是對(duì)于父類中的方法,我既可以去使用它(不做改變)也可以按照自己的需求去修改它。Object類的toString()方法就是最好的例子,因?yàn)轭惷?#43;哈希碼的字符串表示在日常生活中應(yīng)用不到,所以推薦每個(gè)類都要重寫一個(gè)toString()方法。
想在重寫父類方法的同時(shí)復(fù)用父類的方法,只要用super關(guān)鍵字就好了,這邊貼一個(gè)代碼演示:
4.3 Fruit類還繼承了Object類的eqauls方法。嘗試分析其功能?自己編寫一個(gè)equals方法覆蓋父類的相應(yīng)方法,功能為當(dāng)兩個(gè)Fruit對(duì)象name相同時(shí)(忽略大小寫),那么返回true。(使用代碼證明你自己覆蓋的eqauls方法是正確的)
equals()方法是用來“Indicates whether some other object is "equal to" this one.”
equals()方法在Object類中的實(shí)現(xiàn):
如源碼所示,Object類中的equals()方法是比較引用的,即引用相同就返回true,不同返回false。
據(jù)說許多人都會(huì)把equals()方法寫錯(cuò),害怕,那我們盡量寫的規(guī)范一點(diǎn)吧,首先這個(gè) 方法有5個(gè)要求:
1. 自反性(reflexive):對(duì)于任何非空引用值 x,x.equals(x) 都應(yīng)返回 true。
2. 對(duì)稱性(symmetric):對(duì)于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true。
3. 傳遞性(transitive):對(duì)于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 應(yīng)返回 true。
4. 一致性(consistent):對(duì)于任何非空引用值 x 和 y,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回 false,前提是對(duì)象上 equals 比較中所用的信息沒有被修改。
5. 對(duì)于任何非空的引用x,x.equals(null)應(yīng)該返回false
附上參考鏈接!
而且,文檔中還有說到:
Note that it is generally necessary to override the {@code hashCode} method whenever this method is overridden, so as to maintain the general contract for the {@code hashCode} method, which states that equal objects must have equal hash codes.
就是要重寫hashcode()這個(gè)方法……
看上去很難,我本來想好好的思考一下怎么寫的,但是自己太懶,想用eclipse生成hashcode()和equals()方法,然后再自己實(shí)現(xiàn),沒想到然后就??都做好了啊???那就不客氣了,貼代碼了,然后我來解釋下吧:
這個(gè)自動(dòng)生成的代碼寫的太好了。只可意會(huì),不可言傳。我也解釋不了什么……
hashcode()方法就是將一個(gè)Fruit對(duì)象hash成一個(gè)整數(shù)。這邊是結(jié)合了String的hashcode()的方法。
接下來重點(diǎn)介紹一下equals()方法:
如果引用相同,那說明比較的是同一個(gè)對(duì)象,那么就返回true。滿足自反性。
非空的對(duì)象和null比較,返回false。滿足第五條要求。
兩個(gè)對(duì)象的類要是相同的,類不同的話,相同無從談起。這邊用getClass()方法來代替instanceof,因?yàn)楹笳咧皇桥袛嘧筮厡?duì)象是否是右邊類的實(shí)例,那如果左邊是子類的對(duì)象,右邊是父類,其實(shí)也是可以通過的,因?yàn)榇嬖诶^承關(guān)系,so不好。在上面equals()方法附上的鏈接里面有詳細(xì)的說明。
還有要對(duì)name是否為空進(jìn)行特判,上次在敲深克隆的代碼時(shí),因?yàn)闆]有注意到null,一直A不掉。結(jié)果試了一下,如果沒有特判null,是會(huì)拋出異常的,所以以后都要注意的。后面就是返回字符串之間equals()的返回值了,沒什么了。我唯一改了一下,就是要忽略大小寫。
4.4 在4.3的基礎(chǔ)上使用ArrayList fruitList存儲(chǔ)多個(gè)fruit,要求如果fruitList中已有的fruit就不再添加,沒有的就添加進(jìn)去。請(qǐng)編寫相關(guān)測(cè)試代碼。并分析ArrayList的contatins方法是如何實(shí)現(xiàn)其功能的?
public class Main {public static void main(String[] args) {// TODO Auto-generated method stubArrayList<Fruit> fruits = new ArrayList<Fruit>();Fruit[] fruits2 = new Fruit[6];fruits2[0] = new Fruit("apple");fruits2[1] = new Fruit("Apple");fruits2[2] = new Fruit("apqle");fruits2[3] = new Fruit("蘋果");fruits2[4] = new Fruit("平果");fruits2[5] = new Fruit("apPle");for (int i = 0; i < fruits2.length; i++) {if (!fruits.contains(fruits2[i])) {fruits.add(fruits2[i]);}}for (Fruit fruit : fruits) {System.out.println(fruit.getName());}}}測(cè)試結(jié)果如圖所示:
要分析ArrayList是如何實(shí)現(xiàn)contains()方法,就看看源碼吧:
//contains()方法 public boolean contains(Object o) {return indexOf(o) >= 0; }//indexOf()方法 public int indexOf(Object o) {if (o == null) {for (int i = 0; i < size; i++)if (elementData[i]==null)return i;} else {for (int i = 0; i < size; i++)if (o.equals(elementData[i]))return i;}return -1; }歸根到底,還是要用到equals()方法,因?yàn)橐榭词欠裼邪?#xff0c;就需要有對(duì)象的比較。正如各位所看到的,我們寫的equals()方法是不區(qū)分大小寫的,所以諸如Apple和apPle之類的都是不能加進(jìn)這個(gè)ArrayList的。
5.代碼閱讀:PersonTest.java(abstract、多態(tài))
5.1 畫出類的繼承關(guān)系
5.2 讀懂main函數(shù),將自己推測(cè)的出代碼運(yùn)行結(jié)果與真正運(yùn)行結(jié)果進(jìn)行比較。嘗試分析原因
真正的運(yùn)行結(jié)果:
Manager [bonus=12000.3, toString()=Employee [salary=90000.1, toString()=Person [name=Clark, adress=GE, phonenumber=111, email=111@mail.com, age=10, gender=mail]]]
Student [status=1, toString()=Person [name=wang, adress=110, phonenumber=15959, email=15959@163.com, age=18, gender=male]]
Employee [salary=1000.0, toString()=Person [name=zhang, adress=136, phonenumber=1360, email=1360@mail.com, age=21, gender=female]]
Programmer [allowance=50000.0, toString()=Employee [salary=100000.0, toString()=Person [name=Gates, adress=usa, phonenumber=911, email=911@com, age=59, gender=male]]]
分析原因:首先Person類是一個(gè)抽象類,所以根本就不存在可以實(shí)例化對(duì)象。因此這邊只要分析Employee、Student、Manager和Programmer這四個(gè)類就行了。觀察這四個(gè)類的toString()方法,我們可以發(fā)現(xiàn)他們具有統(tǒng)一的格式,就是輸出自己特有的成員變量,然后調(diào)用父類的同名方法,對(duì)于Manager和Programmer這兩個(gè)類,因?yàn)樗麄兊母割怑mployee類也是繼承Person類,所以他們會(huì)有兩層嵌套。
5.3 子類中里面使用了super構(gòu)造函數(shù),作用是什么?如果將子類中的super構(gòu)造函數(shù)去掉,行不行?
作用是調(diào)用父類的構(gòu)造器。
不可以,因?yàn)槿绻麑uper構(gòu)造器去掉,那么編譯器會(huì)自動(dòng)加入對(duì)父類無參構(gòu)造器的調(diào)用,然而這個(gè)例子中沒有一個(gè)類是有無參構(gòu)造器的,所以會(huì)編譯出錯(cuò)。我們會(huì)被要求“Must explicitly invoke another constructor”。所以即使無參構(gòu)造器不會(huì)起到任何作用,我們還是最好能加上它,這樣如果有其他類繼承當(dāng)前類,就可以在代碼中隱式地調(diào)用這個(gè)什么都不做的構(gòu)造器,然后顯式地完成全新的初始化(就假如所有的成員變量都不需要用到父類的構(gòu)造器就能夠完成初始化)。
5.4 PersonTest.java中的代碼哪里體現(xiàn)了多態(tài)?你覺得多態(tài)有什么好處?多態(tài)和繼承有什么關(guān)系嗎?
首先要理解什么是多態(tài),如果從廣義的角度去理解,多態(tài)是一個(gè)很寬泛的概念。大致分為三種:
1.特設(shè)多態(tài)(Ad hoc polymorphism),函數(shù)重載和運(yùn)算符重載。
2.參數(shù)化多態(tài),就是把類型作為參數(shù)的多態(tài)。例如C++的模板。
3.子類型化。
通過類繼承機(jī)制和虛函數(shù)機(jī)制生效于運(yùn)行期。可以優(yōu)雅地處理異質(zhì)對(duì)象集合,只要其共同的基類定義了虛函數(shù)的接口。也被稱為子類型多態(tài)(Subtype polymorphism)或包含多態(tài)(inclusion polymorphism)。在面向?qū)ο蟪绦蛟O(shè)計(jì)中,這被直接稱為多態(tài)。多態(tài)(計(jì)算機(jī)科學(xué))來自維基
所以我們這邊就來聊聊OOP中的多態(tài),就是子類型化。實(shí)現(xiàn)多態(tài)的方法叫做后期綁定,也叫做動(dòng)態(tài)綁定或運(yùn)行時(shí)綁定。即編譯器一直不知道對(duì)象的類型,但是方法調(diào)用機(jī)制能找到正確的方法體,并加以調(diào)用。這樣我們就可以編寫只與父類打交道的代碼,并且這些代碼對(duì)所有的子類都可以正確運(yùn)行。
我們來列舉這邊出現(xiàn)的多態(tài):
- System.out.println(person);/* Person類是一個(gè)抽象類,不能產(chǎn)生對(duì)象,所以也不會(huì)直接能夠輸出。但是我們并不知道到底輸出的是屬于哪個(gè)類的對(duì)象,直到運(yùn)行的時(shí)候,才能知道,比如第0個(gè)就是Employee類的對(duì)象,就調(diào)用Employee類的toString()方法,第一個(gè)就是Student類的對(duì)象,就調(diào)用Student類的toString()方法。 */
- 其他就沒發(fā)現(xiàn)了,因?yàn)槎鄳B(tài)要和發(fā)送消息聯(lián)系起來,也就是方法的調(diào)用,這邊用父類調(diào)用方法的只有上述一個(gè)例子。
多態(tài)的好處:
1.可替換性(substitutability)。多態(tài)對(duì)已存在代碼具有可替換性。例如,多態(tài)對(duì)圓Circle類工作,對(duì)其他任何圓形幾何體,如圓環(huán),也同樣工作。
2.可擴(kuò)充性(extensibility)。多態(tài)對(duì)代碼具有可擴(kuò)充性。增加新的子類不影響已存在類的多態(tài)性、繼承性,以及其他特性的運(yùn)行和操作。實(shí)際上新加子類更容易獲得多態(tài)功能。例如,在實(shí)現(xiàn)了圓錐、半圓錐以及半球體的多態(tài)基礎(chǔ)上,很容易增添球體類的多態(tài)性。
3.接口性(interface-ability)。多態(tài)是超類通過方法簽名,向子類提供了一個(gè)共同接口,由子類來完善或者覆蓋它而實(shí)現(xiàn)的。超類Shape規(guī)定了兩個(gè)實(shí)現(xiàn)多態(tài)的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實(shí)現(xiàn)多態(tài),完善或者覆蓋這兩個(gè)接口方法。
4.靈活性(flexibility)。它在應(yīng)用中體現(xiàn)了靈活多樣的操作,提高了使用效率。
5.簡(jiǎn)化性(simplicity)。多態(tài)簡(jiǎn)化對(duì)應(yīng)用軟件的代碼編寫和修改過程,尤其在處理大量對(duì)象的運(yùn)算和操作時(shí),這個(gè)特點(diǎn)尤為突出和重要。
網(wǎng)上都有比較統(tǒng)一的答案了,這邊就不多說了
簡(jiǎn)而言之,多態(tài)可以讓我們更優(yōu)雅地寫出代碼。
多態(tài)和繼承的關(guān)系:
多態(tài)要用單一的接口去操作不同的對(duì)象。這邊的接口不是專指Java中的interface,而是泛指對(duì)象上可以操作的方法。那么一個(gè)是interface的接口實(shí)現(xiàn)(后面再說),還有一種就是從父類繼承的相同接口,然后使用該接口的不同形式,即不同版本的動(dòng)態(tài)綁定方法。面向?qū)ο蟮娜筇匦?#xff1a;封裝、繼承和多態(tài),可以說前面兩個(gè)是為最后一個(gè)多態(tài)來服務(wù)的,而且多態(tài)不能單獨(dú)來看,它只能作為類關(guān)系“全景”中的一部分,與其他特性協(xié)同工作。
3.使用碼云管理Java代碼
4.PTA實(shí)驗(yàn)
- 4-1,有什么好說的嗎?按部就班就好了。就是注意通過super來調(diào)用父類方法就好了。
- 4-2,和書面作業(yè)的第五題其實(shí)是類似的,用父類開數(shù)組,然后每個(gè)元素用子類去實(shí)例化,最后輸出,則是用到了多態(tài),因?yàn)槭峭ㄟ^父類的接口去實(shí)現(xiàn)子類的方法。
- 4-3,首先要比較的是父類的屬性,如果父類屬性不等直接返回false好了,至于父類的equals()方法怎么寫,就不關(guān)我們事了。其次就是要比較子類特有的company和salary兩個(gè)變量。只要注意company可能為null,需要特判一下,其他按照提示做下來,就A掉了。
- 4-4,這一題比較難,被卡了一會(huì)兒。這邊需要介紹一下深克隆和淺克隆的區(qū)別。首先如果都是基本數(shù)據(jù)類型,不存在深克隆和淺克隆。那么如果是對(duì)象,那么將會(huì)復(fù)制引用,而不是對(duì)象的內(nèi)容,這邊拿一張圖來做個(gè)分析:
圖片來源 csdn 詳解Java中的clone方法 -- 原型模式
在淺拷貝中,p1對(duì)p進(jìn)行拷貝,但是p1的name域和p的name域都指向同一個(gè)字符串,這樣就會(huì)存在一個(gè)問題,如果我對(duì)p的字符串進(jìn)行修改,那么p1的字符串也會(huì)發(fā)生改變。所以我們需要深拷貝,就是復(fù)制對(duì)象的內(nèi)容,而非引用。
做這道題時(shí)有幾個(gè)問題,首先clone()方法的返回值需要是當(dāng)前類,比如本例就是Car類。其次就是需要判斷對(duì)象是否為空,如果對(duì)象是空的話,就可以直接復(fù)制,這時(shí)候如果對(duì)null調(diào)用方法,就會(huì)拋出異常,所以我一開始一直都A不過去。
然后就是要注意需要用clone()方法的類需要Cloneable的接口。這個(gè)編譯器會(huì)自動(dòng)加好的0.0 - 5-4,就是按部就班按照提示去做就好了,沒什么特別的地方,用到了抽象類和繼承的思想。在父類當(dāng)中定義好抽象的方法之后,在子類當(dāng)中注意定義就好了。如果沒有定義,將還是被視作是抽象類,也就是還是要加上abstract關(guān)鍵字。至于sumAllArea()和sumAllPerimeter()方法放在主類當(dāng)中就好了,可以用。
- 5-5,這道題就更沒什么好說的了,將近一半的代碼都是自動(dòng)生成的。每一次加入都要判定之前是否已經(jīng)存在同一個(gè)對(duì)象,就要涉及到equals()方法的撰寫,稍微注意特判空就行了。
- 5-6,之前我們用了比較器Comparator,這道題我是用的是Comparable接口,只要自己撰寫compareTo()方法就好了,這道題代碼比較長(zhǎng),不過都是按部就班地做下來,主要考察的是ArrayList的使用,用Collections.sort()來完成Arraylist的排序,今天早上做題目的時(shí)候楞了一下,忘記了。
看的不過癮的請(qǐng)點(diǎn)下面
回到頂部
做Java作業(yè)砸的時(shí)間挺多的,基本上交Java作業(yè)之前都是熬夜到1點(diǎn)左右,有點(diǎn)吃不消。下周開始就是密集的比賽,時(shí)間比較緊迫,所以可能會(huì)做的比較粗糙,望諒解。不過話說回來,好好地花時(shí)間研究,看《Java編程思想》,真的收獲還是不小的。之前看一點(diǎn)就放棄了,覺得太艱深了,果然還是要結(jié)合自己在pta上做題的經(jīng)驗(yàn),然后再回過頭看書,才有用。還有中英文維基百科結(jié)合起來一起用,也會(huì)學(xué)到很多。
轉(zhuǎn)載于:https://www.cnblogs.com/ljl36/p/6561006.html
總結(jié)
以上是生活随笔為你收集整理的201521123091 《Java程序设计》第4周学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps命令显示uid而不是用户名的解决方法
- 下一篇: FastJson、Jackson、Gso