Rumah >Java >javaTutorial >Analisis definisi dan contoh penggunaan tatasusunan Java

Analisis definisi dan contoh penggunaan tatasusunan Java

PHPz
PHPzke hadapan
2023-04-21 21:52:18787semak imbas

Analisis definisi dan contoh penggunaan tatasusunan Java

一维数组

Java语言中的数组是一种引用数据类型;不属于基本数据类型;数组的父类是Object
数组实际上是一个容器,可以同时容纳多个元素。(数组是一个数据的集合)
    数组:字面意思是“一组数据”
数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据。
数组因为是引用类型,所以数组对象是堆内存当中。(数组是存储在堆当中的)
数组当中如果存储的是“java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组中不能直接存储java对象(存它的地址)。

Analisis definisi dan contoh penggunaan tatasusunan Java

数组一旦创建,在java中规定,长度不可变。(数组长度不可变)
数组的分类:一维数组、二维数组、三维数组、多维数组...(一维数组较多,二维数组偶尔使用!)
所有的数组对象都有length属性(java自带的),用来获取数组中元素的个数。
java中的数组要求数组中元素的类型统一。比如int类型数组只能存储int类型,Person类型数组只能存储Person类型。例如:超市购物,购物袋中只能装苹果,不能同时装苹果和橘子。(数组中存储的元素类型统一)
数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排列的)是连续的。内存地址连续。这是数组存储元素的特点(特色)。数组实际上是一种简单的数据结构。
所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象的内存地址。)
数组中每一个元素都是有下标的,下标从0开始,以1递增。最后一个元素的下标是:length - 1;下标非常重要,因为我们对数组中元素进行“存取”的时候,都需要通过下标来进行。
数组这种数据结构的优点和缺点是什么?
       优点:查询/查找/检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构。为什么检索效率高?
  第一:每一个元素的内存地址在空间存储上是连续的。
  第二:每一个元素类型相同,所以占用空间大小一样。
  第三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个内存地址,直接定位的。)
       缺点
            第一:为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。
            第二:数组不能存储大数据量,为什么?因为很难在内存空间上找到一块特别大的连续的内存空间。对于数组中最后一个元素的增删,是没有效率影响的。

怎么声明/定义一个一维数组?
      语法格式:

int[] array1;
double[] array2;
boolean[] array3;
String[] array4;
Object[] array5;

怎么初始化一个一维数组呢?
        包括两种方式:静态初始化一维数组,动态初始化一维数组。
        (1)静态初始化语法格式:
            int[] array = {100, 2100, 300, 55};
        (2)动态初始化语法格式:
            int[] array = new int[5];

这里的5表示数组的元素个数。
            初始化一个5个长度的int类型数组,每个元素默认值0
            再例如:String[] names = new String[6];

初始化6个长度的String类型数组,每个元素默认值null。

什么时候使用静态数组初始化?什么时候使用动态数组初始化?

(1)创键数组的时候,确定数组中存储哪些具体的元素时,采用静态初始化方式

(2)创键数组的时候,不确定将来存储哪些数据,可以采用动态初始化的方式,预先分配内存空间

package com.bjpowernode.javase.array;

public class ArrayTest01 {
    public static void main(String[] args) {
    //1.静态初始化
       int[] a1 = {1,3,5,7,9};
        //所有的数组对象都有length属性,而不是方法!
        System.out.println("数组元素的个数是:"+a1.length);
        //取第一个元素
        System.out.println(a1[0]);
        //取最后一个元素
        System.out.println(a1[a1.length-1]);
        //改数据
        a1[a1.length-1] = 0;
        //遍历数据
        for(int i=0;i< a1.length;i++){
            System.out.println(a1[i]);
        }
        //数据下标越界异常,例如:访问下面为6的数据元素
        //System.out.println(a1[6]);// ArrayIndexOutOfBoundsException


    //2.动态初始化
        int[] a2 = new int[5]; //默认值是0
        for(int i=0;i< a2.length;i++){
            System.out.println(a2[i]);
        }
        //初始化一个Object类型的数组,
          //1.采用静态初始化方式
        Object o1 = new Object();
        Object o2 = new Object();
        Object o3 = new Object();
        Object[] object = {o1,o2,o3};
        //上面就等价于:Object[] object = {new Object(),new Object(),new Object()};
        for(int i=0;i<object.length;i++){
            System.out.println(object[i]);// 默认调用toString方法
        }
          //2.采用动态初始化的方式
        Object[] obj = new Object[3];
        for(int i=0;i<obj.length;i++){
            System.out.println(obj[i]);// null null null
        }

        //初始化一个String类型的数组
          //1.静态初始化
        String[] str1 = {"abc","bcd","cde"};
        for (int i = 0; i < str1.length; i++) {
            System.out.println(str1[i]);
        }
        //2.动态初始化
        String[] str2 = new String[3];
        for (int i = 0; i < str2.length; i++) {
            System.out.println(str2[i]);
        }

    }

}

动态存储内存图

Analisis definisi dan contoh penggunaan tatasusunan Java

方法的参数是数组

当传递的是一个数组,方法也用数组的形式进行接收;这个数组可以是静态的,也可以是动态创建的;并且我们把方法写成写成静态的,这样不需要new对象就可以调用

例1:

package com.bjpowernode.javase.array;

public class ArrayTest02 {
    //也可以采用C++的风格,写成String args[]
    public static void main(String args[]) {
        System.out.println("HelloWorld");
        // 1.方法的参数传数组---静态初始化方式
        int[] a = {1,2,3,4,5};
        printArray(a);
        // 2.方法的参数传数组---动态初始化方式
        int[] arr = new int[5];
        printArray(arr);
        //   直接一步完成
        printArray(new int[3]);

    }
    //静态方法进行打印
    public static void printArray(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

}

例2:(掌握)

(1)一种特殊情况传递静态数组;如果直接传递一个静态数组的话,语法必须这样写!

(2)我们先看一个例子:int[] arr = {1,2,3};我们传递数组的参数时候,一般就是传递数组名arr,例如:printArray(arr);但是另一种方法就是传过去,去掉数组名arr剩余的组成部分:

int[]{1,2,3},但是要加上new关键字,例如: printArray(new int[]{1,2,3});

package com.bjpowernode.javase.array;

public class ArrayTest03 {
    public static void main(String[] args) {
     //----------1.动态初始化一位数组(两种传参方式)
        //第一种传参方式
        int[] a1 = new int[5];//默认是5个0
        printArray(a1);
        System.out.println("-------------");
        //第二种传参方式
        printArray(new int[3]);
        System.out.println("-------------");
     //----------2.静态初始化一位数组(两种传参方式)
        //第一种传参方式
        int[] a2 = {1,2,3};
        printArray(a2);
        System.out.println("-------------");
        //第二种传参方式----直接传递一个静态数组
        printArray(new int[]{4,5,6});

    }
    //调用的静态方法----静态方法比较方便,不需要new对象
    public static void printArray(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

main方法中的String数组

(1)对于main(String[] args);分析一下:谁负责调用main方法(JVM)
     JVM调用main方法的时候,会自动传一个String数组过来,长度为0。

例1:

package com.bjpowernode.javase.array;

public class ArrayTest04 {
    // 这个方法程序员负责写出来,JVM负责调用。JVM调用的时候一定会传一个String数组过来。
    public static void main(String[] args) {
        // JVM默认传递过来的这个数组对象的长度?默认是0
        // 通过测试得出:args不是null。
        System.out.println("JVM给传递过来的String数组参数,它这个数组的长度是?"
        + args.length); //0

        // 以下这一行代码表示的含义:数组对象创建了,但是数组中没有任何数据。就等价于:
        String[] strs = new String[0]; //动态的方式
        //String[] strs = {}; // 静态初始化数组,里面没东西。
        printLength(strs); //调用printLength静态方法

/*
     既然传过来的“String[] args”数组里什么都没有;那么这个数组什么时候里面会有值呢?
     其实这个数组是留给用户的,用户可以在控制台上输入参数,这个参数自动会被转换为“String[] args”
     例如这样运行程序:java ArrayTest04 abc def xyz;相当于在编译时进行传参
     那么这个时候JVM会自动将“abc def xyz”通过空格的方式进行分离,分离完成之后,自动放到“String[] args”数组当中。
     所以main方法上面的String[] args数组主要是用来接收用户输入参数的。
     把abc def xyz 转换成字符串数组:{"abc","def","xyz"}
*/
        // 遍历数组
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        //既然是编译时进行传参,对于编译运行一体的IDEA怎么使用呢?
        //Run--->EditConfiguration--->Program Arguments里面进行传参,然后在从后重新运行

    }

    public static void printLength(String[] args){
        System.out.println(args.length); // 0
    }
}

例2:

(1)main方法上面的“String[] args”有什么用?

可以用来模拟一个登陆系统!请看下面这个有趣的例题:

package com.bjpowernode.javase.array;
/*
   模拟一个系统,假设这个系统要使用,必须输入用户名和密码。
*/
public class ArrayTest05 {
    public static void main(String[] args) {
        //先判断长度,是不是两个字符串长度,不是2直接终止程序
        if(args.length != 2){
            System.out.println("请输入用户名和密码");
            return;
        }

        //取出用户名和密码
        String username = args[0];
        String password = args[1];
        // 假设用户名是admin,密码是123的时候表示登录成功。其它一律失败。
        // 判断两个字符串是否相等,需要使用equals方法。
        // if(username.equals("admin") && password.equals("123")){ //这样有可能空指针异常
        // 下面这种编写方式,也可以避免空该指针异常!
        if("admin".equals(username) && "123".equals(password)){ 
            System.out.println("恭喜你,登录成功");
            System.out.println("您可以继续使用该系统");
        }else{
            System.out.println("账户或密码错误,请重新输入");
        }
    }
}

数组中存储引用数据类型(重点)

(1)一维数组的深入:数组中存储的类型为:引用数据类型;对于数组来说,实际上只能存储java对象的“内存地址”。数组中存储的每个元素是“引用”。下面这个例题重点理解!

(2)数组要求数组中元素的类型统一;但是也可以存储它的子类型

package com.bjpowernode.javase.array;
public class ArrayTest06 {
    public static void main(String[] args) {
        //1.静态创建一个Animal类型的数组
        Animal a1 = new Animal();
        Animal a2 = new Animal();
        Animal[] animals = {a1,a2};

        //对Animal数组进行遍历
        for (int i = 0; i < animals.length; i++) {
            //方法1
            /*Animal a = animals[i];
            a.move();*/
            //方法2
            animals[i].move();
        }

        //2.动态初始化一个长度为2的animal类型的数组
        Animal[] ans = new Animal[2];
        ans[0] = new Animal();
        //ans[1] = new Product(); //err,Product和Animals没有任何关系
        //Animal数组中只能存放Animal类型,不能存放Product类型

        //3.Animal数组中可以存放Cat类型的数据,因为Cat是Animal一个子类
       ans[1] = new Cat();
        for (int j = 0; j < ans.length; j++) {
            ans[j].move();
        }

        //4.创建一个Animal类型的数据,数组当中存储Cat和Bird
          //4.1静态创建
        Cat cat = new Cat();
        Bird bird = new Bird();
        Animal[] anim = {cat,bird};
        for (int i = 0; i < anim.length; i++) {
            //直接调用子类和父类都有的move()方法
            //anim[i].move();
            
            //这里想要调用子类Bird里面特有的方法,需要向下转型
            if(anim[i] instanceof Bird){
                Bird b = (Bird)anim[i]; //向下转型
                b.move();
                b.sing(); //调用子类特有的方法
            }else{
                anim[i].move();
            }

        }


    }
}
//动物类
class Animal{
    public void move(){
        System.out.println("Animals move.....");
    }
}
//商品类
class Product{

}

//有一个猫类继承动物类
class Cat extends Animal{
    public void move(){
        System.out.println("Cat move.....");
    }
}

//有一个鸟类继承动物类
class Bird extends Animal{
    public void move(){
        System.out.println("Bird move.....");
    }

    //鸟特有的方法
    public void sing(){
        System.out.println("鸟儿在歌唱!");
    }
}

数组扩容和拷贝

在Java开发中,数组长度一旦确定不可变,那么数组满了,需要扩容怎么办?
(1)java中对数组的扩容是:先创建一个大容量的数组,然后将小容量数组中的元素一个个拷贝到大数组当中,小容量会被释放。
(2)结论:数组扩容效率较低。因为涉及到拷贝的问题。所以在以后的开发中请注意:尽可能少的进行数组的拷贝。可以在创建数组对象的时候预估计以下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率。

(3)利用System.arraycopy进行拷贝,总共5个参数;System.arraycopy(源头数组,下标,目的地数组,下标,要拷贝的个数)

package com.bjpowernode.javase.array;
public class ArrayTest07 {
    public static void main(String[] args) {
        //java中的数组是怎样拷贝的呢?System.arraycopy(5个参数)
        //System.arraycopy(源,下标,目的地,下标,个数)

        //拷贝源---把3、5、7拷贝过去
        int[] src = {1,3,5,7,9};
        //拷贝目的地---拷贝到下标为5的地方
        int[] dest = new int[20];
        //调用拷贝函数
        System.arraycopy(src,1,dest,5,3);
        //打印验证
        for (int i = 0; i < dest.length; i++) {
            System.out.println(dest[i]+" ");
        }

        //拷贝引用数据类型
        String[] str = {"hello","world"};
        String[] strs = new String[10];
        System.arraycopy(str,0,strs,3,2);
        for (int i = 0; i < strs.length; i++) {
            System.out.println(strs[i]);
        }
        System.out.println("--------------");
        
        //采用动态开辟的时候拷贝的是地址
        Object[] objs = {new Object(),new Object(),new Object()};
        Object[] objects = new Object[5];
        System.arraycopy(objs,0,objects,0,3);
        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]);

        }

    }
}

内存图

Analisis definisi dan contoh penggunaan tatasusunan Java

Atas ialah kandungan terperinci Analisis definisi dan contoh penggunaan tatasusunan Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam