为什么 《Java栈与堆》是垃圾 这样的东西,为什么得以流传? http://topic.csdn.net/u/20081123/12/f70f1632-24be-4caa-bc20-29cf8267afab.html 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 不晓得,还是去看看《深入jvm》吧 对变量的内存分配不看类型看位置。有人问,基本类型变量和引用变量保存在哪里,这不是一个有效的问题。基本类型变量和引用变量都可能保存在stack或heap中,关键是看它们声明的位置——到底是域还是局部变量。我想了解一下,大家都是在自学吗? JAVA的对象生存在堆中,而JAVA的各项成员变量,则根据JVM判断放栈还是掷堆 上大学的时候写过几次有关c、c++的blog,过了一段时间自己就发现了错误,从那以后就再也不写blog了,免得自欺又欺人。 楼主你要是强你就像ZangXT一样给大家普及普及JVM的深层知识, 你这种发言只能让大家觉得你在装B 另外,JVM的深层知识在你学习Java的前两年不需要知道! 原文及其错误:1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 【栈(stack)与堆(heap)在Java的内存管理中是逻辑概念,这里“Ram中”说法不太好。“与C++不同,”不严谨】2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。【“另外,栈数据可以共享,详见第3点。”不知所云。其他基本正确,但是“运行时动态分配内存,存取速度较慢。”stack也是动态分配内存。】 3. Java中的数据类型有两种。一种是基本类型(primitive types), ……值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。 【“不是类的实例,即不是类的引用”,看人了,对于初学者这是错误的。“引用”的大小是可知的。“如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。”什么东西阿,没有这样的说法。“字面值的数据”其中“的数据”删除;字面值……存在于栈中,基本的概念都错了!】既然基本的概念都错了,后面的错误就多了。 25楼,我只是回应TinyJimmy。“错误就指正他!”7楼已经说了。至于原作者不懂Java内存管理、包装类的问题、String str = "abc"与常量池就不说了。但是“5. 关于String str = "abc"的内部工作”。有很多是对的,而且对的和错的搅和在一起。 感觉还是稍微看点c的基础的好,首先要真正了解new delete,就知道里面东西错的太多,我没有看完50%就关了。居然说“查找相等的内存”之类的,不好评价了,基本上对内存没有什么概念。 楼主要详细了解请看这个 http://topic.csdn.net/u/20081123/12/f70f1632-24be-4caa-bc20-29cf8267afab.html通俗的说是值传递基本数据类型采用值传递方式向方法传递参数基本类型的变量存储在"栈"中引用传递对象类型采用引用传递方式向方法传递参数对象类型的变量值存储在"堆"中 没注意看帖子内容不说离题,只说内容,如果你说全部错误,我还正接受不了,原话是《 深入浅出JDK6.0 》 涂传滨 电子工业出版社 第32页第11行,一字未变数据结构与算法(Java版) 一个美国人写的我不是科班出身,编程全部是看书的,向你请教正确答案 值传递 基本数据类型采用值传递方式向方法传递参数 基本类型的变量存储在"栈"中 引用传递 对象类型采用引用传递方式向方法传递参数 对象类型的变量值存储在"堆"中 1、Java中只有值传递,Java创始人说的,其他的说我们都不听,也不争论了。2、class A{int i;int j}这些i、j在哪里存储?告诉涂传滨,在heap中。 三鹿奶粉有毒,如果我国的书籍的错误有索赔制度,垃圾书籍就少得多。轻轻地呼吁,版主将那篇《Java栈与堆》删除,居然有人推荐,我都不知道是什么人在推荐。 其实对于单纯学java的人来说, 已经不太重要了。 重要的是明白String s = "abc";这个经典案例就行了。对堆和栈有所了解就好, 毕竟大多数人要做的是企业应用, 不是系统应用, 研究到内存那个级别没有太大的实用价值。 我不认识Java的创始人,也懒的去读一堆E文关于你上面的两个说法,我的意见是:1.Java中一切皆对象,操纵的标识符实际上是对象的一个“引用”(reference)。任何事物都是“按值传递的没错”,也许这个一种精确但令人费解的解释,但我认为我这种简化的概念上的理解并没错。 (Thiking In Java 4) 21页页末2.class A{int i;int j} i、j存储在heap中没错,但是 JAVA中任何传递对象的场合一样,这里传递的实际上是应用,对于基本数据类型来说是一个例外,通常,尽管传递的是对象,实际上传递的是对象的引用。(Thiking In Java 4) 27页页末 按照你的观点,你不可能知道变量的生命周期,于是你不可能理解局部类(local class)中只能访问外包方法(局部类所在方法)的final局部变量。你说一下,位于方法内部的局部类,为什么只能访问操作y而不能操作x?void go(int x,final int y)这些东西没有什么高深的地方,基础知识而已。 下面的一个代码可以说明JAVA参数传递的问题:class Arg{ Arg(){ i=0; } int i;}public class ArgumentPass { public static void testPrimitive(int x){ //这里的代码不能改变参数传递前的原值,说明它修改的只不过是一个拷贝 x++; } public static void testObject1(Arg x){ //这里的代码真实地修改了参数对象里面的成员值,说明对象参数并不是拷贝,而是对象指针(引用) x.i++; } public static void testObject2(Arg x){ //虽然重新给参数x赋予了新的对象,但其实没起作用,说明x里面放的指针值(引用值)也只不过是一个拷贝。 x=new Arg(); x.i++; } public static void main(String[] args) { int y=0; System.out.println("before call:"+y); testPrimitive(y); System.out.println("after call:"+y); Arg a=new Arg(); System.out.println("before call:"+a.i); testObject1(a); System.out.println("after call:"+a.i); Arg b=new Arg(); System.out.println("before call:"+b.i); testObject2(b); System.out.println("after call:"+b.i); }}针对上面的例子再打比方:1、testPrimitive传递原始类型参数,相对于调用者手上有一个纸片,上面写着参数值。然后它复制了一个同样的纸片给被调用者。因此被调用者在这个纸片上乱涂乱改也对调用者没有任何影响。2、testObject1和testObject2传递对象。例子是图书馆,对象假设是一本书,调用者自己有一个纸片上记录了这本书的位置,比如“第1排第2行第1格”。然后它复制了一张纸片给被调用者。被调用者可以根据纸片上的值找到这本书,然后在上面乱涂乱改,这对调用者是起作用的(正如testObject1所示)。但是,如果被调用者仅仅是在纸片上乱涂乱改,对调用者一点作用也没有(正如testObject2所示)。无论是什么样的说法,不管是传值、传指针、传引用、传地址,最管总的说法是“传-值拷贝”。对于primitive,传的是数值拷贝,对于对象,传的是地址值拷贝 51楼的例子很好,要是能画个内存图就完美了.记得Core java上有图形说明,很清晰. 以后我遇到说“按引用传递”的,我首先问他,你说的是TIJ的“按引用传递”,还是计算机科学的“按引用传递”。TIJ的“按引用传递”,它看见C语言的学习者,他会说,指针传递也是TIJ的“按引用传递”。 请看看什么是“按引用传递”和“按值传递 ”。C++代码#include <stdio.h> void change(int i) { i/=2; } //void change1(int* i){ *i/=2; }void change2(int &i){ i /=2;}void main(void){ int a=100;printf("before:a=%d ",a); int *p1; p1 = &a; printf("p1=%d\n\n",p1); change(a); printf("after change(a): a=%d\n",a); change(*p1); printf("after change(*p1): a=%d and %d\n",a,p1); change1(p1); printf("after change1(p1): a=%d and %d\n",a,p1); change1(&a); printf("after change1(&a): a=%d and %d\n",a,p1); change2(a); printf("after change2(a): a=%d and %d \n",a,&a); change2(*p1);printf("after change2(*p1):a=%d and %d \n",a,p1); } 这篇文章根本不值得一驳,因为它基本上就没有说对的内容。但实在不忍心看到这么多初学者被这篇超级大忽悠文章误导,还是浪费点口水吧。就拿"栈中的数据可以共享"这个荒谬的观点开刀。文章说道int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。 简直笑死我了!你打开class文件,这2句就4个字节,内容是“06 3B 06 3C”对应的虚拟机指令就是: 0 iconst_3 1 istore_0 [a] 2 iconst_3 3 istore_1 [b]学过计算机原理的人都知道,第1个字节06 iconst_3是一个指令,这个指令就是让CPU把寄存器放上3的值第2个字节3B istore_0也是一个指令,就是让CPU把寄存器的值放到第1个变量的内存中第4个字节3C istore_1也是一个指令,就是让CPU把寄存器的值放到第2个变量的内存中这里可以看到JAVA虚拟机的一个小技巧,它把一些对常用常量(比如0,1,2,3,4,5)的操作直接定义成了指令,而不是传统的操作指令后带操作数。目的是减少指令长度。有心的人再用 int a = 6...试,根本就没有iconst_6的指令!而是bipush 6,机器码10 06, 2个字节,10就是bipush, 06就是操作数6,就是传统的指令+操作数。大家用脑子想想“在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址”这句话,问自己一个问题:这样说起来容易,虚拟机实现起来呢?再问一个问题:这样做是不是脱裤子放屁,多此一举呢? 新手~~不太清楚~~刚刚开始学习java~~ls各位都那么牛~~很精彩的一个贴阿~ 首先要理解jvm是基于栈的,寄存器就不要提了。 希望大家指出http://topic.csdn.net/u/20081127/23/bd9ca56e-44d3-4f94-80f7-88f469f6dd79.html中的错误。 嗯,我这个是说错了。jvm spec上叫“Operand Stack”,翻译过来是“操作数 栈” 同意这种简单的提法:1 . java只有传值,对象靠引用来调用,对象参数传递的时候传递“引用”的值,用这点解释足够了,概念创造越多初学者越糊涂。2. 至于数值存放在哪里?只要记住“所有局部变量存放在栈中,所有对象存堆中”就可以了,具体实例可以据此引申出来。 a 局部变量如果是基本类型,则存栈中;如果是对象类型,实际上操作的是一个引用,引用存栈中,对象存堆中。 b 对象存堆中的含义就是对象的所有字段存堆中,所以对象的字段不管是基本数据类型和引用一律在堆中,引用指向的对象自然也在堆中。 这些知识都是最基础的!做C++的应该都知道的,不知道为什么在JAVA区会有如此激烈的讨论! 我们应否尊重不尊重编程的项目经理? 面试题 统计并返回数组中出现次数最多的元素 考软件设计师有用吗?进来有分! B/S、C/S双客户类型系统研究的问题 java Socket报文信息丢失的问题 急!!!怎样用JavaPrintService打印PDF文件?分不够可以再加! jtree产生后的问题 关于一个文件存放路径的问题? 这个最简单的绘图程序错在哪里? access的模糊查询问题! 上传问题 着急!!!!!!!!!!!!!!!!!!!! putValue有什么用法,好处
JAVA的对象生存在堆中,而JAVA的各项成员变量,则根据JVM判断放栈还是掷堆
另外,JVM的深层知识在你学习Java的前两年不需要知道!
【栈(stack)与堆(heap)在Java的内存管理中是逻辑概念,这里“Ram中”说法不太好。“与C++不同,”不严谨】2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
【“另外,栈数据可以共享,详见第3点。”不知所云。其他基本正确,但是“运行时动态分配内存,存取速度较慢。”stack也是动态分配内存。】 3. Java中的数据类型有两种。一种是基本类型(primitive types), ……值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。
【“不是类的实例,即不是类的引用”,看人了,对于初学者这是错误的。“引用”的大小是可知的。“如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。”什么东西阿,没有这样的说法。“字面值的数据”其中“的数据”删除;字面值……存在于栈中,基本的概念都错了!】既然基本的概念都错了,后面的错误就多了。
“错误就指正他!”7楼已经说了。
至于原作者不懂Java内存管理、包装类的问题、String str = "abc"与常量池就不说了。但是“5. 关于String str = "abc"的内部工作”。有很多是对的,而且对的和错的搅和在一起。
基本数据类型采用值传递方式向方法传递参数
基本类型的变量存储在"栈"中引用传递
对象类型采用引用传递方式向方法传递参数
对象类型的变量值存储在"堆"中
没注意看帖子内容
不说离题,只说内容,
如果你说全部错误,我还正接受不了,
原话是《 深入浅出JDK6.0 》 涂传滨 电子工业出版社 第32页第11行,一字未变
数据结构与算法(Java版) 一个美国人写的
我不是科班出身,编程全部是看书的,向你请教正确答案
基本数据类型采用值传递方式向方法传递参数
基本类型的变量存储在"栈"中 引用传递
对象类型采用引用传递方式向方法传递参数
对象类型的变量值存储在"堆"中 1、Java中只有值传递,Java创始人说的,其他的说我们都不听,也不争论了。
2、class A{int i;int j}这些i、j在哪里存储?告诉涂传滨,在heap中。
如果我国的书籍的错误有索赔制度,
垃圾书籍就少得多。轻轻地呼吁,版主将那篇《Java栈与堆》删除,
居然有人推荐,我都不知道是什么人在推荐。
对堆和栈有所了解就好, 毕竟大多数人要做的是企业应用, 不是系统应用, 研究到内存那个级别没有太大的实用价值。
我不认识Java的创始人,也懒的去读一堆E文
关于你上面的两个说法,我的意见是:
1.Java中一切皆对象,操纵的标识符实际上是对象的一个“引用”(reference)。任何事物都是“按值传递的没错”,也许这个一种精确但令人费解的解释,但我认为我这种简化的概念上的理解并没错。 (Thiking In Java 4) 21页页末
2.class A{int i;int j} i、j存储在heap中没错,但是 JAVA中任何传递对象的场合一样,这里传递的实际上是应用,对于基本数据类型来说是一个例外,通常,尽管传递的是对象,实际上传递的是对象的引用。(Thiking In Java 4) 27页页末
按照你的观点,你不可能知道变量的生命周期,
于是你不可能理解局部类(local class)中只能访问外包方法(局部类所在方法)的final局部变量。
你说一下,位于方法内部的局部类,为什么只能访问操作y而不能操作x?
void go(int x,final int y)这些东西没有什么高深的地方,基础知识而已。
Arg(){
i=0;
}
int i;
}
public class ArgumentPass {
public static void testPrimitive(int x){
//这里的代码不能改变参数传递前的原值,说明它修改的只不过是一个拷贝
x++;
}
public static void testObject1(Arg x){
//这里的代码真实地修改了参数对象里面的成员值,说明对象参数并不是拷贝,而是对象指针(引用)
x.i++;
}
public static void testObject2(Arg x){
//虽然重新给参数x赋予了新的对象,但其实没起作用,说明x里面放的指针值(引用值)也只不过是一个拷贝。
x=new Arg();
x.i++;
}
public static void main(String[] args) {
int y=0;
System.out.println("before call:"+y);
testPrimitive(y);
System.out.println("after call:"+y);
Arg a=new Arg();
System.out.println("before call:"+a.i);
testObject1(a);
System.out.println("after call:"+a.i);
Arg b=new Arg();
System.out.println("before call:"+b.i);
testObject2(b);
System.out.println("after call:"+b.i);
}
}
针对上面的例子再打比方:
1、testPrimitive
传递原始类型参数,相对于调用者手上有一个纸片,上面写着参数值。然后它复制了一个同样的纸片给被调用者。因此被调用者在这个纸片上乱涂乱改也对调用者没有任何影响。
2、testObject1和testObject2
传递对象。例子是图书馆,对象假设是一本书,调用者自己有一个纸片上记录了这本书的位置,比如“第1排第2行第1格”。然后它复制了一张纸片给被调用者。被调用者可以根据纸片上的值找到这本书,然后在上面乱涂乱改,这对调用者是起作用的(正如testObject1所示)。但是,如果被调用者仅仅是在纸片上乱涂乱改,对调用者一点作用也没有(正如testObject2所示)。无论是什么样的说法,不管是传值、传指针、传引用、传地址,最管总的说法是“传-值拷贝”。对于primitive,传的是数值拷贝,对于对象,传的是地址值拷贝
记得Core java上有图形说明,很清晰.
我首先问他,你说的是TIJ的“按引用传递”,还是计算机科学的“按引用传递”。TIJ的“按引用传递”,它看见C语言的学习者,他会说,指针传递也是TIJ的“按引用传递”。
void change(int i) { i/=2; } //
void change1(int* i){ *i/=2; }
void change2(int &i){ i /=2;}
void main(void){
int a=100;printf("before:a=%d ",a);
int *p1;
p1 = &a; printf("p1=%d\n\n",p1); change(a); printf("after change(a): a=%d\n",a);
change(*p1); printf("after change(*p1): a=%d and %d\n",a,p1);
change1(p1); printf("after change1(p1): a=%d and %d\n",a,p1);
change1(&a); printf("after change1(&a): a=%d and %d\n",a,p1);
change2(a); printf("after change2(a): a=%d and %d \n",a,&a);
change2(*p1);printf("after change2(*p1):a=%d and %d \n",a,p1);
}
但实在不忍心看到这么多初学者被这篇超级大忽悠文章误导,还是浪费点口水吧。就拿"栈中的数据可以共享"这个荒谬的观点开刀。文章说道
int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。 简直笑死我了!
你打开class文件,这2句就4个字节,内容是“06 3B 06 3C”
对应的虚拟机指令就是:
0 iconst_3
1 istore_0 [a]
2 iconst_3
3 istore_1 [b]
学过计算机原理的人都知道,
第1个字节06 iconst_3是一个指令,这个指令就是让CPU把寄存器放上3的值
第2个字节3B istore_0也是一个指令,就是让CPU把寄存器的值放到第1个变量的内存中
第4个字节3C istore_1也是一个指令,就是让CPU把寄存器的值放到第2个变量的内存中这里可以看到JAVA虚拟机的一个小技巧,它把一些对常用常量(比如0,1,2,3,4,5)的操作直接定义成了指令,而不是传统的操作指令后带操作数。
目的是减少指令长度。有心的人再用 int a = 6...试,根本就没有iconst_6的指令!
而是bipush 6,机器码10 06, 2个字节,10就是bipush, 06就是操作数6,就是传统的指令+操作数。大家用脑子想想“在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址”这句话,
问自己一个问题:这样说起来容易,虚拟机实现起来呢?
再问一个问题:这样做是不是脱裤子放屁,多此一举呢?
ls各位都那么牛~~很精彩的一个贴阿~
http://topic.csdn.net/u/20081127/23/bd9ca56e-44d3-4f94-80f7-88f469f6dd79.html
中的错误。
嗯,我这个是说错了。jvm spec上叫“Operand Stack”,翻译过来是“操作数 栈”
同意这种简单的提法:
1 . java只有传值,对象靠引用来调用,对象参数传递的时候传递“引用”的值,用这点解释足够了,概念创造越多初学者越糊涂。2. 至于数值存放在哪里?只要记住“所有局部变量存放在栈中,所有对象存堆中”就可以了,具体实例可以据此引申出来。
a 局部变量如果是基本类型,则存栈中;如果是对象类型,实际上操作的是一个引用,引用存栈中,对象存堆中。
b 对象存堆中的含义就是对象的所有字段存堆中,所以对象的字段不管是基本数据类型和引用一律在堆中,引用指向的对象自然也在堆中。
做C++的应该都知道的,不知道为什么在JAVA区会有如此激烈的讨论!