2021-03-25

Day04 内存划分、递归、数组初识

  1. 内存划分
    1.1 程序和进程

程序 : 可执行文件(指令集合),是个静态概念,一般保存在硬盘中

进程 : 正在执行的文件,是一个动态概念,
运行起来的程序,就是指载入到内存中的可执行文件,这个时候操作系统会开启一个进程来运行内存中的这个文件对象,如果要关闭某个程序,就可以直接杀死这个进程

1.2 JVM内存划分
Xxx.class 是个静态概念,保存在硬盘中,当我们执行java 运行命令的时候,会把该class文件载入内存中
Java Runtime Data Area : java运行时数据区域,我们一般叫JVM内存

内存被划分为5个区域 : 程序计数器,方法区/静态区/静态代码段 , 栈内存(虚拟机栈) , 本地方法栈 , 堆内存

程序计数器 : 是一块较小的内存区域,作用可以看做是当前执行的行号,比如 if , 循环, 跳转,异常处理等 都需要依赖程序计数器来完成

静态区/方法区/静态代码段 : 是用来存放我们载入内存中的class文件,包括我们的方法,还有代码段都会保存在静态区
内部还有一个运行常量池
虚拟机栈 : 又叫栈内存
方法是在栈内存中执行的,包括局部变量也是在栈内存
栈内存 : 是一个以栈数据结构为模型,创建的一段空间
栈 : 是一种数据结构,先进后出,类似于子弹夹
栈空间 : 就是指以栈数据结构为模型开辟的空间
栈帧 : 就是栈内存中每一个栈元素
栈顶元素 : 指最后一个保存进去的元素
栈底元素 : 指最先保存进去的元素

栈操作
压栈 : 把元素添加到栈空间的过程
弹栈 : 在栈空间中把数据删除的过程
本地栈 : 和VM栈结构一致,只不过是用来执行本地方法,比如 hashCode(),我们自己写的方法都在VM栈执行

堆内存 : 用来保存对象
根据静态区的class文件,创建的用于存储成员属性的空间
每个对象空间
1 头部部分 : hashCode值
2 数据部分 : 成员变量
3 类型 : 是由哪个类创建的对象,静态区的地址
1.3 Java执行过程
1 java程序编写
文本编辑器
2 java程序编译
Javac 命令
3 Java程序的执行
Java 命令
3.1 开启java虚拟机,载入对应的class文件,载入到静态区
3.2 jvm自动调用main方法
3.3 main被调用,JVM会在栈内存开辟一个main的空间,用于执行main中的代码
如果main中没有其他方法调用,执行完就弹栈,结束,JVM关闭
如果main方法中有其他方法调用,就会在栈内存再次开辟栈帧,把对应的方法放入栈内存,开始执行
如果被调用方法中还有其他方法调用,同上
一直到某一个方法栈中,没有其他方法调用,该方法如果代码执行完成,则该栈帧弹栈,如果需要返回数据,会占用临时空间把数据传递回去
弹栈后 返回上一个栈帧中方法调用处,继续执行
一直到main方法弹栈,则整个栈帧调用链结束.JVM关闭

栈内存是真正执行程序的地方,其他内存都是存储数据
方法调用 就等于是 压栈操作
方法执行结束 就等于是 弹栈操作

动态加载和静态加载
动态加载 : 只载入当前程序和需要的文件,如果执行过程中需要别的文件,再去硬盘中找
静态加载 : 开始执行,把所有和当前程序相关的文件,全部一次性载入

  1. 递归
    2.1 概述
    方法体内部对当前方法进行调用
    递归是什么 : 方法体中对当前方法进行调用
    基本思想 :
    以此类推,同时也是循环的基本思想
    递归和迭代是等价的,迭代就是循环
    所以 都需要起始值,终止条件,步长
    2.2 应用场景
  •  一般树状结构都可以遍历查询等操作
    
  •  递归比普通的循环,算法耗内存,运行效率低,谨慎使用
    
  •  能使用循环搞定的,就不要使用递归,除非循环搞不定
    
  •  例如 : 获取目录下所有的文件(包括子文件夹中的 文件)
    

1 获取根目录下所有直接子文件
2 判断每一个子文件是否是文件夹
3 不是, 直接操作(说明是文件)
4 如果是文件夹,就把该文件夹作为跟目录再去获取所有子目录,再进行判断
5 一直是重复操作,直到把所有的文件夹都遍历完

1层目录,使用1个循环
2层目录,使用2个嵌套循环
3层目录,使用3个嵌套循环

如果不确定目录结构呢? 循环就搞不定了

常见问题
文件夹复制
斐波那契数列
阶乘
累加加和
汉诺塔

难点 : 不容易理解,画栈帧图即可
2.3 累加加和案例
public static void main(String[] args) {
// m1();
int sum = sum(5);
System.out.println(sum);
}
public static int sum(int n) {
if (n == 1) {
return 1;
} else {
return n + sum(n - 1);
// return 5 + sum(4);
}
}
2.4 n-m偶数和

public static int sum(int n, int m) {
	// 转换为偶数
	// 比如 3-7 , 就是 4+6 , 4 = 3+1 , 6 = 7-1;
	// 1 先比较大小
	// 2 转换为偶数
	// n < m : n+1 , m - 1
	// n> m : n-1 , m+1
	if (n < m) {
		if (n % 2 == 1 || n % 2 == -1) {
			n++;
		}
		if (m % 2 == 1 || m % 2 == -1) {
			m--;
		}
		// 只要能到这里 说明n和m已经是偶数了
		if (m == n) {
			return n;
		}
		return n + sum(n + 2, m);
		// return m + sum(n,m-2);
	} else if (n > m) {
		if (n % 2 == 1 || n % 2 == -1) {
			n--;
		}
		if (m % 2 == 1 || m % 2 == -1) {
			m++;
		}
		// 只要能到这里 说明n和m已经是偶数了
		if (m == n) {
			return n;
		}
		return n + sum(n - 2, m);
		// return m+sum(n,m+2);
	} else {
		// 如果相等
		if (n % 2 == 1 || n % 2 == -1) {
			// 奇数为0
			return 0;
		} else {
			// 偶数是自身
			return n;
		}
	}
}

2.5 斐波那契数列
2.5.1 递归实现

  • 斐波那契数列
  • 除了前两位是1,后面每一位都等于前两位的和
  • 1,1,2,3,5,8,13,21,34,55,89…

public static void main(String[] args) {
System.out.println(fibonacci(46));
m1(55);
}

// 递归实现
public static int fibonacci(int n){
	if (n == 1 || n == 2) {
		return 1;
	}
	return fibonacci(n-1) + fibonacci(n-2);
}

2.5.2 循环实现
// 循环实现
public static void m1(int n){
if (n == 1 || n == 2) {
System.out.println(“第一位和第二位的值 都是 1”);
return ;
}
// 第三位开始
// 默认表示第一位,同时表示当前位的前两位
int i1 = 1;
// 默认表示第二位,同时表示当前位的前一位
int i2 = 1;
// 第三位(当前位)
int i3 = 0;
for (int i = 3; i <= n; i++) {
// 得到 当前位的值
i3 = i1 + i2;
System.out.println("第 “+i+” 位的值为 : "+i3);
i1 = i2;
i2 = i3;
}
}

2.6 常见异常
栈满
3. 数组
3.1 概述
基于底层的数据结构,任何语言都有
用于存储多个数据

  • 1 java中的数组
    可以看做多个相同数据类型的存储容器
    有序,可重复
    线性,空间是连续的
    内置对象,保存在堆内存,占用两块空间(栈内存变量 指向 堆内存 对象)

  • 2 Arrays类
    java.util.Arrays 类 是java提供用于操作数据的工具类

  • 3 引用类型
    数组,类,接口
    意味着 数组保存的是地址

  • 4 length
    数组对象中有一个默认的length属性,保存当前数组的长度
    数组长度一旦确定,不能更改
    意味着 数组不能删除数据,想要删除数据,必须重新创建数组空间
    然后把原空间中的内容依次复制过去,在复制过程中,可以进行删除操作(不复制它即可)

  • 5 索引
    数组采用第一个元素的地址,作为整个数组的地址,通过偏移量,可以找到其他元素
    通过内存地址直接查询,所以查询效率极高
    并且每一个元素空间,都有一个独一无二的编号
    而 第一个元素 用 0 表示 以此类推 , 最后一个元素索引 就是 个数-1

特性 :

  •  查询更改快,添加删除慢
    
  •  下标从0开始
    

3.2 数据结构
是计算机存储、组织数据的一种方式
通常选择合适的数据结构 可以带来更高的执行/存储效率

3.3 数组声明
3.3.1 静态声明

  • 1 静态声明 : 在知道数组中每一个元素的值的情况下,使用静态声明

     		数据类型[] 变量 = {值,值,值.....}  多个值 用逗号隔开
    
     		int i = 1;
     		int 一维数组,里面存储 int 值
     		int[] is = {1,2,3,4};
     		int 二维数组,里面存储 int[] 值
     		int[][] iss = {{1,2,3,4},{1,2,3,4},{1,2,3,4}}
     		int[][][] isss = { {{1,2},{3}} , {{2},{1}} }
    
     		boolean[] bs = {false,false,true};
    
     		[] 可以放到变量后面,也可以放到数据类型后面
     		int[] a ; 和 int a[] 一样
    

3.3.2 动态声明

  •   2 动态声明 : 预先不知道保存具体值的情况下使用动态声明,但是需要指定长度
      		(你可以不知道每一个元素的值,但是你得知道有多少元素)
    
      		数据类型[] 变量名 = new 数据类型[长度];
    
      		int[] as = new int[10];   动态声明一个int一维数组,并且里面可以有10个int值
      		int[][] ass = new int[10][2]; 动态声明一个int二维数组,里面有10个一维数组,并且每个一维数组中都有2个int值
      		boolean[] bs = new boolean[2];
      		比如创建的是int一维数组,有10个元素,则 会用对应的默认值 占位(也就是现在数组中有10个0)
      		int[] is = new int[10] : 10个0
      		boolean[] bs = new boolean[4] : 4个false
      		整数型 : 0
      		浮点型 : 0.0
      		字符型 : \u0000
      		布尔型 : false
      		引用类型 : null
    
  • 不管使用哪种声明方式,对应的内存结构和使用操作,都一样

  • 与之相对应的 还有一种数据结构 是 链表
    3.4 数组操作
    3.4.1 获取/访问
    int[] is = {1,22,4,6};
    int[] is1 = new int[3];
    /**
    * 获取/访问 数组对象[ 索引 ] 索引又叫下标,从0开始
    /
    // 4 长度
    System.out.println(is.length);
    // 获取第一个元素
    System.out.println(is[0]);
    // 最后一个元素
    System.out.println(is[3]);
    System.out.println(is[ is.length-1 ]);
    // 0 都是0
    System.out.println(is1[2]);
    3.4.2 设置/更改
    /
    *
    * 设置/更改
    */
    int[] is2 = new int[3];
    // 更改第一个元素
    is2[0] = 123;
    // 更改最后一个元素
    is2[2] = 345;
    is2[ is2.length-1 ] = 10;
    System.out.println(is2[0]);
    System.out.println(is2[1]);
    System.out.println(is2[2]);
    3.5 常见异常
    // 没赋值 默认是null
    static int[] arr1 ;
    public static void main(String[] args) {
    int[] arr = { 1, 2, 3 };
    // 数组下标 不能小于0 , 不能大于等于 长度
    // (因为最后一个是长度-1,而第一个是0 , 只要小于0,大于等于长度,说明找不到)
    // java.lang.ArrayIndexOutOfBoundsException
    // System.out.println(arr[-1]);
    // System.out.println(arr[ 3 ]);
    // System.out.println(arr[ 4 ]);

     // java.lang.NullPointerException 空指针异常
     System.out.println(arr1[0]);
    

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值