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

几周前我开始接触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++ 中那样的实际内存地址,而是一些唯一的对象标识符)


那么我的假设正确吗?非平凡对象(又名在堆上分配的对象)是通过引用传递的吗?


慕尼黑的夜晚无繁华
浏览 112回答 2
2回答

潇湘沐

Java 语言不允许您像 C 和 C++ 那样在代码中区分堆/堆栈。相反,它将所有数据类型分为两组:基本类型:这些是简单的内置数字类型,例如int,double或boolean(不是 Java 中的数字类型)。注意String不是这样的类型!对象类型:如果是类,那么它就是对象类型。这适用于内置类型(例如)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 有诸如Integer和Booleanfor 它们的包装类。您可能想阅读有关“装箱”和“拆箱”的内容。还要注意的另一件事是,某些类型是不可变的 - 也就是说,它们不提供在创建后更改数据的方法。String在Java中是一种不可变类型,但它也与任何其他类型有所不同。它有特殊的特权。虽然 Java 不像 C++ 那样支持运算符重载,但对于String类型,该语言确实提供了一种特殊的方法+ operator来执行字符串连接。然而,由于String对象是不可变的,任何串联操作都会创建一个全新的String对象,甚至是这样的:String a = "Hello"; a = a + " world!";这将创建一个新字符串“Hello world”并将对其的引用存储在 中a,而对旧“Hello”字符串的引用将在将来的某个时刻被垃圾收集。

森林海

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

相关分类

Java