3.陣列、面向物件和異常(狂神說)
阿新 • • 發佈:2021-08-03
Java陣列
陣列的定義
- 陣列是相同型別資料的有序集合
- 陣列描述的是相同型別的若干資料,按照一定先後次序排序組合而成
- 其中,每一個數據稱作一個數組元素,每個陣列元素可以通過下標訪問它們
陣列的宣告建立
- 首先必須宣告陣列變數,才能在程式中使用陣列。
dataType[] arrayRefVar; //首選
dataType arrayRefVar[]; //效果相同,但不是首選
- Java語言使用new操作符來建立陣列,語法如下
dataType[] arrayRefVar = new dataType[arraySize]; //int[] nums=new int[10]
- 陣列的元素是通過索引訪問的,陣列索引從0開始
- 獲取陣列長度:arrays.length
int[] nums; //1.宣告一個數組
nums = new int[3]; //2.建立一個數組
//3.給陣列元素賦值
nums[0]=1;
nums[1]=2;
nums[2]=3;
for (int num : nums) { //列印陣列所有元素
System.out.println(num);
}
記憶體分析
陣列的三種初始化
- 靜態初始化
//靜態初始化:建立+賦值
int[] a={1,2,3};
Man[] mans={new Man(1,1),new Man(2,2)}
- 動態初始化
//包含預設初始化 int[] a=new int[2]; //預設值為0 a[0]=1; a[1]=2;
預設初始化
- 陣列是引用型別,它的元素相當於類的例項變數,因此陣列一經分配空間,其中的每個元素也被按照例項變數同樣的方式被隱式初始化。
陣列的基本特點
-
其長度是確定的,陣列一旦被建立,它的大小就是不可改變的。
-
其元素必須是相同型別,不允許出現混合型別。
-
陣列中的元素可以是任何資料型別,包括基本型別和引用型別。
-
陣列變數屬於引用型別,陣列也可以看作物件,其中每個元素相當於該物件的成員變數。
陣列本身就是物件,Java中物件是在堆中的,因此陣列無論儲存原始型別還是其他物件型別,
陣列本身是在堆中的。
陣列的使用
- For-Each迴圈
int[] arrays = {1,2,3,4,5}; //列印全部的陣列元素 JDK1.5 沒有下標 for (int array : arrays) { System.out.println(array); }
- 陣列作方法入參
//列印陣列元素
public static void printArray(int[] a){
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
- 陣列作返回值
//反轉陣列
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
//反轉的操作
for (int i = 0; i < arrays.length; i++) {
result[i] = arrays[arrays.length-i-1];
}
return result;
}
多維陣列
- 多維陣列可以看成陣列的陣列,比如二維陣列就是一個特殊的陣列,其每一個元素都是一個一維陣列。
int arr[][] = new int[3][2]; //二維陣列,三行兩列
Arrays類
-
陣列的工具類java.util.Arrays
-
由於陣列物件本身並沒有什麼方法可以供我們使用,但API提供了一個工具類Arrays供我們使用。
-
Array類中的方法都是static修飾的靜態方法,使用時直接使用類名進行呼叫,可以不用物件呼叫。
-
常用功能
- 給陣列賦值:fill方法。
- 排序:sort方法,升序。
- 比較陣列:equals方法比較陣列中元素值是否相等。
- 查詢陣列元素:binarySearch對排序好的陣列進行二分查詢法操作。
int[] a = {1,2,3,4,9000,32145,451,21}; System.out.println(a); // [I@28d93b30 (hashcode) //Arrays.toString 列印陣列元素 System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 9000, 32145, 451, 21] //二分法查詢某值 返回下標 System.out.println(Arrays.binarySearch(a, 9000)); // 4 //填充 Arrays.fill(a,2,4,0); //陣列[a[2]~a[4])之間填充0 System.out.println(Arrays.toString(a)); //[1, 2, 0, 0, 9000, 32145, 451, 21] //升序排序 Arrays.sort(a);
稀疏陣列
//建立一個二維陣列 11*11 0:沒有棋子,1:黑棋 2:白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
//輸出原始的陣列
System.out.println("原始的陣列:");
for (int[] array : array1) {
for (int i : array) {
System.out.print(i+"\t");
}
System.out.println();
}
//轉換為稀疏陣列儲存
//1.有效值的個數
int sum = 0; //有效值總數
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if(array1[i][j]!=0){
sum++;
}
}
}
//2.建立一個稀疏陣列
int[][] array2 = new int[sum+1][3];
array2[0][0] = 11;
array2[0][1] = 11;
array2[0][2] = sum;
//3.遍歷二維陣列,將有效值存放到稀疏陣列
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if(array1[i][j]!=0){
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
//4.輸出稀疏陣列
System.out.println("稀疏陣列:");
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j]+"\t");
}
System.out.println();
}
/* 結果:
輸出原始的陣列
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
稀疏陣列
11 11 2
1 2 1
2 3 2
*/
面向物件
- 面向物件程式設計(Object-Oriented Programming, OOP)
- 本質:以類的方式組織程式碼,以物件的組織(封裝)資料。
- 抽象
- 三大特性
- 封裝
- 繼承
- 多型
- 從認識論的角度考慮是先有物件後有類。物件是具體的事物,類是物件的抽象。
- 從程式碼執行角度考慮是先有類後有物件。類是物件的模板。
建立與初始化物件
- 使用new來建立物件。
- 使用new關鍵字建立的時候,除了分配記憶體之外,還會給建立好的物件進行預設的初始化,以及對類中構造器的呼叫。
- 類中的構造器也被稱為構造方法,建立物件時必須要呼叫。有以下特點:
- 必須和類的名字相同
- 沒有返回型別,也不能寫void
- 一個類即使什麼都不寫,也會存在一個預設的構造方法
構造器
public class Person {
//一個類即使什麼都不寫,也會存在一個預設的無參構造方法
//顯示地定義構造器
String name;
//作用:1. 使用new關鍵字,本質是在呼叫構造器
//2. 用來初始化物件的值
public Person(){} //無參構造
//有參構造 3.一旦定義了有參構造,無參就必須顯示定義
public Person(String name){
this.name=name;
}
//Alt+insert 快捷鍵插入構造方法
}
記憶體分析
//定義一個寵物類
public class Pet {
public String name; //預設 null
public int age; //預設 0
//無參構造
public void shout(){
System.out.println("叫了一聲");
}
}
//應用類,建立呼叫物件
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺財";
dog.age = 3;
dog.shout();
}
}
- 物件通過引用型別來操作:棧 - - ->堆
封裝
- 該露的露,該藏的藏
- 我們程式設計要追求“高內聚,低耦合”。高內聚就是類的內部資料細節由自己完成,不允許外部干涉;低耦合:僅暴露少量的方法給外部使用
- 封裝(資料的隱藏)
- 通常,應禁止直接訪問一個物件中資料的實際表示,而應通過操作介面來訪問,稱為資訊隱藏。
- 作用
- 提高程式的安全性,保護資料
- 隱藏程式碼的實現細節
- 統一介面
- 系統可維護性增加了
繼承
- 繼承的本質是對某一批類的抽象,從而實現對世界更好地建模。
- extends的意思是”擴充套件“。子類是父類的擴充套件,使用關鍵字extends來表示。
- Java中類只有單繼承,沒有多繼承!一個類只能繼承一個父類。
- 繼承是類與類之間的一種關係,此外還有依賴、組合、聚合等。
- 繼承關係的兩個類,一個為子類(派生類),一個為父類(基類)子類繼承父類。
- 子類和父類之間,從意義上講應該具有”is a“的關係。
//學生類(子類)繼承 人類(父類)
public class Student extends Person{ /*Person extends Object*/
...
}
- 子類繼承了父類,就會擁有父類的全部方法,而private私有屬性及方法無法繼承。
- 在Java中,所有類,都預設直接或間接繼承Object類 (Ctrl+H 可以檢視類關係)
- 被final修飾的類,無法被繼承(斷子絕孫)。
super & this
- super()呼叫父類的構造方法,必須在構造方法的第一個
- super必須只能出現在子類的方法或構造方法中
- super()和this()不能同時呼叫構造方法,因為this也必須寫在第一行
- super與this的區別:super代表父類物件的引用,只能在繼承條件下使用;this呼叫自身物件,沒有繼承也可以使用。
super(); //隱藏程式碼,預設呼叫了父類的無參構造,要寫只能寫第一行
方法的重寫
- 重寫:子類的方法必須與父類方法必須一致,方法體不同。
- 重寫是方法的重寫,與屬性無關
- 重寫方法只與非靜態方法有關,與靜態方法無關(靜態方法不能被重寫)
- 靜態方法屬於類,非靜態方法屬於物件
- 注意點:
- 方法名、引數列表必須相同
- 修飾符範圍可以擴大,不能縮小(public>protect>private)
- 丟擲的異常 範圍可以被縮小,不能擴大
- 被static(屬於類,不屬於例項),final(常量方法),private(私有)修飾的方法不能重寫
多型
-
動態編譯:型別
-
即同一方法可以根據傳送物件的不同而採用不同的行為方式
-
一個物件的實際型別是確定的,但可以指向物件的引用可以有很多
-
多型存在條件
- 有繼承關係
- 子類重寫父類方法
- 父類引用指向子類物件
注意點:
- 多型是方法的多型,沒有屬性的多型
- 父類和子類,有聯絡 型別轉換異常: ClassCastException
- 存在條件:繼承關係,方法需要重寫,父類引用指向子類物件!
instanceof和型別轉換
- instanceof 引用型別比較,判斷一個物件是什麼型別
public static void main(String[] args) {
// Object > String
// Objest > Person > Student
// Objest > Person > Teacher
Object object = new Student();
// X instanceof Y,X引用指向的物件是不是Y的子類
System.out.println(object instanceof Student); //true
System.out.println(object instanceof Person); //true
System.out.println(object instanceof Teacher); //false
System.out.println(object instanceof Object); //true
System.out.println(object instanceof String); //false
//型別之間的轉化:父-子(高-低),低可以轉換為高
Person obj = new Syudent(); //只能用Person方法(重寫了用子類重寫過的方法)
(Student)obj.go(); //強轉之後可以用Student方法(Student->go())
}
型別轉換
- 父類引用指向子類的物件
- 把子類轉換為父類,向上轉型,會丟失自己原來的一些方法
- 把父類轉換為子類,向下轉型,強制轉換,才呼叫子類方法
- 方便方法的呼叫(轉型),減少重複的程式碼,簡潔。
Static
- 靜態變數可以直接用類名訪問,也稱類變數。
- 靜態變數(或方法)對於類,所有物件(例項)所共享。
- 靜態區程式碼 載入類時一起被初始化,最早執行且只執行一次(第一次new)。
- Math->隨機數:
//靜態匯入包
import static java.lang.Math.random;
public class Application {
public static void main(String[] args) {
//第一種隨機數,不用導包
System.out.println(Math.random()); //0.7562202902634543
//第二種隨機數,靜態匯入包
System.out.println(random()); //0.5391606223844663
}
}
在建立物件是,執行順序:靜態程式碼塊(最早,但只執行一次)、匿名程式碼塊、構造方法;
抽象類(abstract)
- abstract修飾的類就是抽象類,修飾的方法就是抽象方法。
- 抽象類中可以沒有抽象方法,但有抽象方法的類一定要宣告為抽象類。
- 抽象類不能使用new來建立物件,它是用來讓子類繼承的。
- 抽象方法只有方法的宣告,沒有實現,讓其子類實現。
- 子類繼承抽象類,必須實現抽象類的所有方法,否則該子類也要宣告為抽象類。
//abstract 抽象類 類只能單繼承(介面可以多繼承)
public abstract class Action {
//約束~有人幫我們實現~
//抽象方法只有方法名,沒有方法的實現
public abstract void doSth();
//1.不能new抽象類,只能靠子類去實現它,僅作為一個約束
//2.抽象方法只能出現在抽象類中,抽象類可以有普通方法
//3.抽象類有構造器,可以派生子類
//4.抽象類的意義:約束,提高開發效率。但是類只能單繼承,所以有侷限 用的不多
}
介面(interface)
-
普通類:只有具體實現
-
抽象類:具體實現和規範(抽象方法)都有
-
介面:只有規範,沒有方法實現,專業的約束!約束與實現分離:面向介面程式設計~
-
介面就是規範,定義的是一組規則,"你是什麼…必須做什麼…"的思想。
-
介面的本質是約束,就像人間法律一樣,制定好大家都遵守。
//interface介面,介面都要有繼承類
//實現類(implements 可以繼承多個介面)
//多繼承,利用介面實現多繼承
public interface UserService {
//定義的屬性都是常量,預設修飾 public static final
public static final int AGE = 99; //一般不用
//所有的定義的方法都是抽象的 預設public abstract
public abstract void run();
void add();
void query();
void delete();
}
注意點
- 介面沒有構造方法,不能被例項化
- 實現類必須要重寫介面中的方法
- 實現類(implements) 可以實現多個介面
內部類
- 內部類就是在一個類的內部再定義一個類,比如A類中定義了一個B類,那麼B就是A的內部類,而A相對B來說就是外部類
- 成員內部類:可以操作外部類的私有屬性及方法
- 靜態內部類:static修飾,不能訪問外部類私有屬性
- 區域性內部類:外部類的方法裡定義的類
- 匿名內部類:沒有名字初始化類
異常
- 軟體程式在執行過程中,經常可能遇到異常問題,異常英文(Exception),意思是例外,這些例外情況需要我們寫程式做出合理的處理,而不至於讓程式崩潰。
- 異常指程式執行中出現的不期而至的各種狀況:檔案找不到,網路連線錯誤,非法引數等。
- 異常發生在程式執行期間,它影響了正常的執行流程。
簡單分類
- 檢查型異常:最具代表性異常是使用者錯誤或問題引起的異常,這是程式設計師無法預見的。例如使用者要開啟一個不存在的檔案時引發的異常,這些異常在編譯時不能被簡單地忽略。
- 執行時異常:是可能被程式設計師避免的異常,與檢查性異常相反,執行時異常可以在編譯時忽略。
- 錯誤Error:錯誤不是異常,而是脫離程式設計師控制的問題。錯誤在程式碼經常被忽略。例如當棧溢位,一個異常就發生了,它們在編譯也檢查不到。
異常處理機制
- 丟擲異常
- 捕獲異常
- 異常處理關鍵字:try、catch、finally、throw、throws
public static void main(String[] args) {
int a = 1;
int b = 0;
try { //try監控區域
System.out.println(a/b);
}catch (ArithmeticException e){ //catch 捕獲異常
System.out.println("程式出現異常,變數b不能為0");
}catch (Exception e){
e.printStackTrace();
}finally { //一定會執行,處理善後工作,如關閉資源
System.out.println("finally");
}
if(b==0){ //丟擲異常一般在方法中使用
throw new ArithmeticException(); //主動丟擲異常
}
}
//Ctrl+Alt+T 快捷鍵插入 try-catch