定义全局常量量里面放的值还是地址;如果放的值:常量值是放在常量池中的,常量名是放在栈中的,他怎么能找到?

java 基本类型
与常量池和栈
[问题点数:40分]
本版专家分:0
结帖率 50%
CSDN今日推荐
本版专家分:0
本版专家分:561
本版专家分:7197
本版专家分:4526
本版专家分:4526
本版专家分:2151
本版专家分:2362
本版专家分:4526
本版专家分:0
本版专家分:0
本版专家分:0
本版专家分:4526
本版专家分:7197
本版专家分:0
本版专家分:7197
本版专家分:20
本版专家分:4526
本版专家分:32939
2008年9月 Java大版内专家分月排行榜第二2008年8月 Java大版内专家分月排行榜第二
2008年10月 Java大版内专家分月排行榜第三
匿名用户不能发表回复!|
其他相关推荐java 常量池 到底是在堆中还是栈中?_百度知道
java 常量池 到底是在堆中还是栈中?
请简单说明 谢谢
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
java常量池不在堆中也不在栈中,是独立的内存空间管理。 1. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。) 2. 堆:存放所有new出来的对象。 3. 常量池:存放字符串常量和基本类型常量(public static final)。对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
软件工程师
既不在堆中也不再栈中static静态变量,需要放在内存中的data segment中
本回答被提问者采纳
请参考:程序运行时,我们最好对数据保存到什么地方做到心中有数。特别要注意的是内存的分配。有六个地方都可以保存数据:(1) 寄存器。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹。(2) 堆栈。驻留于常规RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在堆栈里——特别是对象句柄,但Java对象并不放到其中。(3) 堆。一种常规用途的内存池(也在RAM区域),其中保存了Java对象。和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!(4) 静态存储。这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。(5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。(6) 非RAM存储。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。即使程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。一旦需要,甚至能将它们恢复成普通的、基于RAM的对象。Java 1.1提供了对Lightweight persistence的支持。未来的版本甚至可能提供更完整的方案
其他1条回答
为您推荐:
其他类似问题
您可能关注的内容
常量的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。Java中变量的堆栈及常量池存储比较
Java中变量的堆栈及常量池存储比较文章开始把我喜欢的这句话送个大家:这个世界上还有什么比自己写的代码运行在一亿人的电脑上更酷的事情吗,如果有那就是让这个数字再扩大十倍。1.栈内存位于RAM当中,通过堆栈指针可以从处理器获得直接支持。堆栈指针向下移动,则分配新的内存;向上移动,则释放那些内存。这种存储方式速度仅次于寄存器。(常用于存放对象引用和基本数据类型,而不用于存储对象)2.堆内存一种通用的内存池,也位于RAM当中。其中存放的数据由JVM自动进行管理。堆相对于栈的好处来说:编译器不需要知道存储的数据在堆里存活多长。当需要一个对象时,使用new写一行代码,当执行这行代码时,会自动在堆里进行存储分配。同时,因为以上原因,用堆进行数据的存储分配和清理,需要花费更多的时间。3.常量池常量(字符串常量和基本类型常量)通常直接存储在程序代码内部(常量池)。这样做是安全的,因为它们的值在初始化时就已经被确定,并不会被改变。常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种声明方式相同之处:堆与栈都是用于程序中的数据在RAM(内存)上的存储区域。并且Java会自动地管理堆和栈,不能人为去直接设置。不同之处:1.存储数据类型:栈内存中存放局部变量(基本数据类型和对象引用),而堆内存用于存放对象(实体)。2.存储速度:就存储速度而言,栈内存的存储分配与清理速度更快于堆,并且栈内存的存储速度仅次于直接位于处理器当中的寄存器。3.灵活性:就灵活性而言,由于栈内存与堆内存存储机制的不同,堆内存灵活性更优于栈内存。这样两种存储方式的不同之处,也是由于它们自身的存储机制所造成的。所以为了理解它们,首先我们应该弄清楚它们分别的存储原理和机制,在Java中:— 栈内存被要求存放在其中的数据的大小、生命周期必须是已经确定的;— 堆内存可以被虚拟机动态的分配内存大小,无需事先告诉编译器的数据的大小、生命周期等相关信息。栈内存和堆内存的存储数据类型为何不同?我们知道在Java中,变量的类型通常分为:基本数据类型变量和对象引用变量。首先,8种基本数据类型中的数字类型实际上都是存储的一组位数(所占bit位)不同的二进制数据;除此之外,布尔型只有true和false两种可能值。其次,对象引用变量存储的,实际是其所关联(指向)对象在内存中的内存地址,而内存地址实际上也是一串二进制的数据。所以,局部变量的大小是可以被确定的;接下来,java中,局部变量会在其自身所属方法(或代码块)执行完毕后,被自动释放。所以局部变量的生命周期也是可以被确定的。那么,既然局部变量的大小和生命周期都可以被确定,完全符合栈内存的存储特点。自然,局部变量被存放在栈内存中。String类型对象:String s1 = "abc";String s2 = "abc";System.out.print(s1==s2);打印的结果为true。首先String s = "abc"和String s = new String("abc")两张声明方式的不同之处:如果是使用String s = "abc"这种形式,也就是直接用双引号定义的形式。可以看做我们声明了一个值为”abc“的字符串对象引用变量s。但是,由于String类是final的,所以事实上,可以看做是声明了一个字符串引用常量。存放在常量池中。如果是使用关键字new这种形式声明出的,则是在程序运行期被动态创建,存放在堆中。所以,对于字符串而言,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中;如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中可以有多份。String s = ”abc“的工作过程可以分为以下几个步骤:
(1)定义了一个名为"s"的String类型的引用。
(2)检查在常量池中是否存在值为"abc"的字符串对象;
(3)如果不存在,则在常量池(字符串池)创建存储进一个值为"abc"的字符串对象。如果已经存在,则跳过这一步工作。
(4)将对象引用s指向字符串池当中的”abc“对象。String s = new String(”abc“)的步骤则为:
(1)定义了一个名为"s"的String类型的引用。
(2)检查在常量池中是否存在值为"abc"的字符串对象;
(3)如果不存在,则在常量池(字符串池)存储进一个值为"abc"的字符串对象。如果已经存在,则跳过这一步工作。
(4)在堆中创建存储一个”abc“字符串对象。
(5)将对象引用指向堆中的对象。这里指的注意的是,采用new的方式,虽然是在堆中存储对象,但是也会在存储之前检查常量池中是否已经含有此对象,如果没有,则会先在常量池创建对象,然后在堆中创建这个对象的”拷贝对象“。这也就是为什么有道面试题:String s = new String(“xyz”);产生几个对象?的答案是:一个或两个的原因。因为如果常量池中原来没有”xyz”,就是两个。再看上面的例子,在执行String s1 = 'abc"时;常量池中还没有对象,所以创建一个对象。之后在执行String s2 = 'abc"的时候,因为常量池中已经存在了"abc'对象,所以说s2只需要指向这个对象就完成工作了。那么s1和s2指向同一个对象,用”==“比较自然返回true。所以常量池与栈内存一样,也可以实现数据共享。还有值得注意的一点的就是:我们知道局部变量存储于栈内存当中。那么成员变量呢?答案是:成员变量的数据存储于堆中该成员变量所属的对象里面。而栈内存与堆内存的另一不同点在于,堆内存中存放的变量都会进行默认初始化,而栈内存中存放的变量却不会。这也就是为什么,我们在声明一个成员变量时,可以不用对其进行初始化赋值。而如果声明一个局部变量却未进行初始赋值,如果想对其进行使用就会报编译异常的原因了。加油吧,程序员!
java 堆栈常量池,String创建图解
Java堆、栈和常量池以及相关String的讲解
Java中的栈,堆,方法区和常量池
jvm下的栈、堆、方法区和常量池的存储机制
Java内存模型分析(堆、栈和常量池以及相关String的详细讲解)
Java中堆栈常量池等内存分配原理详解
java 栈、堆、方法区、常量池以及变量的内存分配
java中的堆,栈,静态域,常量池
字符串常量池、堆、栈
Java堆、栈和常量池在应用中的区别
没有更多推荐了,JVM解读-方法区 - 简书
JVM解读-方法区
java是基于一门虚拟机的语言,所以了解并且熟知虚拟机运行原理非常重要。
方法区,Method Area, 对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。对于其他虚拟机(如BEA JRockit、IBM J9等)来说是不存在永久代的概念的。
主要存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)。
注意:JDK 6 时,String等字符串常量的信息是置于方法区中的,但是到了JDK 7 时,已经移动到了Java堆。所以,方法区也好,Java堆也罢,到底详细的保存了什么,其实没有具体定论,要结合不同的JVM版本来分析。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。
运行时常量池溢出:比如一直往常量池加入数据,就会引起OutOfMemoryError异常。
类型全限定名。
类型的直接超类的全限定名(除非这个类型是java.lang.Object,它没有超类)。
类型是类类型还是接口类型。
类型的访问修饰符(public、abstract或final的某个子集)。
任何直接超接口的全限定名的有序列表。
类型的常量池。
字段信息。
方法信息。
除了常量意外的所有类(静态)变量。
一个到类ClassLoader的引用。
一个到Class类的引用。
1.1 Class文件中的常量池
在Class文件结构中,最头的4个字节用于存储Megic Number,用于确定一个文件是否能被JVM接受,再接着4个字节用于存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池,由于常量的数量是不固定的,所以常量池的入口放置一个U2类型的数据(constant_pool_count)存储常量池容量计数值。
常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
类和接口的全限定名
字段名称和描述符
方法名称和描述符
1.2 运行时常量池
CLass文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
1.3 常量池的好处
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
双等号==的含义
基本数据类型之间应用双等号,比较的是他们的数值。
复合数据类型(类)之间应用双等号,比较的是他们在内存中的存放地址。
1.4 基本类型的包装类和常量池
java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean。
这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。 两种浮点数类型的包装类Float,Double并没有实现常量池技术。
Integer与常量池
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
System.out.println("i1=i2
" + (i1 == i2));
System.out.println("i1=i2+i3
" + (i1 == i2 + i3));
System.out.println("i1=i4
" + (i1 == i4));
System.out.println("i4=i5
" + (i4 == i5));
System.out.println("i4=i5+i6
" + (i4 == i5 + i6));
System.out.println("40=i5+i6
" + (40 == i5 + i6));
(1)Integer i1=40;Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
(2)Integer i1 = new Integer(40);这种情况下会创建新的对象。
(3)语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。
String与常量池
String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println(str3 == str4);//false
String str5 = "string";
System.out.println(str3 == str5);//true
(1)new String("abcd")是在常量池中拿对象,"abcd"是直接在堆内存空间创建一个新的对象。只要使用new方法,便需要创建新的对象。
(2)连接表达式 +
只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。
对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。
public static final String A; // 常量A
public static final String B;
public static void main(String[] args) {
// 将两个常量用+连接对s进行初始化
String s = A + B;
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
System.out.println("s不等于t,它们不是同一个对象");
s不等于t,它们不是同一个对象。
A和B虽然被定义为常量,但是它们都没有马上被赋值。在运算出s的值之前,他们何时被赋值,以及被赋予什么样的值,都是个变数。因此A和B在被赋值之前,性质类似于一个变量。那么s就不能在编译期被确定,而只能在运行时被创建了。
String s1 = new String("xyz"); //创建了几个对象?
考虑类加载阶段和实际执行时。
(1)类加载对一个类只会进行一次。”xyz”在类加载时就已经创建并驻留了(如果该类被加载之前已经有”xyz”字符串被驻留过则不需要重复创建用于驻留的”xyz”实例)。驻留的字符串是放在全局共享的字符串常量池中的。
(2)在这段代码后续被运行的时候,”xyz”字面量对应的String实例已经固定了,不会再被重复创建。所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1 持有。
这条语句创建了2个对象。
public static void main(String[] args) {
String s1 = new String("计算机");
String s2 = s1.intern();
String s3 = "计算机";
System.out.println("s1 == s2? " + (s1 == s2));
System.out.println("s3 == s2? " + (s3 == s2));
s1 == s2? false
s3 == s2? true
String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。
public class Test {public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.println((hello == "Hello") + " "); //true
System.out.println((Other.hello == hello) + " "); //true
System.out.println((other.Other.hello == hello) + " "); //true
System.out.println((hello == ("Hel"+"lo")) + " "); //true
System.out.println((hello == ("Hel"+lo)) + " "); //false
System.out.println(hello == ("Hel"+lo).intern()); //true
class Other {
static String hello = "Hello";
public class Other {
public static String hello = "Hello";
在同包同类下,引用自同一String对象.
在同包不同类下,引用自同一String对象.
在不同包不同类下,依然引用自同一String对象.
在编译成.class时能够识别为同一字符串的,自动优化成常量,引用自同一String对象.
在运行时创建的字符串具有独立的内存地址,所以不引用自同一String对象.
与 收藏文章 !
个人介绍:
高广超 :多年一线互联网研发与架构设计经验,擅长设计与落地高可用、高性能互联网架构。目前就职于美团网,负责核心业务研发工作。
本文首发在
转载请注明!
互联网一线从业者。
持续稳定输出技术文档,欢迎关注、欢迎转发。
百战程序员_ Java1573题 QQ群:034603 掌握80%年薪20万掌握50%年薪10万 全程项目穿插, 从易到难,含17个项目视频和资料持续更新,请关注www.itbaizhan.com 国内最牛七星级团队马士兵、高淇等11位十年开发经验专...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
需要说明的一点是,这篇文章是以《深入理解Java虚拟机》第二版这本书为基础的,这里假设大家已经了解了JVM的运行时区域,以及class文件结构,类加载流程等基础内容。当然,文中我们也会提一提相关的内容作为复习总结 一.JVM有几种常量池
主要分为:Class文件常量...
这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的差异也比较大。 不过文中一些JVM参数示例都是实际项目里调优的结果,还是经受过实战考验的。 目录 JVM简介 JVM结构2.1 方法区2.1.1 常量池2.1....
转自:http://blog.csdn.net/jackfrued/article/details/ Java面试题全集(中) :
http://www.jianshu.com/p/cbc7fcb62951Java面试题全集(下) :
http://ww...
《U型理论》认为,沿着U型路径发生5项运动: ? 共同创造:聆听生命的召唤,联结与这种召唤有关的人和事物,组成一个核心团队,启发共同意愿。 ? 共同感知:去往最具潜力的地方;观察,观察,观察;用完全打开的思维和心灵去聆听。 ? 共同自然流现:去往能让个人和集体沉静的地方,敞...
白洱的微博其实在当晚就看到了 不过以为是段子之类的 因为懒 所以没有理睬 第二天看到四万评论的时候 进去掺和了一下 说想要手帐 结果成真了 原来这种普通人之间的相互实现梦想 真的可以带了无限的正能量 我打算9号向陌生人说生日快乐 毕竟穷啊 希望手帐快快收到 希望正能量永不息
自己查了24,学校查了30.
iOS中读写文件 iOS提供了两种方法对文件进行写入,针对NSData、NSDictionary等都提供了此方法,有Apple官方文档可查 - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag - (BOOL)...
现在的手机一般都会提供相机功能,有些相机大镜头已经支持1000万以上的像素,有些还支持光学变焦,这些手机已经变成了专业数码相机,为了充分利用手机上的相机功能,Android应用可以控制拍照和录制视频。 首先在项目中添加以下权限 拍照 一、通过系统Intent进行拍照 ...小小的小菜鸟
基本数据类型数据是放在栈还是常量池?
1.什么是常量
用final修饰的成员变量表示常量,值一旦给定就无法改变!
final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
2.Class文件中的常量池
在Class文件结构中,最头的4个字节用于存储魔数Magic Number,用于确定一个文件是否能被JVM接受,再接着4个字节用于存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池,由于常量的数量是不固定的,所以常量池的入口放置一个U2类型的数据(constant_pool_count)存储常量池容量计数值。
常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
类和接口的全限定名
字段名称和描述符
方法名称和描述符
3.方法区中的运行时常量池
运行时常量池是方法区的一部分。
CLass文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。
个人理解:
1.只有被final修饰的基本数据类型和String类型变量在编译时才会被确定下来,因此存放在常量池中。
(A constant variable is a final variable of primitive type or type String that is initialized with a constant
expression ().
Whether a variable is a constant variable or not may have implications with respect to class initialization (),
binary compatibility (,
and definite assignment ().
带final的基础类型和String类型并且用常量表达式初始化的才算constant
variable,其他的都不是)
2.而对于int a=1,数据是存在栈中的,因为这个值并不是常量(区别于常量的定义)
没有更多推荐了,}

我要回帖

更多关于 vb全局常量 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信