Java異常鏈表throw結(jié)構(gòu)assert詳細(xì)解讀
1、異常的捕獲與處理
異常時(shí)導(dǎo)致程序中斷執(zhí)行的一種指令流。程序出現(xiàn)異常沒用合理處理,就會(huì)導(dǎo)致程序終止執(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;//會(huì)出現(xiàn)錯(cuò)誤
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)
*/
這個(gè)時(shí)候程序出現(xiàn)了錯(cuò)誤,那么出現(xiàn)錯(cuò)誤之后程序不執(zhí)行了,而是直接進(jìn)行了錯(cuò)誤信息的輸出,并且直接結(jié)束了程序,但是,出現(xiàn)了錯(cuò)誤,應(yīng)該去處理才對,但是現(xiàn)在沒有處理。
1.1 處理異常
現(xiàn)在,如果希望程序出現(xiàn)了異常之后,程序依然可以正常的完成的話,那么就可以使用如下的格式進(jìn)行異常的處理;
try{
可能出現(xiàn)異常的語句
}[catch(異常類型 異常對象){
處理異常;
}catch(異常類型 異常對象){
處理異常;
}…][finally{
異常統(tǒng)一出口
不管是否出現(xiàn)異常,都執(zhí)行此代碼;
}]
使用該操作進(jìn)行異常的處理
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),異常處理時(shí)的錯(cuò)誤輸出信息和之前相比,出錯(cuò)的信息不明確了,那么為了讓錯(cuò)誤的信息更加完整,一般而言,都會(huì)調(diào)用printStackTrace()方法進(jìn)行異常信息的打印
這個(gè)方法(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("不管是否異常都會(huì)執(zhí)行");
}
System.out.println("3,除法程序結(jié)束");
}
}
但是,對于之前的程序現(xiàn)在又有了問題:現(xiàn)在執(zhí)行數(shù)學(xué)計(jì)算的兩個(gè)參數(shù),都是由程序默認(rèn)提供,那么如果說現(xiàn)在兩個(gè)計(jì)算的參數(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("不管是否異常都會(huì)執(zhí)行");
}
System.out.println("3,除法程序結(jié)束");
}
}
時(shí)候發(fā)現(xiàn),數(shù)據(jù)由外部傳送,那么在這種情況下,就有可能出現(xiàn)一下幾類問題:
執(zhí)行時(shí)不輸入?yún)?shù),ArrayIndexOutOfBoundsException,未處理。
輸入的參數(shù)不是數(shù)字,NumberFormatException,未處理。
被除數(shù)為0,ArithmeticException,已處理。
可以發(fā)現(xiàn),以上的程序?qū)嶋H上是存在三種異常,而程序之中只能處理一種,而對于不能處理的異常,發(fā)現(xiàn)程序依然會(huì)直接中斷執(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("不管是否異常都會(huì)執(zhí)行");
}
System.out.println("3,除法程序結(jié)束");
}
}
此時(shí),問題就來了,如果按照以上的方式一次一次的測試來進(jìn)行異常類型的推斷,還不如直接編寫if…else。
1.2 異常處理的流程
以上已經(jīng)完成了異常的基本處理流程,但是也可以發(fā)現(xiàn)問題,所有的異常都像之前那樣一條條的判斷似乎是一件不可能完成的任務(wù),因?yàn)橐院罂隙〞?huì)接觸到一些不常見的異常信息,那么下面就必須首先研究異常的流程和結(jié)構(gòu)。
首先查看兩個(gè)異常的繼承結(jié)構(gòu)
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下有兩個(gè)子類:
Error:指的是JVM錯(cuò)誤,這個(gè)時(shí)候的程序并沒有執(zhí)行,無法處理;
Exception:指的是程序之中出現(xiàn)了錯(cuò)誤信息,可以進(jìn)行異常處理,主要關(guān)心Exception。
那么通過繼承關(guān)系可以發(fā)現(xiàn),肯定在進(jìn)行日常處理的時(shí)候是以Exception為主,而這個(gè)時(shí)候就可以形成以下的異常處理流程。
1.3 throw關(guān)鍵字
throws關(guān)鍵字主要是在方法定義上使用的,表示的是此方法之中不進(jìn)行異常處理,而交給被調(diào)用處處理。
class MyMath{
//現(xiàn)在的div()方法之中拋了一個(gè)異常出來,表示的是,所有的異常交給被調(diào)用處進(jìn)行處理。
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聲明方法的時(shí)候,一定要使用異常處理操作進(jìn)行異常的處理,這是是屬于強(qiáng)制性的處理,而現(xiàn)在主方法本身也屬于方法,那么實(shí)際上在主方法上也可以繼續(xù)使用throws進(jìn)行異常的拋出。
class MyMath{
//現(xiàn)在的div()方法之中拋了一個(gè)異常出來,表示的是,所有的異常交給被調(diào)用處進(jìn)行處理。
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();
}
}
}
這個(gè)時(shí)候表示的是將異常繼續(xù)向上拋,交給JVM進(jìn)行異常的處理。
請解釋throw和throws區(qū)別?
throw用于方法內(nèi)部表示進(jìn)行手工的拋出throws主要用于方法聲明上使用,明確的告訴本方法可能產(chǎn)生的異常,同時(shí)該方法可能不處理異常。
1.4 異常處理模型
現(xiàn)在覺得有兩個(gè)內(nèi)容實(shí)在沒用finally,throw。
現(xiàn)在要求定義一個(gè)div()方法,而這個(gè)方法有如下一些要求:
在進(jìn)行除法操作之前,輸出一行提示信息。
在除法操作執(zhí)行完畢后,輸出一行提示信息。
如果中間產(chǎn)生了異常,則應(yīng)該交給被調(diào)用處來進(jìn)行處理。
class MyMath{
public static int div(int x, int y) throws Exception{
int result = 0;
//不寫catch語句的執(zhí)行流程
//首先進(jìn)行try代碼塊的執(zhí)行后執(zhí)行finally代碼塊執(zhí)行完成后執(zhí)行
//throws進(jìn)行異常捕獲,捕獲完成后再主方法catch語句中進(jìn)行執(zhí)行
try{
System.out.println("before進(jìn)行除法計(jì)算");
result = x / y;
}finally{
System.out.println("after進(jìn)行除法計(jì)算");
}
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);
}
}
這個(gè)方法就是將一個(gè)字符串變?yōu)榱嘶緮?shù)據(jù)類型,而后執(zhí)行乘法操作,但是下面來看一下parseInt()方法的定義:
Public static int parseInt(String s) throws NumberFomatException
發(fā)現(xiàn)這個(gè)方法上拋出了一個(gè)NumberFomatException的異常,按照之前所講,如果存在了throw,則必須使用try….catch進(jìn)行處理,可是現(xiàn)在去沒有強(qiáng)制要求處理,來觀察一下NumberFomatException的繼承結(jié)構(gòu)。
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的異常類型可以有選擇型的來進(jìn)行處理,在開發(fā)之中,如果,沒有處理,那么出現(xiàn)異常之后將交給JVM默認(rèn)進(jìn)行處理。
Exception和RuntimeException的區(qū)別?請你舉出常見的RuntimeException?
- Exception是RuntimeException的父類,使用Exception定義的異常必須使用異常處理
- RuntimeException可以由用戶選擇性的異常處理
- 常見的Exception:NumberFormatException,ClassCastException,NullPointException,ArithmeticException,ArrayIndexOutBoundException。
1.6 斷言:assert
斷言指的是程序執(zhí)行到某行之后,其結(jié)果一定是預(yù)期的結(jié)果,而在JDK1.4之后增加了一個(gè)assert關(guān)鍵字。
public class DuanYan{ public static void main(String args[]){ int x = 10; //假設(shè)經(jīng)過了很多操作 assert x == 30:"x的內(nèi)容不是三十"; System.out.println(x); }}
默認(rèn)情況下,Java之中的斷言不會(huì)在正常執(zhí)行的代碼中出現(xiàn),如果想要啟用斷言,則應(yīng)該早呢更加一些選項(xiàng)。
1.7 自定義異常
在Java之中本省已經(jīng)提供了大量的異常類型,但是在開發(fā)之中,這些異常類型根本就不能滿足開發(fā)的需要,所以在一些系統(tǒng)架構(gòu)之中往往會(huì)提供一些新的異常類型,來表示一些特殊的錯(cuò)誤,而這種操作就稱為自定義異常類,而要想實(shí)現(xiàn)這種自定義異常類,那么可以讓一個(gè)類繼承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é)構(gòu),但好似對于數(shù)據(jù)結(jié)構(gòu)的部分,強(qiáng)調(diào)一下幾點(diǎn):
在整個(gè)Java開發(fā)領(lǐng)域之中,沒有一本書去真正講解數(shù)據(jù)結(jié)構(gòu)的書,只能去看C語言的數(shù)據(jù)結(jié)構(gòu):在所有開發(fā)之中,都會(huì)存在數(shù)據(jù)結(jié)構(gòu)的身影,可以這樣去解釋:數(shù)據(jù)結(jié)構(gòu)的精通與否,完全決定于以后。數(shù)據(jù)結(jié)構(gòu)的核心:引用數(shù)據(jù)類型操作。
鏈表實(shí)際上可以理解為遺傳數(shù)據(jù),或者按照專業(yè)性的說法,可以理解為動(dòng)態(tài)的對象數(shù)組,對象數(shù)組的最大優(yōu)點(diǎn):是表示“多”的概念,例如:多個(gè)雇員。但是傳統(tǒng)的對象數(shù)組有一個(gè)最大的問題在于,里面保存的數(shù)據(jù)長度是固定的。思考:如果現(xiàn)在想要擴(kuò)大一個(gè)對象數(shù)組的范圍?
建立一個(gè)新的對象數(shù)組,而后將原本的內(nèi)容拷貝到新的數(shù)組之中,再改變原數(shù)組的引用方式。
public class TestLinkDemo{
public static void main(String args[]){
Object ob[] = new Object [3];
}
}
但是再實(shí)際的開發(fā)之中,要面臨的一個(gè)問題是:數(shù)組是一個(gè)定長的線性結(jié)構(gòu),也就是說雖然以上代碼可以滿足于存放多個(gè)內(nèi)容,但是一旦我們呢的內(nèi)容不足或者是內(nèi)容過多,可能會(huì)導(dǎo)致資源的浪費(fèi)。要想解決此類問題最好的做法就是不定義一個(gè)固定長度的數(shù)組 ,有多少數(shù)據(jù)就保存多少數(shù)據(jù)。
2.1 鏈表基本的結(jié)構(gòu)
class Node{//因?yàn)橹挥蠳ode類才可以在保存數(shù)據(jù)的同時(shí)設(shè)置數(shù)據(jù)
private Object data;//真正要保存的數(shù)據(jù)
private Node next;//定義下一個(gè)節(jié)點(diǎn)
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.封裝幾個(gè)節(jié)點(diǎn)
Node root = new Node("火車頭");
Node n1 = new Node("車廂1");
Node n2 = new Node("車廂2");
Node n3 = new Node("車廂3");
//2.設(shè)置節(jié)點(diǎn)關(guān)系
root.setNext(n1);
n1.setNext(n2);
n2.setNext(n3);
//3.輸出鏈表
print(root);
}
public static void print(Node node){
if(node != null){//表示當(dāng)前是有節(jié)點(diǎn)的
System.out.println(node.getData());
print(node.getNext());//繼續(xù)向下取出
}
}
}
在整個(gè)鏈表的實(shí)現(xiàn)過程中,Node類的作用:保存數(shù)據(jù)和保存下一個(gè)節(jié)點(diǎn),但是我們發(fā)現(xiàn)客戶端需要自己來進(jìn)行節(jié)點(diǎn)的創(chuàng)建操作以及關(guān)系的配置。所謂的鏈表就是需要有一個(gè)單獨(dú)的類,假設(shè)叫Link,通過Link類來實(shí)現(xiàn)Node的數(shù)據(jù)保存和關(guān)系處理。
2.2 鏈表實(shí)現(xiàn)結(jié)構(gòu)說明
通過之前的分析,可以發(fā)現(xiàn)鏈表的最大作用類就是Node,但是以上程序都是由用戶自己去匹配節(jié)點(diǎn)關(guān)系的,但是這些節(jié)點(diǎn)的匹配工作不應(yīng)該由用戶完成,應(yīng)該由一個(gè)程序?qū)iT去負(fù)責(zé)。
那么專門負(fù)責(zé)幾點(diǎn)操作的類,就成為鏈表類——Link,負(fù)責(zé)處理幾點(diǎn)關(guān)系,而用戶不用關(guān)心節(jié)點(diǎn)的問題,只需關(guān)心Link的處理操作即可。

真實(shí)開發(fā)——標(biāo)準(zhǔn)過程

class Link{//負(fù)責(zé)對鏈表的操作
//將Node定義內(nèi)部類,表示Node類只能為Link類提供服務(wù)
private class Node{//負(fù)責(zé)數(shù)據(jù)與節(jié)點(diǎn)的關(guān)系匹配
private Object data;//真正要保存的數(shù)據(jù)
private Node next;//定義下一個(gè)節(jié)點(diǎn)
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ā)下,對于鏈表的實(shí)現(xiàn),Node類是整個(gè)操作的關(guān)鍵,但是首先來研究一下之前程序的問題:Node是一個(gè)單獨(dú)的類是可以被用戶直接使用的,但是這個(gè)類由用戶直接去使用,沒有任何意義,即:這個(gè)類有用,但不能讓用戶去使用,讓Link類去使用。
class Link{//負(fù)責(zé)對鏈表的操作
//將Node定義內(nèi)部類,表示Node類只能為Link類提供服務(wù)
private class Node{//負(fù)責(zé)數(shù)據(jù)與節(jié)點(diǎn)的關(guān)系匹配
private Object data;//真正要保存的數(shù)據(jù)
private Node next;//定義下一個(gè)節(jié)點(diǎn)
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é)點(diǎn)關(guān)系
if(this.next == null){ //當(dāng)前節(jié)點(diǎn)下一個(gè)為空
this.next = newNode;
}else{//當(dāng)前節(jié)點(diǎn)的下一個(gè)不為空
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é)點(diǎn),沒有根節(jié)點(diǎn)就無法數(shù)據(jù)的保存
//增加數(shù)據(jù)
public void add(Object data){
if(data == null){//人為追加規(guī)定,不允許存放null值
return ;//結(jié)束方法調(diào)用
}
//如果要想進(jìn)行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面
//如果沒有封裝,則無法確認(rèn)好節(jié)點(diǎn)的先后順序
Node newNode = new Node(data);
if(this.root == null){
this.root = newNode;//第一個(gè)節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn)
}else{//根節(jié)點(diǎn)存在了
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 增加多個(gè)數(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)計(jì)數(shù)據(jù)個(gè)數(shù)—public int size()
在Link類中定義
private int count;//統(tǒng)計(jì)個(gè)數(shù)
在增加數(shù)據(jù)的最后一行添加count++
public void add(Object data){
if(data == null){//人為追加規(guī)定,不允許存放null值
return ;//結(jié)束方法調(diào)用
}
//如果要想進(jìn)行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面
//如果沒有封裝,則無法確認(rèn)好節(jié)點(diǎn)的先后順序
Node newNode = new Node(data);
if(this.root == null){
this.root = newNode;//第一個(gè)節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn)
}else{//根節(jié)點(diǎn)存在了
this.root.addNode(newNode);
}
count++;
}
2.6 鏈表數(shù)據(jù)轉(zhuǎn)換為對象數(shù)組—public Object[] toArray()
對于鏈表的這種數(shù)據(jù)結(jié)構(gòu),最為關(guān)鍵的是兩個(gè)操作:刪除和取得全部數(shù)據(jù)。
在Link類中定義一個(gè)操作數(shù)組的腳標(biāo):
private int foot = 0;
要把數(shù)據(jù)保存的數(shù)組,Link類和Node類都需要使用,那么可以在Link類中定義返回?cái)?shù)組,必須以屬性的形式出現(xiàn),只有這樣,Node類才可以訪問這個(gè)數(shù)組并進(jìn)行操作。
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();
}
}
不過按照以上的方式進(jìn)行開發(fā),每一次調(diào)用toArray()方法,都要重復(fù)的進(jìn)行數(shù)據(jù)的的遍歷,如果在數(shù)據(jù)沒有修改的情況下,這種做法是一種低效的做法,最好的方法是增加一個(gè)修改標(biāo)記,如果發(fā)現(xiàn)數(shù)據(jù)增加了或刪除的話,表示要重新遍歷數(shù)據(jù)。

2.7 鏈表查詢數(shù)據(jù)—public boolean contains(查找對象)
現(xiàn)在如果想查詢某個(gè)數(shù)據(jù)是否存在,那么基本的操作原理:逐個(gè)盤查,盤查的具體對象應(yīng)該交給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類中,完成具體查詢,查詢流程為:
判斷當(dāng)前節(jié)點(diǎn)的內(nèi)容是否滿足于查詢內(nèi)容,如果滿足返回ture;
如果當(dāng)前節(jié)點(diǎn)內(nèi)容不滿足,則向后繼續(xù)查詢,如果沒有后續(xù)節(jié)點(diǎn)了,則返回false。
public boolean containsNode(Object search){
if(search.equals(this.data))
return true;
else{
if(this.next != null){//判斷下一個(gè)節(jié)點(diǎn)是否為空
return this.next.containsNode(search);
}
return false;
}
}
2.8 根據(jù)索引取得數(shù)據(jù)—public Object get(int index)
在一個(gè)鏈表之中會(huì)有多個(gè)節(jié)點(diǎn)保存數(shù)據(jù),現(xiàn)在要求可以取得指定節(jié)點(diǎn)的數(shù)據(jù)。但是在進(jìn)行這一操作的過程之中,有一個(gè)小問題:如果要取得數(shù)據(jù)的索引超過了數(shù)據(jù)的保存?zhèn)€數(shù),那么是無法取得的。
在Link類之中增加一個(gè)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類之中增加一個(gè)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ù)只需要進(jìn)行數(shù)據(jù)的替換。
在Link類之中增加一個(gè)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類之中增加一個(gè)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)容,之前完成的是增加操作和查詢操作,但是從鏈表之中也會(huì)存在刪除數(shù)據(jù)的操作,可是刪除數(shù)據(jù)的操作要分為兩種情況討論:
情況一:刪除的數(shù)據(jù)不是根節(jié)點(diǎn),待刪節(jié)點(diǎn)的上一個(gè)next指向待刪節(jié)點(diǎn)的next。
所有的處理操作應(yīng)該交給Node進(jìn)行處理。
情況二:刪除的數(shù)據(jù)是根節(jié)點(diǎn),下一個(gè)節(jié)點(diǎn)保存為跟節(jié)點(diǎn)。
如果刪除的是根節(jié)點(diǎn),意味著Link中的根節(jié)點(diǎn)的保存需要發(fā)生變化,該操作主要在Link中處理。

在Link中增加一個(gè)刪除remove(Object data)方法
//刪除數(shù)據(jù)
public void remove(Object data){
if(this.contains(data)){//如果數(shù)據(jù)存在則進(jìn)行數(shù)據(jù)處理
if(this.root.data.equals(data)){//首先需要判斷要?jiǎng)h除的數(shù)據(jù)是否為根節(jié)點(diǎn)數(shù)據(jù)
this.root = this.root.next;//根節(jié)點(diǎn)變?yōu)橄乱粋€(gè)節(jié)點(diǎn)
}else{//不是根節(jié)點(diǎn)
this.root.next.removeNode(this.root,data);
}
this.count --;
}
}
在Node類之中增加一個(gè)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)){//當(dāng)前節(jié)點(diǎn)為要?jiǎng)h除的節(jié)點(diǎn)
previous.next = this.next;
}else{
this.next.removeNode(this,data);
}
}
Link鏈表類模板
class Link{//負(fù)責(zé)鏈表的操作
//將Node定義內(nèi)部類,表示Node類只能為Link類提供服務(wù)
private class Node{//負(fù)責(zé)數(shù)據(jù)與節(jié)點(diǎn)的關(guān)系匹配
private Object data;//真正要保存的數(shù)據(jù)
private Node next;//定義下一個(gè)節(jié)點(diǎn)
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é)點(diǎn)關(guān)系
if(this.next == null){ //當(dāng)前節(jié)點(diǎn)下一個(gè)為空
this.next = newNode;
}else{//當(dāng)前節(jié)點(diǎn)的下一個(gè)不為空
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){//判斷下一個(gè)節(jié)點(diǎn)是否為空
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)){//當(dāng)前節(jié)點(diǎn)為要?jiǎng)h除的節(jié)點(diǎn)
previous.next = this.next;
}else{
this.next.removeNode(this,data);
}
}
}
//以下為Link類------------------------------------------------
private Object [] retData ; //返回類型
private int foot = 0;//操作下標(biāo)
private int count;//統(tǒng)計(jì)個(gè)數(shù)
private Node root; //屬于根節(jié)點(diǎn),沒有根節(jié)點(diǎn)就無法數(shù)據(jù)的保存
//增加數(shù)據(jù)
public void add(Object data){
if(data == null){//人為追加規(guī)定,不允許存放null值
return ;//結(jié)束方法調(diào)用
}
//如果要想進(jìn)行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面
//如果沒有封裝,則無法確認(rèn)好節(jié)點(diǎn)的先后順序
Node newNode = new Node(data);
if(this.root == null){
this.root = newNode;//第一個(gè)節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn)
}else{//根節(jié)點(diǎn)存在了
this.root.addNode(newNode);
}
count++;
}
//判斷鏈表是否為空
public boolean isEmpty(){
this.count=0;
return false;
}
//增加多個(gè)數(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ù)存在則進(jìn)行數(shù)據(jù)處理
if(this.root.data.equals(data)){//首先需要判斷要?jiǎng)h除的數(shù)據(jù)是否為根節(jié)點(diǎn)數(shù)據(jù)
this.root = this.root.next;//根節(jié)點(diǎn)變?yōu)橄乱粋€(gè)節(jié)點(diǎn)
}else{//不是根節(jié)點(diǎn)
this.root.next.removeNode(this.root,data);
}
this.count --;
}
}
}
綜合案例
建立寵物商店,包括銷售寵物上架、下架、關(guān)鍵字查詢,要求程序的關(guān)系即可,對于寵物的信息只要有三項(xiàng):名字、年齡、顏色。
對應(yīng)的關(guān)系:一個(gè)寵物商店有多種寵物,如果按照表設(shè)計(jì)應(yīng)該屬于一對多關(guān)系映射,但是現(xiàn)在問題,一方是寵物商店,多方是寵物,但是寵物又分為貓、狗、豬、驢、魚等。

1、建立寵物標(biāo)準(zhǔn)
interface Pet{//定義寵物
public String getName();
public String getColor();
public int getAge();
}
2、對于寵物商店,只關(guān)注于寵物的標(biāo)準(zhǔn),而不關(guān)心具體是那種寵物
class PetShop{
private Link pets = new Link();//開辟一個(gè)鏈表,保存寵物信息
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){//關(guān)鍵字查找
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{//負(fù)責(zé)鏈表的操作
//將Node定義內(nèi)部類,表示Node類只能為Link類提供服務(wù)
private class Node{//負(fù)責(zé)數(shù)據(jù)與節(jié)點(diǎn)的關(guān)系匹配
private Object data;//真正要保存的數(shù)據(jù)
private Node next;//定義下一個(gè)節(jié)點(diǎn)
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é)點(diǎn)關(guān)系
if(this.next == null){ //當(dāng)前節(jié)點(diǎn)下一個(gè)為空
this.next = newNode;
}else{//當(dāng)前節(jié)點(diǎn)的下一個(gè)不為空
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){//判斷下一個(gè)節(jié)點(diǎn)是否為空
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)){//當(dāng)前節(jié)點(diǎn)為要?jiǎng)h除的節(jié)點(diǎn)
previous.next = this.next;
}else{
this.next.removeNode(this,data);
}
}
}
//以下為Link類------------------------------------------------
private Object [] retData ; //返回類型
private int foot = 0;//操作下標(biāo)
private int count;//統(tǒng)計(jì)個(gè)數(shù)
private Node root; //屬于根節(jié)點(diǎn),沒有根節(jié)點(diǎn)就無法數(shù)據(jù)的保存
//增加數(shù)據(jù)
public void add(Object data){
if(data == null){//人為追加規(guī)定,不允許存放null值
return ;//結(jié)束方法調(diào)用
}
//如果要想進(jìn)行數(shù)據(jù)的保存,那么必須將數(shù)據(jù)封裝在Node類里面
//如果沒有封裝,則無法確認(rèn)好節(jié)點(diǎn)的先后順序
Node newNode = new Node(data);
if(this.root == null){
this.root = newNode;//第一個(gè)節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn)
}else{//根節(jié)點(diǎn)存在了
this.root.addNode(newNode);
}
count++;
}
//判斷鏈表是否為空
public boolean isEmpty(){
this.count=0;
return false;
}
//增加多個(gè)數(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ù)存在則進(jìn)行數(shù)據(jù)處理
if(this.root.data.equals(data)){//首先需要判斷要?jiǎng)h除的數(shù)據(jù)是否為根節(jié)點(diǎn)數(shù)據(jù)
this.root = this.root.next;//根節(jié)點(diǎn)變?yōu)橄乱粋€(gè)節(jié)點(diǎn)
}else{//不是根節(jié)點(diǎn)
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();//開辟一個(gè)鏈表,保存寵物信息
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){//關(guān)鍵字查找
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]);
}
}
}

到此這篇關(guān)于Day10基礎(chǔ)不牢地動(dòng)山搖-Java基礎(chǔ)的文章就介紹到這了,更多相關(guān)Java基礎(chǔ)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringSecurity實(shí)現(xiàn)自定義登錄接口的詳細(xì)過程
本文詳細(xì)介紹了如何使用SpringSecurity實(shí)現(xiàn)自定義登錄接口,文章還涉及了對用戶實(shí)體類的增強(qiáng)以滿足詳細(xì)信息的需求,適合需要深入了解和實(shí)現(xiàn)SpringSecurity自定義登錄功能的開發(fā)者,感興趣的朋友跟隨小編一起看看吧2024-10-10
Maven中dependency和plugins的繼承與約束
這篇文章主要介紹了Maven中dependency和plugins的繼承與約束,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
SpringBoot?整合MyBatis+MyBatis-Plus+MyBatisX插件使用
本文主要介紹了SpringBoot?整合MyBatis+MyBatis-Plus+MyBatisX插件使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-04-04
Lombok同時(shí)使?@Data和@Builder踩坑總結(jié)
這篇文章主要介紹了Lombok同時(shí)使?@Data和@Builder踩坑總結(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值需要的小伙伴可以參考一下,希望對你的學(xué)習(xí)有所幫助2022-05-05
詳解Java中多線程異常捕獲Runnable的實(shí)現(xiàn)
這篇文章主要介紹了詳解Java中多線程異常捕獲Runnable的實(shí)現(xiàn)的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這樣的知識(shí),需要的朋友可以參考下2017-10-10
springboot接口如何多次獲取request中的body內(nèi)容
這篇文章主要介紹了springboot接口多次獲取request中的body內(nèi)容的過程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Spring MVC獲取HTTP請求頭的兩種方式小結(jié)
這篇文章主要介紹了Spring MVC獲取HTTP請求頭的兩種方式小結(jié),幫助大家更好的理解和使用Spring MVC,感興趣的朋友可以了解下2021-01-01

