数组&声明初始化&遍历&操作
思维导图:
一维数组
思维导图:
==概念:==数组具有连续内存位置的引用数据类型(对象 实际存储在堆中),由0个1个或多个具有相同类型、相同名称,不同索引的数据组合。
备注:
相同类型:组成数组的数据必须是相同的类型;
相同名称:这些数据共用一个名字,即数组的名字;
不同索引:数组是基于索引的,每个数据都有独一无二的索引,数组的第一个元素存储的索引为0;
特性:
1.数组是一种引用数据类型,数组是对象,数组存于堆内存中,且在内存中是一块连续的空间;
2.数组一旦创建,其本身长度不可改变(数组的缺陷);每个数组在被创建时,都必须有一个长度;
3.数组的索引是唯一的,我们可以根据索引去更好操作管理数组中的元素
声明初始化数组
1.静态初始化
语法格式:
type[] arrayName = {element1,element2,element3...};
//类型[] 数组名 = {多个数据用逗号隔开};
int[] == int型数组类型
代码示例:
// 静态初始化数组
/**
* 声明和初始化必须在同一行
* 数组的值都是预先定义好的值,无需指明长度,据值的数计算出长度
*/
int arrays[] = {1,2,3}; //静态声明初始化数组必须在同一行
int [] q = {2};
int[] a = {}; //空数组 无法往里添加元素 数组长度不变
int []b = {};
System.out.println(arrays); //获得逻辑上的地址 18a992f
System.out.println(Arrays.toString(arrays));//返回指定数组内容的字符串表现形式;
System.out.println(arrays[2]);
运行结果:
JVM中数组静态初始化内存分析图:
内存图中,main方法是存储在栈中,栈是先进后出的数据结构,而数组数值确是存储在堆中,对是一颗完全二叉树(如下图),后期有时间再出数据结构的详析,堆的百度百科:https://wapbaike.baidu.com/item/堆/20606834?fr=aladdin&ms=1&rid=7986314704718741775
数组静态初始化 , 我们在栈中有了数组变量 , 其存储的不是数组对象本身 , 而是存储的是堆中的一个地址 , 该地址指向了数组对象;
我们通过数组变量就可以访问和操作堆中实际的数组对象 ; 数组变量通过自身存储的地址来找到的数组对象 ;
数组变量以后可以更改自己存储的地址 , 若对其进行重新赋值 , 那么它存储的地址就会改变 , 就指向了新的对象 , 以后再操作这个数组变量,实际操作的是新的数组对象 ;
静态初始化 , 在构建数组对象时 , 会计算有多少个数据来构成本数组 , 自行计算出数组的长度 , 然后依次存入值 , 这些值是预先定义好的 ;
输出静态初始化的数组的内容,以字符串的形式输出:
System.out.println(Arrays.toString(its);//返回指定数组内容的字符串表现形式;
2.动态初始化
语法格式:
type[] arrayName;
arrayName = new type[length];//new是一个关键字,用来创建对象;
代码示例:
//动态初始化
/**
* 动态初始化必须指明长度,不可自定义数组的值,
* 数组创建后悔有该类型的默认值
* 可同行也可不同行
*/
int[] its; //声明数组
its = new int [5];//new 是一个关键字 长度为5
int[] it = new int[18];
System.out.println(Arrays.toString(its));
运行结果:
注意:
1.动态初始化必须指明长度,且不可以自定义数组的值,数组创建好了后会有该类型的默认值;
2.动态初始化的声明和初始化可在同一行,也可不在同一行;
JVM中数组动态初始化内存分析图:
3.动静结合初始化
语法格式:
type[] arrayName;
arrayName = new type[]{element1,element2,element3,...};
//类型[] 数组名;
//数组名 = new 类型[]{多个数据用逗号隔开};
代码示例:
//动静结合初始化
/**
* 声明初始化可在同一行,也可不在一行
* 数组值可自定义 无需指明数组长度
*/
String[] arrayName;
arrayName = new String[]{"hi","hello","how are you"};
System.out.println(Arrays.toString(arrayName));
System.out.println(arrayName);
// System.out.println(arrayName[-1]);//ArrayIndexOutOfBoundsException 数组越界异常 要检查下是否访问了不存在的索引
arrayName[1] = "i am fine";
System.out.println(Arrays.toString(arrayName));
System.out.println(arrayName.length);
运行结果:
注意
动静结合初始化综合了以上两种方式的特点:
1.声明初始化可在一行,也可不在同一行;
2.数组的值可以自定义,无需指明数组的长度;
JVM中数组动态初始化内存分析图:
数组的常用操作
1.获取数组中元素的值、修改元素的值
获取数组和修改数组中元素的值:依靠数组的名字+[索引];
例:
int x = its[0];//获取名为its数组中的第0个元素的值;
its[0]=12;//这样可以修改操作its数组的第0个元素,将原有值改成12;
注意
1.使用这种方式可以获取\修改任意一个元素的值,但是不能删除这个元素;
2.索引不能超出数组的索引范围,索引的范围是[0,数组长度-1];如果使用了超出范围的索引,则会报"数组索引异常";
3.数组长度:数组变量.length,即可获得该数组的长度;
System.out.println(arrayName[-1]);//ArrayIndexOutOfBoundsException 数组越界异常 要检查下是否访问了不存在的索引
案例:
声明25个长度的数组,通过键盘录入学生成绩,并每个元素赋值为学生的分数成绩
package array;
import java.util.Arrays;
import java.util.Scanner;
/**
* 声明25个长度的数组,通过键盘录入学生成绩,
* 并每个元素赋值为学生的分数成绩
* @author Acer
*
*/
public class StuArrays {
public static void main(String[] args) {
//方法一
/*Scanner sc = new Scanner(System.in);
System.out.println("输入学生成绩");
//声明数组
int[] score = new int [25]; //动态初始化
// int[] score = {}; //静态初始化 运行错误 ArrayIndexOutOfBoundsException 数组越界异常
// int [] score = new int[]{};//运行错误 ArrayIndexOutOfBoundsException 数组越界异常
//可能是动静结合方式必须一开始就赋值?
System.out.println(score);
// JAVA 中只有值传递 但是引用数据类型存储就是地址 所以传递的是地址
//键盘录入数组元素值
for(int i = 0;i <score.length ;i++){
score[i] = sc.nextInt();
}
System.out.println(Arrays.toString(score));*/
//方法二
int[] its = new int[25];
random(its);
}
/**
* 给数组元素随机赋值
*/
private static void random(int[] its) {
// TODO Auto-generated method stub
for(int i = 0;i < its.length;i++){
its[i] = (int) (Math.random()*101);
}
System.out.println(Arrays.toString(its));
}
}
代码中用静态初始化和动静结合声明数组越界异常(ArrayIndexOutOfBoundsException)是因为 ==动态初始化声明是有初始长度的,并且这个长度是由你指定的,指定多少就会在内存开辟多大空间,但若使用静态初始化数组和动静结合初始化数组的方式。数组长度则都是0,这都相当于一个空数组,所以往里添加元素时会产生数组越界异常! 静态和动静结合要赋初始值,不赋值的情况下,语法不会报错,就是数组长度为0,即空数组,空数组无法添加元素,因为数组长度固定不变。
2.遍历(获取数组中所有元素的值)
遍历的两种方式:
方式1:for循环+数组名[索引] , 索引递增即可遍历到所有元素的值;
代码:
package array;
public class TraversalArrays {
/**
* 遍历数组
*/
public static void main(String[] args) {
// 遍历数组方式一: for 循环 + 数组名[索引]
int[] array = {1,3,6,7,9};
for(int i = 0;i < array.length;i++){
System.out.print(array[i] + "");//通过这种方式可以获取每个位置上的元素的值
}
System.out.println("\n--------");
int[] view = {5,9,1,3,7,6,4};
showView(view);
}
/**
* 遍历int型数组 for循环 + 索引
*/
public static void showView(int[] view){
for(int i = 0; i < view.length; i++){
System.out.print(view[i] + "");
}
}
}
方式2:增强for循环+数组名; 数组 + 集合
package array;
public class TraversalArrays2 {
/**
* 遍历数组
*/
public static void main(String[] args) {
// 遍历数组方式二: for 循环 + 数组名[索引]
int[] array = {1,3,4,6,7,9,5};
for(int i : array) //把array的元素赋值给i,一次赋值一个,从0索引开始赋值,直到所有元素都被赋值
System.out.print(i + " "); //这种方式获取到元素的值,无法对每个位置上的值进行修改
System.out.println("\n-----------------");
int[] array2 = {45,23,87,45,12,62};
showView2(array2);
}
/**
* foreach 增强for循环遍历数组
*/
public static void showView2(int[] array2){
// 数组元素的类型 数组元素变量 : 数组变量
for( int i : array2 ) //每次循环把array中的一个值赋值给i 依次给 直到所有值
System.out.print(i + " ");
}
}
累加和,平均值,最大值…
package array;
import java.util.Arrays;
import java.util.Scanner;
/**
* 声明25个长度的数组,通过键盘录入学生成绩,
* 并每个元素赋值为学生的分数成绩
* @author Acer
*
*/
public class StuArrays {
public static void main(String[] args) {
//方法一
/*Scanner sc = new Scanner(System.in);
System.out.println("输入学生成绩");
//声明数组
int[] score = new int [25]; //动态初始化声明是有初始长度的,且这个长度是由你指定的,指定多少就会在内存中开辟多大空间
// int[] score = {}; //静态初始化 运行错误 ArrayIndexOutOfBoundsException 数组越界异常
// int [] score = new int[]{};//运行错误 ArrayIndexOutOfBoundsException 数组越界异常
//但使用静态初始化数组和动静结合初始化数组的方式,数组长度都是0,即相当于一个空数组,所有往里添加元素时会产生数组越界异常
System.out.println(score);
// JAVA 中只有值传递 但是引用数据类型存储就是地址 所以传递的是地址
//键盘录入数组元素值
for(int i = 0;i <score.length ;i++){
score[i] = sc.nextInt();
}
System.out.println(Arrays.toString(score));*/
//方法二
int[] score = new int[25];
random(score);
showView(score);
//总和
int sum = sumArray(score);
System.out.println("\n数组累加之和为:" + sum);
//计算平均值
double avg = sum/1.0/score.length;
System.out.println("数组均值为:" + avg);
//求最大值
System.out.println("最大值为:" + maxValue(score));
//及格人数
System.out.println("及格人数:" + passStu(score));
//给不足60的+20
for(int i = 0; i < score.length;i++)
if(score[i] < 60)
score[i] += 20;
showView(score);
}
private static int passStu(int[] score) {
// TODO Auto-generated method stub
int count = 0;
for(int i : score)
if(i >= 60)
count++;
return count;
}
/**
* 求最大值
*/
public static int maxValue(int[] its){
int max =its[0];
for(int i = 0; i < its.length; i++){
if(max < its[i])
max = its[i];
}
return max;
}
/**
* 计算数组的累加之和 并返回
*/
private static int sumArray(int[] array) {
// TODO Auto-generated method stub
int sum = 0;
for(int i : array){
sum += i;
}
return sum;
}
/**
* 遍历int型数组 for循环 + 索引
*/
public static void showView(int[] view){
for(int i = 0; i < view.length; i++){
System.out.print(view[i] + " ");
}
}
/**
* 给数组元素随机赋值
*/
private static void random(int[] its) {
// TODO Auto-generated method stub
for(int i = 0;i < its.length;i++){
its[i] = (int) (Math.random()*101);
}
}
}
一维数组的内存图:
Java中值传递
经常会有人说 , java中有值传递也有引用传递 ; 我们可以认为 java 只有值传递 ;
因为在调用引用数据类型时 , 传的是地址 , 这个地址就叫引用 , 本质上地址也是存的值 ;
java 中基本数据类型存储的就是值本身 , 传递时传的也是值本身 ;
引用数据类型存储的不是值本身 , 存储的是地址 , 传递时传递的是地址 ; 多个变量乃至多个线程都可以指向同一个对象 ;