为了账号安全,请及时绑定邮箱和手机立即绑定

Java 函数调用。非平凡对象是否通过引用复制?

Java 函数调用。非平凡对象是否通过引用复制?

慕尼黑的夜晚无繁华 2023-09-27 10:22:43
几周前我开始接触java。在此之前,我在嵌入式目标上使用 c/c++ 工作,并在 Win PC 上使用带有 UI Stuff 的 c# 工作多年。我得到了这个非常简单的例子:public class StreamProcessing {    public static void main(String[] args) {        Stream stream = new Stream(); //after this line: Stream string empty        StreamFiller.fillStream(stream);   //after this line: Stream string not empty any more        StreamPrinter.printStream(stream);    }}我希望无论 StreamFiller.fillStream() 做什么,参数都会被复制。然而,看起来 fillStream 正在修改实际的流对象本身。Stream 类基本上包含一个字符串public class Stream {    private String content = "";    int index = 0;    public char readChar() {        if (index < content.length()) {            return content.charAt(index++);        } else {            return 0;        }    }    public void writeString(String str) {        content += str;    }}Streamfiller 应该修改它的流副本,而不是原始引用public class StreamFiller {    public static void fillStream( Stream stream ) {         stream.writeString( "This is a" );         stream.writeString( " stream." );    }        }如果我错了,请纠正我,但由于字符串类的实际文本是在堆上分配的,因此 StreamProcessing () Stream 对象和 fillStream() 的(假定复制的)本地对象都指向相同的地址堆(是的,我现在它不是像 c/c++ 中那样的实际内存地址,而是一些唯一的对象标识符)那么我的假设正确吗?非平凡对象(又名在堆上分配的对象)是通过引用传递的吗?
查看完整描述

2 回答

?
潇湘沐

TA贡献1816条经验 获得超6个赞

Java 语言不允许您像 C 和 C++ 那样在代码中区分堆/堆栈。

相反,它将所有数据类型分为两组:

  1. 基本类型:
    这些是简单的内置数字类型,例如int,doubleboolean(不是 Java 中的数字类型)。
    注意String不是这样的类型!

  2. 对象类型:
    如果是类,那么它就是对象类型。这适用于内置类型(例如)String和用户定义类型(例如您的Stream类)。
    对于这些类型,您看到的只是引用,无论您查看的是局部变量、类成员、实例成员还是函数参数。

让我们看一个简单的例子:


public class A {

    public int a;


    public static void main(String [] args) {

        A var1 = new A();

        A var2 = var1;


        var1.a = 42;


        System.out.println("var2.a = " + var2.a);

    }

}

如果编译并运行这个示例,它将打印 42。
在 C++ 中,该行将A var2 = var1;调用复制构造函数并创建一个新对象,但在 Java 中没有这样的事情。如果你想要一个副本,你需要clone显式调用方法。

保存var1和复制的内容var2只是一个参考。所以两个变量“指向”同一个对象。

再说一遍——课程是否琐碎并不重要。即使一个类完全是空的,您仍然只能获得并使用对该类的任何对象的引用。

至于前面提到的基本类型,Java 有诸如IntegerBooleanfor 它们的包装类。您可能想阅读有关“装箱”和“拆箱”的内容。

还要注意的另一件事是,某些类型是不可变的 - 也就是说,它们不提供在创建后更改数据的方法。

String在Java中是一种不可变类型,但它也与任何其他类型有所不同。
它有特殊的特权。
虽然 Java 不像 C++ 那样支持运算符重载,但对于String类型,该语言确实提供了一种特殊的方法+ operator来执行字符串连接。

然而,由于String对象是不可变的,任何串联操作都会创建一个全新的String对象,甚至是这样的:

String a = "Hello";
a = a + " world!";

这将创建一个新字符串“Hello world”并将对其的引用存储在 中a,而对旧“Hello”字符串的引用将在将来的某个时刻被垃圾收集。


查看完整回答
反对 回复 2023-09-27
?
森林海

TA贡献2011条经验 获得超2个赞

尽管在 Java 中一切都是按值传递的,但是原始数据类型(例如 int、char 和 boolean)与引用数据类型传递给方法的方式之间存在差异。当传递原始数据类型的值时,该值只能在特定方法的范围内更改。当传递引用数据类型的值时,引用将保持不变,但值将全局更改(或在对象初始化的任何范围内)。

查看完整回答
反对 回复 2023-09-27
  • 2 回答
  • 0 关注
  • 111 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信