JVM内存图
ps:JVM内存的划分,根据人为的不同可以划分为不同的样式,上图是基本的内存图
程序计数器
当前线程所执行的字节码行号(执行到那个位置就添加对一个序号)
本地方法栈
为虚拟机使用native方法所提供的服务(java中有一些方法是使用native修饰,没有具体方法体,他们的实现是通过本地 系统C++类库或C类库进行实现)
Java虚拟基栈(栈空间)
描述Java方法执行的内存模型,每个方法执行的时候都会站在栈中创建一个栈帧,栈帧可以存储局部变量,操作栈,动态链
接,方法的出口等信息 ps:每一个方法,创建一个栈帧,栈帧张总存放了当前方的数据信息,当前反方执行完成之后,会还行弹栈,销毁栈帧
Java堆 被所有线程共享的一块存储区域,在虚拟机启动的时候会创建.所有对象都是开辟在堆空间中
ps:在堆开辟空间,需要使用一个关键字 new -->代表在堆中开辟了一块新空间
方法区
所有线程共享的区域,存储已被虚拟机加载的类信息(.class)、常量、静态变量,即实时编译所的到的数据都存在这个区 域
Java数组
声明变量–>>>数据类型 变量 = 值;
声明变量的作用是方便在代码中对数据的一种操作
当出现相对来说比较大的数据量是,使用变量进行管理就不回特别方便;此时java提供了一种数据结构,对大量数据进行储存并进行统一管理,这个数据结构就是–>>数组
1、数组储存数据的时候会记录数据的位置和具体值方便操作
2、数组是一个定长的数据结构(一旦确定数组大小,就不能存储超过范围的数据)
3、数组是开辟在堆空间,连续存的一个内存空间
4、数组中只能储存相同数据类型的元素(值)ps:不是绝对的,学习object后,数组也可以存所有object类型的数据(子类) 数组是一种数据结构,储存在数组中的数据是按照一定顺序排列而成的
数组中元素的数据类型
数组的可以声明成基本类型和引用数据类型
引用数据类型:数组,字符串,自定义类,集合等等
无论是基本数据类型还是引用数据类型,创建数组的时候,数组中都会存储默认值
整数类型存储默认值都是:0
小数类型存储的默认值都是 0.0
char类型存储的是一个空字符-->不可见
引用类型存的是 null --> 空 --> 在堆中没有开辟
ps:需要注意一个问题NullPoniterException空指针异常 这个异常的原因是因为,使用null进行一些操作
如何声明数组
/**
* 数组的四种创建方式 * @author JKMaster *
*/
public class ArrayDemo1 {
public static void main(String[] args) {
// 1.标准创建 :创建数组的同时指定数组的大小
//语法 数组中元素的数据类型[] 数组名 = new 数组中元素的数据类型[数组中元素的个数(即是数组的大小也是数组的长度)];
//数组的数据类型是: 数据类型[]
//[]之前的数据类型是:数组元素的数据类型即数组中可以存储什么样的值
int[] arr = new int[10];
//2.先声明,然后在对数组进行赋值(创建类时,数组作为类的属性存在)
/*
* 数组中元素的数据类型[] 数组名;
** 数组名 = new 数组中元素的数据类型[数组中元素的个数(即是数组的大小也是数组的长度)];
**/
int[] arr1;
arr1 = new int[10];
//3.创建数组的同时指定数组中元素
//语法: 数组中元素的数据类型[] 数组名 = new 数组中元素的数据类型[]{元素1,元素2,元素3.....};
//ps:绝对不能再[]中写入数组大小,当前数组是根据后面{ }中的元素来决定数组多大的
int[] arr2 = new int[] {1,2,3,4,5};
//此时数组的大小即5
//4.就是第三种简化
//语法: 数组中元素的数据类型[] 数组名 = {元素1,元素2,元素3.....};
int[] arr3 = {1,2,3,4,5};
}
}
如何操作数组
import java.util.Arrays;
import java.util.Scanner;
/**
* 数组基本操作
* @author JKMaster *
*/
public class ArrayDemo2 {
public static void main(String[] args) { //创建数组
//数组中元素的数据类型[] 数组名 = new 数组中元素的数据类型[数组中元素的个数(即数组大小,数组长 度)]
int[] arr = new int[10];
//[I@70dea4e-->不是数组的地址
//不能通过打印数组对象的方式来打印出数组中存储的元素 System.out.println(arr);
//创建数组的同时,数组是有默认元素值
//整数默认值是都是0
//若数组中存储的是引用类型,默认值是null一定要注意判断在使用不认会出现空指针异常
//若创建引用类型的时候,没有赋值之前(即开辟堆空间),不要使用 System.out.println(Arrays.toString(arr));
//取出数组某一个元素的值怎么办?
// 下标(角标) 从0开始 到当前数组长度-1结束
//例如 有一个数组,数组的长度是5 它的下标就是 0,1,2,3,4
//要修改数组中第一个元素的值
//语法:数组名[下标值] = 值;
总结:
若访问数组中的元素,需要通过下标完成,下标范围 从0开始(第一位) 到 当前数组长度-1结束(最后一位)
数组名[下标值] = 值; --> (赋值)
数组类型 变量名 = 数组名[下标值] 或 System.out.println(数组名[下标]) --> (取值)
下标值不能是负数或大于等于数组长度,不然会出现一个异常
ArrayIndexOutOfBoundsException -->数组下标越界异常(数组中的下标超出了范围)
获取数组长度: 数组名.length --> 便捷的获取数组的最后一位的下标 数组名.length-1
//通过数组下标对应的元素进行修改
arr[0] = 100; System.out.println(Arrays.toString(arr));
//需要取出数组中的值 —>>>语法 数组名[下标值];
//ps:需要注意数组下标的值绝对不能是负数或是大于等于数组的长度 //ArrayIndexOutOfBoundsException -->数组下标越界异常(数组中的下标超出了范围) //System.out.println(“访问数组中的元素:”+arr[10]);
//获取数组长度
System.out.println(“数组的长度:”+arr.length); //访问数组中最后一个元素 System.out.println(“数组中最后一个元素是:”+arr[arr.length-1]);
如何给数组赋值
//1.静态赋值
int[] nums = {1,2,3,4,5,6};
//2.动态赋值
Scanner input = new Scanner(System.in);
arr2[0] = input.nextInt();
//使用随机数
arr2[1] = (int)(Math.random()*100); System.out.println(Arrays.toString(arr2));
} }
如何遍历数组
1、普通for循环
2、增强for循环(foreach)
/**
* 遍历数组的两种方式 * @author JKMaster *
*/
public class LoopArrayDemo {
public static void main(String[] args) {
int[] arr = new int[10];
//向数组中随机插入0-100之间值
//普通for循环
//i =0的原因是因为:若需要操作数组中的元素,需要使用下标
//i作为循环变量,从0开始,数组中第一个元素的下标
//通过不断的自增i变量以达到操作数组下标的目的
//当下标到达数组长度的时候,循环停止即可
for(int i = 0; i<arr.length;i++) {
arr[i] = (int)(Math.random()*100);
}
//打印数组中的值
for(int i = 0;i<arr.length;i++) {
System.out.println("数组中第"+(i+1)+"位置的值是:"+arr[i]); }
System.out.println("-------------------------------------------------华丽的分割线---- -------------------------------------");
//增强for循环 /*
* 语法: for(数组中元素数据类型 变量名:数组名){ 操作当前变量就等于获取了数组存储的元素值
* } */
* //通过增强for循环改变数组原有的值
* // 在for循环中相同定义了变量a 这个a获取数组每一个元素 /*
int ai[];
int l = (ai = arr).length;
for (int j = 0; j < l; j++){
int a = ai[j];
a = 0;
}
*
*/
for(int a : arr) {
//这个所做的并不是给数组中修改值,而是给当前局部变量a修改值 a = 0;
}
//增强for循环对数组进行打印,不能赋值 System.out.println("通过增强for循环对数组中元素进行赋值");
for(int a1 : arr) {
System.out.println(a1);
}
}
}
数组排序
数组中排序有很多种:冒泡,选择,插入,快排,堆,归并等排排序方式
冒泡排序:
//打印没有排序之前数组值 System.out.println(Arrays.toString(arr));
//对数组进行排序操作 //1.数组中所有的元素都需要进行一次比较,所以通过循环满足每一个元素比较 for(int i = 0 ;i<arr.length;i++) {
//控制比较次数
//arr.length-1的目的是为了方式数组下标越界异常 原因在于 j+1 会到大数组的长度
//-i随着比较次数的逐渐增多,每一次都会有一个正确数放到正确的位置,那么通过-i操作
//减少当前需要排序的元素个数
for(int j = 0; j<arr.length-1-i;j++) {
//具体元素的比较
if(arr[j] > arr[j+1]) { //交换
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
选择排序:
//先确定循环的次数,有多少个元素就执行多次
for(int i = 0;i<arr.length;i++) {
//循环的次数即比较次数
//j的初始变量值是i+1 即i的下位,因为i是固定比较值
for(int j = i+1;j<arr.length;j++) {
//具体数据的比较
//i值就是一个固定的元素值
if(arr[i] > arr[j]) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
线性查找和二分查找
当前这两种查找方式都可以在数组查找出需要的数据
线性查找
/**
* 线性查找数据
* @param arr 是一个整数数组
* @param num 是要查找的值
* @return 返回的值正数就知道即下标 */
返回的是-1即没有找到
public static int LinearSearchNumber(int[] arr,int num) { //线性查找即顺序查找,将整个数组进行遍历比较每一个元素
for(int i = 0; i<arr.length;i++) {
if(arr[i] == num) {
return i;
}
}
//当循环是通过循环条件正常停止,即没有找到相同的数据所以此时返回-1
return -1; }
二分查找
- 二分查找理论
1.先定义一个开始值beginIndex也就是起始的位置即下标第一位
2.在定义一个结束值endIndex也就是结束的为位置即下标的最后一位
3.通过 (beginIndex+endIndex)/2得到一个中值即middleIndex
4.通过中间值获取对应数组中的数据,然后和要比较的数据进行比较
4.1当前比较的值大于中间值所对应数据,此时就需要去中间值的右半区进行查找
需要重新计算中间值,需要移动开始值beginIndex = middleIndex+1
重计算中间值即 (beginIndex+endIndex)/2得到一个中值即middleIndex
4.2当前比较的值小于中间值所对应的数据,此时就需要去中间值的左半区进行查找 需要重新计算中间值,需要移动结束值endIndex = middleIndex-1重计算中间值即 (beginIndex+endIndex)/2得到一个中值即middleIndex
4.3 查找到当前数据,即中间值的位置就要查找的数据
4.4 没有找到出现了交叉 即 beginIndex > endIndex
传值和传址
数组工具类
import java.util.Arrays;
public class ArrayTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[10];
for(int i=0;i<arr.length;i++) {
arr[i]= (int)(Math.random()*100);
}
String str = Arrays.toString(arr);
System.out.println(str);
//排序(升序)
Arrays.parallelSort(arr);
System.out.println(Arrays.toString(arr));
//二分查找
/**
* 找到即下标,找不到负数
*/
int index = Arrays.binarySearch(arr, 20);
//复制数组
/**
* 深拷贝:数组的地址和内容都要复制
* 浅拷贝:只复制数组怼内容不复制数组怼地址
* 第一个参数是要复制的数组
* 第二个参数是复制的长度,这个长度不能为负数
* 这里是浅拷贝
*/
int[] newArr = Arrays.copyOf(arr, 15);
System.out.println(Arrays.toString(newArr));
/*
* 拷贝范围内的数组
*
* 第一个参数要拷贝数组
* 第一个参数是开始的位置
* 第三个参数是结束的位置
* 包括开始但是不包括结束,参数是下标
* 能是负数 不能超过范围
*/
int[] newArr2 = Arrays.copyOfRange(arr, 2, 5);
System.out.println(Arrays.toString(newArr2));
/*
* 引用类型进行比较(不能使用==)
* 使用==判断引用类型,比较的是内存地址值,不是内容
* 需要使用equals进行判断
*/
int[] a1 = {1,2,3,4};
int[] a2 = {1,2,3,4};
System.out.println("a1和a2是一样吗?"+(Arrays.equals(a1, a2)));
}
}
今日总结:JVM内存原理浅析,声明数组,数组赋值,操作数组,排序遍历问题,两种查找,传值和传址