Objects and references
new object
The most simple example:
new Object();
Simply put, new Object () is an instance of type Object created (instance), allocated in the JVM heap memory
To public method as an example, look at:
PS: Whether the method is public or private / protected / package method, or method of construction is, even in a static block, static variables, instance variables, new Object for this action, it is very much the same
public class Test {
public void fun1() {
Object o = new Object();
}
}
In fun1 method of Test class is instantiated an Object, and assigned to a variable of type Object, when this method is called, what happened?
1. Perform javac Test.java
compiled to Test.class
file
2. execution javap -v Test.class
, you can view the compiled .class
byte code file. Here are just a fun1
public void fun1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: astore_1
8: return
LineNumberTable:
line 3: 0
line 4: 8
Focusing Code section
stack = 2 indicates that the process requires a depth of operand stack 2
locals = 2 indicates that the process requires two local variable space of Slot
Here is followed by the offset and the corresponding JVM instruction set, we can analyze these step by step set of instructions to do something
First, the initialization of the operand stack and local variable space is such that:
Instruction Set | Corresponding CODE |
---|---|
0: new, create an instance of a type java.lang.Object, and its reference value onto the operand stack of the stack (PS: This does not refer to a reference value Object o ) of the operand stack: [free], [objectRef] local variable table: [the this], [free] |
new Object() |
3: dup, copy the value stack operand stack, and stack the operand value onto the stack operand stack: [objectRef], [objectRef] local variable table: [the this], [free] |
new Object() |
4: invokespecial, calling the java.lang.Object "
the operand stack: [free], [objectref] local variable table: [the this], [free] |
new Object() |
7: astore_1, the reference value of the top of the stack into local variables second operand stack: [free], [free] local variable table: [the this], [objectRef] |
Object o = new Object (), mainly the assignment operator |
8: return, from the current method returns void |
From the analysis of the above steps can be found, a simple method in a new Object operation, the JVM is executed three instructions, namely:
- Create object and stack reference value
- Copy the top of the stack value
- Call the superclass constructor
This reference value objectref more easily lead to ambiguity, we usually say that the reference is to Object o = new Object()
the give the operator the left of the Object O , be noted that this sentence does not create a reference, but the reference to Object instance, into local variables
VS is not assigned assignment
When you create objects to use, look at this situation
Object o = new Object();
o.toString();
Create an instance of type Object, and then call its toString
method
The same wording can also be this way:
new Object().toString();
Is there any difference of these two methods? By JVM instructions to look
Source:
public class Test {
public void invokeWithoutReference() {
new Object().toString();
}
public void invokeWithReference() {
Object o = new Object();
o.toString();
}
}
Instruction set ( javap -v Test.class
retaining only the instruction set section):
public void invokeWithoutReference();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>": ()V
7: invokevirtual #3 // Method java/lang/Object.toString:()Ljava/lang/String;
10: pop
11: return
public void invokeWithReference();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>": ()V
7: astore_1
8: aload_1
9: invokevirtual #3 // Method java/lang/Object.toString:()Ljava/lang/String;
12: pop
13: return
There is no difference between the reference and is the reference, in invokeWithReference
the generating Object
the examples, executed astore_1
and aload_1
two instructions, wherein:
astore_1
Shows a stack reference value is stored in the second local variable table Slot, representing the assignment operator ( =
) do
aload_1
Said the second reference type local variable stack pushed onto the operand stack
Specifically, at two different methods of instruction execution sets:
invokeWithoutReference
Instruction Set | Corresponding CODE |
---|---|
0: new, create an instance of a type java.lang.Object, stack and its reference value onto the operand stack operand stack: [free], [objectRef] local variable table: [the this] |
new Object() |
3: dup, copy the value stack operand stack, and stack the operand value onto the stack operand stack: [objectRef], [objectRef] local variable table: [the this] |
new Object() |
4: invokespecial, calling the java.lang.Object "
the operand stack: [free], [objectref] local variable table: [the this] |
new Object() |
7: invokevirtual, toString java.lang.Object method invocation because toString method returns a value, the result will be performed where the stack is pushed into the operand stack: [free], [java.lang.String] local variable table : [the this] |
new Object().toString(); |
10: pop, the top of the stack value pop operation of stack: [free], [free] local variable table: [the this] |
new Object().toString(); |
11: return, return void from the current method |
invokeWithReference
Instruction Set | Corresponding CODE |
---|---|
0: new, create an instance of a type java.lang.Object, and its reference value onto the top of stack operand stack of the operand stack: [free], [objectRef] local variable table: [the this], [idle ] |
new Object() |
3: dup, copy the value stack operand stack, and stack the operand value onto the stack operand stack: [objectRef], [objectRef] local variable table: [the this], [free] |
new Object() |
4: invokespecial, calling the java.lang.Object "
the operand stack: [free], [objectref] local variable table: [the this], [free] |
new Object() |
7: astore_1, the reference value of the top of the stack into local variables second operand stack: [free], [free] local variable table: [the this], [objectRef] |
Object o = new Object(); |
8: aload_1,将第二个本地变量推入栈顶 操作数栈:[空闲], [objectref] 局部变量表:[this], [objectref] |
|
9: invokevirtual,调用java.lang.Object的toString方法,因为toString方法有返回值,所以这里会将执行的结果推入栈顶 操作数栈:[空闲], [java.lang.String] 局部变量表:[this], [objectref] |
new Object().toString(); |
12: pop,将栈顶数值弹出 操作数栈:[空闲], [空闲] 局部变量表:[this], [objectref] |
new Object().toString(); |
13: return,从当前方法返回void |
引用?
首先,什么是引用?
《深入理解JVM虚拟机》一书中多次对Java的引用进行了讨论
对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)——《深入理解JVM虚拟机》 2.2.2 Java虚拟机栈
建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。——《深入理解JVM虚拟机》 2.3.3 对象的访问定位
一般来说,虚拟机实现至少都应当能通过这个引用做到两点,一是从此引用中直接或间接地查找到对象在Java堆中地数据存放地起始地址索引,二是此引用中直接或间接地查找到对象所属数据类型在方法区中的存储的类型信息 ——《深入理解JVM虚拟机》 8.2.1 局部变量表
对于new Object()
来说,JVM执行的new(0xbb)
指令天然的就会将新实例的引用压入操作数栈的栈顶
而Object o = new Object()
只是利用=
运算符,让JVM执行了astore_n
指令,将这个引用保存到了局部变量表中,以便我们以后可以直接通过o.xxx()
来对这个实例做一些操作
等到我们需要使用的时候,JVM再通过aload_n
将指定的局部变量表中的引用类型值推到操作数栈的栈顶进行后续操作
所以在我看来,Object o
其实是一个引用类型的本地变量
创建对象到底赋值吗?
回到初衷,是否定义一个引用类型的本地变量,没有一个绝对的优劣
Object o = new Object()
仅仅是比new Object()
多在局部变量表中保存了一个Object o
引用类型,但它可以让我们在创建了实例之后,重复对这个实例进行操作
new Object()
在进行了new Object().toString()
这种方式的调用之后,由于局部变量表中没有了该实例的引用,操作数栈中的那个两个由dup
产生的两个引用,也已经分别因为invokespecial
和invokevirtual
弹出栈了,所以这个对象已经没有指向它的引用了
如果我们对于实例只是一次性调用,那么直接new Object()
的方式也未尝不可