關於數組的基礎知識
1、 Java語言中的數組是一種引用數據類型,不屬於基本數據類型。數組的父類是Object。
2、數組實際上是一個容器,可以同時容納多個元素。(數組是一個數據的集合)數組:宇面意思是“一組數據”。
3、數組當中可以存儲"基本數據類型"的數據,也可以存儲"引用數據類型"的數據。
4、數組因為是引用類型,所以數組對象是堆內存當中。(數組是存儲在堆當中的)
5、數組在內存方面是怎么樣的一個圖形?

6、數組當中如果存儲的是"java對象”的話,實際上存儲的是對象的“引用(內存地址)"。
7、數組一旦創建,在java中規定,數組長度不可變。
8、數組的分類:一維數組、二維數組、三維數組、多維救組... (一維數組較多,二維數組偶爾使用)
所有的數組對象都有Length屬性(java自帶的),用來獲取數組中元素的個數。
9、java中的數組要求數組中元素的類型統一。
比如int類型數組只能存儲int類型,Person類型數組只能存儲person類型。
10、數組在內存方面存儲的時候,數組中的元素內存地址(存儲的每一個元素都是有規劇的挨着排列的)是連續的。內存地址連續這是救組存儲元素的特點(符色)。數組實際上是一種簡單的教據結構。
11、所有的數組都是拿"第一個小方框的內存地址”作為整個數組對象的內存地址。數組中每一個元素都是有下標的,下標從0開始,以1遞增。最后一個元素的下標是:Length - 1。下標非常重要,因為我們對數組中元素進行"存取"的時候,都需要通過下標來進行。
例圖:

- 數組這種數據結構的優點和缺點
1、優點:
查詢/查找/檢索某個下標上的元素時效事極高。可以說是查詢效率最高的一個數據結構。
為什么檢索效率高?
①:每一個元素的內存地址在空間存儲上是連續的。
②:每一個元素類型相同,所以占用空間大小一樣。
③:知道第一個元素內存地址,知道每一個元素占用空間的大小,又知道下標,所以通過一個數學表達式就可以計算出某個下標上元素的內存地址。直接通過內存地址定位元素,所以數組的檢索效率是最高的。數組中存儲100個元素,或者存儲100萬個元素,在元素查詢/檢索方面,效率是相同的。因為數組中元素查找的時候不會一個一個找,是通過數學表達式計算出來的。(算出一個內存地址,直接定位的。)
2、缺點
①:由於為了保證數組中每個元素的內存地址連續,所以在數組上隨機刪除或者增加元素的時候效率較低,因為隨機增刪元素會涉及到后面元素統一向前或者向后位移的操作。
②:數組不能存儲大數據量。
因為很難在內存空間上找到一塊特別大的連續的內存空間。注意:對於數組中最后一個元素的增刪,是沒有效率影響的。
一維數組
- 怎么聲明/定義一個一維數組?
語法格式:
int [] arrayl;
double[] array2;
boolean[] array3;
String[] array4;
Object[] array5;
- 怎么初始化一個一維數組呢?
包括兩種方式:靜態初始化一維數組,動態初始化一堆數組。靜態初始化語法格式:
int[] array = {100, 2100, 300, 55};
動態切始化語法格式:
int[] array = new int[5];
/*這里的5表示數組的元素個數。初始化
一個5個長度的int類型數組,每個元素默認值0.
*/
String[] names = new String[6];
/*初化6個長度的string類型數組,
每個元素默認值null。*/
- 一維數組中元素的訪問
代碼示例(靜態初始化方式):
public class DemoTest{
public static void main(String[] args) {
//靜態初始化方式
int[] a = {1, 2, 3, 4, 5, 6};
//所有的數組對象都有length屬性
System.out.println("數組中的元素個數為:" + a.length);
//數組中每一個元素都有下標
// 通過下標對數組中的元素進行存和取。
// 取(讀)
System.out.println("第一個元素是:" + a[0]);
System.out.println("最后一個元素是:" + a[5]);
System.out.println("最后一個元素是:" + a[a.length - 1]);
//存(改)
//把第一個元素改為111
a[0] = 111;
System.out.println("修改后的第一個元素是:" + a[0]);
//把最后一個元素改為666
a[a.length - 1] = 666;
System.out.println("修改后的最后一個元素是:" + a[a.length - 1]);
}
}
輸出:

- 一維數組遍歷
代碼示例:
public class DemoTest{
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5, 6};
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
for (int i = a.length; i > 0; i--) {
System.out.println("顛倒順序輸出:" + a[i - 1]);
}
//System.out.println(a[6]);
/*出現著名異常:
ArrayIndexOutOfBoundsException
也就是:下標越界異常
常見著名異常還有:
空指針異常、類型轉換異常.
*/
}
}
- 動態初始化一維數組
代碼示例:
public class DemoTest{
public static void main(String[] args) {
/*采用動態初始化的方式創建長度為4的int數組,
數組中每個元素的默認值是0*/
int[] a = new int[4];
for (int i = 0; i < a.length; i++) {
System.out.println("數組中下標為" + i + "的元素是:" + a[i]);
}
/*采用動態初始化的方式創建長度為3的Object數組,
數組中每個元素的默認值是null*/
Object[] ob = new Object[3];
for (int i = 0; i < ob.length; i++) {
System.out.println(ob[i]);
}
/*采用靜態初始化的方式創建*/
Object object = new Object();
Object object1 = new Object();
Object object2 = new Object();
Object[] o = {object,object1,object2};
/*還可以采用以下方式:
* Object[] o = {new Object(), new Object(), new Object()};
* */
for (int i = 0; i < o.length; i++) {
System.out.println(o[i]);
}
}
}
- 什么時候采用靜態初始化方式?什么時候使用動態初始化方式呢?
當創建數組的時候,確定數組中存儲那些具體的元素時,采用靜態初始化方式。
當創建數組的時候,不確定將來教組中存儲那些數據,你可以采用動態初始化的方式,預先分配內存空間。
- 當方法的參數是數組時
1、代碼示例:
public class DemoTest{
public static void main(String[] args) {
int[] x = {1,2,3};
String[] s = {"qqq","www","eee"};
printArray(x);
printArray(s);
}
/*
這里使用靜態方法比較方便,
不需要new對象
*/
public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
public static void printArray(String[] args){
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
輸出:

2、 直接傳遞一個靜態數組
printArray(new int[]{7,8,9});
- main方法上面的"string[] args"有什么用?
1、JVM負責調用main方法
JVM調用main方法的時候,會自動傳一個String數組過來。
2、代碼示例:
public class DemoTest{
public static void main(String[] args) {
System.out.println(args.length);//輸出:0
/*
* 經過測試,args不是null,而是默認為0.
* 這個數組什么時候里面會有值呢?
* 其實這個數組是留給用戶的,
* 用戶可以在控制台上輸入參數,
* 這個參數自動會被轉換為"string[] args"。
* */
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
/*
* 用命令行這樣運行程序: java DemoTest abc def
* 那么這個時候JVM會自動將"abc def"通過空格
* 的方式進行分離,分離完成之后,自動放到
* "String[] args"數組里面
* 在工具里面需要如下設置
* */
}
}
設置前輸出:

在IDEA里面設置后:

輸出:

- 數組中存儲引用數據類型
1、一維數組的深入,數組中存儲的類型為:引用數據類型
對於數組來說,實際上只能存儲java對象的“內存地址”。數組中存儲的每個元素是“引用"。
2、代碼示例:
public class DemoTest{
public static void main(String[] args) {
Demo a1 = new Demo();
Demo a2 = new Demo();
Demo[] demos1 = {a1,a2};
for (int i = 0; i < demos1.length; i++) {
Demo a = demos1[i];
a.move();
//也可以采用以下方法,更簡潔。
demos1[i].move();
}
Demo[] demos = {new Cat(), new Bird()};
for (int i = 0; i < demos.length; i++) {
//demos[i].move();
if(demos[i] instanceof Cat){
Cat cat = (Cat)demos[i];
cat.catchM();
}else if(demos[i] instanceof Bird){
Bird bird = (Bird)demos[i];
bird.fly();
}
/*這里需要判斷類型,然后向下強制轉換
* 到相應的類型,才能調用其特有的方法*/
}
}
}
public class Demo{
public void move(){
System.out.println("animal move");
}
}
public class Cat extends Demo{
@Override
public void move() {
System.out.println("貓");
}
public void catchM(){
System.out.println("貓在抓老鼠");
}
}
public class Bird extends Demo{
@Override
public void move() {
System.out.println("鳥兒");
}
public void fly(){
System.out.println("flying");
}
}
- 一維數組的擴容/拷貝
1、在java開發中,數組長度一旦確定不可變,那么數組滿了怎么辦?
數組滿了,需要擴容。
java中對數組的擴容是:先新建一個大容量的數組,然后將小容量數組中的數據一個一個拷貝到大數組當中。
2、結論:數組擴容效率較低。
因為涉及到烤貝的問題。所以在以后的開發中請注意:盡可能少的進行數組的拷貝。
可以在創建數組對象的時候預估計以下多長合適,最好預估准確,這樣可以減少數組的擴容次數。提高效率。
3、代碼示例:
public class DemoTest{
public static void main(String[] args) {
/*System.arraycopy(5個參數);
5個參數分別為:
(拷貝源數組名,
需要拷貝的起始位置(下標),
目標數組名,
需要拷貝到目標數組的起始位置(下標),
拷貝長度)
拷貝長度可以理解為:
將源數組上的一段剪下來,
覆蓋在目標數組的一段相應位置。
*/
//拷貝源
int[] src = {1,2,3,4};
//拷貝到目標數組上
int[] dest = new int[7];
//調用arraycopy方法完成數組的拷貝
System.arraycopy(src, 1, dest, 3, 2);
//拷貝之后遍歷目標數組
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}
}
}
輸出:

public class Demo{
//數組中如果存儲的元素是引用也可以拷貝。
public static void main(String[] args) {
Object[] object = {new Object(), new Object(), new Object()};
Object[] newobj = new Object[5];
System.arraycopy(object,0,newobj,0,object.length);
for (int i = 0; i < newobj.length; i++) {
System.out.println(newobj[i]);
}
}
}
輸出:

4、相應的內存圖:

二維數組
- 關於二維數組的描述
1、二維數組其實是一個特殊的一維數組,特殊在這個一維數組當中的每一個元素是一個一維數組。
2、二維數組的訪問:
a[二維數組中的一維教組的下標][一維數組的下標]
- 二維數組靜態初始化:
int[][] a = {
{1,2,3},
{4,5,6},
{7,8,9}
};
- 二維數組的length屬性及遍歷
代碼示例:
public class DemoTest{
public static void main(String[] args) {
int[][] a = {
{1,2,3},
{4,5,6},
{7,8,9}
};
/*length屬性*/
System.out.println(a.length);
System.out.println("一:" + a[0].length
+ " 二:" + a[1].length + " 三:" + a[2].length);
System.out.println("=====================");
/*遍歷*/
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.println(a[i][j]);
}
}
}
}
- 二維數組的動態初始化
public class Demo{
public static void main(String[] args) {
int[][] a = new int[3][4];
a[0] = new int[]{1, 1, 1, 1};
a[1] = new int[]{2, 2, 2, 2};
a[2] = new int[]{3, 3, 3, 3};
printArray(a);
}
public static void printArray(int[][] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]);
}
System.out.println();
}
}
}
