Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
引用和变量传递。解释这个简单java程序的输出?_Java - Fatal编程技术网

引用和变量传递。解释这个简单java程序的输出?

引用和变量传递。解释这个简单java程序的输出?,java,Java,快速总结我需要的帮助: 什么是不可变类? 对于Java的String类,为什么不能像对待其他类一样使用C术语“指向”一个字符串变量?例如,字符串x=Stringy;将y的值复制到x。为什么? 例如,对于我自己的类“Test”,testx=Testy;是否正确地将x“指向”y。 字符串在这里的行为是否与其不变性有关? 我有一个Java程序。。。有人能解释一下这些参考资料是怎么回事吗 public class Main { public static void foo(String a){

快速总结我需要的帮助:

什么是不可变类? 对于Java的String类,为什么不能像对待其他类一样使用C术语“指向”一个字符串变量?例如,字符串x=Stringy;将y的值复制到x。为什么? 例如,对于我自己的类“Test”,testx=Testy;是否正确地将x“指向”y。 字符串在这里的行为是否与其不变性有关? 我有一个Java程序。。。有人能解释一下这些参考资料是怎么回事吗

public class Main {

    public static void foo(String a){
        a="2";
    }

    public static void main(String[] args) {
        String x="1";
        foo(x);
        System.out.println("x="+x);

    }

}
输出:

x=1
x=3
y=1
预期产出:

x=2
x=3
y=3
x=3
y=3
发生什么事了?我认为我在foo中对a所做的任何事情都会影响x,因为a只是x的别名-否

这里有一个类似的问题:

public class Main {
    public static void main(String[] args) {
        String x=new String("1");
        String y=new String("2");
        y=x;
        x="3";
        System.out.println("x="+x);
        System.out.println("y="+y);
    }

}
输出:

x=1
x=3
y=1
预期产出:

x=2
x=3
y=3
x=3
y=3
有人能解释一下吗

编辑:

为什么这些例子产生了预期的结果,而我上面的带有字符串的例子却没有

1:

产出和预期产出:

x=2
2:

产出和预期产出:

x=2
x=3
y=3
x=3
y=3

Java总是按值传递

传递的是对对象的引用,而不是对象本身

对于字符串,它是一个不可变的类。因此,您无法更改该字符串引用在foo方法中指向的内容

但是,您可以这样做:

package cruft;

public class Main
{
    private String value;

    public Main(String s)
    {
        this.value = s;
    }

    public String getValue()
    {
        return value;
    }

    public void setValue(String value)
    {
        this.value = value;
    }

    public static void foo(Main main)
    {
        main.setValue("2");
    }

    @Override
    public String toString()
    {
        return "Main{" +
            "value='" + value + '\'' +
            '}';
    }

    public static void main(String[] args)
    {
        Main main = new Main("1");
        System.out.println("before: " + main);
        foo(main);
        System.out.println("after: " + main);

    }

}

看到区别了吗?我没有在foo方法中更改对Main的引用;我只是改变了它的一部分状态。

Java总是按值传递

传递的是对对象的引用,而不是对象本身

对于字符串,它是一个不可变的类。因此,您无法更改该字符串引用在foo方法中指向的内容

但是,您可以这样做:

package cruft;

public class Main
{
    private String value;

    public Main(String s)
    {
        this.value = s;
    }

    public String getValue()
    {
        return value;
    }

    public void setValue(String value)
    {
        this.value = value;
    }

    public static void foo(Main main)
    {
        main.setValue("2");
    }

    @Override
    public String toString()
    {
        return "Main{" +
            "value='" + value + '\'' +
            '}';
    }

    public static void main(String[] args)
    {
        Main main = new Main("1");
        System.out.println("before: " + main);
        foo(main);
        System.out.println("after: " + main);

    }

}

看到区别了吗?我没有在foo方法中更改对Main的引用;我只是改变了它的一部分状态。

将对象视为在内存中浮动的数据块。您定义的变量(如字符串s)指向这些blob:它们并不表示blob本身


相反,整数直接引用值。

将对象视为内存中浮动的数据块。您定义的变量(如字符串s)指向这些blob:它们并不表示blob本身

相反,整数直接引用值。

a!=在第一种情况下为x。a是引用x的副本,可以认为是指向公共字符串的指针的副本。因此,a=2表示使a等于对2的引用,而不是使指向a的值等于2

在第二种情况下也发生了类似的误解,x&y是不同的引用,您正在更新它们以指向不同的值

基本上,所有除基元的java值都是C++中的引用类型,即某些类,所有函数都是按值传递的。因此,调用具有某些引用类型作为参数的方法会复制这些参数。

a!=在第一种情况下为x。a是引用x的副本,可以认为是指向公共字符串的指针的副本。因此,a=2表示使a等于对2的引用,而不是使指向a的值等于2

在第二种情况下也发生了类似的误解,x&y是不同的引用,您正在更新它们以指向不同的值

基本上,所有除基元的java值都是C++中的引用类型,即某些类,所有函数都是按值传递的。因此,调用具有某些引用类型作为参数的方法会复制这些参数

为什么我用自己的类而不是字符串得到预期的结果

简单地说,因为你是在比较苹果和桔子。您的字符串示例是执行a=2;但后面的示例正在执行a.val=2;。第一个正在尝试更新调用方中的引用。。。这不管用。第二个是成功的,因为它是你告诉它使用。运算符更改由引用表示的对象的状态

如果您将后面的示例更改为字符串示例试图执行的操作,您会发现它们也不起作用

第二点是,您不能更改字符串的状态,因为字符串API的设计目的是使这一点不可能实现。相比之下,类的设计允许更改其状态。但这并不能解释您看到的行为,因为您的字符串示例甚至没有试图更改字符串的状态

为什么我用自己的类而不是字符串得到预期的结果

简单地说,因为你是在比较苹果和桔子。您的字符串示例是执行a=2;但后面的示例正在执行a.val=2;。第一个正在尝试更新调用方中的引用。。。这不管用。第二个是成功的,因为它是你告诉它使用。运算符更改由引用表示的对象的状态< /p> 如果您将后面的示例更改为字符串示例试图执行的操作,您会发现它们也不起作用


第二点是,您不能更改字符串的状态,因为字符串API的设计目的是使这一点不可能实现。相比之下,类的设计允许更改其状态。但这并不能解释您看到的行为,因为您的字符串示例甚至没有试图改变字符串的状态。

首先:我知道这是虚伪的,但我认为最好的方法是抓取一本Java教科书或可能的在线教程。我不认为你能通过我们的回答对这些概念有一个坚实的理解

也许我没读过这些,只是略读了一下:

我将尝试用另一种方式回答这个问题。正确的答案已经在那里了,但这类事情在我看来是很难解释的,如果你不是面对面的话

这是您的第一段代码:

public class Main {

    public static void foo(String a){
        a="2";
    }

    public static void main(String[] args) {
        String x="1";
        foo(x);
        System.out.println("x="+x);

    }

}
问题是线a=2。简单来说,它的意思是:使变量“a”指向值为“2”的字符串实例。这意味着:忘记“a”当前指向的字符串,这样它就可以指向这个新值。因此,您告诉它忘记它指向作为参数传递给方法的字符串,这样它就可以指向新的字符串

作为参数传递的字符串仍然存在,变量“x”仍然指向它。您没有更改变量“x”指向的字符串,只更改了变量“a”指向的字符串


如上所述,这是因为Java使用按值传递,而不是按引用传递。

首先:我知道这是虚伪的,但我认为最好的方法是抓取一本Java教科书或可能的在线教程,让这个想法在你的头脑中变得坚实。我不认为你能通过我们的回答对这些概念有一个坚实的理解

也许我没读过这些,只是略读了一下:

我将尝试用另一种方式回答这个问题。正确的答案已经在那里了,但这类事情在我看来是很难解释的,如果你不是面对面的话

这是您的第一段代码:

public class Main {

    public static void foo(String a){
        a="2";
    }

    public static void main(String[] args) {
        String x="1";
        foo(x);
        System.out.println("x="+x);

    }

}
问题是线a=2。简单来说,它的意思是:使变量“a”指向值为“2”的字符串实例。这意味着:忘记“a”当前指向的字符串,这样它就可以指向这个新值。因此,您告诉它忘记它指向作为参数传递给方法的字符串,这样它就可以指向新的字符串

作为参数传递的字符串仍然存在,变量“x”仍然指向它。您没有更改变量“x”指向的字符串,只更改了变量“a”指向的字符串


如上所述,这是因为Java使用按值传递而不是按引用传递。

+1,这很有意义。x仍然按照预期的方式通过值传递自身的引用,但它不是成为别名,而是简单地复制通过传递的引用找到的值,并将自身创建为新字符串right?。所以如果我使用自己的自定义非不变类,那么在这两种情况下都会得到预期的结果?此外,如何区分不可变类和非不可变类,以及如何创建自己的不可变类?不可变类的行为到底是什么?这是不正确的,字符串类的可变性在这种情况下并不重要。有趣的是@Incrediman说+1,但到目前为止,帖子只有一个向下投票,没有向上投票。在Kevin的评论之后,我取消了向上投票,无法编辑我的帖子:我更改了答案。希望它对你更有帮助。+1,这是有道理的。x仍然按照预期的方式通过值传递自身的引用,但它不是成为别名,而是简单地复制通过传递的引用找到的值,并将自身创建为新字符串right?。所以如果我使用自己的自定义非不变类,那么在这两种情况下都会得到预期的结果?此外,如何区分不可变类和非不可变类,以及如何创建自己的不可变类?不可变类的行为到底是什么?这是不正确的,字符串类的可变性在这种情况下并不重要。有趣的是@Incrediman说+1,但到目前为止,帖子只有一个向下投票,没有向上投票。在Kevin的评论之后,我取消了向上投票,无法编辑我的帖子:我更改了答案。希望对你更有帮助。为什么要投反对票?仅仅因为你不理解它并不意味着这是一个错误的答案。String类的不变性是不相关的,重要的是通过值传递语义复制引用。Java是通过值传递的-总是。-就像我说的。然后我演示了如何更改已通过的对象的状态。为什么要投否决票?仅仅因为你不理解它并不意味着这是一个糟糕的答案。不变性

字符串类的属性是不相关的,重要的是传递值语义复制引用。Java是传递值-始终。-就像我说的。然后我演示了如何更改传入的对象的状态。对于第二个示例,这是有意义的。但在第一个例子中,我还是不太明白。这是字符串特有的行为吗?我的意思是,它在我自己的类中的行为不符合我的要求吗?@incrediman-调用foo时,您正在复制对字符串的引用。然后更新引用副本以指向新的引用,它对原始引用没有影响。字符串的不变性并不重要。现在如果你要调用一个方法,因为原始和副本都指向同一个对象实例。@Kevin Montrose你能重新表述最后一句话吗?@Kevin Montrose我也更新了我的帖子,以帮助解释我对你答案的原始答复:为什么我用自己的类而不是字符串得到预期的结果?@incrediman-if您要调用一个方法或引用一个字段,情况会有所不同,因为两者都引用原始对象实例和复制对象实例。错别字,我的错。您的新示例的行为有所不同,因为您使用了“.”运算符,它在C术语中取消了指针的引用;基本上,您的测试类示例并不等同于原始字符串1。对于第二个示例,这是有意义的。但在第一个例子中,我还是不太明白。这是字符串特有的行为吗?我的意思是,它在我自己的类中的行为不符合我的要求吗?@incrediman-调用foo时,您正在复制对字符串的引用。然后更新引用副本以指向新的引用,它对原始引用没有影响。字符串的不变性并不重要。现在如果你要调用一个方法,因为原始和副本都指向同一个对象实例。@Kevin Montrose你能重新表述最后一句话吗?@Kevin Montrose我也更新了我的帖子,以帮助解释我对你答案的原始答复:为什么我用自己的类而不是字符串得到预期的结果?@incrediman-if您要调用一个方法或引用一个字段,情况会有所不同,因为两者都引用原始对象实例和复制对象实例。错别字,我的错。您的新示例的行为有所不同,因为您使用了“.”运算符,它在C术语中取消了指针的引用;您的测试类示例基本上不等同于原始字符串1;其中y是一个字符串,它没有试图改变x的状态?为什么不?@incrediman-因为它不是!因为Java就是这样定义的!当您在x和expr具有任何对象类型时写入x=expr时,您将为x指定一个引用值,而不更改x先前引用的对象的状态。假设我这样做:字符串y=新字符串;字符串x=cat;y=x;x=狗。。。为什么x和y现在不同了?@incrediman-因为你给它们分配了不同的引用。那么字符串x=cat和说字符串x=new-Stringcat是一样的吗??这是我能想到的唯一能解释这个的东西;其中y是一个字符串,它没有试图改变x的状态?为什么不?@incrediman-因为它不是!因为Java就是这样定义的!当您在x和expr具有任何对象类型时写入x=expr时,您将为x指定一个引用值,而不更改x先前引用的对象的状态。假设我这样做:字符串y=新字符串;字符串x=cat;y=x;x=狗。。。为什么x和y现在不同了?@incrediman-因为你给它们分配了不同的引用。那么字符串x=cat和说字符串x=new-Stringcat是一样的吗??这是我能想到的唯一能解释这一点的东西。这非常有用。那么带字符串的=运算符基本上就是这样做的?public void setString n{this.val=n.val}其中n是=运算符右侧的字符串此处的关键是要意识到变量“x”、“y”等仅指向字符串的实例。他们不是绳子本身。所以你可以将它们指向不同的字符串,它们指向的字符串仍然是uhnchange,尽管它现在可能会永远丢失。也就是说字符串x=1;字符串y=2;字符串z=x;将为您提供指向同一字符串1的x和z。然后你可以说x=y;现在x和y将指向相同的字符串2,z仍然指向1。这对任何不可变或非灵长类的对象都是一样的。明白了!谢谢你和我在一起。我现在明白了:@incrediman-那么带字符串的=运算符基本上就是这样做的?public void setString n{this.val=n.val}。绝对不是!首先,字符串没有特殊的赋值运算符;对于所有引用类型,赋值的工作方式完全相同。第二,引用类型的赋值指定引用。它不会更改被引用对象的状态。从来没有。好吧,那我就不明白了。为什么这是一个错误
为字符串指定x=y后,以后更改x不会更改y???如果我在任何其他类中这样做,它确实会改变y!!这很有帮助。那么带字符串的=运算符基本上就是这样做的?public void setString n{this.val=n.val}其中n是=运算符右侧的字符串此处的关键是要意识到变量“x”、“y”等仅指向字符串的实例。他们不是绳子本身。所以你可以将它们指向不同的字符串,它们指向的字符串仍然是uhnchange,尽管它现在可能会永远丢失。也就是说字符串x=1;字符串y=2;字符串z=x;将为您提供指向同一字符串1的x和z。然后你可以说x=y;现在x和y将指向相同的字符串2,z仍然指向1。这对任何不可变或非灵长类的对象都是一样的。明白了!谢谢你和我在一起。我现在明白了:@incrediman-那么带字符串的=运算符基本上就是这样做的?public void setString n{this.val=n.val}。绝对不是!首先,字符串没有特殊的赋值运算符;对于所有引用类型,赋值的工作方式完全相同。第二,引用类型的赋值指定引用。它不会更改被引用对象的状态。从来没有。好吧,那我就不明白了。为什么在为字符串指定x=y之后,以后更改x不会更改y???如果我在任何其他类中这样做,它确实会改变y!!