此查询的目的是比较 Java 和 C++ 的一个方面,这与“new”运算符有关。
现在,我知道在 C++ 中有两种创建对象的方法;有或没有“新”运算符。如果没有该运算符,则不会在堆区域中分配空间,而在存在该运算符时,会在堆区域中分配空间。
爪哇呢?我注意到“new”运算符用于创建每个对象。甚至数组也是使用“new”运算符创建的。这是否意味着在 Java 中对象只有一个存在的地方——即堆区域?
谢谢。
此查询的目的是比较 Java 和 C++ 的一个方面,这与“new”运算符有关。
现在,我知道在 C++ 中有两种创建对象的方法;有或没有“新”运算符。如果没有该运算符,则不会在堆区域中分配空间,而在存在该运算符时,会在堆区域中分配空间。
爪哇呢?我注意到“new”运算符用于创建每个对象。甚至数组也是使用“new”运算符创建的。这是否意味着在 Java 中对象只有一个存在的地方——即堆区域?
谢谢。
是的,new 运算符总是为堆上的对象分配内存。与 C++ 不同,Java 中的对象不能在堆栈上创建。
本地原始类型和对对象类型的本地引用都占用“堆栈”内存,就像它们作为参数传递给方法时一样。
所有对象本身都存在于一个“堆”的等价物中。
从应用程序和应用程序程序员2的角度来看,所有 Java 对象(即所有具有引用的事物)都分配在堆1中。Java 不支持在堆栈上显式分配对象。对象引用可以存储在堆节点(即类或实例字段)和堆栈帧(即局部变量等)中。
事实上,有几种方法可以在不涉及使用new
关键字的 Java 中创建一流的 Java 对象。
{ ... }
数组初始值设定项语法可以在没有关键字的数组声明中使用new
。
字符串文字涉及创建字符串对象(在类加载时)。
装箱转换将(通常)创建一个新的包装器对象,而无需显式new
或方法调用。
反射newInstance
和类似方法创建没有显式new
.
在底层,Java 序列化的实现使用Unsafe
类中的一种特殊方法来创建对象,而无需执行任何已声明的构造函数。
您还可以使用 JNI / JNA api 在本机代码中创建 Java 对象。
(有一个强烈的论点是最后两个“不是 Java”,但无论如何它们都值得一提。字符串文字和自动装箱案例涉及在底层使用new
的 Java 代码。)
1 - 可以有多个堆,尽管这对应用程序是透明的。
2 - 最新的 Hotspot JVM 具有实验性的“逃逸分析”功能,可确定对象是否从创建它们的上下文中“逃逸”。不会逃逸的对象可以安全地分配到堆栈上。再一次,这种优化对应用程序是透明的。
在 Java 中,所有对象都在 Heap 上动态分配。这与 C++ 中的对象可以在堆栈或堆上分配内存不同。在 C++ 中,当我们使用 分配 abject 时new()
,abject 分配在堆上,否则如果不是全局或静态的,则分配在堆栈上。
在Java中,当我们只声明一个类类型的变量时,只会创建一个引用(不为对象分配内存)。要将内存分配给对象,我们必须使用 new()。所以对象总是在堆上分配内存。
示例 1: 给出编译错误。
class Test {
void show() {
System.out.println("Test::show() called");
}
}
public class Main {
public static void main(String[] args) {
Test t;
t.show(); // Error here because t is not initialed
}
示例 2:new()
使用使上述程序工作的 分配内存。
class Test {
void show() {
System.out.println("Test::show() called");
}
}
public class Main {
public static void main(String[] args) {
Test t = new Test(); //all objects are dynamically allocated
t.show(); // No error
}
}