一、JDK1.8内存结构

数组 - 图1
这里介绍的是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文件
数组 - 图2

二、数组

1. 数组的概念与特点

public static void main(String[] args) {
//定义一个学生的名字
String name1 = “徐家豪”; //字符串常量
//…. 定义55位同学的名字 就要创建55个变量存储 55位同学的名字
String name55 = “李杰”;

  1. //定义一个变量 存储55位同学的名字<br /> //数组就是主要一个大容器 能存储很多的数据
  2. System.out.println(name1);//0x123<br />}<br />数组的目的就是解决存储 很多个数据<br />数组:是一种存储空间是连续的,元素类型是一致的 这么一个装东西的容器。并且这个容器可以使用下标,或者叫索引的东西,可以去进行检索
  1. 数组可以连续的存储很多个数据
  2. 容器中必须定义存储的是什么 的数据 (数据类型)
  3. 数据可以从容器中取出

例如 :存储学生的姓名 (55名学生)
定义一个数组,类型是String类型 ,存储容量是55
String[] names = new String[55];

2.数组的声明和赋值

数组的声明 :语法
类型[] 变量名 = new 类型[数组的容量];
//定义数组时 必须定义容量
定义数组时 分为两部分 :

  1. 数组的声明 //声明一个数组 存储10个数字
    int[] nums ; //定义了一个数组的变量
  2. 数组的赋值数组的赋值分为两种 :
    • 静态赋值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 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;
    1. 数组中数据的获取在获取数组中值的时候, 使用下标进行获取//定义一个数组 存储学生的成绩
      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(citys[i]);
}
System.out.println(“======”);
// 定义一个数组 存储学生的成绩 10 个成绩 然后再把学生成绩 循环遍历出来
int[] scores = new int[10];
Random r = new Random();
for(int i=0;i scores[i] = r.nextInt(100)+1;
}

//打印出所有成绩
System.out.println(“所有学生成绩:”);
for(int i=0;i System.out.print(scores[i]+” “);
}

//打印出 及格学生的成绩
System.out.println(“及格学生的成绩:”);
for(int i=0;i if(scores[i] >= 60){
System.out.print(scores[i] + “ “);
}
}

//计算出 所有学生的平均分
int sum = 0;
for(int i=0;i sum += scores[i];
}
System.out.println(“品均分:”+sum / (scores.length * 1.0));

//输出 最高成绩 和 最低成绩
int max = 0; //假设是最高成绩
int min = 100; //假设是最低成绩

for(int i=0;i if(max < scores[i]){
max = scores[i] ;
}

}
System.out.println(“最高分是:”+max);

}
}
案例 :在数组中查询一个数据 ,如果查询到打印出来 ,查不到提示查不到

4.数组内存分析

在Java中如果是基本数据类型 ,存储在栈区 ,因为基本数据类型 在Java虚拟机中已经被定义好 。
引用类型:必须是用户自定义 ,在虚拟机中存储 ,存储在堆区,然后使用的时候,使用的是引用类型的 引用(变量名字称),通过引用在堆区找到引用对象 ,所以在引用上存储的是引用对象的地址。
数组 - 图3
数组就是一个引用类型 :
定义一个数组:
//静态赋值
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();

User[] users = new User[];
数组 - 图4

5.数组的小算法

  1. 浅拷贝地址的复制两个数组的引用 指向同一个内存地址 数组 - 图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]);
    }
    }
  2. 深拷贝 在内存中在拷贝一个数组对象 ,把元数组的元素数据 ,转到新数组中去 ,两个数组互补影响数组 - 图6public 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;i ms[i] = nums[i];
    }

    nums[2] = 1000;

    for(int i=0;i System.out.println(ms[i]);
    }
    }
    }

  3. 冒泡排序是排序算法的一种 int[] nums = {2,4,12,7,56,45,23,99,77} ;
    int temp = 0 ; //定义一个临时变量 用于数据交换
    for(int i=0;i for(int j=0;j if(nums[j] > nums[j+1]){
    //如果前面的数据比后面的数据大 ,数据交换
    temp = nums[j];
    nums[j] = nums[j+1];
    nums[j+1] = temp;
    }
    }
    }加强for循环 : 和之前下标循环(普通for循环达到的功能是一样的,目的简化循环操作)语法 :/
    类型 : 数据的类型
    变量 : 循环出来的每一个数据 自定义命名
    容器 :循环的目标
    /
    for (类型 变量 : 容器(数组、集合)) {
    // 循环体
    }

for(int i :nums) {
System.out.println(i);
}

String[] names = {“jim”,”jack”,”张三丰”,”张无忌”,”赵敏”};
for(String s : names){
System.out.println(s);
}不能直接获取到下标

  1. 选择排序 public class Test02_选择排序 {
    public static void main(String[] args) {
    int[] nums = {12,4,77,56,34,88,74,23} ;

    //找到此数组最大数据所在的下标
    /int max = 0 ;//假设最大数的下标就是0
    for(int i=1;i if(nums[max] < nums[i]){
    max = i;
    }
    }

    System.out.println(nums[max]);
    /

    int temp = 0;//临时存储变量

    for(int i=0;i int max = i ; //假设这是最大数据的下标

    for(int j= i+1;j if(nums[max] > nums[j]){
    max = j;
    }
    }

    //判断是否需要交换数据
    if(max != i){
    temp = nums[max];
    nums[max] = nums[i];
    nums[i] = temp;
    }
    }

    for(int i :nums){
    System.out.println(i);
    }
    }
    }
  2. 二分查找二分查找是一种快速查询数据的方式 ,但是这个数组或者集合 必须是经过排序的public static int getIndex(int[] nums ,int data){
    int left = 0;
    int right = nums.length-1;

    while(left <= right){
    int mid = (left + right) / 2 ;

     if(nums[mid] == data) {<br />            return mid;<br />        }else if(nums[mid] > data){<br />            right = mid-1;<br />        }else if(nums[mid] < data){<br />            left = mid+1;<br />        }<br />    }
    

    return -1 ;
    }

    三、二维数组

    二维数组是程序员给起的名字。
    二维数组的意思是 数组元素中存储的也是一个数组
    int[] nums = {2,3,5,6,8,9};// 一般一维数组
    int[][] datas = {{1,2,3} ,{4,5,6} ,{6,7,8},{,1,22,33,44,55}}
    二维数组在内存的存储 :
    数组 - 图7
    二维数组的定义:

  3. 静态赋值int[][] datas = {{1,2,3} ,{4,5,6} ,{6,7,8},{,1,22,33,44,55}}

  4. 动态赋值int[][] datas ; //二维数组的声明 null;
    datas = new int[4][]; //在定义二维数组的时候 一位一定要给长度 二维中不需要制定长度
    // int[][] datas = new int[4][];
    //如何给二维数组赋值
    datas[0][0] = 10;
    datas[0][1] = 20;
    datas[0][2] = 30;
    // 上述赋值完之后 ,datas数组的 0号位上 被赋予了值 这个值是一个 数组 {10,20,30} 其他号位 是 null 值

datas[1] = new int[3] ;
datas[1][2] = 201;3.二维数组的遍历int[][] datas = {{1,2,3} ,{4,5,6} ,{6,7,8},{1,22,33,44,55}} ;//遍历这个数组
public class Test04_二维数组 {

public static void main(String[] args) {


int[][] datas = {{1,2,3} ,{4,5,6} ,{6,7,8},{1,22,33,44,55}} ;//遍历这个数组

    for(int i=0;i<datas.length;i++) {<br />            //获取的每一个 i 上值 都是一个 数组<br />            for(int j=0;j<datas[i].length;j++){<br />                System.out.print(datas[i][j] + " ");<br />            }<br />            <br />            System.out.println();<br />        }<br />        System.out.println("======================");<br />        //定义一个二维数组  数组中存储 每一个省份的城市<br />        String[][] citys = {<br />                {"合肥市","芜湖市","蚌埠市","淮北市","淮南市"},    <br />                {"南京市","无锡市","苏州市","常州市","镇江市"},    <br />                {"武汉市","恩施市","黄冈市","襄阳市","孝感市"},    <br />                {"济南市","青岛市","潍坊市","菏泽市","烟台市"},    <br />                {"石家庄市","秦皇岛市","唐山市","承德市","邯郸市"}<br />        };<br />        <br />        for(String[] arr :citys){<br />            for(String s :arr){<br />                System.out.print(s + " ");<br />            }<br />            <br />            System.out.println();<br />        }<br />    }<br />}
  1. 只要超过一位的数组 ,都叫多维数组 ,多维数组的本质 就是在数组的元素上存储的依然是一个数组下面以三位数组为例 :三位数组的定义 :数组 - 图8因为数组中有null 值 ,所以循环的时候 一定要判断 数组中的元素不能是null 值 ( 不是最后一维 )因为null 值 不能调用属性和方法 ,紫瑶使用null调用属性和方法 就会报 空指针异常public class Test05_多维数组 {


    public static void main(String[] args) {

    String[][][] areas = {
    {{“合肥一区”,”合肥二区”,”合肥三区”},{“芜湖一区”,”芜湖二区”}},
    {{“南京一区”,”南京二区”,”南京三区”}, {“工业园区”,”姑苏区”,”吴中区”,”吴江区”}}
    };

    for(int i=0;i for(int j=0;j for(int k=0;k System.out.print(areas[i][j][k] + “ “);
    }

    System.out.println();
    }

    System.out.println();
    }

    //动态赋值
    int[][][] nums = new int[3][][];
    nums[0] = new int[2][];
    nums[0][0] = new int[3];

    //赋值
    nums[0][0][0] = 1000;
    //必须对数组进行初始化 创建对象
    nums[2] = new int[3][];
    nums[2][2] = new int[3];
    //赋值
    nums[2][2][2] = 500;

    for(int i=0;i if(nums[i] != null){ //判断不是null 值
    for(int j=0;j if(nums[i][j] != null) { //判断不是null 值
    for(int k=0;k System.out.println(nums[i][j][k]);
    }
    System.out.println();
    }

    }
    System.out.println();
    }

    }
    }
    }

    四、多维数组

    • 静态赋值String[][][] citys = {
      {{“合肥一区”,”合肥二区”,”合肥三区”},{“芜湖一区”,”芜湖二区”}},
      {{“南京一区”,”南京二区”,”南京三区”}, {“工业园区”,”姑苏区”,”吴中区”,”吴江区”}}
      };
    • 动态赋值


五、数组与一般应用变量的区别

public class Test01 {
    public static void main(String[] args) {
        String str1="A";
        String[] st1= {"a","A"};
        String[] st2=new String[2];
        //比较字符串和数组调用方法的返回的区别
        //字符串
        System.out.println("字符串");//便于区分
        System.out.println(str1);//A
        String str2=change(str1);//A
        System.out.println(str1);//Aa
        System.out.println(str2);
        //字符串数组
        System.out.println("字符串数组");//便于区分
        System.out.println(st1);//地址 [Ljava.lang.String;@6504e3b2
        for(String i:st1) {//a,A
            System.out.print(i+" ");
        }
        System.out.println();

        st2=changeArr(st1);
        System.out.println(st1);//地址 [Ljava.lang.String;@6504e3b2
        for(String i:st1) {//A,a
            System.out.print(i+" ");
        }
        System.out.println();

        System.out.println(st2);//地址 [Ljava.lang.String;@6504e3b2
        for(String i:st2) {//A,a
            System.out.print(i+" ");
        }

    }

    public static String change(String str) {
        str+=(char)(str.charAt(0)+32);

        return str;
    }
    public static String[] changeArr(String[] st) {
        String temp;
        temp = st[0];
        st[0] = st[1];
        st[1] = temp;
        return st;
    }
}

可以得出数组不经过特殊处理是在原数组上进行修改,而变量则会拷贝一份新的数据在进行操作