zoukankan      html  css  js  c++  java
  • JavaSE基础之数组

    数组

    一、静态初始化

    1. 格式一
    数据类型[] 变量名 = {元素1,元素2,元素3...};
    
    1. 格式二
    数据类型[] 变量名 = new 数据类型{元素1,元素2,元素3...};
    

    或者:

    数据类型[] 变量名;
    变量名 = new 数据类型{元素1,元素2,元素3...};
    

    二、动态初始化

    1. 格式
    数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];
    

    或者:

     数组存储的数据类型[] 数组名字;
     数组名字 = new 数组存储的数据类型[长度];
    

    元素的类型可以是任意的java的数据类型,int,String。
    数据的长度一旦指定,不可更改。

    2、数组元素的默认值

    当确定了数组的长度,但是在没有给数组元素复制的情况下,数组的元素存在默认值。
    byte、short、int、long、float、double的默认值为0,其中long为0L,float为0.0F,double为0.0;
    char为0或"u0000"(变现为空),我认为String类型变现为char类型数组,String默认为空,故char类型默认变现为空;
    boolean类型为false;
    引用类型为null。

    三、数组内存

    1. 内存概述

    内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。

    Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。

    1. Java虚拟机的内存划分
    1. 数组在内存中的存储
    1. 一个数组内存
    public static void main(String[] args) {
      	int[] arr = new int[3];
      	System.out.println(arr);//[I@5f150435
    }
    

    思考:打印arr为什么是[I@5f150435,它是数组的地址吗?

    答:它不是数组的地址。

    问?不是说arr中存储的是数组对象的首地址吗?

    答:arr中存储的是数组的首地址,但是因为数组是引用数据类型,打印arr时,会自动调用arr数组对象的toString()方法,默认该方法实现的是对象类型名@该对象的hashCode()值的十六进制值。

    问?对象的hashCode值是否就是对象内存地址?

    答:不一定,因为这个和不同品牌的JVM产品的具体实现有关。例如:Oracle的OpenJDK中给出了5种实现,其中有一种是直接返回对象的内存地址,但是OpenJDK默认没有选择这种方式。

    四、数组使用过程中常见异常

    1. 数组越界异常 ArrayIndexOutOfBoundsException

    2. 数组空指针异常 NullPointerException

    public static void main(String[] args) {
        int[] arr = {1,2,3};
        arr = null;
        System.out.println(arr[0]);
    }
    
    	public static void main(String[] args){
    		//声明一个String[]类型的数组,用来存储三个学生的姓名
    		String[] names = new String[3];
    		int count = names[0].length();
    		System.out.println("第一个学生姓名的字数:" + count);
    	}
    

    五、java内存管理(堆、栈、方法区)

    1. java堆
      堆内存用来存放由new创建的对象实例和数组。(重点)
    1. java栈
      在栈内存中保存的是堆内存空间的访问地址,或者说栈中的变量指向堆内存中的变量(Java中的指针)(重点)。
    1. 方法区
      方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 (重点)。

    具体实现向下。

    六、java内存管理的具体实现

    我们看以下一个简单代码实现:

    public class Student {
         private String name;
         private int age;
     
         public void study() {
             System.out.println("I love study!");
         }
     
         public String getName() {
             return name;
         }
     
         public void setName(String name) {
             this.name = name;
         }
     
         public int getAge() {
             return age;
         }
     
         public void setAge(int age) {
             this.age = age;
         }
     }
    
    public class StudentDemo {
         public static void main(String[] args) {
             Student student = new Student();
     
             System.out.println(student.getName() + ":" + student.getAge());
             student.setName("John");
             student.setAge(23);
             System.out.println(student.getName() + ":" + student.getAge());
             
             student.study();
             
             Student student2 = student;
             student2.setName("Jack");
             student2.setAge(25);
             System.out.println(student2.getName() + ":" + student2.getAge());
             System.out.println(student.getName() + ":" + student.getAge());
         }
     }
    

    第一、二步:

    运行程序时,JVM会把Student类与StudentDemo类编译完然后加载到JVM中一个叫方法区的地方,类的成员变量与成员方法也被加载到方法区中

    第三步

    接着JVM会自动寻找main方法,在栈中为main方法申请一个空间,这个过程也叫入栈,然后执行Student student = new Student();

    第四步

    在栈中分配一块内存空间用于指向堆空间中的Student对象区的内存地址

    第五、六步

    接着执行student.setName("John"); student.setAge(23); 程序为student对象的成员变量赋值,JVM会根据student所指向的地址在堆内存中寻找Student类的变量,并为变量赋新的值

    第七步

    student对象调用study方法,JVM在栈空间中为study方法申请了一块内存空间。study方法执行完后,立即释放栈空间。
    注意:方法执行完后会立即释放,main函数会在执行完所有代码后释放。

    第八步

    执行Student student2 = student; student2对象的引用指向了student所指向的地址。执行student2.setName("Jack"); student2.setAge(25); 由于student2与student指向了同一个地方,所以这时student对象中变量的值也被改变

    第九步

    main方法中所有代码执行完毕,main方法所占用的栈空间也被回收,而堆空间等待GC回收

    七、数组的查找算法

    1、数组的顺序查找

    public static void main(String[] args) {
    	int[] ints = {2,5,7,3,1,0,7};
    	int value = 0;
    	boolean hasFind = false;
    	
    	for(int i : ints) {
    		if(i == 0) {
    			hasFind = true;
    		}
    	}
    	
    	if(hasFind) {
    		System.out.println("查找到");
    	}else {
    		System.out.println("没有查找到");
    	}
    }
    

    2、数组的二分查找

    public static void main(String[] args) {
    	int[] ints = {2,5,8,9,34,78};
    	int num = 34;
    	boolean hasFind = false;
    	int start = 0;
    	int end = ints.length - 1;
    	int mid = (start + end) / 2;
    	
    	while(start <= end) {
    		if(ints[mid] == num) {
    			hasFind = true;
    			break;
    		}
    		if(ints[mid] > num) {
    			end = mid;
    		}else if(ints[mid] < num) {
    			start = mid;
    		}
    		mid = (start + end) / 2;
    	}
    	
    	if(hasFind) {
    		System.out.println("查找到");
    	}else {
    		System.out.println("没有查找到");
    	}
    }
    

    3、冒泡排序

    原理:比较两个相邻的元素,将值大的元素交换至右端。
    注意,每一轮比较,都会找到数组内的最大值并将其安排至数组的最后一位。
    因此需要进行数组.length-1轮比较。

    public statis void main(String[] args) {
    	int[] ints = {2,5,7,3,1,0,7};
    	int num = 0;
    	for(int i = 0; i < ints.length-1; i++) {
    		for(int j = 0; j < ints.length-i-1; j++){
    			if(ints[j] > ints[j+1]) {
    			num = ints[j];
    			ints[j] = ints[j+1];
    			ints[j+1] = num;
    			}
    		}
    	}
    	
    	for(int i = 0; i < ints.length; i++) {
    		System.out.print(ints[i]);
    	}
    }
    

    4、简单选择排序

    代码有一些问题

    public static void main(String[] args) {
    	int[] ints = {2,5,7,3,1,0,7};
    	for(int i = 1; i < ints.length; i++) {
    		int min = ints[i-1];
    		int index = 0;
    		for(int j = 0; j < ints.length; j++) {
    			if(ints[j] < min) {
    				min = ints[j];
    				index = j;
    			}
    		}
    		if(index != i-1){
    			int num = ints[i-1];
    			ints[i-1] = ints[index];
    			ints[index] = num;
    		}
    	}
    
    	for(int i = 0; i < ints.length; i++) {
    		System.out.print(ints[i]);
    	}
    }
    

    二维数组

    1、二维数组的初始化

    1.静态初始化

    	元素的数据类型[][] 二维数组名 = new 元素的数据类型[][]{
    			{元素1,元素2,元素3 。。。}, 
    			{第二行的值列表},
    			...
    			{第n行的值列表}
    		};
    
    	元素的数据类型[][] 二维数组名;
    	二维数组名 = new 元素的数据类型[][]{
    	            {元素1,元素2,元素3 。。。}, 
    	            {第二行的值列表},
    	            ...
    	            {第n行的值列表}
    	        };		
    	// 以下格式要求声明与静态初始化必须一起完成
    	元素的数据类型[][] 二维数组的名称 = {
    	            {元素1,元素2,元素3 。。。}, 
    	            {第二行的值列表},
    	            ...
    	            {第n行的值列表}
    	        };
    	
    

    2.动态初始化(规则二维表:每一行的列数是相同的)

    //(1)确定行数和列数
    元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n];
    	m:表示这个二维数组有多少个一维数组。或者说一共二维表有几行
    	n:表示每一个一维数组的元素有多少个。或者说每一行共有一个单元格
    
    // 此时创建完数组,行数、列数确定,而且元素也都有默认值
    
    //(2)再为元素赋新值
    二维数组名[行下标][列下标] = 值;
    

    3.动态初始化(不规则:每一行的列数可能不一样)

    //(1)先确定总行数
    元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];
    
    // 此时只是确定了总行数,每一行里面现在是null
    
    //(2)再确定每一行的列数,创建每一行的一维数组
    二维数组名[行下标] = new 元素的数据类型[该行的总列数];
    
    // 此时已经new完的行的元素就有默认值了,没有new的行还是null
    
    // (3)再为元素赋值
    二维数组名[行下标][列下标] = 值;
    

    部分内容参考:原文链接:https://blog.csdn.net/weixin_41043145/article/details/95663118

  • 相关阅读:
    .netcore2.1 ef 使用外键关联查询
    Parallel.ForEach 使用多线遍历循环
    ZKEACMS 无法运行问题汇总
    ASP.NET MVC 开源建站系统 ZKEACMS 推荐,从此网站“拼”起来
    C#中定义数组--字符串及数组操作
    LinQ 定义带有返回类型的扩展方法3.2
    LinQ 定义扩展方法3.1
    LinQ转换运算符ToLookup
    combobox中的数据
    转换数据类型
  • 原文地址:https://www.cnblogs.com/njuptzheng/p/13046660.html
Copyright © 2011-2022 走看看