值类型 与 引用类型 是如果使用内存的?


看了很多资料都说的很含糊, 希望高手帮忙指点下.

特别是他们在栈内存与堆内存中是如何调用的......主要就是这里有点含糊.......忘高手指点!

谢谢!!!

比如 什么一个引用类型 NEW一个之后 又使用了堆内存啊, 然后那个什么栈内存又是引用的堆内存的值啊.....混乱中...
...全文
358 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
dclete 2010-10-26
  • 打赏
  • 举报
回复
存储方式不同
效率不同
lccycc 2010-04-17
  • 打赏
  • 举报
回复
顶楼上!
loven_11 2010-04-17
  • 打赏
  • 举报
回复
楼主去看下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

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
}
}






博客内有更精彩的内容
  • 打赏
  • 举报
回复

那么是不是我们通过栈中的变量去引用堆中的资源????
ZangXT 2010-04-16
  • 打赏
  • 举报
回复

1.常量池具体在哪里我也证明不了,只不过我理解的常量池是在栈里面,汇编里面栈的概念
错误。常量池在方法区。sun jvm中的PermGen。
http://zangxt.javaeye.com/blog/472236

2.静态变量不是放在常量池里的,是放哪里呢?
方法区。

3.成员变量没有static一说?单例模式写一个看看有没有static的
严格说java根本没有成员变量之说。

4.即使时是用了final,也只是进行了编译器优化
试想它修饰局部变量和其他局部变量一样也是方法完就销毁的

final修饰的变量 生命周期还是在去测试下吧,写个内部类测试下就明白了
final修饰的变量,方法没了肯定没了。内部类是复制了一份,并不是局部的final变量了。final在这种情况下起到一个锁定作用。
qjtttt 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 allvictory 的回复:]
根据《深入JAVA虚拟机》书中描述:常量池是属于类型信息的一部分,类型信息也就是每一个被转载的类型,这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的。

常量池在栈里这个说话真恶心!
[/Quote]
常量池具体在哪里我也证明不了,只不过我理解的常量池是在栈里面,汇编里面栈的概念
静态变量不是放在常量池里的,是放哪里呢?
成员变量没有static一说?单例模式写一个看看有没有static的

即使时是用了final,也只是进行了编译器优化
试想它修饰局部变量和其他局部变量一样也是方法完就销毁的

final修饰的变量 生命周期还是在去测试下吧,写个内部类测试下就明白了
J79091304 2010-04-16
  • 打赏
  • 举报
回复
new 出来的对象都分配在堆内存中 ,理解一下内存的使用机制就好记住了
ripya 2010-04-16
  • 打赏
  • 举报
回复
楼主可以参看Java编程思想里面堆和栈这一块内容的讲解,自己好好理解去。问别人得到的知识别人片面的理解而已,还是自己去理解的好
allvictory 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 qjtttt 的回复:]

2楼只是用C作为引入简单的讲了下,其实没有什么大错
对象本来就是放在堆区的,变量也仅仅只是一个引用,自己去输出一下看看吧,能理解C里面指针的概念就很容易理解java的引用,java要简单的多!!!
你问的静态变量我告诉你,在java中放在常量池里面,和静态块一样,常量池全部都在栈内
至于对象的成员变量,你这个问题问的一点意义都没有,对象被放到了堆区,对象的属性你说该放哪里?
先说到这里了……
[/Quote]
谢谢楼上的指导,继续说
4:静态变量不是放在常量池里的,常量池放的是些基本的整数和编译后的String常量,常量池在栈里这个说法很可笑了
5:成员变量没有static一说
6:即使时是用了final,也只是进行了编译器优化,因为final能够修饰所有变量,试想它修饰局部变量和其他局部变量一样也是方法完就销毁的,没有任何持久存在的必要,如果修饰成员变量,每个对象new出来也包含它在有的
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 zangxt 的回复:]
引用 18 楼 sunle818 的回复:
有没有大众化一点的理解了??? 感觉你们说的太深奥.....对于一个自学者来说 你们说的好像不太好理解.......
希望能有通俗一点的讲解 谢谢了!!!

不必纠结这东西,没用。
[/Quote]

这个不是有用没用的问题啊.....你知道的啦 自习一般以看书为主,里面经常提到 堆栈这些概念 不清楚不行啊.....
ZangXT 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 sunle818 的回复:]
有没有大众化一点的理解了??? 感觉你们说的太深奥.....对于一个自学者来说 你们说的好像不太好理解.......
希望能有通俗一点的讲解 谢谢了!!!
[/Quote]
不必纠结这东西,没用。
wyang1991 2010-04-16
  • 打赏
  • 举报
回复
看看thinking in java的前三章就知道了
  • 打赏
  • 举报
回复
有没有大众化一点的理解了??? 感觉你们说的太深奥.....对于一个自学者来说 你们说的好像不太好理解.......
希望能有通俗一点的讲解 谢谢了!!!
allvictory 2010-04-16
  • 打赏
  • 举报
回复
学习了,谢谢楼上的大侠
ZangXT 2010-04-16
  • 打赏
  • 举报
回复
关于内部类方法访问局部变量时,局部变量需要声明为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.class

Compiled 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: return

public 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
cyousor 2010-04-15
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 believefym 的回复:]
引用 1 楼 believefym 的回复:

懂c的话更好理解一点
int *a = (int*)malloc(sizeof(int)*10);

a自己只是一个指针,也是一个变量,存在栈
后面malloc的那块空间在堆上
a指向那块空间

转到java
A a = new A();
其实是一样的,尽管都说java没指针,不过我觉得当指针那么理解也无所谓。


值类型……
[/Quote]

支持
believefym 2010-04-15
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 believefym 的回复:]

懂c的话更好理解一点
int *a = (int*)malloc(sizeof(int)*10);

a自己只是一个指针,也是一个变量,存在栈
后面malloc的那块空间在堆上
a指向那块空间

转到java
A a = new A();
其实是一样的,尽管都说java没指针,不过我觉得当指针那么理解也无所谓。
[/Quote]

值类型: a (栈上) 自己存的就是一个value
引用类型: a (栈上) 存的是一个堆上的地址
believefym 2010-04-15
  • 打赏
  • 举报
回复
懂c的话更好理解一点
int *a = (int*)malloc(sizeof(int)*10);

a自己只是一个指针,也是一个变量,存在栈
后面malloc的那块空间在堆上
a指向那块空间

转到java
A a = new A();
其实是一样的,尽管都说java没指针,不过我觉得当指针那么理解也无所谓。
ZangXT 2010-04-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 allvictory 的回复:]
3:曾经有高手指出过:java的指针是指向的是一个两个机器字大小的对象头

[/Quote]
对象头是“对象”的“头”,后面还跟着数据呢。
allvictory 2010-04-15
  • 打赏
  • 举报
回复
根据《深入JAVA虚拟机》书中描述:常量池是属于类型信息的一部分,类型信息也就是每一个被转载的类型,这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的。

常量池在栈里这个说话真恶心!
加载更多回复(6)

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧