Java異常鏈表throw結(jié)構assert詳細解讀
1、異常的捕獲與處理
異常時導致程序中斷執(zhí)行的一種指令流。程序出現(xiàn)異常沒用合理處理,就會導致程序終止執(zhí)行。
觀察沒有異常產(chǎn)生的程序
public class TestDemo1{ public static void main(String args[]){ System.out.println("1、除法程序開始"); int result =10/2; System.out.println("2、除法程序結(jié)果:"+result); System.out.println("3、除法程序結(jié)束"); } } /* 1、除法程序開始 2、除法程序結(jié)果:5 3、除法程序結(jié)束 */
產(chǎn)生異常的程序
public class YiChang{ public static void main(String args[]){ System.out.println("1,除法程序開始"); int result =10/0;//會出現(xiàn)錯誤 System.out.println("2,除法程序結(jié)果:"+result); System.out.println("3,除法程序結(jié)束"); } } /* Exception in thread "main" java.lang.ArithmeticException: / by zero at YiChang.main(YiChang.java:5) */
這個時候程序出現(xiàn)了錯誤,那么出現(xiàn)錯誤之后程序不執(zhí)行了,而是直接進行了錯誤信息的輸出,并且直接結(jié)束了程序,但是,出現(xiàn)了錯誤,應該去處理才對,但是現(xiàn)在沒有處理。
1.1 處理異常
現(xiàn)在,如果希望程序出現(xiàn)了異常之后,程序依然可以正常的完成的話,那么就可以使用如下的格式進行異常的處理;
try{ 可能出現(xiàn)異常的語句 }[catch(異常類型 異常對象){ 處理異常; }catch(異常類型 異常對象){ 處理異常; }…][finally{ 異常統(tǒng)一出口 不管是否出現(xiàn)異常,都執(zhí)行此代碼; }]
使用該操作進行異常的處理
public class TestDemo1{ public static void main(String args[]){ System.out.println("1、除法程序開始"); try{ int result =10/0; System.out.println("2、除法程序結(jié)果:"+result); }catch(ArithmeticException e){ System.out.println("異常被正確的處理了"); } System.out.println("3、除法程序結(jié)束"); } } /* 1、除法程序開始 異常被正確的處理了 3、除法程序結(jié)束 */
可以發(fā)現(xiàn)加入了異常處理之后,程序之中即使有了異常,程序也可以正常執(zhí)行完畢,但是現(xiàn)在發(fā)現(xiàn),異常處理時的錯誤輸出信息和之前相比,出錯的信息不明確了,那么為了讓錯誤的信息更加完整,一般而言,都會調(diào)用printStackTrace()方法進行異常信息的打印
這個方法(printStackTrace)打印的異常信息是最完整的:
try{ int x = 10/0; //異常 System.out.println("2,除法程序結(jié)果:"+x); }catch(ArithmeticException e){ e.printStackTrace(); }
try catch finallly 操作
public class TestDemo1{ public static void main(String args[]){ System.out.println("1,除法程序開始"); try{ int x = 10/0; //異常 System.out.println("2,除法程序結(jié)果:"+x); }catch(ArithmeticException e){ e.printStackTrace(); }finally{ System.out.println("不管是否異常都會執(zhí)行"); } System.out.println("3,除法程序結(jié)束"); } }
但是,對于之前的程序現(xiàn)在又有了問題:現(xiàn)在執(zhí)行數(shù)學計算的兩個參數(shù),都是由程序默認提供,那么如果說現(xiàn)在兩個計算的參數(shù)通過初始化參數(shù)傳遞呢?
public class TestDemo2{ public static void main(String args[]){ System.out.println("1,除法程序開始"); try{ int x = Integer.parseInt(args[0]); //接收參數(shù) int y = Integer.parseInt(args[1]); //接收參數(shù) int result = x/y; System.out.println("2,除法程序結(jié)果:"+result); }catch(ArithmeticException e){ e.printStackTrace(); }finally{ System.out.println("不管是否異常都會執(zhí)行"); } System.out.println("3,除法程序結(jié)束"); } }
時候發(fā)現(xiàn),數(shù)據(jù)由外部傳送,那么在這種情況下,就有可能出現(xiàn)一下幾類問題:
執(zhí)行時不輸入?yún)?shù),ArrayIndexOutOfBoundsException,未處理。
輸入的參數(shù)不是數(shù)字,NumberFormatException,未處理。
被除數(shù)為0,ArithmeticException,已處理。
可以發(fā)現(xiàn),以上的程序?qū)嶋H上是存在三種異常,而程序之中只能處理一種,而對于不能處理的異常,發(fā)現(xiàn)程序依然會直接中斷執(zhí)行。
public class TestDemo2{ public static void main(String args[]){ System.out.println("1,除法程序開始"); try{ int x = Integer.parseInt(args[0]); //接收參數(shù) int y = Integer.parseInt(args[1]); //接收參數(shù) int result = x/y; System.out.println("2,除法程序結(jié)果:"+result); }catch(ArithmeticException e){ e.printStackTrace(); }catch(ArrayIndexOutOfBoundsException e){ e.printStackTrace(); }catch(NumberFormatException e){ e.printStackTrace(); }finally{ System.out.println("不管是否異常都會執(zhí)行"); } System.out.println("3,除法程序結(jié)束"); } }
此時,問題就來了,如果按照以上的方式一次一次的測試來進行異常類型的推斷,還不如直接編寫if…else。
1.2 異常處理的流程
以上已經(jīng)完成了異常的基本處理流程,但是也可以發(fā)現(xiàn)問題,所有的異常都像之前那樣一條條的判斷似乎是一件不可能完成的任務,因為以后肯定會接觸到一些不常見的異常信息,那么下面就必須首先研究異常的流程和結(jié)構。
首先查看兩個異常的繼承結(jié)構
ArithmeticException java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.ArithmeticException ArrayIndexOutOfBoundsException java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException
可以發(fā)現(xiàn)所有的異常類型最高的繼承類是Throwable,通過doc文檔可以發(fā)現(xiàn)Throwable下有兩個子類:
Error:指的是JVM錯誤,這個時候的程序并沒有執(zhí)行,無法處理;
Exception:指的是程序之中出現(xiàn)了錯誤信息,可以進行異常處理,主要關心Exception。
那么通過繼承關系可以發(fā)現(xiàn),肯定在進行日常處理的時候是以Exception為主,而這個時候就可以形成以下的異常處理流程。
1.3 throw關鍵字
throws關鍵字主要是在方法定義上使用的,表示的是此方法之中不進行異常處理,而交給被調(diào)用處處理。
class MyMath{ //現(xiàn)在的div()方法之中拋了一個異常出來,表示的是,所有的異常交給被調(diào)用處進行處理。 public int div(int x,int y) throws Exception{ return x/y; } } public class TestDemo3{ public static void main(String args[]){ try{ System.out.println(new MyMath().div(10,0)); }catch(Exception e){ e.printStackTrace(); } } }
在調(diào)用throws聲明方法的時候,一定要使用異常處理操作進行異常的處理,這是是屬于強制性的處理,而現(xiàn)在主方法本身也屬于方法,那么實際上在主方法上也可以繼續(xù)使用throws進行異常的拋出。
class MyMath{ //現(xiàn)在的div()方法之中拋了一個異常出來,表示的是,所有的異常交給被調(diào)用處進行處理。 public int div(int x,int y) throws Exception{ return x/y; } } public class TestDemo3{ public static void main(String args[]) throws Exception{ try{ System.out.println(new MyMath().div(10,0)); }catch(Exception e){ e.printStackTrace(); } } }
這個時候表示的是將異常繼續(xù)向上拋,交給JVM進行異常的處理。
請解釋throw和throws區(qū)別?
throw用于方法內(nèi)部表示進行手工的拋出throws主要用于方法聲明上使用,明確的告訴本方法可能產(chǎn)生的異常,同時該方法可能不處理異常。
1.4 異常處理模型
現(xiàn)在覺得有兩個內(nèi)容實在沒用finally,throw。
現(xiàn)在要求定義一個div()方法,而這個方法有如下一些要求:
在進行除法操作之前,輸出一行提示信息。
在除法操作執(zhí)行完畢后,輸出一行提示信息。
如果中間產(chǎn)生了異常,則應該交給被調(diào)用處來進行處理。
class MyMath{ public static int div(int x, int y) throws Exception{ int result = 0; //不寫catch語句的執(zhí)行流程 //首先進行try代碼塊的執(zhí)行后執(zhí)行finally代碼塊執(zhí)行完成后執(zhí)行 //throws進行異常捕獲,捕獲完成后再主方法catch語句中進行執(zhí)行 try{ System.out.println("before進行除法計算"); result = x / y; }finally{ System.out.println("after進行除法計算"); } return result; } } public class TestDemo4{ public static void main(String args[]){ try{ System.out.println(MyMath.div(10,0)); }catch(Exception e){ e.printStackTrace(); } } }
1.5 RuntimeException
public class TestDemo4{ public static void main(String args[]){ String str = "123"; int num = Integer.parseInt(str); System.out.println(num*num); } }
這個方法就是將一個字符串變?yōu)榱嘶緮?shù)據(jù)類型,而后執(zhí)行乘法操作,但是下面來看一下parseInt()方法的定義:
Public static int parseInt(String s) throws NumberFomatException
發(fā)現(xiàn)這個方法上拋出了一個NumberFomatException的異常,按照之前所講,如果存在了throw,則必須使用try….catch進行處理,可是現(xiàn)在去沒有強制要求處理,來觀察一下NumberFomatException的繼承結(jié)構。
java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.NumberFormatException
發(fā)現(xiàn)NumberFormatException屬于RuntimeException的子類,而在Java之中明確規(guī)定了,對于RuntimeException的異常類型可以有選擇型的來進行處理,在開發(fā)之中,如果,沒有處理,那么出現(xiàn)異常之后將交給JVM默認進行處理。
Exception和RuntimeException的區(qū)別?請你舉出常見的RuntimeException?
- Exception是RuntimeException的父類,使用Exception定義的異常必須使用異常處理
- RuntimeException可以由用戶選擇性的異常處理
- 常見的Exception:NumberFormatException,ClassCastException,NullPointException,ArithmeticException,ArrayIndexOutBoundException。
1.6 斷言:assert
斷言指的是程序執(zhí)行到某行之后,其結(jié)果一定是預期的結(jié)果,而在JDK1.4之后增加了一個assert關鍵字。
public class DuanYan{ public static void main(String args[]){ int x = 10; //假設經(jīng)過了很多操作 assert x == 30:"x的內(nèi)容不是三十"; System.out.println(x); }}
默認情況下,Java之中的斷言不會在正常執(zhí)行的代碼中出現(xiàn),如果想要啟用斷言,則應該早呢更加一些選項。
1.7 自定義異常
在Java之中本省已經(jīng)提供了大量的異常類型,但是在開發(fā)之中,這些異常類型根本就不能滿足開發(fā)的需要,所以在一些系統(tǒng)架構之中往往會提供一些新的異常類型,來表示一些特殊的錯誤,而這種操作就稱為自定義異常類,而要想實現(xiàn)這種自定義異常類,那么可以讓一個類繼承Exception或RuntimeException。
class MyException extends Exception{ public MyException(String str){ super(str); }}public class TestDemo5{ public static void main(String args[]) throws Exception{ throw new MyException("自己的異常類"); }}
如果以后見到了一些沒見過的異常類型,那么基本都是自定義的異常類。
2、鏈表
鏈表是一種基本的數(shù)據(jù)結(jié)構,但好似對于數(shù)據(jù)結(jié)構的部分,強調(diào)一下幾點:
在整個Java開發(fā)領域之中,沒有一本書去真正講解數(shù)據(jù)結(jié)構的書,只能去看C語言的數(shù)據(jù)結(jié)構:在所有開發(fā)之中,都會存在數(shù)據(jù)結(jié)構的身影,可以這樣去解釋:數(shù)據(jù)結(jié)構的精通與否,完全決定于以后。數(shù)據(jù)結(jié)構的核心:引用數(shù)據(jù)類型操作。
鏈表實際上可以理解為遺傳數(shù)據(jù),或者按照專業(yè)性的說法,可以理解為動態(tài)的對象數(shù)組,對象數(shù)組的最大優(yōu)點:是表示“多”的概念,例如:多個雇員。但是傳統(tǒng)的對象數(shù)組有一個最大的問題在于,里面保存的數(shù)據(jù)長度是固定的。思考:如果現(xiàn)在想要擴大一個對象數(shù)組的范圍?
建立一個新的對象數(shù)組,而后將原本的內(nèi)容拷貝到新的數(shù)組之中,再改變原數(shù)組的引用方式。
public class TestLinkDemo{ public static void main(String args[]){ Object ob[] = new Object [3]; } }
但是再實際的開發(fā)之中,要面臨的一個問題是:數(shù)組是一個定長的線性結(jié)構,也就是說雖然以上代碼可以滿足于存放多個內(nèi)容,但是一旦我們呢的內(nèi)容不足或者是內(nèi)容過多,可能會導致資源的浪費。要想解決此類問題最好的做法就是不定義一個固定長度的數(shù)組 ,有多少數(shù)據(jù)就保存多少數(shù)據(jù)。
2.1 鏈表基本的結(jié)構
class Node{//因為只有Node類才可以在保存數(shù)據(jù)的同時設置數(shù)據(jù) private Object data;//真正要保存的數(shù)據(jù) private Node next;//定義下一個節(jié)點 public Node(Object data){ this.data = data; } public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; } public void setNext(Node next){ this.next = next; } public Node getNext(){ return this.next; } } public class TestLinkDemo{ public static void main(String args[]){ //1.封裝幾個節(jié)點 Node root = new Node("火車頭"); Node n1 = new Node("車廂1"); Node n2 = new Node("車廂2"); Node n3 = new Node("車廂3"); //2.設置節(jié)點關系 root.setNext(n1); n1.setNext(n2); n2.setNext(n3); //3.輸出鏈表 print(root); } public static void print(Node node){ if(node != null){//表示當前是有節(jié)點的 System.out.println(node.getData()); print(node.getNext());//繼續(xù)向下取出 } } }
在整個鏈表的實現(xiàn)過程中,Node類的作用:保存數(shù)據(jù)和保存下一個節(jié)點,但是我們發(fā)現(xiàn)客戶端需要自己來進行節(jié)點的創(chuàng)建操作以及關系的配置。所謂的鏈表就是需要有一個單獨的類,假設叫Link,通過Link類來實現(xiàn)Node的數(shù)據(jù)保存和關系處理。
2.2 鏈表實現(xiàn)結(jié)構說明
通過之前的分析,可以發(fā)現(xiàn)鏈表的最大作用類就是Node,但是以上程序都是由用戶自己去匹配節(jié)點關系的,但是這些節(jié)點的匹配工作不應該由用戶完成,應該由一個程序?qū)iT去負責。
那么專門負責幾點操作的類,就成為鏈表類——Link,負責處理幾點關系,而用戶不用關心節(jié)點的問題,只需關心Link的處理操作即可。
真實開發(fā)——標準過程
class Link{//負責對鏈表的操作 //將Node定義內(nèi)部類,表示Node類只能為Link類提供服務 private class Node{//負責數(shù)據(jù)與節(jié)點的關系匹配 private Object data;//真正要保存的數(shù)據(jù) private Node next;//定義下一個節(jié)點 public Node(Object data){ this.data = data; } public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; } } //以下為Link類 } public class TestLinkDemo{ public static void main(String args[]){ } }
2.3 增加鏈表數(shù)據(jù)—public void add(數(shù)據(jù))
通過上面程序的分析,可以發(fā)下,對于鏈表的實現(xiàn),Node類是整個操作的關鍵,但是首先來研究一下之前程序的問題:Node是一個單獨的類是可以被用戶直接使用的,但是這個類由用戶直接去使用,沒有任何意義,即:這個類有用,但不能讓用戶去使用,讓Link類去使用。
class Link{//負責對鏈表的操作 //將Node定義內(nèi)部類,表示Node類只能為Link類提供服務 private class Node{//負責數(shù)據(jù)與節(jié)點的關系匹配 private Object data;//真正要保存的數(shù)據(jù) private Node next;//定義下一個節(jié)點 public Node(Object data){ this.data = data; } public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; } public void setNext(Node next){ this.next = next; } public Node getNext(){ return this.next; } //第一次調(diào)用:this = Link.root //第二次調(diào)用:this = Link.root.next //第三次調(diào)用:this = Link.root.next.next public void addNode(Node newNode){//處理節(jié)點關系 if(this.next == null){ //當前節(jié)點下一個為空 this.next = newNode; }else{//當前節(jié)點的下一個不為空 this.next.addNode(newNode); } } public void nodePrint(){ System.out.println(this.getData()); if (this.getNext()==null) { return; }else{ this.getNext().nodePrint(); } } } //以下為Link類------------------------------------------------ private Node root; //屬于根節(jié)點,沒有根節(jié)點就無法數(shù)據(jù)的保存 //增加數(shù)據(jù) public void add(Object data){ if(data == null){//人為追加規(guī)定,不允許存放null值 return ;//結(jié)束方法調(diào)用 } //如果要想進行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面 //如果沒有封裝,則無法確認好節(jié)點的先后順序 Node newNode = new Node(data); if(this.root == null){ this.root = newNode;//第一個節(jié)點設置為根節(jié)點 }else{//根節(jié)點存在了 this.root.addNode(newNode); } } //輸出數(shù)據(jù) public void print(){ if (this.root == null){ return; } System.out.println(this.root.getData()); if (this.root.getNext()==null){ return; } else{ this.root.getNext().nodePrint(); } } } public class TestLinkDemo1{ public static void main(String args[]){ Link link = new Link(); link.add("Hello"); link.add("World"); link.print(); } }
2.4 增加多個數(shù)據(jù)—public void addAll(數(shù)據(jù)數(shù)組)
public void addAll(String date[]){ for(int x = 0;x<date.length;x++){ this.add(date[x]); } }
2.5 統(tǒng)計數(shù)據(jù)個數(shù)—public int size()
在Link類中定義
private int count;//統(tǒng)計個數(shù)
在增加數(shù)據(jù)的最后一行添加count++
public void add(Object data){ if(data == null){//人為追加規(guī)定,不允許存放null值 return ;//結(jié)束方法調(diào)用 } //如果要想進行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面 //如果沒有封裝,則無法確認好節(jié)點的先后順序 Node newNode = new Node(data); if(this.root == null){ this.root = newNode;//第一個節(jié)點設置為根節(jié)點 }else{//根節(jié)點存在了 this.root.addNode(newNode); } count++; }
2.6 鏈表數(shù)據(jù)轉(zhuǎn)換為對象數(shù)組—public Object[] toArray()
對于鏈表的這種數(shù)據(jù)結(jié)構,最為關鍵的是兩個操作:刪除和取得全部數(shù)據(jù)。
在Link類中定義一個操作數(shù)組的腳標:
private int foot = 0;
要把數(shù)據(jù)保存的數(shù)組,Link類和Node類都需要使用,那么可以在Link類中定義返回數(shù)組,必須以屬性的形式出現(xiàn),只有這樣,Node類才可以訪問這個數(shù)組并進行操作。
private Object [] retData ; //返回類型
在Link類中增加toArray()方法:
//鏈表數(shù)據(jù)轉(zhuǎn)換為對象數(shù)組 public Object[] toArray(){ if(this.count == 0){ return null; } this.retData = new Object[this.count]; this.root.toArrayNode(); this.foot = 0;//下表清零操作 return this.retData; }
在Node中增加toArrayNode()方法:
public void toArrayNode(){ Link.this.retData[Link.this.foot++] = this.data; if(this.next != null){ this.next.toArrayNode(); } }
不過按照以上的方式進行開發(fā),每一次調(diào)用toArray()方法,都要重復的進行數(shù)據(jù)的的遍歷,如果在數(shù)據(jù)沒有修改的情況下,這種做法是一種低效的做法,最好的方法是增加一個修改標記,如果發(fā)現(xiàn)數(shù)據(jù)增加了或刪除的話,表示要重新遍歷數(shù)據(jù)。
2.7 鏈表查詢數(shù)據(jù)—public boolean contains(查找對象)
現(xiàn)在如果想查詢某個數(shù)據(jù)是否存在,那么基本的操作原理:逐個盤查,盤查的具體對象應該交給Node去完成,前提是:有數(shù)據(jù)存在。
在Link類之中,增加查詢操作:
//查找鏈表的指定數(shù)據(jù)是否存在 public boolean contains(Object search){ if(search == null && this.root == null) return false; return this.root.containsNode(search); }
在Node類中,完成具體查詢,查詢流程為:
判斷當前節(jié)點的內(nèi)容是否滿足于查詢內(nèi)容,如果滿足返回ture;
如果當前節(jié)點內(nèi)容不滿足,則向后繼續(xù)查詢,如果沒有后續(xù)節(jié)點了,則返回false。
public boolean containsNode(Object search){ if(search.equals(this.data)) return true; else{ if(this.next != null){//判斷下一個節(jié)點是否為空 return this.next.containsNode(search); } return false; } }
2.8 根據(jù)索引取得數(shù)據(jù)—public Object get(int index)
在一個鏈表之中會有多個節(jié)點保存數(shù)據(jù),現(xiàn)在要求可以取得指定節(jié)點的數(shù)據(jù)。但是在進行這一操作的過程之中,有一個小問題:如果要取得數(shù)據(jù)的索引超過了數(shù)據(jù)的保存?zhèn)€數(shù),那么是無法取得的。
在Link類之中增加一個get(int index)方法:
//根據(jù)索引取得數(shù)據(jù) public Object get(int index){ if(index >= this.count){ return null; } this.foot = 0; return this.root.getNode(index); }
在Node類之中增加一個getNdoe(int index)方法:
//第一次this == Link.root //第二次this == Link.root.next public Object getNode(int index){ if(Link.this.foot++ == index){ return this.data; }else{ return this.next.getNode(index); } }
2.9 修改指定索引數(shù)據(jù)—public void set(int index,Object newData)
如果修改數(shù)據(jù)只需要進行數(shù)據(jù)的替換。
在Link類之中增加一個set(int index,Object newData)方法:
//修改指定索引數(shù)據(jù) public void set(int index,Object newData){ if(index >= this.count){ return ; } this.foot = 0; this.root.setNode(index,newData); }
在Node類之中增加一個getNode(int index)方法:
public void setNode(int index, Object newData){ if(Link.this.foot ++ == index){//索引相同 this.data = newData; }else{ if(this.next != null){ this.next.setNode(index,newData); } } }
2.10 刪除數(shù)據(jù)—public void remove(數(shù)據(jù))
對于鏈表之中的內(nèi)容,之前完成的是增加操作和查詢操作,但是從鏈表之中也會存在刪除數(shù)據(jù)的操作,可是刪除數(shù)據(jù)的操作要分為兩種情況討論:
情況一:刪除的數(shù)據(jù)不是根節(jié)點,待刪節(jié)點的上一個next指向待刪節(jié)點的next。
所有的處理操作應該交給Node進行處理。
情況二:刪除的數(shù)據(jù)是根節(jié)點,下一個節(jié)點保存為跟節(jié)點。
如果刪除的是根節(jié)點,意味著Link中的根節(jié)點的保存需要發(fā)生變化,該操作主要在Link中處理。
在Link中增加一個刪除remove(Object data)方法
//刪除數(shù)據(jù) public void remove(Object data){ if(this.contains(data)){//如果數(shù)據(jù)存在則進行數(shù)據(jù)處理 if(this.root.data.equals(data)){//首先需要判斷要刪除的數(shù)據(jù)是否為根節(jié)點數(shù)據(jù) this.root = this.root.next;//根節(jié)點變?yōu)橄乱粋€節(jié)點 }else{//不是根節(jié)點 this.root.next.removeNode(this.root,data); } this.count --; } }
在Node類之中增加一個removeNode(Node previous, Object data)方法:
//第一次:this = Link.root.next、previous= Link.root; //第二次:this = Link.root.next.next、previous= Link.root.next; public void removeNode(Node previous, Object data){ if(this.data.equals(data)){//當前節(jié)點為要刪除的節(jié)點 previous.next = this.next; }else{ this.next.removeNode(this,data); } }
Link鏈表類模板
class Link{//負責鏈表的操作 //將Node定義內(nèi)部類,表示Node類只能為Link類提供服務 private class Node{//負責數(shù)據(jù)與節(jié)點的關系匹配 private Object data;//真正要保存的數(shù)據(jù) private Node next;//定義下一個節(jié)點 public Node(Object data){ this.data = data; } public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; } public void setNext(Node next){ this.next = next; } public Node getNext(){ return this.next; } //第一次調(diào)用:this = Link.root //第二次調(diào)用:this = Link.root.next //第三次調(diào)用:this = Link.root.next.next public void addNode(Node newNode){//處理節(jié)點關系 if(this.next == null){ //當前節(jié)點下一個為空 this.next = newNode; }else{//當前節(jié)點的下一個不為空 this.next.addNode(newNode); } } public void nodePrint(){ System.out.println(this.getData()); if (this.getNext()==null) { return; }else{ this.getNext().nodePrint(); } } public void toArrayNode(){ Link.this.retData[Link.this.foot++] = this.data; if(this.next != null){ this.next.toArrayNode(); } } public boolean containsNode(Object search){ if(search.equals(this.data)) return true; else{ if(this.next != null){//判斷下一個節(jié)點是否為空 return this.next.containsNode(search); } return false; } } //第一次this == Link.root //第二次this == Link.root.next public Object getNode(int index){ if(Link.this.foot++ == index){ return this.data; }else{ return this.next.getNode(index); } } public void setNode(int index, Object newData){ if(Link.this.foot ++ == index){//索引相同 this.data = newData; }else{ if(this.next != null){ this.next.setNode(index,newData); } } } //第一次:this = Link.root.next、previous= Link.root; //第二次:this = Link.root.next.next、previous= Link.root.next; public void removeNode(Node previous, Object data){ if(this.data.equals(data)){//當前節(jié)點為要刪除的節(jié)點 previous.next = this.next; }else{ this.next.removeNode(this,data); } } } //以下為Link類------------------------------------------------ private Object [] retData ; //返回類型 private int foot = 0;//操作下標 private int count;//統(tǒng)計個數(shù) private Node root; //屬于根節(jié)點,沒有根節(jié)點就無法數(shù)據(jù)的保存 //增加數(shù)據(jù) public void add(Object data){ if(data == null){//人為追加規(guī)定,不允許存放null值 return ;//結(jié)束方法調(diào)用 } //如果要想進行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面 //如果沒有封裝,則無法確認好節(jié)點的先后順序 Node newNode = new Node(data); if(this.root == null){ this.root = newNode;//第一個節(jié)點設置為根節(jié)點 }else{//根節(jié)點存在了 this.root.addNode(newNode); } count++; } //判斷鏈表是否為空 public boolean isEmpty(){ this.count=0; return false; } //增加多個數(shù)據(jù) public void addAll(String date[]){ for(int x = 0;x<date.length;x++){ this.add(date[x]); } } public int size(){ return this.count; } //輸出數(shù)據(jù) public void print(){ if (this.root == null){ return; } System.out.println(this.root.getData()); if (this.root.getNext()==null){ return; } else{ this.root.getNext().nodePrint(); } } //鏈表數(shù)據(jù)轉(zhuǎn)換為對象數(shù)組 public Object[] toArray(){ if(this.count == 0){ return null; } this.retData = new Object[this.count]; this.root.toArrayNode(); this.foot = 0;//下表清零操作 return this.retData; } //查找鏈表的指定數(shù)據(jù)是否存在 public boolean contains(Object search){ if(search == null && this.root == null) return false; return this.root.containsNode(search); } //根據(jù)索引取得數(shù)據(jù) public Object get(int index){ if(index >= this.count){ return null; } this.foot = 0; return this.root.getNode(index); } //修改指定索引數(shù)據(jù) public void set(int index,Object newData){ if(index >= this.count){ return ; } this.foot = 0; this.root.setNode(index,newData); } //刪除數(shù)據(jù) public void remove(Object data){ if(this.contains(data)){//如果數(shù)據(jù)存在則進行數(shù)據(jù)處理 if(this.root.data.equals(data)){//首先需要判斷要刪除的數(shù)據(jù)是否為根節(jié)點數(shù)據(jù) this.root = this.root.next;//根節(jié)點變?yōu)橄乱粋€節(jié)點 }else{//不是根節(jié)點 this.root.next.removeNode(this.root,data); } this.count --; } } }
綜合案例
建立寵物商店,包括銷售寵物上架、下架、關鍵字查詢,要求程序的關系即可,對于寵物的信息只要有三項:名字、年齡、顏色。
對應的關系:一個寵物商店有多種寵物,如果按照表設計應該屬于一對多關系映射,但是現(xiàn)在問題,一方是寵物商店,多方是寵物,但是寵物又分為貓、狗、豬、驢、魚等。
1、建立寵物標準
interface Pet{//定義寵物 public String getName(); public String getColor(); public int getAge(); }
2、對于寵物商店,只關注于寵物的標準,而不關心具體是那種寵物
class PetShop{ private Link pets = new Link();//開辟一個鏈表,保存寵物信息 public void add(Pet pet){//上架寵物 this.pets.add(pet); } public void delete(Pet pet){//下架寵物 this.pets.delete(pet); } public Link getPets(){ //得到全部寵物 return this.pets; } public Link search(String keyword){//關鍵字查找 Link result = new Link(); Object [] data = this.pets.toArray(); for(int i = 0; i < data.length ; i++){ Pet pet = (Pet) data[i]; if(pet.getName().contains(keyword) || pet.getColor().contains(keyword)){ result.add(pet); //滿足查詢結(jié)果 } } return result; } }
3、定義寵物狗
class Dog implements Pet{ private String name; private String color; private int age; public String getName(){ return this.name; } public String getColor(){ return this.color; } public boolean equals(Object obj){ if(obj == null){ return false; } if(this == obj){ return false; } if(!(obj instanceof Dog)){ return false; } Dog pet = (Dog) obj; return this.name.equals(pet.name) && this.color.equals(pet.color) && this.age.equals(pet.age); } public int getAge(){ return this.age; } public Dog(String name, String color, int age){ this.name = name ; this.color = color; this.age = age; } public String toString(){ return "【狗】名字 = " + this.name + "顏色 = " + this.color + "年齡 = " +this.age; } }
4、定義寵物貓
class Cat implements Pet{ private String name; private String color; private int age; public String getName(){ return this.name; } public String getColor(){ return this.color; } public boolean equals(Object obj){ if(obj == null){ return false; } if(this == obj){ return false; } if(!(obj instanceof Cat)){ return false; } Cat pet = (Cat) obj; return this.name.equals(pet.name) && this.color.equals(pet.color) && this.age.equals(pet.age); } public int getAge(){ return this.age; } public Cat(String name, String color, int age){ this.name = name ; this.color = color; this.age = age; } public String toString(){ return "【貓】名字 = " + this.name + "顏色 = " + this.color + "年齡 = " +this.age; } }
5、測試類
public class Pets{ public static void main(String args[]){ PetShop ps = new PetShop(); ps.add(new Dog("小黑","黑色",1)); ps.add(new Dog("金毛","金色",2)); ps.add(new Dog("拉布拉多","白色",3)); ps.add(new Dog("薩摩耶","白色",2)); ps.add(new Cat("加菲貓","黃色",3)); ps.add(new Dog("波斯貓","金色",4)); ps.delete(new Dog("薩摩耶","白色",2)); Link all = ps.search("白"); Object [] data = all.toArray(); for(int i = 0 ; i < data.length ; i++){ System.out.println(data[i]); } } }
6、完整代碼
class Link{//負責鏈表的操作 //將Node定義內(nèi)部類,表示Node類只能為Link類提供服務 private class Node{//負責數(shù)據(jù)與節(jié)點的關系匹配 private Object data;//真正要保存的數(shù)據(jù) private Node next;//定義下一個節(jié)點 public Node(Object data){ this.data = data; } public void setData(Object data){ this.data = data; } public Object getData(){ return this.data; } public void setNext(Node next){ this.next = next; } public Node getNext(){ return this.next; } //第一次調(diào)用:this = Link.root //第二次調(diào)用:this = Link.root.next //第三次調(diào)用:this = Link.root.next.next public void addNode(Node newNode){//處理節(jié)點關系 if(this.next == null){ //當前節(jié)點下一個為空 this.next = newNode; }else{//當前節(jié)點的下一個不為空 this.next.addNode(newNode); } } public void nodePrint(){ System.out.println(this.getData()); if (this.getNext()==null) { return; }else{ this.getNext().nodePrint(); } } public void toArrayNode(){ Link.this.retData[Link.this.foot++] = this.data; if(this.next != null){ this.next.toArrayNode(); } } public boolean containsNode(Object search){ if(search.equals(this.data)) return true; else{ if(this.next != null){//判斷下一個節(jié)點是否為空 return this.next.containsNode(search); } return false; } } //第一次this == Link.root //第二次this == Link.root.next public Object getNode(int index){ if(Link.this.foot++ == index){ return this.data; }else{ return this.next.getNode(index); } } public void setNode(int index, Object newData){ if(Link.this.foot ++ == index){//索引相同 this.data = newData; }else{ if(this.next != null){ this.next.setNode(index,newData); } } } //第一次:this = Link.root.next、previous= Link.root; //第二次:this = Link.root.next.next、previous= Link.root.next; public void removeNode(Node previous, Object data){ if(this.data.equals(data)){//當前節(jié)點為要刪除的節(jié)點 previous.next = this.next; }else{ this.next.removeNode(this,data); } } } //以下為Link類------------------------------------------------ private Object [] retData ; //返回類型 private int foot = 0;//操作下標 private int count;//統(tǒng)計個數(shù) private Node root; //屬于根節(jié)點,沒有根節(jié)點就無法數(shù)據(jù)的保存 //增加數(shù)據(jù) public void add(Object data){ if(data == null){//人為追加規(guī)定,不允許存放null值 return ;//結(jié)束方法調(diào)用 } //如果要想進行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面 //如果沒有封裝,則無法確認好節(jié)點的先后順序 Node newNode = new Node(data); if(this.root == null){ this.root = newNode;//第一個節(jié)點設置為根節(jié)點 }else{//根節(jié)點存在了 this.root.addNode(newNode); } count++; } //判斷鏈表是否為空 public boolean isEmpty(){ this.count=0; return false; } //增加多個數(shù)據(jù) public void addAll(String date[]){ for(int x = 0;x<date.length;x++){ this.add(date[x]); } } public int size(){ return this.count; } //輸出數(shù)據(jù) public void print(){ if (this.root == null){ return; } System.out.println(this.root.getData()); if (this.root.getNext()==null){ return; } else{ this.root.getNext().nodePrint(); } } //鏈表數(shù)據(jù)轉(zhuǎn)換為對象數(shù)組 public Object[] toArray(){ if(this.count == 0){ return null; } this.retData = new Object[this.count]; this.root.toArrayNode(); this.foot = 0;//下表清零操作 return this.retData; } //查找鏈表的指定數(shù)據(jù)是否存在 public boolean contains(Object search){ if(search == null && this.root == null) return false; return this.root.containsNode(search); } //根據(jù)索引取得數(shù)據(jù) public Object get(int index){ if(index >= this.count){ return null; } this.foot = 0; return this.root.getNode(index); } //修改指定索引數(shù)據(jù) public void set(int index,Object newData){ if(index >= this.count){ return ; } this.foot = 0; this.root.setNode(index,newData); } //刪除數(shù)據(jù) public void remove(Object data){ if(this.contains(data)){//如果數(shù)據(jù)存在則進行數(shù)據(jù)處理 if(this.root.data.equals(data)){//首先需要判斷要刪除的數(shù)據(jù)是否為根節(jié)點數(shù)據(jù) this.root = this.root.next;//根節(jié)點變?yōu)橄乱粋€節(jié)點 }else{//不是根節(jié)點 this.root.next.removeNode(this.root,data); } this.count --; } } } interface Pet{//定義寵物 public String getName(); public String getColor(); public int getAge(); } class PetShop{ private Link pets = new Link();//開辟一個鏈表,保存寵物信息 public void add(Pet pet){//上架寵物 this.pets.add(pet); } public void delete(Pet pet){//下架寵物 this.pets.remove(pet); } public Link getPets(){ //得到全部寵物 return this.pets; } public Link search(String keyword){//關鍵字查找 Link result = new Link(); Object [] data = this.pets.toArray(); for(int i = 0; i < data.length ; i++){ Pet pet = (Pet) data[i]; if(pet.getName().contains(keyword) || pet.getColor().contains(keyword)){ result.add(pet); //滿足查詢結(jié)果 } } return result; } } class Dog implements Pet{ private String name; private String color; private int age; public String getName(){ return this.name; } public String getColor(){ return this.color; } public boolean equals(Object obj){ if(obj == null){ return false; } if(this == obj){ return false; } if(!(obj instanceof Dog)){ return false; } Dog pet = (Dog) obj; return this.name.equals(pet.name) && this.color.equals(pet.color) && this.age == pet.age; } public int getAge(){ return this.age; } public Dog(String name, String color, int age){ this.name = name ; this.color = color; this.age = age; } public String toString(){ return "【狗】名字 = " + this.name + ",顏色 = " + this.color + ",年齡 = " +this.age; } } class Cat implements Pet{ private String name; private String color; private int age; public String getName(){ return this.name; } public String getColor(){ return this.color; } public boolean equals(Object obj){ if(obj == null){ return false; } if(this == obj){ return false; } if(!(obj instanceof Cat)){ return false; } Cat pet = (Cat) obj; return this.name.equals(pet.name) && this.color.equals(pet.color) && this.age == pet.age; } public int getAge(){ return this.age; } public Cat(String name, String color, int age){ this.name = name ; this.color = color; this.age = age; } public String toString(){ return "【貓】名字 = " + this.name + ",顏色 = " + this.color + ",年齡 = " +this.age; } } public class Pets{ public static void main(String args[]){ PetShop ps = new PetShop(); ps.add(new Dog("小黑","黑色",1)); ps.add(new Dog("金毛","金色",2)); ps.add(new Dog("拉布拉多","白色",3)); ps.add(new Dog("薩摩耶","白色",2)); ps.add(new Cat("加菲貓","黃色",3)); ps.add(new Dog("波斯貓","金色",4)); ps.delete(new Dog("薩摩耶","白色",2)); Link all = ps.search("白"); Object [] data = all.toArray(); for(int i = 0 ; i < data.length ; i++){ System.out.println(data[i]); } } }
到此這篇關于Day10基礎不牢地動山搖-Java基礎的文章就介紹到這了,更多相關Java基礎內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringSecurity實現(xiàn)自定義登錄接口的詳細過程
本文詳細介紹了如何使用SpringSecurity實現(xiàn)自定義登錄接口,文章還涉及了對用戶實體類的增強以滿足詳細信息的需求,適合需要深入了解和實現(xiàn)SpringSecurity自定義登錄功能的開發(fā)者,感興趣的朋友跟隨小編一起看看吧2024-10-10Maven中dependency和plugins的繼承與約束
這篇文章主要介紹了Maven中dependency和plugins的繼承與約束,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12SpringBoot?整合MyBatis+MyBatis-Plus+MyBatisX插件使用
本文主要介紹了SpringBoot?整合MyBatis+MyBatis-Plus+MyBatisX插件使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-04-04Lombok同時使?@Data和@Builder踩坑總結(jié)
這篇文章主要介紹了Lombok同時使?@Data和@Builder踩坑總結(jié),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下,希望對你的學習有所幫助2022-05-05詳解Java中多線程異常捕獲Runnable的實現(xiàn)
這篇文章主要介紹了詳解Java中多線程異常捕獲Runnable的實現(xiàn)的相關資料,希望通過本文能幫助到大家,讓大家理解掌握這樣的知識,需要的朋友可以參考下2017-10-10springboot接口如何多次獲取request中的body內(nèi)容
這篇文章主要介紹了springboot接口多次獲取request中的body內(nèi)容的過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Spring MVC獲取HTTP請求頭的兩種方式小結(jié)
這篇文章主要介紹了Spring MVC獲取HTTP請求頭的兩種方式小結(jié),幫助大家更好的理解和使用Spring MVC,感興趣的朋友可以了解下2021-01-01