一、JDK1.8内存结构
这里介绍的是JDK1.8 JVM内存模型。1.8同1.7比,最大的差别就是:元数据区取代了永久代(方法区)。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存
1.程序计数器
每个线程一块,指向当前线程正在执行的字节码代码的行号。如果当前线程执行的是native方法,则其值为null。
(程序计数器 一般不需要我没关心的)
2.Java虚拟机栈
线程私有,生命周期与线程同进同退。每个Java方法在被调用的时候都会创建一个栈帧,并入栈。一旦完成调用,则出栈。所有的的栈帧都出栈后,线程也就完成了使命。
在程序执行过程中,把方法加载到内存中(这块内存我们叫 栈内存,所以我们的局部变量就存储在栈空间)
3.本地方法栈
功能与Java虚拟机栈十分相同。区别在于,本地方法栈为虚拟机使用到的native方法服务不需要关心,当Java语言调用 windows系统中的 c语言方法的时候 ,把C语言加载到本地方法栈
4.堆 (重点)
此内存区域的唯一作用就是用来存放对象实例,几乎所有的对象实例都在这里分配内存。堆是java虚拟机管理的内存中最大的一块,被所有线程共享。由于堆是垃圾收集器管理的主要区域,所以也被称为GC堆。由于现代收集器基本都采用分代收集算法,所以java堆中还可以细分为新生代,老年代。新生代又细分为Edan区、From Survivor区(S0)、To Survivor区(S1)
JDK1.8里面 ,把常量也存储到堆区
5.元数据区
存储已被虚拟机加载的类信息。随着JDK8的到来,JVM不再有方法区(PermGen),原方法区存储的信息被分成两部分:1、虚拟机加载的类信息,2、运行时常量池。分别被移动到了元空间和堆中
存储的是class文件
二、数组
1. 数组的概念与特点
public static void main(String[] args) {
//定义一个学生的名字
String name1 = “徐家豪”; //字符串常量
//…. 定义55位同学的名字 就要创建55个变量存储 55位同学的名字
String name55 = “李杰”;
//定义一个变量 存储55位同学的名字<br /> //数组就是主要一个大容器 能存储很多的数据
System.out.println(name1);//0x123<br />}<br />数组的目的就是解决存储 很多个数据<br />数组:是一种存储空间是连续的,元素类型是一致的 这么一个装东西的容器。并且这个容器可以使用下标,或者叫索引的东西,可以去进行检索
- 数组可以连续的存储很多个数据
- 容器中必须定义存储的是什么 的数据 (数据类型)
- 数据可以从容器中取出
例如 :存储学生的姓名 (55名学生)
定义一个数组,类型是String类型 ,存储容量是55
String[] names = new String[55];
2.数组的声明和赋值
数组的声明 :语法
类型[] 变量名 = new 类型[数组的容量];
//定义数组时 必须定义容量
定义数组时 分为两部分 :
- 数组的声明 //声明一个数组 存储10个数字
int[] nums ; //定义了一个数组的变量 - 数组的赋值数组的赋值分为两种 :
- 静态赋值int[] nums ;
nums = {10,20,30,40,50,60,70,80,90,100}; //静态赋值
//int[] nums = {10,20,30,40,50,60,70,80,90,100};
- 静态赋值int[] nums ;
int datas[] = {1,4,5,7,8,34,67,89,100} ;静态赋值的时候,不需要考虑数组的容量 ,你给多少个值 就是多大容量
- 动态赋值动态赋值 ,先把数组定义好,并且初始化好 ,然后利用数据的下标进行赋值int[] scores = new int[10];
//数组的下标是从0开始
scores[0] = 89;
scores[1] = 78;
//。。。
scores[9] = 65;- 数组中数据的获取在获取数组中值的时候, 使用下标进行获取//定义一个数组 存储学生的成绩
double[] scores = new double[5];
scores[0] = 89;
scores[1] = 67;
scores[2] = 87;
scores[3] = 45;
scores[4] = 79;
//scores[5] = 100; 超出容量
- 数组中数据的获取在获取数组中值的时候, 使用下标进行获取//定义一个数组 存储学生的成绩
double x = scores[1];
定义一个数组 ,存储5个城市的名字 然后把5个城市的名字获取到 并输出
public class Test02_数组的取值 {
public static void main(String[] args) {
//定义一个数组 ,存储5个城市的名字 然后把5个城市的名字获取到 并输出
String[] citys = {“北京”,”南京”,”上海”,”东京”,”深圳”};
System.out.println(citys[0]);
System.out.println(citys[1]);
System.out.println(citys[2]);
System.out.println(citys[3]);
System.out.println(citys[4]);
//System.out.println(citys[5]); 超出边界
/
java.lang.ArrayIndexOutOfBoundsException 数组越界错误
*/
System.out.println(“============================”);
String[] pros = new String[5];
pros[0] = “江苏省”;
pros[1] = “湖南省”;
pros[2] = “江西省”;
pros[3] = “浙江省”;
pros[4] = “山东省”;
//pros[5] = “上海市”; //越界
System.out.println(pros[3]);<br /> }<br />}
3.数组的使用
如何获取一个数组的元素个数 (数组的容量):
String[] citys = {“北京”,”南京”,”上海”,”东京”,”深圳”};
//数组中有一个属性 length
System.out.println(“citys数组的长度:”+citys.length);
public class Test03_数组的遍历 {
public static void main(String[] args) {
String[] citys = {“北京”,”南京”,”上海”,”东京”,”深圳”};
//循环遍历打印这个数组
for(int i=0;i
}
System.out.println(“======”);
// 定义一个数组 存储学生的成绩 10 个成绩 然后再把学生成绩 循环遍历出来
int[] scores = new int[10];
Random r = new Random();
for(int i=0;i
}
//打印出所有成绩
System.out.println(“所有学生成绩:”);
for(int i=0;i
}
//打印出 及格学生的成绩
System.out.println(“及格学生的成绩:”);
for(int i=0;i
System.out.print(scores[i] + “ “);
}
}
//计算出 所有学生的平均分
int sum = 0;
for(int i=0;i
}
System.out.println(“品均分:”+sum / (scores.length * 1.0));
//输出 最高成绩 和 最低成绩
int max = 0; //假设是最高成绩
int min = 100; //假设是最低成绩
for(int i=0;i
max = scores[i] ;
}
}
System.out.println(“最高分是:”+max);
}
}
案例 :在数组中查询一个数据 ,如果查询到打印出来 ,查不到提示查不到
4.数组内存分析
在Java中如果是基本数据类型 ,存储在栈区 ,因为基本数据类型 在Java虚拟机中已经被定义好 。
引用类型:必须是用户自定义 ,在虚拟机中存储 ,存储在堆区,然后使用的时候,使用的是引用类型的 引用(变量名字称),通过引用在堆区找到引用对象 ,所以在引用上存储的是引用对象的地址。
数组就是一个引用类型 :
定义一个数组:
//静态赋值
int[] nums = {1,4,23,56,66};
//动态赋值
int[] ages = new int[5];
ages[0] = 18;
ages[3] = 20;
//日期对象数组
Date[] dates = new Date[5];
dates[0] = new Date();
dates[2] = new Date();
5.数组的小算法
- 浅拷贝地址的复制两个数组的引用 指向同一个内存地址 改变任何一个数组的元素值,另外一个数组会变化,因为他们指向的是同一个数组public class Test05_数组拷贝 {
public static void main(String[] args) {
//数组的浅拷贝
int[] nums = {1,2,3,4,5} ; // 0x123 nums = 0x123
int[] ms = nums ;//浅拷贝
nums[2] = 100 ;
System.out.println(ms[2]);
}
} - 深拷贝 在内存中在拷贝一个数组对象 ,把元数组的元素数据 ,转到新数组中去 ,两个数组互补影响public class Test05_数组拷贝 {
public static void main(String[] args) {
//数组的深拷贝
int[] nums = {1,2,3,4,5} ; // 0x123 nums = 0x123
int[] ms = new int[nums.length];
for(int i=0;ims[i] = nums[i];
}
nums[2] = 1000;
for(int i=0;iSystem.out.println(ms[i]);
}
}
}