Java 与 Go:数组

数组是任何编程语言都绕不过去的话题,因为它就是最基本的数据结构之一,它是是用来存储固定大小的同类型元素的线性结构。依稀记得当时上数据结构与算法的时候,老师布置的作业就是用最基本的数组和链表实现ArrayList,Stack,Queue,还有HashMap。那么今天我们一起来学习Java和Go在数组上的区别,今天只谈用法。

声明和初始化

Java

如果你知道数组元素具体都有谁,那我们可以直接创建,无需给定元素个数(事实上这个初始值会自动确定)

// 直接声明并初始化一个整数数组
int[] myArray = {1, 2, 3, 4, 5};

/** 果我们看其他人的代码,有的人习惯写
* int[] myArray;   <- 我个人偏爱这个写法,一眼就明了这是int数组
* 但是有人更喜欢
* int myArray[];  <- 其实是一样的效果
/

不过大部分时间我们都是先创建一个已知大小的数组,然后动态填入数据

// 声明一个整数数组,但不初始化
int[] myArray = new int[5];

// 分配元素值
myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;
myArray[3] = 4;
myArray[4] = 5;

GO

如果已知元素

// 使用数组字面量声明并初始化一个数组
myArray := [5]int{1, 2, 3, 4, 5}
//也可以不写长度,让编译器自动推断
myArray := [...]int{1, 2, 3, 4, 5}

如果只知道长度

// 声明并初始化一个包含5个整数的数组
var myArray [5]int
//后续再动态填入

以上部分Java和Go还算相同,接下来来介绍一下Go的独特用法和需要注意的点

  • 部分初始化
// 部分初始化数组,未指定的元素默认为零值
myArray := [5]int{1, 2}
//在这种情况下,数组的前两个元素被初始化为1和2,
//而剩余的元素将被设置为整数的零值,即0。
  • 使用索引初始化数组
// 使用索引初始化数组元素
myArray := [5]int{0: 100, 2: 86}
//因为数组的坐标是从0开始的,所以上述代码的意思是
//第一个元素初始值是100
//第三个元素初始值是86
  • 对Go语言来说,数组长度是类型的一部分
    咱们直接看代码
    我先写一个Java的
int[] myArray = new int[2];
myArray = new int[]{1, 2, 3, 4, 5, 6};
for (int i : myArray) {
    System.out.println(i);
}

再来看看Go

var myArray [3]int
myArray = [5]int{0: 100, 2: 86}
//这会报错,而错误是
//Cannot use '[5]int{0: 100, 2: 86}' (type [5]int) as the type [3]int

在Go语言中,数组的长度是编译时确定的,因此无法在运行时动态创建数组所以大家在使用的时候要注意,如果真的有需要我们可以用之后会学到的切片(slice)来实现类似动态数组的功能,因为切片的长度是动态变化的。

传递类型

Java

Java语言的数组在传参时是采用引用传递,这意味着在Java中,数组传递的是数组的引用(可以理解成数组的地址),而不是数组的副本(并不是在其他地方开辟新的空间进行完完全全地复制)。这种传递方式使得在方法内部对数组的修改会影响到原始数组。

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        modifyArray(arr);
        System.out.println("After modifying:");
        for (int num : arr) {
            System.out.println(num);
        }
    }

    public static void modifyArray(int[] array) {
        // 在方法内部修改数组的值
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i] * 2;
        }
    }
}

所以大家在使用的时候需要注意,在不同的地方对同一数组进行操作而导致意外的行为。

Go

在Go语言中,数组是值类型的概念意味着当你将一个数组赋值给另一个变量时,实际上是在内存中创建了一个新的数组副本。这与引用类型(如切片)不同,对引用类型的操作会影响到底层数据结构,因为它们指向同一片内存空间(像前面Java一样)。

理解Go语言中数组是值类型的概念,可以通过以下几个要点:

  1. 数组赋值会复制整个数组:
    当你将一个数组赋值给另一个变量时,会复制整个数组的内容,包括数组中的每个元素。这意味着对新数组的修改不会影响原始数组,反之亦然。可以理解在一个空白的地方盖一座一模一样的房子。
array1 := [3]int{1, 2, 3}
array2 := array1 // 复制 array1 到 array2

array2[0] = 100
fmt.Println(array1) // 输出 [1 2 3]
fmt.Println(array2) // 输出 [100 2 3]
  1. 作为函数参数传递时会复制整个数组:
    当你将一个数组作为参数传递给函数时,会将整个数组复制一份传递给函数。这意味着在函数内部对数组的修改不会影响到原始数组。
func modifyArray(arr [3]int) {
    arr[0] = 100
    fmt.Println("Inside function:", arr)
}

array := [3]int{1, 2, 3}
modifyArray(array)
fmt.Println("Outside function:", array)
// 输出:
// Inside function: [100 2 3]
// Outside function: [1 2 3]
  1. 值类型的特点带来了安全性和预测性:
    因为数组是值类型,对数组的操作是安全的,不会因为在不同的地方对同一数组进行操作而导致意外的行为。这有助于编写更加清晰、可预测的代码。

总的来说,我们可以讲Go中的数组当作基本类型,但是我就是想传递数组本身怎么办?之后指针章节我们会解决这个问题。

长度获取

Java

在Java中,获取数组的长度可以使用数组对象的 length 属性来实现。这个属性会返回数组中元素的个数。

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};

        // 使用数组的 length 属性获取数组的长度
        int length = arr.length;

        System.out.println("Array length: " + length);
    }
}

数组长度是数组本身的一部分,如果我们看JVM布局

图片来源于文章:https://ost.51cto.com/posts/14956

Go

在Go语言中,获取数组的长度可以使用内置函数 len() 来实现。len() 函数用于获取数组、切片、映射、通道等数据结构的长度。

package main

import "fmt"

func main() {
    // 声明并初始化一个整型数组
    myArray := [5]int{1, 2, 3, 4, 5}

    // 使用内置函数 len() 获取数组的长度
    length := len(myArray)

    fmt.Println("Array length:", length)
}

len() 函数对于数组、切片、映射、通道等数据结构都适用,因此它是一个非常有用的工具函数,用于获取这些数据结构的大小或长度。

迭代

Java

  1. 使用普通的 for 循环:
int[] array = {1, 2, 3, 4, 5};

for (int i = 0; i < array.length; i++) {
    System.out.println(array[i]);
}
  1. 使用增强型 for 循环(for-each 循环):
int[] array = {1, 2, 3, 4, 5};

for (int num : array) {
    System.out.println(num);
}

这两个方法都可以用来迭代(遍历)Java数组中的元素。根据你的需求和代码的清晰度,可以选择其中一种方法。增强型 for 循环在简单的迭代过程中更为常用,而普通的 for 循环则更灵活,可以在迭代过程中执行更复杂的操作例如改变数组中的值。

###Go
在Go语言中,可以使用 for 循环和 range 关键字来迭代(遍历)数组中的元素。以下是几种常用的迭代方法:

  1. 使用普通的 for 循环:
package main

import "fmt"

func main() {
    // 声明并初始化一个整型数组
    array := [5]int{1, 2, 3, 4, 5}

    // 使用普通的 for 循环遍历数组
    for i := 0; i < len(array); i++ {
        fmt.Println(array[i])
    }
}
  1. 使用 range 关键字:
package main

import "fmt"

func main() {
    // 声明并初始化一个整型数组
    array := [5]int{1, 2, 3, 4, 5}

    // 使用 range 关键字遍历数组,_替代了索引,有需要的就用变量接收
    for _, num := range array {
        fmt.Println(num)
    }
}

在这里,range 关键字返回数组的索引和元素值,_ 用来忽略索引值,如果你需要索引值,可以替换为一个变量名。

以上是两种常见的迭代数组的方法,根据你的需求和代码的清晰度,可以选择其中一种方法。使用 range 关键字可以更简洁地遍历数组,并且更常用。

多维数组

Java

在Java中创建多维数组非常简单,你可以使用类似于一维数组的语法来声明和初始化多维数组。以下是几种常见的创建多维数组的方法:

  1. 使用数组变量声明和初始化:
// 声明一个二维整型数组
int[][] twoDimArray;

// 初始化二维数组
twoDimArray = new int[3][3];

这里声明了一个二维整型数组变量 twoDimArray,然后使用 new 关键字创建了一个3x3的二维数组对象。

  1. 声明并初始化多维数组:
// 声明并初始化一个二维整型数组
int[][] twoDimArray = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

这里声明了一个二维整型数组 twoDimArray,并用大括号括起来的初始化列表初始化了数组的每个元素。

  1. 使用循环初始化多维数组:
// 声明一个三维整型数组
int[][][] threeDimArray = new int[3][3][3];

// 初始化三维数组
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        for (int k = 0; k < 3; k++) {
            threeDimArray[i][j][k] = i + j + k;
        }
    }
}

这里声明了一个三维整型数组 threeDimArray,然后使用嵌套的循环初始化了数组的每个元素。

以上是几种创建多维数组的常用方法。根据你的需求和代码的清晰度,可以选择最适合你的方法来创建多维数组。

Go

在Go语言中,可以使用类似于一维数组的语法来声明和初始化多维数组。以下是几种常见的创建多维数组的方法:

  1. 使用数组变量声明和初始化:
// 声明一个二维整型数组
var twoDimArray [3][3]int

// 初始化二维数组
twoDimArray = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

这里声明了一个二维整型数组变量 twoDimArray,然后使用大括号括起来的初始化列表初始化了数组的每个元素。

  1. 声明并初始化多维数组:
// 声明并初始化一个二维整型数组
twoDimArray := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

这里声明了一个二维整型数组 twoDimArray,并用大括号括起来的初始化列表初始化了数组的每个元素。

  1. 使用循环初始化多维数组:
// 声明一个三维整型数组
var threeDimArray [3][3][3]int

// 初始化三维数组
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        for k := 0; k < 3; k++ {
            threeDimArray[i][j][k] = i + j + k
        }
    }
}

这里声明了一个三维整型数组 threeDimArray,然后使用嵌套的循环初始化了数组的每个元素。

可以看出在多维数组这方面,二者基本一致。不过对于多维的数据结构,Go语言更推荐使用slice切片

总结

总的来说,Go和Java在数组方面有很多相似之处,个人认为只是要额外注意Go的俩个特殊点,一个是数据长度是类型的一部分,另一个是传递参数是,Java是传地址(传的是门牌号,指向的是同一个地方),Go传递的是数组的副本(找个其他地方新盖房子)。

需要免费使用IDEA的小伙伴可以关注公众号【AIGoland之星】回复【idea】领取最新且免费的激活工具。

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值