1.数组(array):
一种用于存储多个相同类型数据的存储模型。
一次性声明大量的用于存储数据的变量。
要存储的数据通常都是同类型的数据。
在java中,数组也是对象。数组中的元素可以是任意类型(基本类型或引用类类型),但同一个数组里只能存放类型相同的元素。
2.数组定义格式:
先使用一个已有的类型,然后加上中括号,组合成一个数组类型,然后再声明这个数组类型的变量。
数组类型的变量,也是引用类型变量,简称引用,它是可以指向对象的(数组对象)
1)格式一:
数据类型[] 变量名;
比如:int[] arr;
表示:定义了一个int类型的数组,数组名为arr。
2)格式二:
数据类型 变量名[];
比如:int arr[];
表示:定义了一个int类型的变量,变量是名为arr的数组。
3.数组初始化方式:
Java中的数组必须先初始化才能使用。
所谓初始化就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
1)动态初始化:
初始化时,只指定数组长度,由系统为数组分配初始值。
//格式
数据类型[] 变量名 = new 数据类型[数组长度];
int[] arr = new int[10];
/*
解释int[] arr:
int说明数组中元素类型是int型
[]说明这是一个数组
arr为数组名称
解释new int[10]:
new为数组申请内存空间
int说明数组中元素类型是int型
[]说明这是一个数组
10表示数组长度,其实就是数组中的元素个数
*/
使用
new
关键字,来创建数组对象,中括号里面的数字,就是数组的长度。
String[] s = new String[2];//数组对象s中,最多存放2个String类型的数据
数组对象在内存中,就是一块连续的内存空间,在这个连续的空间中,可以存放多个类型相同的数据。
🌂:数组对象中都有哪些属性和方法可以使用?
Ⅰ、数组对象中只有一个属性(length),表示数组的长度。可以使用length属性,获取数组对象的长度。
Ⅱ、数组对象中的方法,只有从父类型Object中继承过来的方法。
Ⅲ、除此之外,数组对象中就没有其他属性和方法了。🌂: 数组长度:
Ⅰ、是指在一个数组对象中,最多可以存放多少个同一类型的数据。
Ⅱ、必须在创建数组对象的时候就明确指定。
Ⅲ、一旦确定,就无法再改变。
Ⅳ、可以为0,但是不能为负数。
2)静态初始化:
初始化时,指定每个数组元素的初始值,由系统决定数组长度。
//格式一:
数据类型[] 变量名 = new 数据类型[] {数据1,数据2,数据3,……};
int[] arr = new int[] {1,2,3};
//格式二:
数据类型[] 变量名 = {数据1,数据2,数据3,……};
int[] arr = {1,2,3};
4.数组元素的访问:
1)数组变量的访问方式:
//格式
数组名
数组名就是数组变量,我们可以直接输出。
2)数组内部保存的数据的访问方式:
//格式
数组名[索引]
索引是数组中数据的编号方式,计算机习惯从0开始编号。用于访问数组中的数据使用,数组名[索引]
等同于变量名。
数组对象在JVM的堆区中是一块连续的内存空间,并允许使用下标,设置或获取每一个内存空间的值。
数组的下标的区间为,[0,arr.length-1],假如数组的长度为length的话,那么数组下标的最小值为0,数组下标的最大值就是length-1。如果使用下标访问数组中元素的时候,下标的值超出了其可用范围,那么运行就会报错。
5.Java中的内存分配:
1)Java程序运行时,需要在内存中分配空间。
2)为了提高运算效率,就对空间进行了不同区域的划分。每一片区域都有特定的处理数据方式和内存管理方式。
3)栈内存:存储局部变量。
局部变量:定义在方法中的变量。使用完毕,立即消失。
4)堆内存:存储new出来的内容(实体、对象)。
每一个new出来的东西都有一个地址值。使用完毕,会在GC空闲时被回收。
数组在初始化时,会为存储空间添加默认值。
整数,默认值为0,
浮点数,默认值为0.0,
布尔值,默认值是false,
字符,默认值是空字符,
引用数据类型。默认值是null,表示不指向任何有效对象。
6.数组易错点:
1)索引越界:
访问了数组中不存在的索引对应的元素。
2)空指针异常:
访问的数组已经不再指向堆内存的数据。
7.数组遍历练习:
public class demo{
public static void main(String[] args){
int arr[] = {1,2,3,4,5,6};
for (int x=0;x<6;x++){
System.out.println(arr[x]);
}
}
}
8.获取数组元素数量:
格式:
数组名.length
//比如:arr.length
9.数组常见操作:
1)获取最大值
public class Max{
public static void main(String[] args){
int[] arr = {12,13,23,35};
int max = arr[0];//定义一个变量max,用于存放数组中的最大值,并把数组中第一个数据作为变量的初始值
/* 与数组中剩余数据逐个对比,每次将最大值保存到变量max中 */
for(int i=0;i<arr.length;i++){
if(arr[i]>max)
max=arr[i];
}
System.out.printf("最大值:"+max);
}
}
2)获取最小值
public class Min{
public static void main(String[] args){
int[] arr={12,13,14,1};
int min=arr[0];
for (int x=1;x<arr.length;x++){
if(arr[x]<min)
min=arr[x];
}
System.out.println("最小值:"+min);
}
}
10.数组类型:
1)一般情况下,java中的类(class),是需要提前把代码写好,然后编译成class文件,再加载到内存中,最后在程序中就可以使用到这个类了。而数组和类不同,数组是使用当前已经存在的某一个类型(任意类型都可以),然后再这个类型后面加上一对中括号([]),这时就组成一个了新的类型:数组类型。
//任意类型 + [] = 相应的数组类型
byte + [] ---> byte[]
short + [] ---> short[]
int + [] ---> int[]
long + [] ---> long[]
float + [] ---> float[]
double+ [] ---> double[]
char + [] ---> char[]
boolean+[] ---> boolean[]
String+ [] ---> String[]
int[] + [] ---> int[][]
//一维数组+[]
变为二维数组
2)数组中可以存放一组数据,要求这一组数据的类型是一样(或者兼容的,兼容就表示可以自动转换)。
例如,int类型数组(
int[]
)中,也是可以存放byte数据的,因为byte可以自动转换为int(兼容)。
11.数组的默认值:
一个数组对象在创建的时候,需要指定数组长度,表示数组中最多存放的元素个数,并且在数组对象创建完成之后,数组中每一个元素位置上,就已经有了相应的默认值,这个默认值和数组的类型有关。
//byte、short、int、long类型数组中的默认值为 0
int[] a = new int[4];//默认4个数据全是0
//float、double类型数组中的默认值为 0.0
double[] d = new double[4];//默认4个数据全是0.0
//boolean类型数组中的默认值为 false
boolean[] d = new boolean[4];//默认4个数据全是false
//char类型数组中的默认值为 '\u0000'
char[] d = new char[4];//默认4个数据全是'\u0000'
//引用类型数组中的默认值为 null
String[] d = new String[4];//默认4个数据全是null
12. 数组拷贝:
1)数组对象的长度确定之后便不能修改,但可以通过复制数组的内容变通实现改变数组长度。
2)在java.lang.System
类中提供一个名为arraycopy
的方法可以实现复制数组中元素的功能。
//该方法的声明
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
//参数1,需要被复制的目标数组
//参数2,从目标数组的哪一个位置开始复制
//参数3,需要把数据复制到另外一个新的数组中
//参数4,把数据复制到新数组的时候,需要把数据从什么位置开始复制进去
//参数5,复制的目标数组的长度
13.工具类:
由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。
1)java.util.Arrays类:
①是JAVASE API中提供的一个工具类。
②作用:就是在代码中辅助我们对数组对象进行操作的。
里面有很多静态方法可以直接调用,主要的功能就是对数组对象进行操作,例如排序、查询、复制、填充数据等等。
2)Arrays中的常用方法:
①toString()
:可以把一个数组变为对应的String形式。
②copyOf()
:可以把一个数组进行复制。
该方法中也是采用了arraycopy方法来实现的功能。
③ copyOfRange
():也是复制数组的方法,但是可以指定从哪一个下标位置开始复制。
该方法中也是采用了arraycopy方法来实现的功能 。
④sort()
:可以对数组进行排序。
⑤binarySearch()
:在数组中,查找指定的值,返回这个指定的值在数组中的下标,但是查找之前需要在数组中先进行排序,可以使用sort()方法先进行排序。
⑥equals()
:可以比较俩个数组是否相等,但是要求俩个数组中的值一一相等并且顺序也要一致才行,所以在比较之前,最好是用sort方法对俩个数组先进行排序。
第一个要求:俩个数组的元素个数相同 。
第二个要求:俩个数组的每个下标对应的数据相同。
⑦fill()
:可以使用一个特定的值,把数组中的空间全都赋成这个值。
⑧asList()
:可以把一组数据,封装到一个List集合中,并且把list集合对象返回。
14.冒泡排序:
1)思想:
在一组数据中,从左到右,俩俩比较,然后把较大的数据往右推,一轮下来之后,最大的一个数据就被推到了最右边。
2)方法定义:
//定义一个冒泡排序的方法,参数是int[],该方法可以对数组进行排序,该方法不需要返回值
public void test(int[] arr){
//获取到数组的长度
int len = arr.length;
//外层循环控制一共比较几轮
for(int i=0;i<len-1;i++){
//内层循环控制每轮比较多少次数,每轮比较的次数是有变化的
for(int j=0;j<(len-i-1);j++){
//比较俩个相邻数据的大小
//如果前一个数据比后一个数据大
if(arr[j]>arr[j+1]){
//交互这个俩个数据的位置
arr[j] = arr[j] ^ arr[j+1];
arr[j+1] = arr[j] ^ arr[j+1];
arr[j] = arr[j] ^ arr[j+1];
}
}
//这个输出,可以看到每一轮比较结束后的结果是怎样的
System.out.println("\t"+Arrays.toString(arr));
}
}
15.选择排序:
1)思想:
每一轮在待排序的区域中比较找到一个最小值后,把这个最小值放到已经排好顺序的区域的末尾,剩下的部分,组成一个新的待排序部分,重复上面的步骤直到排序结束。
🌂:操作的核心目标:
Ⅰ、每轮找到的最小值应该存放的下标位置是什么 。
Ⅱ、每轮找到的最小值现在的下标位置是什么 。
Ⅲ、找到之后,让这俩个位置的值进行交互就可以了 。
Ⅳ、最后一个数字就不用在比较了(前面都排好了,最后一个一定是最大的)。
2)方法定义:
//实现一个方法,参数是int[],该方法可以对数组进行排序,该方法不需要返回值。
public void test(int[] arr){
//数组的长度
int len = arr.length;
//min_now_index表示最小值当前在什么位置
int min_now_index;
//min_should_index表示最小值应用在什么位置
int min_should_index;
//外层循环,控制一共要比较多少轮,同时这个变量i,刚好是每轮我们需要指定的最小值应该存放位置。
for(int i=0;i<len-1;i++){
//每一轮i的值,刚好就是本轮最小值应该存放的位置。
min_should_index = i;
//假设当前i的位置就是本轮最小值的实际位置
min_now_index = i;
//内层循环,负责每轮找出当前未排序区中的一个最小值的实际位置的下标
for(int j=i+1;j<len;j++){
//哪个数据小,就把这个数据下标赋值给min_now_index,目的是让了min_now_index变量中始终保持当前未排序区中的最小值的位置
if(arr[j]<arr[min_now_index]){
min_now_index = j;
}
}
//内层循环结束后,就明确了当前未排序区中的最新值的下标,以及这个最小值应该存放在什么位 置,接下来可以进行交互位置
if(min_now_index != min_should_index){
int temp = arr[min_now_index];
arr[min_now_index] = arr[min_should_index];
arr[min_should_index] = temp;
}
}
}
16.插入排序:
1)思想:
把数组分成俩部分,将后面部分的数据一个一个的和前面部分数据的元素进行比较,如果我们指定的元素比前面部分的元素小,那么就将前面的元素往前移动一步,直到没有比我们这个指定元素还小元素了,那么这个位置就是需要插入的地方。
比较的目的,是为了给当前操作的数字,找一个合适的位置进行插入,注意这个操作数字的位置,有可能是不需要移动的,因为刚好不移动就保持了正常顺序。
🌂:每轮操作完核心目标:
Ⅰ、拿到右边当前要操作的数据,这个值需要临时的保存起来,以便向左边插入合适的位置。
Ⅱ、找出左边一个合适的插入位置。
Ⅲ、最后把右边当前操作的数据,插入到左边合适的位置。
Ⅳ、注意,最后一个数字也需要进行比较,因为要插入到左边一个合适的位置。
2)方法定义:
public void test(int[] arr){
//输出排序前的数组的排列
System.out.println(Arrays.toString(arr));
//当前在右边拿到的第一个要进行操作的数据
int currentValue;
//需要把数据在左边插入的位置
int insertPosition;
//外层循环,控制比较的轮数。同时,变量i的值,还是每一轮我们要操作的右边第一个数字的下标。
for(int i=1;i<arr.length;i++){
//提前保存好我们当前要操作的值
currentValue = arr[i];
//假设当前变量i的值就是要插入的位置,因为这个数据有可能是原位置不动的。
insertPosition = i;
//内层循环,控制每轮比较的次数,以及比较的顺序。同时,变量j的值,还是左边数据中从大到小的下标值。
for(int j=i-1;j>=0;j--){
//每次比较,如果发现arr[j]比当前要操作的数字大
if(arr[j]>currentValue){
//就把这个大的数字往后移动一个位置,就是往后赋值
arr[j+1] = arr[j];
//然后记录一下这个位置,因为这个位置很可能是要插入的位置,到底是不是这个位置,需要和下一个数字比较后才知道
insertPosition = j;
}else{
//如果发现一个比currentValue值还小的值,那么这个值的上一个比较的位置就是我们要找的插入的位置,结束当前循环
break;
}
}
//内层循环结束后,把当前要操作的值currentValue,插入到指定位置insertPosition
//如果insertPosition和当前i值相等,说明当前操作的这个值currentValue是不需要移动 的。
if(insertPosition != i){
//进行值的插入
//把当前右边第一个值(正在操作的值),插入到左边合适的位置
arr[insertPosition] = currentValue;
}
//输出每一轮排序的过程
System.out.println("\t"+Arrays.toString(arr));
}
//最后输出排序的结果
System.out.println(Arrays.toString(arr));
}
笔试常考:数组的动态求和问题
/*
数组的动态求和
输入:1,2,3,4,5
输出:[1,3,6,10,15]
首先要把输入的数据转为数组的形式存储
1,2,3,4,5 => ["1","2","3","4","5"]
*/
import java.util.Scanner;
public class Test{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String[] split = str.split(",");//以逗号的形式分割为数组
int[] nums = new int[split.length];
for (int i = 0; i < nums.length; i++) {
nums[i] = Integer.parseInt(split[i]);//Integer.parseInt()方法是将一个字符串转换为int数字,例如,"109" ==> 109
}
// nums => [1,2,3,4,5]
// => [1,3,6,10,15]
int[] res = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
int sum = 0;
for (int j = 0; j < i + 1; j++) {
sum += nums[j];
}
res[i] = sum;
}
for (int i = 0; i < res.length; i++) {
System.out.println(res[i]);
}
}
}
优化后:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String[] split = str.split(",");
int[] nums = new int[split.length];
for (int i = 0; i < nums.length; i++) {
nums[i] = Integer.parseInt(split[i]);
}
// nums => [1,2,3,4,5]
// => [1,3,6,10,15]
int[] res = new int[nums.length];
//i > 0 res[i] = res[i - 1] + nums[i]
//i = 0 res[i] = nums[i]
res[0] = nums[0];
for (int i = 1; i < res.length; i++) {
res[i] = res[i - 1] + nums[i];
}
for (int i = 0; i < res.length; i++) {
System.out.println(res[i]);
}
}
}