java常量池技术

简介

    常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。

Java是一种动态链接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:

类和接口的全限定名;

字段的名称和描述符;

方法的名称和描述符。

在C语言中,如果一个程序要调用其它库中的函数,在链接时,该函数在库中的位置(即相对于库文件开头的偏移量)会被写在程序中,在运行时,直接去这个地址调用函数;

而在Java语言中不是这样,一切都是动态的。编译时,如果发现对其它类方法的调用或者对其它类字段的引用的语句,记录进class文件中的只能是一个文本形式的符号引用,在连接过程中,虚拟机根据这个文本信息去查找对应的方法或字段。

所以,与Java语言中的所谓“常量”不同,class文件中的“常量”内容很丰富,这些常量集中在class中的一个区域存放,一个紧接着一个,这里就称为“常量池”。

java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。

java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。

常量池中对象和堆中的对象:

public class Test{

	public static void main(String[] args){
		Integer i1=new Integer(1);
		   Integer i2=new Integer(1);
		//i1,i2分别位于堆中不同的内存空间

		   System.out.println(i1==i2);//输出false

		   Integer i3=1;
		   Integer i4=1;
		//i3,i4指向常量池中同一个内存空间

		   System.out.println(i3==i4);//输出true

		//很显然,i1,i3位于不同的内存空间

		System.out.println(i1==i3);//输出false
	}
}

8种基本类型的包装类和对象池:

public class Test{

	public static void main(String[] args){
		   //5种整形的包装类Byte,Short,Integer,Long,Character的对象,

		   //在值小于127时可以使用常量池
		   Integer i1=127;
		   Integer i2=127;
		   System.out.println(i1==i2);//输出true

		   //值大于127时,不会从常量池中取对象
		   Integer i3=128;
		   Integer i4=128;

		   System.out.println(i3==i4);//输出false

		   //Boolean类也实现了常量池技术
		   Boolean bool1=true;
		   Boolean bool2=true;
		   System.out.println(bool1==bool2);//输出true
		   //浮点类型的包装类没有实现常量池技术

		   Double d1=1.0;
		   Double d2=1.0;
		   System.out.println(d1==d2);//输出false

		}
}

String也实现了常量池技术:

public class Test{

public static void main(String[] args){
//s1,s2分别位于堆中不同空间

String s1=new String("hello");
String s2=new String("hello");

System.out.println(s1==s2)//输出false

//s3,s4位于池中同一空间

String s3="hello";
String s4="hello";

System.out.println(s3==s4);//输出true

}
}

用new String()创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间。

String 对象(内存)的不变性机制会使修改String字符串时,产生大量的对象,因为每次改变字符串,都会生成一个新的String。 java 为了更有效的使用内存,常量池在编译期遇见String 字符串时,它会检查该池内是否已经存在相同的String 字符串,如果找到,就把新变量的引用指向现有的字符串对象,不创建任何新的String 常量对象,没找到再创建新的。所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收。

最后

在JDK5.0之前是不允许直接将基本数据类型的数据直接赋值给其对应地包装类的,如:Integer i = 5; 

但是在JDK5.0中支持这种写法,因为编译器会自动将上面的代码转换成如下代码:Integer i=Integer.valueOf(5);  

这就是Java的装箱.JDK5.0也提供了自动拆箱. Integer i =5;  int j = i;  

时间: 2024-08-30 20:36:21

java常量池技术的相关文章

浅谈java常量池_java

java常量池技术 java中常量池技术说的通俗点就是java级别的缓存技术,方便快捷的创建一个对象.当需要一个对象时,从池中去获取(如果池中没有,就创建一个并放入池中),当下次需要相同变量的时候,不用重新创建,从而节省空间. java八种基本类型的包装类和对象池 java中的基本类型的包装类.其中Byte.Boolean.Short.Character.Integer.Long实现了常量池技术,(除了Boolean,都只对小于128的值才支持) 比如,Integer对象 Integer i1

java常量池是如何存放基本类型字面量的?和String 的处理方式是一样的吗?常量池的设计原则是什么?

问题描述 public class Test {public final int a=5;public final int b=5;public final int c=5;String d="abc";String e="abc";String f="abc";}常量池在存储 基本类型的字面量 ,和存储字符串 的存储方式是否一样,比如说 字符串"abc" ,在常量池中只存储一份, 那么基本类型 字面量 比如说上面定义的 5

Java对象池技术的原理及其实现

摘要 本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式.还指出了使用对象池技术时所应注意的问题. 关键词 对象池:对象池技术:Java 对象:性能 Java对象的生命周期分析 Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对象的使用时间,而T3则表示其清除时间.由此,我们可以看出,只有T2是真正有效的时间,而T1.T3则是对象本身的开

Java常量池解析与字符串intern简介

在Java应用程序运行时,Java虚拟机会保存一份内部的运行时常量池,它区别于class文件的常量池,是class文件常量池映射到虚拟机中的数据结构. 关于class文件常量池的部分可以参考之前的博文实例探索Class文件. 1.CONSTANT_Class入口解析 数组类的符号解析较为特殊.若是基本类型数组,那么虚拟机将创建该基本类型的新数组类,并创建一个Class实例来代表该类型,数组类的定义类加载 器为 启动类加载器.若是引用类型的数组,那么在此之前还会进行引用类型的解析,数组类的定义类加

Java常量池详解之抓狂的面试题

今天My partner问我一个让他头疼的Java question,求输出结果: /**   *    * @author DreamSea 2011-11-19   */  public class IntegerTest {      public static void main(String[] args) {              objPoolTest();      }      public static void objPoolTest() {          Inte

利用Java线程池技术实现TCP端口扫描

一个简单的利用线程池技术实现端口扫描(TCP)的小程序: 关键代码如下: // 扫描本机private void getLocal(){ String ip = getIP(); String portStart = txPortStart1.getText().trim(); String portEnd = txPortEnd1.getText().trim(); if (portStart.length() == 0 || portEnd.length() == 0) return; in

请问JAVA常量池究竟在哪里?

问题描述 最近在研究JVM内存模型遇到常量池的问题网上版本很多有的说在堆里有的说在栈里有的说在方法区方法区在堆里有的干脆说既不在堆也不在栈里于是...我晕了有人看过权威点的资料吗究竟是在哪里啊方便的话顺便把大概的内存模式介绍下...什么新生代旧生代永久区谢谢 解决方案 解决方案二:常量池在方法区,但方法区可以在堆上实现也可以在栈中实现权威的资料就是jvmspec第二版解决方案三:"新生代旧生代永久区"这个不是jvm规范里规定的,可以这么做,也可以不这么做.一个可能的jvm实现甚至可以没

Java方法区和运行时常量池溢出问题分析(转)

运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象:否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用. 在JDK1.6及之前版本中,由于常量池分配在永久代中(即方法区),我们可以通过-XX:PermSize和-XX:MaxP

Java的string类常量池及不可变性

1.String常量池     当使用new String("hello")时,JVM会先使用常量池来管理"hello"直接量,再调用String类的构造器来创建一个新的String对象,新创建的对象被保存在堆内存中.即new String("hello")一共产生了两个字符串对象. [常量池constant pool]管理在编译时被确定并保存在已编译的.class文件中的一些数据,包括关于类.方法.接口中的常量,和字符串常量.  [字符串常量池