目錄
1. 方法
1.2 什么是方法
1.2?方法的定義
1.3?方法的調用
1.4?方法的重載
1.5?遞歸
2. 一維數組
2.1 什么是數組
2.2 數組的創建
2.3 數組的初始化
2.4 遍歷數組
2.5 引用數據類型
2.6 關于null?
2.7?數組轉字符串
2.8?數組元素的查找
2.9?數組的排序
2.10?數組的拷貝
2.11?數組逆序
2.12?Arrays類部分方法
3. 二維數組
3.1 二維數組的定義和初始化
3.2 數組的遍歷
?3.3 不規則二維數組
1. 方法
1.2 什么是方法
? ? ? ? Java中的方法就類似于C語言當中的函數,是實現一種特定的,使用頻率高的功能,專門解決一種問題的辦法。例如:求一個數的開平方,判斷一個數是不是素數。
方法也分為兩種,一種是Java語言規定的方法,還有一種是程序員根據自己的需要自定義的一些方法。
當在解決重復問題時,設置一個方法解決重復問題,可以多次調用方法去解決重復問題,不用每次使用就需要寫代碼,減少代碼冗余度。
1.2?方法的定義
修飾符? 返回值類型? 方法名(參數類型){
? ? ? ? ? ? ? ? 方法體代碼;
? ? ? ? ? ? ? ? (return 返回值;)
}
上面是方法的基本形式,舉個例子,寫一個判斷一個數是不是素數的方法:
public static boolean isPrimeNumber(int n){for (int i = 2; i < Math.sqrt(n); i++) {if(n % i == 0){return false;}}return true;}
}
public static 是修飾符,boolean 是返回值類型,返回值類型必須與return返回的類型一致,isPrimeNumber是方法名,int n是參數,下面便是方法體,如果沒有返回值,則返回值類型寫void,不用寫return。
方法不能嵌套定義,方法的命名一般是小駝峰,方法必須在類里面。
1.3?方法的調用
定義好一個方法后,需要在main函數里面進行調用,否則不會調用。
public static void main(String[] args) {Scanner sc = new Scanner(System.in);int a = sc.nextInt();boolean b = isPrimeNumber(a);if (b == true) {System.out.println(a + "是素數");}}
在調用方法時候如果方法需要傳參,便需要在調用的時候傳入對應類型的參數,然后調用方法。? ????????形參是實參的一份臨時拷貝,改變形參的值不會改變實參的值,因為形參和實參不是同一塊地址,每次調用方法都需要在棧中調用一塊空間,方法調用完銷毀。
1.4?方法的重載
方法在調用時候可能需要傳的參數的類型,順序,數量不同,但都是同一種功能的方法,這時候就可以把兩種方法用相同的名字命名,例如:
public static int add(int a,int b){return a + b;}public static double add(double a,double b){return a + b;}
上面代碼是計算兩個數的和的方法,但是傳的參數不一樣,可以用相同的名字來命名方法,這樣調用這個方法時候既可以計算兩個整型的和,也能計算兩個雙精度浮點數的和。
注意:
方法名必須相同
方法參數的類型,順序,數量其中至少有一種不同
與方法的返回值類型無關。
按理來說同一塊作用域不能有兩個相同的標識符,但是為什么類里面可以有相同名字的兩種方法呢?
其實不然,我們編寫的方法名并不是真正存儲在內存中的方法名,而編譯器會將方法+后面的參數編譯成一種方法簽名供機器識別。
我們可以通過JDK自帶的反匯編工具查看方法在機器中存儲的真正名字。
1.先將.java文件編譯成.class文件
2. 找到.class文件所在的目錄,用控制臺打開
3. 輸入javap -v 字節碼文件名就可以顯示反匯編碼了。
上面第一個方法名是add;(II)I,括號里面表示方法的參數是兩個整型,后面表示返回值是整型,第二個方法名add(DD)D,括號里面表示方法的參數是兩個double類型的,后面表示返回值是double類型。機器識別的是這種方法簽名,區分方法的重載。
下面方法簽名的一些符號:
1.5?遞歸
?遞歸就是遞推和回歸的意思,在解決一些問題時,使用遞歸將復雜的問題簡單化,就可以輕松求解。遞歸也就是方法重復調用自己,知道遇到停止條件,才停止調用,返回調用的值。
因此遞歸有兩個重要的部分:
1. 遞推公式
2. 終止條件
例如求n!;
public static void main(String[] args) {//求n的階乘Scanner sc = new Scanner(System.in);int n = sc.nextInt();System.out.println(fib(n));}public static int fib(int a){if(a == 1){return 1;}return a * fib(a-1);}
上面代碼中 a == 1是終止條件,a * fib(a-1)是遞推公式。
但是遞歸也有它的壞處,那就是容易導致棧溢出,因為每次調用方法都需要在棧里面申請空間,如果問題過于復雜,申請的空間過多,就會導致棧溢出,例如用遞歸解決斐波那契數列問題,給的數太大,就會導致棧溢出。
2. 一維數組
2.1 什么是數組
? ? ? ? 數組可以理解為相同元素的集合,數組里面可以存儲許多相同類型的數據,數組在內存中是連續存儲的。
2.2 數組的創建
數組創建的基本形式,下面我以創建整型數組為例:
int[]? a = new int[10];
int[]是數據類型,代表引用類型,a是變量名,稱為引用變量也被稱為引用,new是創建一個新的對象,后面中括號里是數組的大小。
2.3 數組的初始化
數組的初始化分為兩種動態初始化和靜態初始化:
動態初始化:
在創建數組的時候直接指定數組的大小,不指定數組內容,系統默認賦值為0:
int[] a = new int[10];
靜態初始化:
在創建數組的時候不指定數組元素的個數,而是指定數組里面的值:
int[] a = new int[]{1,2,3,4,5};
靜態變量雖然沒有指定數組的大小,但是編譯器會根據后面數據的內容來判斷數組的大小。
靜態變量初始化時候可以簡寫成:
int[] a = {1,2,3,4,5};
在Java中也支持C語言的定義數組的方法:
int a[] = {1,2,3,4,5};
當然不建議平時這樣定義數組和初始化。
在靜態初始化和動態初始化時也可以分開來寫:
//靜態初始化
int[] a;
a = new int[]{1,2,3,4,5};
//動態初始化
int[] b;
b = new int[10];
當然不能寫成如下格式:
//錯誤
int[] a;
a = {1,2,3,4,5};
數組沒有初始化的話,系統默認的值是:
?數組中存儲的是引用類型時的默認值是:null。
2.4 遍歷數組
遍歷數組有三種方法:
方法一:
下面方法中使用循環的方法來遍歷數組并打印,里面用到.length的屬性,.length是求數組長度的屬性。
int[] a = new int[]{1,2,3,4,5};
for(int i = 0;i < a.length;i++) {System.out.print(a[i] + " ");
}
方法二:
下面是for循環的的另一種版本,能夠更簡便的遍歷數組,把數組里的每個值傳給定義的 x變量,并打印。
int[] a = new int[]{1,2,3,4,5};
for (int x,a) {System.out.print(x + " ");
}
方法二的優點是遍歷數組簡單,缺點是獲取不了數組元素的下標,不能改變數組里面的值。
方法三:
這里用到了Arrays里面的toString方法,將數組傳進去返回數字里面的值的字符串形式:
import java.util.Arraysint[] a = new int[]{1,2,3,4,5};
String b = Arrays.toString(a);
System.out.println(b);
輸出結果是:[1,2,3,4,5]
2.5 引用數據類型
數組屬于引用數據類型,引用數據類型就是存儲到是數據在堆區創建的地址,存儲都引用變量里面。下面先介紹一下JVM(java虛擬機):
程序都要在JVM中運行,在JVM中的棧區申請一塊棧幀,存放方法的局部變量等,在堆區創建對象,用引用變量存放對象的地址,來使用對象。
下面是JVM里面的代碼運行時的數據區:
為什么會有兩個棧區?
本地方法棧執行的是由C/C++編寫的方法。
虛擬機棧是執行的Java的方法的。
我們今天只用到堆區和虛擬機棧。
這里定義一個整型數組:
int[] a = new int[]{1,2,3,4,5};
?int[] 是引用類型,a是引用變量,又稱引用,new是創建新對象,后面是創建的新對象,它們在內存中存儲如下:
?
?引用變量a先在棧區申請一塊空間,a是引用變量存放的是對象的地址,new創建的對象存放在堆區,a存放的地址,指向堆區里面創建的數組對象。
1. 一個引用變量只能指向一個對象。
2. 引用變量初始化賦值為null時,引用變量不指向任何對象。
3. 假設兩個引用變量a 和 b,a=b的含義是:a指向的對象變成b指向的對象
4. 引用類型的引用變量存放的是對象的地址。
在Java中數組可以作為返回值,也可以作為方法的參數:
例如:
public static int[] arr(int[] a) {int[] b = new int[a.length];for(int i = 0;i < a.length;i++) {b[i] = a[i];return b;
}
2.6 關于null?
null 在Java中被稱為空引用,也就是不指向任何一個對象:
int[] a = null;
該引用不能進行讀寫操作,或者.length操作等,如果使用就會報錯:
?
?null相當于C語言中的NULL指針,表示的是一個無效的內存。
2.7?數組轉字符串
在Java中有一個名為Arrays的類,里面有很多對數組處理的方法,Arrsys類里面的toString(數組名)的方法,能幫助我們快速的將數組轉換成字符串:
public static void main(String[] args) {//數組轉字符串int[] a = new int[]{1, 2, 3, 4, 5};String b = Arrays.toString(a);System.out.println(b);}
當然我們也可以自己書寫一個將數組轉換為字符串的方法:
public static void main(String[] args) {int[] a = new int[]{1,3,5,7,9};String b = myToString(a);System.out.println(b);
}public static String myToString(int[] a) {String arr = "[";for (int i = 0; i < a.length; i++) {arr += a[i];if(i != a.length-1) {arr += ", ";}}arr += "]";return arr;
}
2.8?數組元素的查找
方法一:順序查找
一次遍歷數組中的每個元素,知道遇到要查找的元素,返回元素下標。
public static void main(String[] args) {//查找數組中的元素,返回下標int[] a = new int[]{1,2,3,4,5};int b = 3;System.out.println(find(a,b));}public static int find(int[] a,int b) {for (int i = 0; i < a.length; i++) {if(b == a[i]) {return i;}}return -1;}
方法二:二分查找
二分查找的前提是數組元素是有序的,一次檢查一半的元素,直到查找到元素,返回下標。
public static int fingOne(int[] a,int b) {int left = 0;int right = a.length - 1;while(left <= right) {int mid = (left + right) / 2;if(b > a[mid]) {left = mid + 1;}else if(b < a[mid]) {right = mid - 1;}else {return mid;}}return -1;}
方法三:系統自帶的二分查找方法
int[] a = new int[]{1,2,3,4,5};int c = Arrays.binarySearch(a,3);System.out.println(c);
用到Arrays類里面的binarySearch(數組名,查找元素)方法?,返回查找的數組下標,如果數組中沒有查找元素,則返回 -(最后一次二分查找左下標 + 1)。
該方法的重載還可以實現指定數組返回進行二分查找元素:
int[] a = new int[]{1,2,3,4,5};int d = Arrays.binarySearch(a,1,3,3);System.out.println(d);
Arrays.binarySearch(數組名,范圍開始下標,范圍結束下標,查找元素);
從數組下標范圍 [1,3)里面查找3元素,返回下標。
2.9?數組的排序
方法一:冒泡排序
升序:對數組中的元素從開始依次相鄰兩個進行比較;大的數后移,直到比較到最后兩個數結束,數組中最大的數就在最后一個位置。循環往復,最后完成數組的升序排列:
public static void main(String[] args) {//冒泡排序(升序)int[] a = new int[]{1,22,5,33,66,55,9};mysort(a);System.out.println(Arrays.toString(a));}public static void mysort(int[] a) {boolean b = true;//輪數for (int i = 0; i < a.length-1; i++) {for (int j = 0; j < a.length-1-i; j++) {if(a[j] > a[j+1]) {int tmp = a[j];a[j] = a[j+1];a[j+1] = tmp;b = false;}}if(b == true) {return;}}return;}
方法二:Java自帶的方法
Arrays類里面的.sort(數組名)方法,默認將數組內容升序排列:
int[] a = new int[]{1,22,5,33,66,55,9};Arrays.sort(a);System.out.println(Arrays.toString(a));
2.10?數組的拷貝
方法一:
自己創建方法實現
public static void main(String[] args) {//數組的拷貝int[] a = new int[]{1,2,3,4,5};int[] b = myCopyArray(a);System.out.println(Arrays.toString(b));}public static int[] myCopyArray(int[] a) {int[] b = new int[a.length];for (int i = 0; i < a.length; i++) {b[i] = a[i];}return b;}
方法二:
Java中自帶的方法
Arrays類中的copyOf(拷貝的數組名,新數組的長度);
int[] a = new int[]{1,2,3,4,5};int[] c = Arrays.copyOf(a,a.length);System.out.println(Arrays.toString(c));
?Arrays類里面還有一種方法可以指定數組范圍拷貝:copyOfRange(拷貝的數組名,拷貝開始的下標,拷貝結束的下標);
int[] a = new int[]{1,2,3,4,5};int[] d = Arrays.copyOfRange(a,2,4);System.out.println(Arrays.toString(d));
注意:拷貝方法的底層方法代碼由C/C++代碼書寫,被關鍵字native修飾的方法是由C/C++代碼書寫的,運行效率高,查看不了源代碼。?
2.11?數組逆序
將數組中的元素逆序輸出:
public static void main(String[] args) {//數組逆序int[] a = new int[]{1,2,3,4,5};move(a);System.out.println(Arrays.toString(a));}public static void move(int[] a) {int left = 0;int right = a.length - 1;while(left < right) {int tmp = a[left];a[left] = a[right];a[right] = tmp;left++;right--;}}
2.12?Arrays類部分方法
查找數組指定元素(二分查找)
Arrays.binarySearch(數組名,查找元素);返回查找元素下標,若不存在查找元素,返回最后一次二分查找的左下標 + 1 取負數。
//查找數組指定元素int[] a = new int[]{1,2,3,4,5};int b = Arrays.binarySearch(a,4);int c = Arrays.binarySearch(a,2,4,3);System.out.println(b);System.out.println(c);
數組的拷貝
Arrays.copyOf(拷貝的數組名,新數組的大小);返回拷貝的新數組。
int[] a = new int[]{1,2,3,4,5};int[] c = Arrays.copyOf(a,a.length);System.out.println(Arrays.toString(c));
Arrays.copyOfRange(拷貝的數組名,拷貝開始下標,拷貝結束下標);拷貝數組指定范圍的數據到新數組。
int[] a = new int[]{1,2,3,4,5};int[] d = Arrays.copyOfRange(a,2,4);System.out.println(Arrays.toString(d));
判斷兩個數組是否相等
Arrays.equals(數組1,數組2);比較數組1和數組2里面的內容是否相等。相等返回true,不相等返回false。
//比較兩個數組是否相等int[] arr1 = new int[]{1,2,3,4,5};int[] arr2 = new int[]{1,2,3,4,5};boolean d = Arrays.equals(arr1,arr2);System.out.println(d);
數組的賦值
Arrays.fill(數組名,值);將值賦值給數組的所有元素。
//數組賦值int[] arr3 = new int[]{1,2,3,4,5};Arrays.fill(arr3,6);System.out.println(Arrays.toString(arr3));
fill方法的重載:Arrays.fill(數組名,賦值開始坐標,賦值結束坐標,值);指定數組范圍賦值。
//數組賦值int[] arr3 = new int[]{1,2,3,4,5};Arrays.fill(arr3,2,4,6);System.out.println(Arrays.toString(arr3));
數組的排序(升序)
Arrays.sort(數組名);對數組內的元素進行升序排列。
int[] a = new int[]{1,22,5,33,66,55,9};Arrays.sort(a);System.out.println(Arrays.toString(a));
數組轉換成字符串
Arrays.toString(數組名);將數組轉換成字符串[1,2,3,4,5]。
//數組轉換成字符串int[] arr4 = new int[]{1,2,3,4,5};System.out.println(Arrays.toString(arr4));
?二維數組轉換成字符串
Arrays.deepToString(數組名) ;將二維數組轉換成[ [1,2,3],[4,5,6] ]。
//二維數組轉換成字符串int[][] a = new int[][]{{1,2,3},{4,5,6}};System.out.println(Arrays.deepToString(a));
3. 二維數組
3.1 二維數組的定義和初始化
下面是定義并初始化數組的寫法:
int[][] a = new int[2][3];int[][] b = new int[][]{{1,2,3},{4,5,6}};int[][] c = {{1,2,3},{4,5,6}};int[][] d;d = new int[2][3];int[][] f;f = new int[][]{{1,2,3},{4,5,6}};
3.2 數組的遍歷
二維數組是特殊的一維數組,假設二維數組int[][] arr = new int[][]{{1,2,3},{4,5,6,}},arr指向的對象是一維數組,里面存放兩個一維數組對象的地址,而兩個地址位置分別是兩個一維數組。
關系如下圖:
方法一:循環遍歷
public static void main(String[] args) {int[][] a = new int[][]{{1,2,3},{4,5,6}};for (int i = 0; i < a.length; i++) {for (int j = 0; j < a[i].length; j++) {System.out.print(a[i][j] + " ");}System.out.println();}}
方法二:for-each遍歷
public static void main(String[] args) {int[][] a = new int[][]{{1,2,3},{4,5,6}};for(int[] b : a) {for(int c : b) {System.out.print(c + " ");}System.out.println();}}
方法三:Java自帶的方法
Arrays.deepToString(數組名);作用是將二維數組轉換成字符串
System.out.println(Arrays.deepToString(a));
打印結果:
?3.3 不規則二維數組
Java中定義數組時不可以省略行的值,可以省略列的值:
public static void main(String[] args) {int[][] a = new int[2][];a[0] = new int[3];a[1] = new int[4];for (int i = 0; i < a.length; i++) {for (int j = 0; j < a[i].length; j++) {System.out.print(a[i][j] + " ");}System.out.println();}}
上面數組a就是不規則數組,第一行有三列,第二行有四列。
打印出來是:
在堆中存儲如下:
?