今天没有学什么东西,上午去大连理工参加百度笔试,打了很专业的酱油,虽然感觉题还可以,只是......(我懂的),今天先写一下以前从网上整理的Java常量池相关的基础知识。
常量池是Java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种声明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。
Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:
在C语言中,如果一个程序要调用其它库中的函数,在连接时,该函数在库中的位置(即相对于库文件开头的偏移量)会被写在程序中,在运行时,直接去这个地址调用函数;而在Java语言中不是这样,一切都是动态的。编译时,如果发现对其它类方法的调用或者对其它类字段的引用的话,记录进class文件中的,只能是一个文本形式的符号引用,在连接过程中,虚拟机根据这个文本信息去查找对应的方法或字段。
所以,与Java语言中的所谓“常量”不同,class文件中的“常量”内容很非富,这些常量集中在class中的一个区域存放,一个紧接着一个,这里就称为“常量池”。
Java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间(貌似这好像是一种设计模式)。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。
在Eclipse中运行的结果显示:
Java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。
package org.ygy.constant; import static org.junit.Assert.*; import org.junit.Test; public class ConstantTest { @Test public void testString() { String a = "abc"; String b = "abc"; assertTrue(a == b); } @Test public void testInteger() { Integer c = 127; Integer d = 127; assertTrue(c == d); Integer e = 128; Integer f = 128; assertFalse(e == f); } @Test public void testBoolean() { Boolean b1 = true; Boolean b2 = true; assertTrue(b1 == b2); } @Test public void testDouble() { Double d1 = 1.0; Double d2 = 1.0; assertFalse(d1 == d2); } }
注:为什么是127呢?
这好像是Java的实现:
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high)//127 return IntegerCache.cache[i + 128]; else return new Integer(i); }
The javap command disassembles a class file. Its output depends on the options used. If no options are used, javap prints out the package, protected, and public fields and methods of the classes passed to it. javap prints its output to stdout. For example, compile the following class declaration:
这个命令可以看到Java的字节码文件,挺好用的,可以试一下。
这是上面的程序使用javap - c命令查看的: