懂c的话更好理解一点 int *a = (int*)malloc(sizeof(int)*10);a自己只是一个指针,也是一个变量,存在栈 后面malloc的那块空间在堆上 a指向那块空间转到java A a = new A(); 其实是一样的,尽管都说java没指针,不过我觉得当指针那么理解也无所谓。
值类型: a (栈上) 自己存的就是一个value 引用类型: a (栈上) 存的是一个堆上的地址
堆中存放的是实际的对象,这个对象占有了一定容量的内存,栈中的引用指向堆中内存的地址,A a = new A(),new A()生成了A的一个实例(堆中存放),而a指向A的实例(a在栈中存放)
楼主去看下scjp吧 Java的基础知识还是要看人家的问题都是哪些的。我原来也是一知半解的。 class B { int id; public B b;
public B(id){ this.id = id; }
public void print(){ System.out.println("this.id===>"+id); } }public class A{ int id; B b; public A(int i, B b) { this.id = id; this.b = b; } public static void main (String[] args){ B b1 = new B(1); B b2 = new B(2); B b3 = new B(3);
b1.b = b2; A a = new A(0,b1); a.b1.print(); //this.id===>1 a.b1.b.print(); //this.id===>2
int *a = (int*)malloc(sizeof(int)*10);a自己只是一个指针,也是一个变量,存在栈
后面malloc的那块空间在堆上
a指向那块空间转到java
A a = new A();
其实是一样的,尽管都说java没指针,不过我觉得当指针那么理解也无所谓。
值类型: a (栈上) 自己存的就是一个value
引用类型: a (栈上) 存的是一个堆上的地址
对象本来就是放在堆区的,变量也仅仅只是一个引用,自己去输出一下看看吧,能理解C里面指针的概念就很容易理解java的引用,java要简单的多!!!
你问的静态变量我告诉你,在java中放在常量池里面,和静态块一样,常量池全部都在栈内
至于对象的成员变量,你这个问题问的一点意义都没有,对象被放到了堆区,对象的属性你说该放哪里?
先说到这里了,还有成员变量被static 、final等修饰等等各种情况再说下去没就底了
2:常量池全部在栈里,这个是第一次听说,带高手求证
3:曾经有高手指出过:java的指针是指向的是一个两个机器字大小的对象头
4:静态变量不是放在常量池里的,常量池放的是些基本的整数和编译后的String常量,常量池在栈里这个说法很可笑了
5:成员变量没有static一说
6:即使时是用了final,也只是进行了编译器优化,因为final能够修饰所有变量,试想它修饰局部变量和其他局部变量一样也是方法完就销毁的,没有任何持久存在的必要,如果修饰成员变量,每个对象new出来也包含它在有的
静态变量不是放在常量池里的,是放哪里呢?
成员变量没有static一说?单例模式写一个看看有没有static的即使时是用了final,也只是进行了编译器优化
试想它修饰局部变量和其他局部变量一样也是方法完就销毁的final修饰的变量 生命周期还是在去测试下吧,写个内部类测试下就明白了
1.常量池具体在哪里我也证明不了,只不过我理解的常量池是在栈里面,汇编里面栈的概念
错误。常量池在方法区。sun jvm中的PermGen。
http://zangxt.javaeye.com/blog/4722362.静态变量不是放在常量池里的,是放哪里呢?
方法区。 3.成员变量没有static一说?单例模式写一个看看有没有static的
严格说java根本没有成员变量之说。4.即使时是用了final,也只是进行了编译器优化
试想它修饰局部变量和其他局部变量一样也是方法完就销毁的final修饰的变量 生命周期还是在去测试下吧,写个内部类测试下就明白了
final修饰的变量,方法没了肯定没了。内部类是复制了一份,并不是局部的final变量了。final在这种情况下起到一个锁定作用。
看下面的代码:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;public class Test extends JFrame { private JButton button; public Test() {
final int localInt = 8;
final StringBuilder builder = new StringBuilder("builder");
button = new JButton("Test");
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(Test.this, builder);
JOptionPane.showMessageDialog(Test.this, localInt);
}
});
this.add(button);
this.setSize(100, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
} public static void main(String[] args) {
new Test();
}
}
这里button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(Test.this, builder);
JOptionPane.showMessageDialog(Test.this, localInt);
}
});
访问了局部变量。
很明显,因为actionPerformed是当按钮单击时才调用的方法,而那时候Test构造方法早就执行完了,而
方法中的局部变量自然在方法调用完毕后不存在了。
那怎么办呢?于是java从语法上施加了一个限制,要求内部类中方法访问的局部变量必须是final的。
因为final变量是不会被改变的,所以java编译器在这偷偷的复制了一份给内部类的对象。
看反编译代码:
内部类Test$1.classCompiled from "Test.java"
class Test$1 extends java.lang.Object implements java.awt.event.ActionListener{
final java.lang.StringBuilder val$builder;final Test this$0;Test$1(Test, java.lang.StringBuilder);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LTest;
5: aload_0
6: aload_2
7: putfield #2; //Field val$builder:Ljava/lang/StringBuilder;
10: aload_0
11: invokespecial #3; //Method java/lang/Object."<init>":()V
14: returnpublic void actionPerformed(java.awt.event.ActionEvent);
Code:
0: aload_0
1: getfield #1; //Field this$0:LTest;
4: aload_0
5: getfield #2; //Field val$builder:Ljava/lang/StringBuilder;
8: invokestatic #4; //Method javax/swing/JOptionPane.showMessageDialog:(Ljava/awt/Component;Ljava/lang/Object;)V
11: aload_0
12: getfield #1; //Field this$0:LTest;
15: bipush 8
17: invokestatic #5; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
20: invokestatic #4; //Method javax/swing/JOptionPane.showMessageDialog:(Ljava/awt/Component;Ljava/lang/Object;)V
23: return}首先我们就能看到类中定义的两个字段:
final java.lang.StringBuilder val$builder; //指向StringBuilder引用
final Test this$0; //指向内部类所在的类Test对象的引用
而且该类的构造方法为Test$1(Test, java.lang.StringBuilder);
在构造方法中对这两个字段进行初始化。
对于 final int localInt = 8;呢,这个不用复制了,常数编译的时候就替换了。看15: bipush 8
17: invokestatic #5;即可很明显,actionPerformed中访问的是Test$1自身的field。再看Test构造方法中注册事件监听的代码:
new #5; //class javax/swing/JButton 创建JButton
18: dup
19: ldc #6; //String Test
21: invokespecial #7; //Method javax/swing/JButton."<init>":(Ljava/lang/String;)V
24: putfield #8; //Field button:Ljavax/swing/JButton;
27: aload_0
28: getfield #8; //Field button:Ljavax/swing/JButton;
31: new #9; //class Test$1,创建内部类的对象
34: dup
35: aload_0
36: aload_2
37: invokespecial #10; //Method Test$1."<init>":(LTest;Ljava/lang/StringBuilder;)V builder在这传递给Test$1的构造方法,引用复制了一份,ok
40: invokevirtual #11; //Method javax/swing/JButton.addActionListener:(Ljava/awt/event/ActionListener;)V
class B {
int id;
public B b;
public B(id){
this.id = id;
}
public void print(){
System.out.println("this.id===>"+id);
}
}public class A{
int id;
B b;
public A(int i, B b) {
this.id = id;
this.b = b;
}
public static void main (String[] args){
B b1 = new B(1);
B b2 = new B(2);
B b3 = new B(3);
b1.b = b2;
A a = new A(0,b1);
a.b1.print(); //this.id===>1
a.b1.b.print(); //this.id===>2
b1.b = b3;
a.b1.print(); //this.id===>1
a.b1.b.print(); //this.id===>3
b1 = b2;
a.b1.print(); //this.id===>1
a.b1.b.print(); //this.id===>3
}
}
博客内有更精彩的内容