1内存划分
1.1相关知识
程序:可执行文件(指令集合),它是个静态概念,一般保存在硬盘中。
进程:正在执行的文件,是一个动态的概念;程序运行起来,指的就是载入到内存中的可执行文件,操作系统会开启一个进程来运行内存中的这个对象,如果要关闭进程,可以直接杀死这个进程。
1.2JVM内存划分
class文件是个静态概念,保存在硬盘中,执行JVM命令的时候,会把class文件载入内存。
Java Runtime Data Area:Java运行时的数据区域,我们一般叫JVM内存。
1.21内存的五个区域
内存分为五个区域:程序计数器,方法区/静态区/静态代码段,栈内存(虚拟机内存),本地方法栈,堆内存。
- 程序计数器:一块较小的内存区域,作用可以看成当前执行的行号,比如if,循环,跳转,异常处理等都需要用到它。
- 方法区:用来保存载入内存的class文件,包括方法,还有代码段,内部有一个运行常量池。
- 栈内存:栈(数据结构,先进后出);方法是在栈内存中执行,局部变量也是在栈内存;它是一个以栈数据结构为模型,创建的一段空间(栈空间);栈帧:栈内存中每一个栈元素;栈顶元素:最后一个保存进去的元素;栈底元素:最先保存进去的元素;栈操作(压栈:把元素添加进栈空间的过程)(弹栈:在栈空间把元素删除的过程)。
- 本地栈:与JVM结构一致,只是用来执行本地方法,例如hashCode(),我们自己写的方法都在VM栈执行。
- 堆内存:用来保存对象,根据静态区class文件,创建存储成员属性的空间;每个对象空间分为头部部分(hashCode值);数据部分(成员变量),类型(由那个类创建的对象,静态区的地址)。
1.3Java执行过程
编写;编译;执行(开启虚拟机,载入对应的class文件到静态区;JVM自动调用main方法;main调用后,JVM会在栈内存开辟一个main空间,执行main中代码,如果main方法中调用其他方法,会再次开辟栈帧,把对应的方法放入栈内存,开始执行,到方法调用全部结束并且执行完,进行弹栈,如果需要返回数据,就占用临时空间将数据返回,直到main方法弹栈,结束,JVM关闭)。
程序的执行是在栈中执行,其他内存就是存储数据,方法调用就是压栈,方法执行结束就是弹栈。
加载:动态加载(只载入当前程序和需要的文件,如果执行过程中需要别的文件,再去硬盘中找);静态加载(开始执行,把所有和当前程序有关的文件一次性载入)。
Java是动态加载。
2递归
方法体中对当前方法进行调用就是递归。
出现栈溢出,最大可能是没有弹栈,只有压栈。
递归和循环是等价的,迭代就是循环,都需要起始值,终止条件,步长。
一般用于树状结构,用于遍历查询等操作。
递归比一般的循环效率低,算法耗内存,运行效率低,谨慎使用,能够用循环搞定,不要用递归,除非循环搞不定。
/**
*
*/
package day04_Test;
/**
* @author SkyMei
*
* @Date 2021年3月25日 上午10:11:41
* 斐波那契数列
* 如果一对两个月大的兔子以后每一个月都可以生一对小兔子,而一对新生的兔子出生两个月后才可以生小兔子。
* 也就是说,1 月份出生,3 月份才可产仔。那么假定一年内没有产生兔子死亡事件,那 么 1年后共有多少对兔子呢?
*/
public class RabbitQues {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int n = 5;
System.out.println(n+","+Fibonacci(n));
}
/**
* 第一个月有一对兔子
* 第二个月有一对兔子
* 第三个月有两对兔子
* 第四个月有三对兔子
* 第五个月有五对兔子
* @param n
* @return
*/
public static int Fibonacci(int n){
int t1,t2;
if(n==1||n==2){// 第一二个月只有一对兔子
return 1;
}else{// 采用递归
t1=Fibonacci(n-1); // f2+f2+f1
t2=Fibonacci(n-2); // f2+f1
return t1+t2;// 计算第n个月的兔子对数
}
}
}
3数组
3.1概述
基于底层的数据结构,任何语言都有,用于存储多个数据。
3.2数据结构
是计算机存储和组织数据的一种方式;通常选择合适的数据结构可以带来更高的执行/存储效率。
数组可以看作是多个相同数据类型的存储容器,是有序可重复的,线性,空间是连续的,内置对象,保存在堆内存,占用两块空间(栈内存变量 指向 堆内存 对象)。
Array类是java.util.Arrays,Java提供的用于操作数据的工具类。
引用类型:数组,类,接口;意味着数组保存的是地址。
数组对象中有一个默认的length属性,保存当前数组的长度,数组长度确定后不能更改,数组不能删除数据,想删除数据需要重新创建数组空间,然后把原空间的内容依次复制过去,在复制过程中可以进行删除操作。
数组采用第一个元素的地址作为整个数组的地址,通过偏移量找到其他元素,通过内存地址直接查询,所以查询效率高,并且每一个元素空间都有一个独一无二的编号,第一个元素用0表示,以此类推最后一个元素就是索引,也就是个数-1,查询更改快,增加删除慢
3.3语法结构
静态声明: 在知道数组中每一个元素值的情况下,使用静态声明。
数据类型[] 变量 = {值,值,值…}多个值用逗号隔开。
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}};
boolean[] bs ={true,false};
int a[]和int[] a是一样的,[]可以放在变量后或者数据类型后。
动态声明:预先不知道保存的具体值,使用动态声明,但是需要指定长度,可以不知道值,需要知道有多少元素。
// 数据类型[] 变量名 = new 数据类型[长度]
int[] as = new int[10];
int[][] ass = new int[10][2];
// 声明一个int二维数组,里面有十个一维数组,每个一维数组中有两个int值
创建一个一维数组,有十个元素,会先启用默认值占位,也就是10个零(false,0.0,null,\u0000)。
不管哪种声明,对应的内存结构和操作方式都一样。
3.4数组操作
int[] is = {1,2,3};
// 获取访问 数组对象[索引] 索引又叫下标 从0开始
int[] is1 = new int[3];
is.length是求数组的长度,is[0]表示数组第一个元素,is[is.length-1]表示最后一个元素。
is1[0]=123相当于给把s1数组第一个值从默认值0改为123。
数组下标不能小于0 ,也不能大于等于长度。