5

我不确定new关键字在 Java 中的行为方式。确定每次我使用new关键字时,都会在堆上创建一个新对象吗?

我在学习以下示例时遇到了这个疑问-

class Mixer {
  Mixer() { }
  Mixer(Mixer m) { m1 = m; }
  Mixer m1;
  public static void main(String[] args) {
    Mixer m2 = new Mixer();
    Mixer m3 = new Mixer(m2); // Does it create any new mixer object?
    m3.go();
    Mixer m4 = m3.m1;          m4.go(); 
    Mixer m5 = m2.m1;          m5.go();
  }
  void go() { System.out.print("hi "); }
}

该行Mixer m3 = new Mixer(m2);调用不创建任何新对象的构造函数。那么,是否没有创建新对象?

此外,Which variable 指的是程序末尾的哪个对象,即直到我们得到NullPointerExcetionvariable m5

4

5 回答 5

10

是的 - 每次使用new(作为关键字)都会创建一个新对象。在这种情况下:

Mixer m3 = new Mixer(m2);

线 Mixer m3 = new Mixer(m2); 调用不创建任何新对象的构造函数。

你的推理是完全错误的。Mixer正在使用m2作为参数创建一个新的。通常这表示一个复制构造函数——创建一个与旧的具有相同属性的新 Mixer(但它始终是一个新的、不同的对象,并且在技术上根本不需要复制传入的对象的属性。)

于 2013-06-05T14:14:28.703 回答
2

new 总是创建一个新实例(所以总是保留堆内存等)。

这应该说明它。请注意,实例上的 == 会告诉您它是同一个实例(对象)还是不同的实例。(这就是为什么你应该总是使用equals,除非这是你想要做的)

我添加了一个有趣的事情发生在字符串上。"abc" 不会创建新实例,而是重用现有实例。但是当您在 String 类上调用 new 时,它确实如此。

public class Test {
    private String value;

    public String getValue() {
        return value;
    }

    public Test() {
        value = "default";
    }
    public Test(Test t) {
        this.value = t.getValue();
    }

    public Test(String value) {
        this.value = value;
    }

    public static void main(String[] argv) {
        Test t1 = new Test();
        Test t2 = new Test(t1);

        if (t1 == t2) {
            System.out.println("t1 == t2. should not happen");
        } else {
            System.out.println("t1 is a different instance from t2");
        }

        String s1 = "test";
        String s2 = "test";

        if (s1 == s2) {
            System.out.println("s1 == s2. strings initialized with quotes don't always get a new instance.");
        } else {
            System.out.println("s1 is a different instance from s2. should not happen");
        }

        String s3 = new String("test");
        String s4 = new String(s3);

        if (s3 == s4) {
            System.out.println("s3 == s4. should not happen.");
        } else {
            System.out.println("s3 is a different instance from s4, as they were newed.");
        }

    }
}
于 2013-06-05T14:39:54.277 回答
1

首先,忘记堆栈/堆的区别——这是编译器或运行时的实现细节(取决于所讨论的语言)。如果您使用 C 或汇编语言进行系统编程,这可能会有所不同,但当您使用垃圾收集语言和 Java 或 .NET 等环境时则不然。

并回答您的问题:new实际上在大多数(?)(所有?)具有这种运算符的语言中做了两件事。它首先在某处分配内存以保存该类型的实例,然后调用构造函数在新分配的内存中初始化该类型的实例。然后,构造函数链接可能会导致调用其他构造函数(在同一类型、该类型的基类/超类或该类型的构造函数需要完成其工作的任何东西上)。

正如@berry120所指出的,采用与构造函数所针对的类型相同类型的参数的构造函数通常表示复制构造函数。实现相同结果的另一种方法是对某个clone()方法进行显式调用,该方法返回调用它的对象的副本。

于 2013-06-05T14:21:17.053 回答
1

从程序员的角度来看,new会导致新对象的创建。

但是,编译器可能会执行逃逸分析以确定对象是否真的需要在运行时在堆上创建。

对于您的最后一个问题,您的代码创建了两个对象。一个被m2、m3.m1和m4引用,另一个被m3引用。

于 2013-06-05T14:19:58.353 回答
0

它确实创建了一个新对象,并且它的构造函数获得了对m2您已经创建的另一个对象的引用。

于 2013-06-05T14:34:30.457 回答