数组
JVM运行时数据区
分类
JVM栈
描述的是Java的普通方法(不带native
)执行时的所占内存的内存模型。
每当Java程序执行一个方法,都会在栈上分配一块只属于该方法的内存区域,称之为栈帧
,局部变量会直接存储在栈帧中。
堆(Heap)
堆是JVM内存中最大的一块,new出来的东西都在堆上。
这片空间是有内存地址的,这个内存地址是留给外界访问用的。
方法区
跟类加载相关
本地方法栈
和JVM栈相似,区别是给本地(native)方法使用的,而不是普通方法。
native方法:没有`{}``方法体,看不到实现
程序计数器(PC)
行号计数器,用来记录字节码指令执行到哪一行
引用数据类型
引用数据类型分为两部分:引用 + 对象
左边称之为引用,右边称之为对象
引用里面存的是对象的地址值
本质
指的是对象
引用数据类型和基本数据类型的区别
- 存储位置(本质区别)
基本数据类型不存在引用这个概念,数据都是直接存储在栈帧里
引用数据类型在栈帧中存储引用,引用作为一个局部变量,存储的是该引用类型在堆上对象的内存地址,存储在堆上的对象存储具体信息,才是引用数据类型的实质 - 打印变量名的区别
基本数据类型,打印变量名就是该变量具体的数值
引用数据类型,没有办法直接访问对象,打印会显示该引用存储的堆上的对象的内存地址
数组的基本操作
直接打印
打印的是该对象的一个地址值
获取数组长度
数组名.length
访问数组元素
通过下标,index
数组名[index]
修改数组元素
通过下标,index
数组名[index] = newVal
eg:
[I@1b6d3586
[
:一维数组
I
:int
1b6d3586
:十六进制数
堆和栈中内容的区别
存储类型
堆上存储的是new出来的东西,是引用数据类型的实质——对象
栈上存储的是局部变量、基本数据类型和引用数据类型的引用
默认值
- 堆上对象中的变量具有默认值:
- 整形(byte、short、int、long)默认值为0
- 浮点类型(float、double)默认值为0.0
- 字符类型(char)默认值是
\u0000
表示编码值为0的字符,一个绝对空字符。 - 布尔类型(boolean)默认值是false
- 引用数据类型默认值是null
- 栈上的局部变量没有默认值,声明局部变量后必须显式的初始化,否则无法使用。
对象中元素赋值的第一步永远是————默认初始化、具有默认值
然后才能赋其它具体值
String类型的比较
- 比较内容的时候用
equals
方法
equals
方法使用的时候注意:s1.equals(String s2)
,要保证s1不为null才可以 ==
比较的是对象地址值
生命周期
栈上局部变量跟方法同生共死
堆上对象存在,但是没有引用指向的时候,被当作了垃圾(垃圾对象),无法直接访问对象,只能通过引用间接访问;通过GC垃圾回收机制,经过一系列算法,回收掉这个垃圾
数组操作中的异常
异常的介绍
异常指的是:程序在运行期间出现了不正常情况,这种不正常情况的信息就会封装成一个异常对象。一旦程序出现异常,JVM就会终止程序执行,并在控制台打印异常信息。
异常往往都是XXXException
异常的信息
- 异常类型的全类名(全限定名)
- 出现异常的原因
- 出现错误的代码行(全类名、方法、行数)
异常的分类
- 编译时异常
- 运行时异常
常见的异常
- 数组下标越界异常(ArrayIndexOutOfBoundsException)
- 空指针异常(NullPointerExceptionE)
对于空指针异常的处理,一般都是通过if进行判断进行处理
数组长度为0和数组为null以及数组未初始化的区别
- 数组未初始化: 这个数组完全是不可用的,没有初始化的数组毫无意义,一旦使用会编译报错。
- 数组长度为0:可以认为是初始化的,可以获取数组长度,不能通过下标访问元素。
- 数组为null:可以认为是初始化的,不可以获取数组长度,不能通过下标访问元素。
数组的常见操作
转义字符\b
数组的遍历
- 普通
for
循环 - JDK自带数组遍历实现
Arrays.toString(数组)
注:要传入一维数组,返回值是一个String对象
- 增强
for
循环
手写遍历
增强for循环(迭代器)
-------> 不能改变元素值 <----------
语法
for(数据类型 变量名:数组名){
// 代码
.....
}
语法中的各个部分:
- 数据类型是要遍历数组或集合中元素的数据类型。比如遍历
int
数组,就应该填入int
。 - 从整个遍历的过程中看来,变量名就表示数组/集合中的某一个元素。整体就代表所有元素。
快捷键
数组名.for
或者`数组名.iter
增强for和普通for遍历数组时的区别
- 增强for的语法更简洁,并且遍历效率也会更高一点。
- 增强for循环中没有使用数组下标,而是直接遍历元素。当你想要在循环中使用数组下标时,就无法使用增强for了。
- 增强for也叫迭代器(iterator),它仅仅作为一个遍历数组/集合的工具而存在, 在增强for当中是不能修改任何元素的取值的,只能通过下标修改。
获取数组的最值
数组的逆序
- 使用二分法进行数组逆序
即下标为“0”和“length-1”位置的元素互换,下标为“1”和“length-2”位置的元素互换…
即,把下标为“i”和“length-1-i”元素互换即可!
只需要交换一半数组的元素即可,不要遍历整个数组,会再交换回去!
public static void reverse(int[] arr) {
for(int x=0; x<arr.length/2; x++) {
int temp = arr[x];
arr[x] = arr[arr.length-1-x];
arr[arr.length-1-x] = temp;
}
}
- 使用2个标记进行逆序
public static void reverse(int[] arr) {
for(int start=0,end=arr.length-1; start<=end; start++,end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
}
数组的拷贝
创建一个新数组,然后拷贝赋值的思路:
- 首先需要明确新数组的长度,初始化这个新数组。
- 然后遍历原先的数组,过滤掉(或者新增)一些元素,给新数组赋值。
数组的增删改查
当然“crud”指的是:
c
,create:新增数据/增加。r
,retrieve/read:检索数据/查询。u
,update:更新数据/修改。d
,delete:删除数据/删除。
数组的排序
Arrays.sort(arr);
可变长参数
指参数个数是不确定的,但类型是确定的情况,Java会自动把可变参数当作数组处理
语法
权限修饰符列表 方法返回值类型 方法名(形参列表,数据类型... 变量名){
...// 方法体
}
eg:
public static void test(int a, int... args){}
注意
注意事项:
-
调用方法时,如果有一个固定参数的方法匹配的同时,也可以与可变参数的方法匹配,则选择固定参数的方法。
-
调用方法时,如果出现两个可变参数的方法都能匹配,则报错,这两个方法都无法调用了。
注:一般来说要避免可变参数方法,发生方法重载,避免导致方法调用失效情况出现。
-
一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数。
参数传递
Java的值传递
实参的copy
Java中是值传递的
Java的引用传递
实参自己
提供一个交换数组的方法swap
public static void swap(int[] arr1, int[] arr2){
int[] temp = arr1;
arr1 = arr2;
arr2 = temp;
}