0

这是我的代码,请在阅读问题之前查看它

 package ict201jansem2012;


public class Qn3b {

    public static void main(String[] args) {
        int a = 1;
        int b[] = {4,5};
        String s = "Good luck!";
        method1(b[1]);
        System.out.println("(1) b[0] = "+b[0]+"; b[1] = "+b[1]);
        method2(b);
        System.out.println("(2) b[0] = "+b[0]+"; b[1] = "+b[1]);
        method3(a);
        System.out.println("(3) a = " + a );
        method4(s);
        System.out.println("(4) s = " + s );
    }
    public static void method1(int b) {
        b = 7;
    }
    public static void method2(int[] b) {
        b[0] = 3;
    }
    public static void method3(int a) {
        a = 3;
    }
    public static void method4(String s) {
        s = "UniSIM";
    }
}

输出:(1) b[0] = 4;b[1] = 5

(2) b[0] = 3;b[1] = 5

(3) a = 1

(4) s = 祝你好运!

所以我的问题是,作为学习程序员,这对我来说很有趣。int b 数组 0 的索引值已更改,但未更改其他变量,例如 String s 和 int a。在我运行这个程序之前,我大致认为变量会随着方法被调用而改变它们的值,这是因为方法被调用并且主方法变量如 a、s 和 b 数组被传递,然后它们正在修改。

那么简而言之,为什么 b 数组 0 的索引被改变而其他变量没有改变呢?

4

4 回答 4

3

因为你说你是一个初学者程序员,所以我会写一些文章来解释(或尝试解释)到底发生了什么。

这是因为您将参数传递给您的method1 - method4方法

这些参数本身就是对其他对象的引用。

当您使用赋值运算符(一个等号)时,您会覆盖当前作用域中值的引用- 其中变量可以“看到”。

在您的代码中:

method1的情况下,您正在创建一个新引用,该变量只能在该范围内看到。也就是说,当您接着执行b = << expr >> 时,您正在为method1范围内的变量 b 分配值,而不是范围内的 b 。您的method3method4方法也是如此,您正在为该范围的各个变量分配一个新值,因为您正在创建新引用而不是更改原始对象。

但是,method2的代码行为不同,这是因为您正在改变该代码中的对象。您正在直接更改对象 - 而不是在该范围内创建新引用。

考虑下面的代码

int[] array = new int[] {1, 2};

public void test()
{
    method1(array);
    System.out.println(array[0] + ", " + array[1]);
    method2(array);
    System.out.println(array[0] + ", " + array[1]);
}

//  because we are working with objects, the identifier, can be different to the arrays identifier
//  in this case, I've chosen to use 'a' instead of 'array' to show this
public void method1(int[] a)
{
    //  this mutates the array object
    a[0] = 2;
}

public void method2(int[] array)
{
    //  this overwrites the method2.array but not the global array
    array = new int[] { 1, 2, 3 };
}

我们创建一个新数组,在全局范围内具有标识符“数组”。(在 Java 中,这将是类自己的范围)

method1中,我们接受一个参数,它是作为全局数组对象传递的同一个对象,所以当我们改变它时,两个对象都会改变。所以,第一个打印语句将是

“2、2”

数组 [0] 已更改的位置

注意因为我们处理的是对象,所以变量的“名称”并不重要——它仍然是对同一个对象的引用

然而,在method2中,我们接受一个参数,就像在method1中一样,但这次我们使用赋值运算符将该变量分配给它当前所在范围内的新值 - 所以全局数组没有改变,所以我们仍然打印出

“2、2”

对于初学者程序员,我会亲自编写一些测试程序,让您充分了解变量和作用域的工作原理。

但是要知道,每次创建新的代码块时,都会创建一个新的作用域,该作用域的局部变量只能在该作用域及其下方的变量中看到。

例如:

public void test()
{
    int a = 5;
    method1(a);
    System.out.println(a);  //  prints 5
}

public void method1(int a)
{
    // a is only viewable in the method1 scope
    //  and any scopes below it, that is, any scopes created within method1
    //  and since we use an assignment operator, we assign method1.a a value, not global 'a' a value
    a = 123;
    if (true)
    {
        // this is a new scope, variables created in this block cannot be seen outside it
        //  but can see variables from above it

        System.out.println(a);  // prints 123
    }
}

在这里,我们在 if 语句中的method1内部创建了一个新范围,可以看到它上面的 a。但是,因为method1test的作用域都是独立的,所以当我们使用赋值运算符时,我们将a的值赋给了本地作用域。所以atestmethod1上都不同

我希望你现在能更好地理解。我不太擅长传达东西,但如果它对理解范围有一点帮助,我做得很好,另外,这很有趣。

于 2012-11-01T04:08:52.787 回答
2

Java 是按值传递的,但大多数值(不是原始的所有值,在本例中为 int[] 和字符串)都是引用,这意味着它们的行为类似于按引用传递。

这是一篇不错的文章:http: //javadude.com/articles/passbyvalue.htm

于 2012-11-01T03:10:25.710 回答
1

arrays是特殊类型的对象,内存将在 HEAP 上分配。当您将数组作为参数传递给方法时,它将作为参考值(参考的副本)传递。

这意味着初始b并且这个新的引用指向同一个对象。除非新的引用指向另一个对象,否则对这个引用的更改将反映在同一个对象上。这就是为什么您看到价值反映在原始阵列上的原因。

于 2012-11-01T03:08:51.590 回答
0

所有的值都传递给了内部方法,但内部方法什么也没返回。但是,method2 修改了传递给它的数组的内部值,因此内部值在返回时出现了修改。

请注意,method2 是唯一一个您没有分配给变量(参数)本身,而是分配给其引用被传入的对象的元素的方法。

修改对对象的引用(指针)和修改对象本身之间有一个关键的区别。

于 2012-11-01T03:17:46.907 回答