主頁 > 後端開發 > # Day10-Java基礎

# Day10-Java基礎

2021-08-16 10:37:15 後端開發

Day10-Java

文章目錄

  • Day10-Java
      • 1、例外的捕獲與處理
          • 1.1 處理例外
          • 1.2 例外處理的流程
          • 1.3 throw關鍵字
          • 1.4 例外處理模型
          • 1.5 RuntimeException
          • 1.6 斷言:assert
          • 1.7 自定義例外
      • 2、鏈表
          • 2.1 鏈表基本的結構
          • 2.2 鏈表實作結構說明
          • 2.3 增加鏈表資料—public void add(資料)
          • 2.4 增加多個資料—public void addAll(資料陣列)
          • 2.5 統計資料個數—public int size()
          • 2.6 鏈表資料轉換為物件陣列—public Object[] toArray()
          • 2.7 鏈表查詢資料—public boolean contains(查找物件)
          • 2.8 根據索引取得資料—public Object get(int index)
          • 2.9 修改指定索引資料—public void set(int index,Object newData)
          • 2.10 洗掉資料—public void remove(資料)
      • Link鏈表類模板
      • 綜合案例

1、例外的捕獲與處理

例外時導致程式中斷執行的一種指令流,程式出現例外沒用合理處理,就會導致程式終止執行,

觀察沒有例外產生的程式

public class TestDemo1{
	public static void main(String args[]){
		System.out.println("1、除法程式開始");
		int result =10/2;
		System.out.println("2、除法程式結果:"+result);
		System.out.println("3、除法程式結束");
	}
}
/*
1、除法程式開始
2、除法程式結果:5
3、除法程式結束
*/

產生例外的程式

public class YiChang{
	public static void main(String args[]){
		System.out.println("1,除法程式開始");
		int result =10/0;//會出現錯誤
		System.out.println("2,除法程式結果:"+result);
		System.out.println("3,除法程式結束");
	}
}
/*
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at YiChang.main(YiChang.java:5)
*/

這個時候程式出現了錯誤,那么出現錯誤之后程式不執行了,而是直接進行了錯誤資訊的輸出,并且直接結束了程式,但是,出現了錯誤,應該去處理才對,但是現在沒有處理,

1.1 處理例外

現在,如果希望程式出現了例外之后,程式依然可以正常的完成的話,那么就可以使用如下的格式進行例外的處理;

		try{
可能出現例外的陳述句
		}[catch(例外型別 例外物件){
			處理例外;
		}catch(例外型別 例外物件){
            處理例外;
}][finally{
    例外統一出口
    不管是否出現例外,都執行此代碼;
}]

使用該操作進行例外的處理

public class TestDemo1{
	public static void main(String args[]){
		System.out.println("1、除法程式開始");
		try{
			int result =10/0;
			System.out.println("2、除法程式結果:"+result);
		}catch(ArithmeticException e){
		System.out.println("例外被正確的處理了");
		}
		System.out.println("3、除法程式結束");
	}
}
/*
1、除法程式開始
例外被正確的處理了
3、除法程式結束
*/

可以發現加入了例外處理之后,程式之中即使有了例外,程式也可以正常執行完畢,但是現在發現,例外處理時的錯誤輸出資訊和之前相比,出錯的資訊不明確了,那么為了讓錯誤的資訊更加完整,一般而言,都會呼叫printStackTrace()方法進行例外資訊的列印

這個方法(printStackTrace)列印的例外資訊是最完整的:

try{
	int x = 10/0;     //例外
	System.out.println("2,除法程式結果:"+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,除法程式結果:"+x);
		}catch(ArithmeticException e){
			e.printStackTrace();
		}finally{
			System.out.println("不管是否例外都會執行");
		}
		System.out.println("3,除法程式結束");
	}
}

但是,對于之前的程式現在又有了問題:現在執行數學計算的兩個引數,都是由程式默認提供,那么如果說現在兩個計算的引數通過初始化引數傳遞呢?

public class TestDemo2{
	public static void main(String args[]){
		System.out.println("1,除法程式開始");
		try{
			int x = Integer.parseInt(args[0]);	//接收引數
			int y = Integer.parseInt(args[1]);    //接收引數
			int result = x/y;   
			System.out.println("2,除法程式結果:"+result);
		}catch(ArithmeticException e){
			e.printStackTrace();
		}finally{
			System.out.println("不管是否例外都會執行");
		}
		System.out.println("3,除法程式結束");
	}
}

時候發現,資料由外部傳送,那么在這種情況下,就有可能出現一下幾類問題:

? 執行時不輸入引數,ArrayIndexOutOfBoundsException,未處理,

? 輸入的引數不是數字,NumberFormatException,未處理,

? 被除數為0,ArithmeticException,已處理,

可以發現,以上的程式實際上是存在三種例外,而程式之中只能處理一種,而對于不能處理的例外,發現程式依然會直接中斷執行,

public class TestDemo2{
	public static void main(String args[]){
		System.out.println("1,除法程式開始");
		try{
			int x = Integer.parseInt(args[0]);	//接收引數
			int y = Integer.parseInt(args[1]);    //接收引數
			int result = x/y;   
			System.out.println("2,除法程式結果:"+result);
		}catch(ArithmeticException e){
			e.printStackTrace();
		}catch(ArrayIndexOutOfBoundsException e){
			e.printStackTrace();
		}catch(NumberFormatException e){
			e.printStackTrace();
		}finally{
			System.out.println("不管是否例外都會執行");
		}
		System.out.println("3,除法程式結束");
	}
}

此時,問題就來了,如果按照以上的方式一次一次的測驗來進行例外型別的推斷,還不如直接撰寫if…else,

1.2 例外處理的流程

以上已經完成了例外的基本處理流程,但是也可以發現問題,所有的例外都像之前那樣一條條的判斷似乎是一件不可能完成的任務,因為以后肯定會接觸到一些不常見的例外資訊,那么下面就必須首先研究例外的流程和結構,

首先查看兩個例外的繼承結構

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

可以發現所有的例外型別最高的繼承類是Throwable,通過doc檔案可以發現Throwable下有兩個子類:

? Error:指的是JVM錯誤,這個時候的程式并沒有執行,無法處理;

? Exception:指的是程式之中出現了錯誤資訊,可以進行例外處理,主要關心Exception,

? 那么通過繼承關系可以發現,肯定在進行日常處理的時候是以Exception為主,而這個時候就可以形成以下的例外處理流程,

1.3 throw關鍵字

throws關鍵字主要是在方法定義上使用的,表示的是此方法之中不進行例外處理,而交給被呼叫處處理,

class MyMath{
    //現在的div()方法之中拋了一個例外出來,表示的是,所有的例外交給被呼叫處進行處理,
	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();	
		}
	}
}

在呼叫throws宣告方法的時候,一定要使用例外處理操作進行例外的處理,這是是屬于強制性的處理,而現在主方法本身也屬于方法,那么實際上在主方法上也可以繼續使用throws進行例外的拋出,

class MyMath{
    //現在的div()方法之中拋了一個例外出來,表示的是,所有的例外交給被呼叫處進行處理,
	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();	
		}
	}
}

這個時候表示的是將例外繼續向上拋,交給JVM進行例外的處理,

請解釋throw和throws區別?

  • throw用于方法內部表示進行手工的拋出
  • throws主要用于方法宣告上使用,明確的告訴本方法可能產生的例外,同時該方法可能不處理例外,
1.4 例外處理模型

現在覺得有兩個內容實在沒用finally,throw,

現在要求定義一個div()方法,而這個方法有如下一些要求:

? 在進行除法操作之前,輸出一行提示資訊,

? 在除法操作執行完畢后,輸出一行提示資訊,

? 如果中間產生了例外,則應該交給被呼叫處來進行處理,

class MyMath{
	public static int div(int x, int y) throws Exception{
		int result = 0;
		//不寫catch陳述句的執行流程
		//首先進行try代碼塊的執行后執行finally代碼塊執行完成后執行
		//throws進行例外捕獲,捕獲完成后再主方法catch陳述句中進行執行
		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);
	}
}

這個方法就是將一個字串變為了基本資料型別,而后執行乘法操作,但是下面來看一下parseInt()方法的定義:

Public static int parseInt(String s) throws NumberFomatException

發現這個方法上拋出了一個NumberFomatException的例外,按照之前所講,如果存在了throw,則必須使用try….catch進行處理,可是現在去沒有強制要求處理,來觀察一下NumberFomatException的繼承結構,

java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.IllegalArgumentException
java.lang.NumberFormatException

發現NumberFormatException屬于RuntimeException的子類,而在Java之中明確規定了,對于RuntimeException的例外型別可以有選擇型的來進行處理,在開發之中,如果,沒有處理,那么出現例外之后將交給JVM默認進行處理,

Exception和RuntimeException的區別?請你舉出常見的RuntimeException?

  • Exception是RuntimeException的父類,使用Exception定義的例外必須使用例外處理

  • RuntimeException可以由用戶選擇性的例外處理

  • 常見的Exception:NumberFormatException,ClassCastException,NullPointException,ArithmeticException,ArrayIndexOutBoundException,

1.6 斷言:assert

斷言指的是程式執行到某行之后,其結果一定是預期的結果,而在JDK1.4之后增加了一個assert關鍵字,

public class DuanYan{	public static void main(String args[]){		int x = 10;		//假設經過了很多操作		assert x == 30:"x的內容不是三十";		System.out.println(x);	}}

默認情況下,Java之中的斷言不會在正常執行的代碼中出現,如果想要啟用斷言,則應該早呢更加一些選項,

1.7 自定義例外

在Java之中本省已經提供了大量的例外型別,但是在開發之中,這些例外型別根本就不能滿足開發的需要,所以在一些系統架構之中往往會提供一些新的例外型別,來表示一些特殊的錯誤,而這種操作就稱為自定義例外類,而要想實作這種自定義例外類,那么可以讓一個類繼承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、鏈表

鏈表是一種基本的資料結構,但好似對于資料結構的部分,強調一下幾點:

  1. 在整個Java開發領域之中,沒有一本書去真正講解資料結構的書,只能去看C語言的資料結構:
  2. 在所有開發之中,都會存在資料結構的身影,可以這樣去解釋:資料結構的精通與否,完全域定于以后,
  3. 資料結構的核心:參考資料型別操作,

鏈表實際上可以理解為遺傳資料,或者按照專業性的說法,可以理解為動態的物件陣列,物件陣列的最大優點:是表示“多”的概念,例如:多個雇員,但是傳統的物件陣列有一個最大的問題在于,里面保存的資料長度是固定的,思考:如果現在想要擴大一個物件陣列的范圍?

建立一個新的物件陣列,而后將原本的內容拷貝到新的陣列之中,再改變原陣列的參考方式,

public class TestLinkDemo{
	public static void main(String args[]){
		Object ob[] = new Object [3];
	}
}

但是再實際的開發之中,要面臨的一個問題是:陣列是一個定長的線性結構,也就是說雖然以上代碼可以滿足于存放多個內容,但是一旦我們呢的內容不足或者是內容過多,可能會導致資源的浪費,要想解決此類問題最好的做法就是不定義一個固定長度的陣列 ,有多少資料就保存多少資料,

2.1 鏈表基本的結構
class Node{//因為只有Node類才可以在保存資料的同時設定資料
	private Object data;//真正要保存的資料
	private Node next;//定義下一個節點
	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.封裝幾個節點
		Node root = new Node("火車頭");
		Node n1 = new Node("車廂1");
		Node n2 = new Node("車廂2");
		Node n3 = new Node("車廂3");
		//2.設定節點關系
		root.setNext(n1);
		n1.setNext(n2);
		n2.setNext(n3);
		//3.輸出鏈表
		print(root);
	}
	public static void print(Node node){
		if(node != null){//表示當前是有節點的
			System.out.println(node.getData());
			print(node.getNext());//繼續向下取出
		}
		
	}
}

在整個鏈表的實作程序中,Node類的作用:保存資料和保存下一個節點,但是我們發現客戶端需要自己來進行節點的創建操作以及關系的配置,所謂的鏈表就是需要有一個單獨的類,假設叫Link,通過Link類來實作Node的資料保存和關系處理,

2.2 鏈表實作結構說明

通過之前的分析,可以發現鏈表的最大作用類就是Node,但是以上程式都是由用戶自己去匹配節點關系的,但是這些節點的匹配作業不應該由用戶完成,應該由一個程式專門去負責,

那么專門負責幾點操作的類,就成為鏈表類——Link,負責處理幾點關系,而用戶不用關心節點的問題,只需關心Link的處理操作即可,

image-20210809111013328

真實開發——標準程序

image-20210809111231614

class Link{//負責對鏈表的操作
	//將Node定義內部類,表示Node類只能為Link類提供服務
	private class Node{//負責資料與節點的關系匹配
		private Object data;//真正要保存的資料
		private Node next;//定義下一個節點
		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 增加鏈表資料—public void add(資料)

通過上面程式的分析,可以發下,對于鏈表的實作,Node類是整個操作的關鍵,但是首先來研究一下之前程式的問題:Node是一個單獨的類是可以被用戶直接使用的,但是這個類由用戶直接去使用,沒有任何意義,即:這個類有用,但不能讓用戶去使用,讓Link類去使用,

class Link{//負責對鏈表的操作
	//將Node定義內部類,表示Node類只能為Link類提供服務
	private class Node{//負責資料與節點的關系匹配
		private Object data;//真正要保存的資料
		private Node next;//定義下一個節點
		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;
		}
		//第一次呼叫:this = Link.root
		//第二次呼叫:this = Link.root.next
		//第三次呼叫:this = Link.root.next.next
		public void addNode(Node newNode){//處理節點關系
			if(this.next == null){ //當前節點下一個為空
				this.next = newNode;
			}else{//當前節點的下一個不為空
				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; //屬于根節點,沒有根節點就無法資料的保存
	//增加資料
	public void add(Object data){
		if(data == null){//人為追加規定,不允許存放null值
			return ;//結束方法呼叫
		}
		//如果要想進行資料的保存,那么必須將資料封裝在Node類里面
		//如果沒有封裝,則無法確認好節點的先后順序
		Node newNode = new Node(data);
		if(this.root == null){
			this.root = newNode;//第一個節點設定為根節點
		}else{//根節點存在了
			this.root.addNode(newNode);
		}		
	}
	//輸出資料
	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 增加多個資料—public void addAll(資料陣列)
public void addAll(String date[]){
	for(int x = 0;x<date.length;x++){
		this.add(date[x]);
	}
}
2.5 統計資料個數—public int size()

在Link類中定義

private int count;//統計個數

在增加資料的最后一行添加count++

public void add(Object data){
    if(data == null){//人為追加規定,不允許存放null值
        return ;//結束方法呼叫
    }
    //如果要想進行資料的保存,那么必須將資料封裝在Node類里面
    //如果沒有封裝,則無法確認好節點的先后順序
    Node newNode = new Node(data);
    if(this.root == null){
        this.root = newNode;//第一個節點設定為根節點
    }else{//根節點存在了
        this.root.addNode(newNode);
    }
    count++;
}
2.6 鏈表資料轉換為物件陣列—public Object[] toArray()

對于鏈表的這種資料結構,最為關鍵的是兩個操作:洗掉和取得全部資料,

在Link類中定義一個操作陣列的腳標:

private int foot = 0;

要把資料保存的陣列,Link類和Node類都需要使用,那么可以在Link類中定義回傳陣列,必須以屬性的形式出現,只有這樣,Node類才可以訪問這個陣列并進行操作,

private Object [] retData ; //回傳型別

在Link類中增加toArray()方法:

//鏈表資料轉換為物件陣列
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();
    }
}

不過按照以上的方式進行開發,每一次呼叫toArray()方法,都要重復的進行資料的的遍歷,如果在資料沒有修改的情況下,這種做法是一種低效的做法,最好的方法是增加一個修改標記,如果發現資料增加了或洗掉的話,表示要重新遍歷資料,

image-20210813171359533

2.7 鏈表查詢資料—public boolean contains(查找物件)

現在如果想查詢某個資料是否存在,那么基本的操作原理:逐個盤查,盤查的具體物件應該交給Node去完成,前提是:有資料存在,

在Link類之中,增加查詢操作:

//查找鏈表的指定資料是否存在
public boolean contains(Object search){
    if(search == null && this.root == null)
        return false;
    return this.root.containsNode(search);
}

在Node類中,完成具體查詢,查詢流程為:

? 判斷當前節點的內容是否滿足于查詢內容,如果滿足回傳ture;

? 如果當前節點內容不滿足,則向后繼續查詢,如果沒有后續節點了,則回傳false,

public boolean containsNode(Object search){
    if(search.equals(this.data))
        return true;
    else{
        if(this.next != null){//判斷下一個節點是否為空
            return this.next.containsNode(search);
        }
        return false;
    }
}
2.8 根據索引取得資料—public Object get(int index)

在一個鏈表之中會有多個節點保存資料,現在要求可以取得指定節點的資料,但是在進行這一操作的程序之中,有一個小問題:如果要取得資料的索引超過了資料的保存個數,那么是無法取得的,

? 在Link類之中增加一個get(int index)方法:

//根據索引取得資料
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 修改指定索引資料—public void set(int index,Object newData)

如果修改資料只需要進行資料的替換,

在Link類之中增加一個set(int index,Object newData)方法:

//修改指定索引資料
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 洗掉資料—public void remove(資料)

對于鏈表之中的內容,之前完成的是增加操作和查詢操作,但是從鏈表之中也會存在洗掉資料的操作,可是洗掉資料的操作要分為兩種情況討論:

? 情況一:洗掉的資料不是根節點,待刪節點的上一個next指向待刪節點的next,

? 所有的處理操作應該交給Node進行處理,

? 情況二:洗掉的資料是根節點,下一個節點保存為跟節點,

? 如果洗掉的是根節點,意味著Link中的根節點的保存需要發生變化,該操作主要在Link中處理,

image-20210813174659850

在Link中增加一個洗掉remove(Object data)方法

//洗掉資料
public void remove(Object data){
    if(this.contains(data)){//如果資料存在則進行資料處理
        if(this.root.data.equals(data)){//首先需要判斷要洗掉的資料是否為根節點資料
            this.root = this.root.next;//根節點變為下一個節點
        }else{//不是根節點
            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)){//當前節點為要洗掉的節點
        previous.next = this.next;
    }else{
        this.next.removeNode(this,data);
    }
}

Link鏈表類模板

class Link{//負責鏈表的操作
//將Node定義內部類,表示Node類只能為Link類提供服務
	private class Node{//負責資料與節點的關系匹配
		private Object data;//真正要保存的資料
		private Node next;//定義下一個節點
		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;
		}
		//第一次呼叫:this = Link.root
		//第二次呼叫:this = Link.root.next
		//第三次呼叫:this = Link.root.next.next
		public void addNode(Node newNode){//處理節點關系
			if(this.next == null){ //當前節點下一個為空
				this.next = newNode;
			}else{//當前節點的下一個不為空
				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){//判斷下一個節點是否為空
					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)){//當前節點為要洗掉的節點
				previous.next = this.next;
			}else{
				this.next.removeNode(this,data);
			}
		}
	}
	//以下為Link類------------------------------------------------
	private Object [] retData ; //回傳型別
	private int foot = 0;//操作下標
	private int count;//統計個數
	private Node root; //屬于根節點,沒有根節點就無法資料的保存
	//增加資料
	public void add(Object data){
		if(data == null){//人為追加規定,不允許存放null值
			return ;//結束方法呼叫
		}
		//如果要想進行資料的保存,那么必須將資料封裝在Node類里面
		//如果沒有封裝,則無法確認好節點的先后順序
		Node newNode = new Node(data);
		if(this.root == null){
			this.root = newNode;//第一個節點設定為根節點
		}else{//根節點存在了
			this.root.addNode(newNode);
		}
			count++;
	}
	//判斷鏈表是否為空
	public boolean isEmpty(){
		this.count=0;
		return false;
	}

	//增加多個資料
	public void addAll(String date[]){
		for(int x = 0;x<date.length;x++){
			this.add(date[x]);
		}
	}
	public int size(){
		return this.count;
	}

	//輸出資料
	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 Object[] toArray(){
			if(this.count == 0){
				return null;
			}
			this.retData = new Object[this.count];
			this.root.toArrayNode();
			this.foot = 0;//下表清零操作
			return this.retData;
	}
	//查找鏈表的指定資料是否存在
	public boolean contains(Object search){
		if(search == null && this.root == null)
			return false;
		return this.root.containsNode(search);
	}
	//根據索引取得資料
	public Object get(int index){
		if(index >= this.count){
			return null;
		}
		this.foot = 0;
		return this.root.getNode(index);
	}
	
	//修改指定索引資料
	public void set(int index,Object newData){
		if(index >= this.count){
			return ;
		}
		this.foot = 0;
		this.root.setNode(index,newData);
	}
	//洗掉資料
	public void remove(Object data){
		if(this.contains(data)){//如果資料存在則進行資料處理
			if(this.root.data.equals(data)){//首先需要判斷要洗掉的資料是否為根節點資料
				this.root = this.root.next;//根節點變為下一個節點
			}else{//不是根節點
				this.root.next.removeNode(this.root,data);
			}
			this.count --;
		}
	}
}

綜合案例

建立寵物商店,包括銷售寵物上架、下架、關鍵字查詢,要求程式的關系即可,對于寵物的資訊只要有三項:名字、年齡、顏色,

對應的關系:一個寵物商店有多種寵物,如果按照表設計應該屬于一對多關系映射,但是現在問題,一方是寵物商店,多方是寵物,但是寵物又分為貓、狗、豬、驢、魚等,

image-20210813223132675

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);	//滿足查詢結果
			}
		}
		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;
	}
}

定義寵物貓

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定義內部類,表示Node類只能為Link類提供服務
	private class Node{//負責資料與節點的關系匹配
		private Object data;//真正要保存的資料
		private Node next;//定義下一個節點
		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;
		}
		//第一次呼叫:this = Link.root
		//第二次呼叫:this = Link.root.next
		//第三次呼叫:this = Link.root.next.next
		public void addNode(Node newNode){//處理節點關系
			if(this.next == null){ //當前節點下一個為空
				this.next = newNode;
			}else{//當前節點的下一個不為空
				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){//判斷下一個節點是否為空
					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)){//當前節點為要洗掉的節點
				previous.next = this.next;
			}else{
				this.next.removeNode(this,data);
			}
		}
	}
	//以下為Link類------------------------------------------------
	private Object [] retData ; //回傳型別
	private int foot = 0;//操作下標
	private int count;//統計個數
	private Node root; //屬于根節點,沒有根節點就無法資料的保存
	//增加資料
	public void add(Object data){
		if(data == null){//人為追加規定,不允許存放null值
			return ;//結束方法呼叫
		}
		//如果要想進行資料的保存,那么必須將資料封裝在Node類里面
		//如果沒有封裝,則無法確認好節點的先后順序
		Node newNode = new Node(data);
		if(this.root == null){
			this.root = newNode;//第一個節點設定為根節點
		}else{//根節點存在了
			this.root.addNode(newNode);
		}
			count++;
	}
	//判斷鏈表是否為空
	public boolean isEmpty(){
		this.count=0;
		return false;
	}

	//增加多個資料
	public void addAll(String date[]){
		for(int x = 0;x<date.length;x++){
			this.add(date[x]);
		}
	}
	public int size(){
		return this.count;
	}

	//輸出資料
	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 Object[] toArray(){
			if(this.count == 0){
				return null;
			}
			this.retData = new Object[this.count];
			this.root.toArrayNode();
			this.foot = 0;//下表清零操作
			return this.retData;
	}
	//查找鏈表的指定資料是否存在
	public boolean contains(Object search){
		if(search == null && this.root == null)
			return false;
		return this.root.containsNode(search);
	}
	//根據索引取得資料
	public Object get(int index){
		if(index >= this.count){
			return null;
		}
		this.foot = 0;
		return this.root.getNode(index);
	}
	
	//修改指定索引資料
	public void set(int index,Object newData){
		if(index >= this.count){
			return ;
		}
		this.foot = 0;
		this.root.setNode(index,newData);
	}
	//洗掉資料
	public void remove(Object data){
		if(this.contains(data)){//如果資料存在則進行資料處理
			if(this.root.data.equals(data)){//首先需要判斷要洗掉的資料是否為根節點資料
				this.root = this.root.next;//根節點變為下一個節點
			}else{//不是根節點
				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);	//滿足查詢結果
			}
		}
		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]);
		}
		
	}
}

image-20210813230334734

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/293948.html

標籤:java

上一篇:Java基礎之方法的呼叫、多載以及簡單的遞回

下一篇:學弟吐槽:太卷了!現在Android面試“質量”都這么高嗎?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more