建底:作为新手的你不必要去纠结这个!因为很累!低层东西太多了!但是你既然问了我们就会回答! Car c = new Car(); Car c术语:字面量! new Car();术语:匿名对象,返回的是一引用地址! 根据JAVA分编译期.运行期原理(编译期.运行期请另行百度.) 一个CLASS文件执行会在编译期先编译;然后把CLASS文件的内容分别放到方法区跟栈! 也就是说字面量在编译期就已经有了! new String("a")是在运行期才有的!所以字面量C先进栈! 下面一个例子说明以上论据: String a = "a"+1; String b = new String("a")+1; String c = "a"+1; System.out.println(a==b);//输入结果为FALSE,B因为在编译期无法确所以为FALSE; System.out.println(a==c);//输入结果为TRUE,a和C在编译期已经确定所以为TRUE
楼上 好像 说的不对好像是和虚拟机无关的吧应该是和 Javac 有关的。不管哪种虚拟机实现,都必须保证字节码的兼容。如果 字节码 是先 new 再 store ,虚拟机是不会先store 再 new的。public class java{ public static void main(){ Integer i = new Integer(90); int c = 9+8; i.toString(); } }Compiled from "java.java" public class java { public java(); Code: 0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了! 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间 3: dup 4: bipush 90 6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的 9: astore_0 // 这个时候才保存到变量中 10: bipush 17 12: istore_1 13: aload_0 14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String; 17: pop 18: return LineNumberTable: line 4: 0 line 5: 10 line 6: 13 line 7: 18 }其实可以 java j = new java(); 看看到底他是怎么调用Object的init的 public class java{ public static void main(){ int c ; int b = 9; System.out.println(b); c = 0; java j = new java(); }}Compiled from "java.java" public class java { public java(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: bipush 9 2: istore_1 3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 6: iload_1 7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 10: iconst_0 11: istore_0 12: new #4 // class java 15: dup 16: invokespecial #5 // Method "<init>":()V 19: astore_2 20: return LineNumberTable: line 6: 0 line 7: 3 line 8: 10 line 9: 12 line 10: 20 }楼上 好像 说的不对好像是和虚拟机无关的吧应该是和 Javac 有关的。不管哪种虚拟机实现,都必须保证字节码的兼容。如果 字节码 是先 new 再 store ,虚拟机是不会先store 再 new的。public class java{ public static void main(){ Integer i = new Integer(90); int c = 9+8; i.toString(); } }Compiled from "java.java" public class java { public java(); Code: 0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了! 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间 3: dup 4: bipush 90 6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的 9: astore_0 // 这个时候才保存到变量中 10: bipush 17 12: istore_1 13: aload_0 14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String; 17: pop 18: return LineNumberTable: line 4: 0 line 5: 10 line 6: 13 line 7: 18 }其实可以 java j = new java(); 看看到底他是怎么调用Object的init的 public class java{ public static void main(){ int c ; int b = 9; System.out.println(b); c = 0; java j = new java(); }}Compiled from "java.java" public class java { public java(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: bipush 9 2: istore_1 3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 6: iload_1 7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 10: iconst_0 11: istore_0 12: new #4 // class java 15: dup 16: invokespecial #5 // Method "<init>":()V 19: astore_2 20: return LineNumberTable: line 6: 0 line 7: 3 line 8: 10 line 9: 12 line 10: 20 }楼上 好像 说的不对好像是和虚拟机无关的吧应该是和 Javac 有关的。不管哪种虚拟机实现,都必须保证字节码的兼容。如果 字节码 是先 new 再 store ,虚拟机是不会先store 再 new的。public class java{ public static void main(){ Integer i = new Integer(90); int c = 9+8; i.toString(); } }Compiled from "java.java" public class java { public java(); Code: 0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了! 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间 3: dup 4: bipush 90 6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的 9: astore_0 // 这个时候才保存到变量中 10: bipush 17 12: istore_1 13: aload_0 14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String; 17: pop 18: return LineNumberTable: line 4: 0 line 5: 10 line 6: 13 line 7: 18 }其实可以 java j = new java(); 看看到底他是怎么调用Object的init的 public class java{ public static void main(){ int c ; int b = 9; System.out.println(b); c = 0; java j = new java(); }}Compiled from "java.java" public class java { public java(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(); Code: 0: bipush 9 2: istore_1 3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 6: iload_1 7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 10: iconst_0 11: istore_0 12: new #4 // class java 15: dup 16: invokespecial #5 // Method "<init>":()V 19: astore_2 20: return LineNumberTable: line 6: 0 line 7: 3 line 8: 10 line 9: 12 line 10: 20 }
Car c = new Car(); 从运算符优先级和同级时的先后顺序来说,先有c,然后再指向new Car() 后来创建的内存地址。 不过我还是同意1楼说的,没必要纠结这个问题。 现在用的大多数都是sun的jdk,如果换之前BEA公司的jrockit 或者换IBM的J9(jrockit和j9分别是BEA公司为WebLogic和IBM公司为产品WebSphere用的jdk) ,可能得到的是另外的答案了。 这个涉及java虚拟机的实现和java虚拟机规范,劝楼主不要纠结这个问题了,没有太大的意义。
Car c = new Car();
Car c术语:字面量!
new Car();术语:匿名对象,返回的是一引用地址!
根据JAVA分编译期.运行期原理(编译期.运行期请另行百度.)
一个CLASS文件执行会在编译期先编译;然后把CLASS文件的内容分别放到方法区跟栈!
也就是说字面量在编译期就已经有了! new String("a")是在运行期才有的!所以字面量C先进栈!
下面一个例子说明以上论据:
String a = "a"+1;
String b = new String("a")+1;
String c = "a"+1;
System.out.println(a==b);//输入结果为FALSE,B因为在编译期无法确所以为FALSE;
System.out.println(a==c);//输入结果为TRUE,a和C在编译期已经确定所以为TRUE
Integer i = new Integer(90);
int c = 9+8;
i.toString();
}
}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了!
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间
3: dup
4: bipush 90
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的
9: astore_0 // 这个时候才保存到变量中
10: bipush 17
12: istore_1
13: aload_0
14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String;
17: pop
18: return
LineNumberTable:
line 4: 0
line 5: 10
line 6: 13
line 7: 18
}其实可以 java j = new java(); 看看到底他是怎么调用Object的init的
public class java{ public static void main(){ int c ;
int b = 9;
System.out.println(b);
c = 0;
java j = new java();
}}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: bipush 9
2: istore_1
3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
10: iconst_0
11: istore_0
12: new #4 // class java
15: dup
16: invokespecial #5 // Method "<init>":()V
19: astore_2
20: return
LineNumberTable:
line 6: 0
line 7: 3
line 8: 10
line 9: 12
line 10: 20
}楼上 好像 说的不对好像是和虚拟机无关的吧应该是和 Javac 有关的。不管哪种虚拟机实现,都必须保证字节码的兼容。如果 字节码 是先 new 再 store ,虚拟机是不会先store 再 new的。public class java{ public static void main(){
Integer i = new Integer(90);
int c = 9+8;
i.toString();
}
}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了!
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间
3: dup
4: bipush 90
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的
9: astore_0 // 这个时候才保存到变量中
10: bipush 17
12: istore_1
13: aload_0
14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String;
17: pop
18: return
LineNumberTable:
line 4: 0
line 5: 10
line 6: 13
line 7: 18
}其实可以 java j = new java(); 看看到底他是怎么调用Object的init的
public class java{ public static void main(){ int c ;
int b = 9;
System.out.println(b);
c = 0;
java j = new java();
}}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: bipush 9
2: istore_1
3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
10: iconst_0
11: istore_0
12: new #4 // class java
15: dup
16: invokespecial #5 // Method "<init>":()V
19: astore_2
20: return
LineNumberTable:
line 6: 0
line 7: 3
line 8: 10
line 9: 12
line 10: 20
}楼上 好像 说的不对好像是和虚拟机无关的吧应该是和 Javac 有关的。不管哪种虚拟机实现,都必须保证字节码的兼容。如果 字节码 是先 new 再 store ,虚拟机是不会先store 再 new的。public class java{ public static void main(){
Integer i = new Integer(90);
int c = 9+8;
i.toString();
}
}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0 // 为什么没有 new呢? 下面 你就知道 new 在哪里了!
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: new #2 // class java/lang/Integer 这个时候应该是分配对象的空间
3: dup
4: bipush 90
6: invokespecial #3 // Method java/lang/Integer."<init>":(I)V 用90做参数 但只是<Init> 这么说来 new 其实是分两步的
9: astore_0 // 这个时候才保存到变量中
10: bipush 17
12: istore_1
13: aload_0
14: invokevirtual #4 // Method java/lang/Integer.toString:()Ljava/lang/String;
17: pop
18: return
LineNumberTable:
line 4: 0
line 5: 10
line 6: 13
line 7: 18
}其实可以 java j = new java(); 看看到底他是怎么调用Object的init的
public class java{ public static void main(){ int c ;
int b = 9;
System.out.println(b);
c = 0;
java j = new java();
}}Compiled from "java.java"
public class java {
public java();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0 public static void main();
Code:
0: bipush 9
2: istore_1
3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
10: iconst_0
11: istore_0
12: new #4 // class java
15: dup
16: invokespecial #5 // Method "<init>":()V
19: astore_2
20: return
LineNumberTable:
line 6: 0
line 7: 3
line 8: 10
line 9: 12
line 10: 20
}
从运算符优先级和同级时的先后顺序来说,先有c,然后再指向new Car() 后来创建的内存地址。
不过我还是同意1楼说的,没必要纠结这个问题。
现在用的大多数都是sun的jdk,如果换之前BEA公司的jrockit 或者换IBM的J9(jrockit和j9分别是BEA公司为WebLogic和IBM公司为产品WebSphere用的jdk) ,可能得到的是另外的答案了。
这个涉及java虚拟机的实现和java虚拟机规范,劝楼主不要纠结这个问题了,没有太大的意义。
我认为先创建字面量C,然后new出对象,然后再把把引用地址给字面量C!我也用你的例子来说明:
堆中的好比是一座火车站,栈里面的好比是一副设计图纸。我(指代虚拟机)看到设计图上有一个车站标识!我去创建一个车站对象!然后再把车站的地址写在设计图车站标识里!
你说的全是废话。javac还是根据JLS来的呢。大家现在讨论的是,为什么javac会这么编译。你还在说javac这样编译,java自然照着javac编译的结果运行。有什么意义?
c在栈里面
new Car()在堆里面
c指向它
就够了.
你所谓的进内存指的是那块内存被申请了可以使用,还是那块内存上存有了有效数据?我简单说下运行过程吧。。
首先这个c楼主的意思应该是某个方法内的局部变量,那么当这个方法被调用时,会在栈内存区新建一个Frame(具体是什么请看JVM规范,反正不是窗体那个Frame),它包括局部变量区和操作符栈(operators stack),所以理论上当一个方法被调用时,他的局部变量就已经存在了。然后运行到c = new Car()这里,首先是在堆内存上申请一块内存,申请完成后会把内存地址push到Frame里的操作符栈上,然后调用Car的构造函数,然后才是将在操作符栈上的地址保存到局部变量里。
所以如果你的意思是哪个内存先被申请,那答案是c所使用的局部变量内存。
如果你的意思是哪个先存入了有效数据,那答案是对象所在的堆内存。上面的运行过程其实还有很多细节,比如编译期如何决定局部变量数量,操作符栈大小,如何创建的Frame,如何传递的参数,以及创建对象new dup invoke astore的过程,如果感兴趣,简单的介绍JVM规范里写得很清楚,具体的过程那就只能直接看源码了。。
如果你真是感兴趣喜欢钻研,那为何不去看JVM规范等权威文献,权威的你不静下心来去钻研,跑到这里问别人,别人要么是道听途说毫无根据的胡乱猜测,要么也只能去翻翻JVM规范查证,查到了还不一定讲得清,你想真正了解还是要亲自去看一遍权威文献原文,不然就纯粹问个热闹,过一阵子就全忘光了,再过一阵可能你问的什么问题都不记得了。
我从理论上来分析一下,java运算都是从右到左进行的。
如:String a="1"+"1";正确
String a="";
"1"+"1"=a;错误
如此从理论上来说,应该是第二种。
分析2:
String a;
a=new String("1"+"1");
这种不用解释,根据代码执行顺序,a肯定先被创建。
实际上应该是你说的那种,但是没有测试过,待考证。
其实很好理解:Car c = new Car(); //别管这行
c = new Car(); //如果构造函数异常,c难道会清空吗= =