Java new运算符解析
1、创建数组时,不使用new操作符
Person [] a; a[0]=new Person(); //Error:variable a might not have been initialized
2、创建对象时,不使用new操作符
Person pe=Person(); pe.talk(); //Error: cannot find symbol // symbol: method Person() // location: class test.DataAbstract Person pe; pe.talk(); //Error: variable pe might not have been initialized
我一直有个困惑,书上说对象的创建3个部分,包括类的加载、对象内存的分配和变量的初始化。官方文档上关于new具体做了什么是这样描述的:
The new operator instantiates a class by allocating memory for a new object and returning a reference to that memory.The new operator also invokes the object constructor.
可以肯定的是,“new Person()”返回的是实例对象的内存空间首地址,可以打印出来的。new作为一个优先级很高的运算符,它的结合性是从右到左,这里它操作的是Person类的构造方法。
好,让我们回到构造方法的定义。
“构造方法是一类特殊的方法,它的名字必须与类名完全相同,且不返回任何数据类型,不能有任何非访问性质的修饰符,也不能用void修饰。”
“构造方法通过new操作符创建对象时被调用。”
书上还说,用一下代码,可以“先创建对象,后初始化对象”:
Person pe; pe=new Person();
所以到底是谁他妈创建了对象?pe不就是一个Person类型的引用变量吗,最终存储的也只是对象的内存地址啊。
查了很久的资料,可以肯定了,构造方法不返回任何东西!不返回类的实例!不返回类的实例!!它的主要工作是初始化已经创建的实例(应该还为实例的创建提供了类的类型)。
以下是选的部分回答:(StackOverflow)
"The Suns' Java tutorial stands that "The new operator is followed by a call to a constructor, which initializes the new object."Initialize does not mean create.“
The AllocObject function documentation stands that "Allocates a new Java object without invoking any of the constructors for the object. Returns a reference to the object." So in JVM object is not allocated by constructor, but only initialized by it. Looking in constructors' bytecode we are seeing that no object is returned (exactly like in void methods).
所以new操作符才是大哥,new操作符的操作数必须是Constructor,new负责动态分配内存,调用Constructor(并把参数传给它进行初始化),最后返回初始化后的instance的内存空间的首地址。
构造器本质上是个"nonstatic method with name <init> and void return type",只不过这个函数已经不是java语言的一部分了。
在另一个回答中,有人对用new创建类实例对象的的机器码(StackOverflow)。
总结起来就是:new动态分配内存(应该根据类型),调用Constructor,Constructor进行初始化,返回内存首地址。
至于调用操作和返回操作到底应不应该算在new头上(或者JVM?),已经不重要了。重要的是,构造器没有返回任何东西,只是初始化了已经创建的实例。
最后贴一个来自bd知道的回答:
例:Date date1 = new Date();
1. 执行这段代码,虚拟机先查找Date.class文件是否已加载,如果已加载直接跳转到第3步,如果没有则从classPath和相对路径等查找,查找方式由classLoader决定。
2. 找到Date.class文件,虚拟机将Date.class文件加载到内存,解析出class类和注解等元信息,虚拟机保证每个Date.class文件只加载一次。
3. 在堆中申请内存空间存放Date的实例同时进行变量的初始化(类的不同实例只有变量部分不同,方法共享同一份内存),调用无参构造方法Date()进行初始化。
4. 在栈中申请内存空间存放date1句柄变量,将初始化后的实例句柄赋予date1变量。