【问题标题】:Still unsure as to why this integer remains unmodified [duplicate]仍然不确定为什么这个整数保持不变[重复]
【发布时间】:2015-07-22 22:59:45
【问题描述】:

我正在学习 Java 中的引用和数据类型,但这段特殊的代码仍然让我感到困惑。我知道 Java 中的所有原始类型都是值类型(字节、短、整数、长、浮点、双精度、布尔值、字符),当您使用字符串或对象时,它是引用类型。当我被教导声明和初始化一个变量时,我被告知要把它想象成一个盒子。因此,如果我创建一个变量“y”并给它一个值“5”,就像我创建了一个名为“y”的盒子,其中包含了 5 的值。我的老师说,如果我然后尝试在 a 中调用 y方法(查看下面的代码以获取更多详细信息)该值将保持不变,因为它是一个原始数据类型,所以我只传入 5,而不是包含 5 的变量。好吧,我很困惑,因为如果我传入值5,为什么下面的方法不加一个呢。

public class ReferenceAndValueTypes {
    public static void main(String[] args) {

        int y = 5;
        addOneTo(y);

        System.out.println(y);

    }


    static void addOneTo(int number){
        number = number + 1;
    }
}

输出是 5,这让我很困惑。老师说因为 int 是一个值类型,所以我们没有传入 y 变量,也不是对那个变量进行操作,而是对那个变量的值进行操作。但是,该变量的值为 5,并且由于该方法加一,它不应该是 6 吗?或者,是不是因为 y 是值类型,所以该方法无法使用它,所以它只需要打印出 y 的初始值,即 5?

【问题讨论】:

  • 您正在对该变量的副本进行操作。
  • 该值为 6。但仅在 addOneTo 方法中。 (尝试在您的 addOneTo 方法中打印出数字变量)......您将值“5”传递给您的 add-method。你给它加 1 --> 给出“6”。但是从你调用它的地方..值没有改变(它应该怎么......你只是将 VALUE 传递给你的方法)
  • @Seelenvirtuose 我不确定这是一个合理的欺骗,因为 OP 不理解传递值和传递引用之间的区别。
  • 谢谢大家的解释,现在更有意义了!
  • @PatrickCollins 当然,即使不知道要搜索的单词,也很难找到可能回答您的问题。但这并不意味着这个问题本身就是一个新问题。可能的“重复”仍然包含 Carson Clark 需要知道的所有答案。至少,我(有点)同意你的观点,这就是我没有投反对票的原因。

标签: java types int


【解决方案1】:

因为 Java 中的原始类型是按值传递的,而不是按引用传递的。 addOne() 内部 i 被视为从传递的参数复制的局部变量,因此其中的任何更改都不会更改调用者传递的变量。


P.S. 这确实也适用于对象。比如这段代码sn -p:

void changeString(String s) {
    s = new String("new");
}

String s = "old";
changeString(s);
System.out.println(s);  

打印"old",因为在changeString()中,s引用被复制,因此在方法内部更改它(分配新引用)对调用者的s变量没有影响。 p>

【讨论】:

    【解决方案2】:

    虽然很简单,java 写成pass-by-value。如果您在 addOneTo 方法中增加数字,那么您正在更改参数编号的引用值。这样,该数字不再引用您原来的 y 变量,因此会增加它。这不适用于任何原始类型。

    【讨论】:

    • “你的参数的引用值”——这是什么意思?
    • 应该是传给addOneTo的值,代表内存中的number参数。
    • "number 不再引用您原来的 y 变量,因此会增加它" this 是什么意思?
    【解决方案3】:

    Java 原语(int、long、boolean 等)不是引用,它们是实际值。当您拥有addOneTo(y); 时,addOneTo 会收到该值的副本。复制的值加一,然后在方法退出时丢失。

    打个比方,当您看到原始方法参数时,您可以将其视为复印机。相反,对象引用与传递写有内容的记事本相同。该方法将看到相同的对象,而不是它的副本,因此对其所做的更改将在方法退出后呈现。

    更改参数的名称可以使这个更清楚一点

    static void addOneTo(int numberA) {  // numberA is not the same as the int in the calling method, it's just an exact copy of it
        numberA = numberA + 1; // numberA is now incremented by one
        // method exits, numberA is lost
    }
    

    如果你想要一个提供增量功能的方法,你可以定义一个返回结果的方法。

    public static void main(String[] args) {
        int x = 3;
        addOneTo(x); // x is still 3
        x = addOneTo(x); x is now 4
    }
    
    static int addOneTo(int number) {
        return number + 1;
    }
    

    【讨论】:

    • 非常感谢你的类比
    • 如果您想要更改变量,您可以将该方法更改为具有 int 作为返回类型,然后返回它。也许也可以为此提供一个例子?
    • 在你运行并测试与 String 对象的类比之前,请确保你了解不可变实例。
    • 所以如果我想从方法中返回值,我只需要包含 Sys.out.print(y);那么当调用该方法时,它也会打印出 y 的值,并且不会丢失?
    • 对象/原始的区别在这里具有误导性。即使我们谈论的是对象类型,在这种情况下观察到的行为也是一样的。
    【解决方案4】:

    如果变量x 持有引用类型,则它指向一个对象。如果它持有值类型,则它指向该值。当您调用某个函数f(x) 时,传递给f 的东西是x 指向 的东西,而不是x 本身。

    所以在这里,如果你说类似

    int y[] = new int[1]{5}
    

    然后说

    number[0] = number[0] + 1;
    

    addOneTo 的内部,那么y 的值将在外部被修改——addOneTo 作用的对象是包含该数字的数组

    另一方面,当int y = 5 时,那么你正在采取的行动是数字。您正在创建一个指向相同值 (5) 的新名称,并且当您说

    number = number + 1;
    

    你真正的意思是:

    number2 = number + 1;
    number = number2;
    

    然后你把结果扔掉。

    【讨论】:

    • 它不指向值,它值(或者可能值)。
    • @OliverCharlesworth 我认为说“变量点”通常是一个公平的说法——它们指的是包含值的内存地址。 y = 5 表示“5 引用的内存地址包含值 5”,而 y = new int[1]{5} 表示“5 引用的内存地址包含长度为 1 的数组”。我不认为说“有时变量是值,有时变量是别的东西”会让初学者清楚地知道发生了什么。
    • 不过,基本类型和对象类型之间存在根本区别。如果 Java 初学者不了解这种差异,他们就不会走得太远。
    • @OliverCharlesworth 首先学习了 C 编程,我发现说“每个变量都是内存地址的名称;有时您让名称引用不同的内存地址,其他时候您改变内存地址处的东西”是最自然的思维方式。是的,JVM 将它从你那里抽象出来,但我认为基本思想是相同的。 YMMV。
    【解决方案5】:

    你的问题有答案

    int 是一种基本数据类型,它们通过值而不是通过引用传递,因此值保持不变:)

    【讨论】:

      猜你喜欢
      • 2019-11-28
      • 1970-01-01
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      • 2020-01-08
      • 1970-01-01
      • 2015-11-11
      • 1970-01-01
      相关资源
      最近更新 更多