对象池 ---------------常量池
注意注意:::八种基本数据类型 int short long float double byte char boolean 的包装类 就Double Float这两个包装类没有对象池,其它的都有
对象池
(1)Interger对象池装一个字节的基本数字对象 -128 到 127 这256个对象
如 Integer i=110; jvm执行的时候会进行装箱 Integer i=Integer.valueOf(110); 指的对象就是对象 对象池new Integer(110)的地址;
如 Integer i2=110; jvm执行的时候会进行装箱 Integer i2=Integer.valueOf(110); 指的对象就是对象 对象池new Integer(110)的地址;
所以 i==i2;引用相同 他们是对象不是基本数据类型,记住了
Integer i3=new Integer(110);
Integer i4=new Integer(110);
i3!=i4 虽然他们的内容一样但是他们的引用不同,只要new 就会创建一个新的对象,不在对象池中!!! 所以i3==i4是错了,比引用不是比内容
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),
他们的值相同,因此结果为True。
(2)Double Float 就他俩没有对象池
Double d=120.0;
Double d2=120.0;
System.out.println(d==d2); //false 因为装箱直接new
Float f=110f;
Float f2=110f;
System.out.println(f==f2); //false 因为装箱直接new
public static Double valueOf(double d) {
return new Double(d);
}
public static Float valueOf(float f) {
return new Float(f);
}
(3)Long Short Integer
Long l=110L;
Long l2=110L;
System.out.println(l==l2);//true 装箱没有直接new看属于那一个字节的有没有
Short s=110;
Short s2=110;
System.out.println(s==s2); //true 装箱没有直接new看属于那一个字节的有没有
Integer i=110;
Integer i2=110;
System.out.println(i==i2); //true 装箱没有直接new看属于那一个字节的有没有
public static Long valueOf(long v) {
return v >= 128 || v < -128 ? new Long(v) : SMALL_VALUES[((int) v) + 128];
}
public static Short valueOf(short s) {
return s < -128 || s >= 128 ? new Short(s) : SMALL_VALUES[s + 128];
}
public static Short valueOf(short s) {
return s < -128 || s >= 128 ? new Short(s) : SMALL_VALUES[s + 128];
}
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
(4)Character Byte
Character c='a';
Character c2='a';
Character c3='你';
Character c4='你';
System.out.println(c==c2);//true a 字符在对象池中有
System.out.println(c3==c4);// false 你 字符对象池中没有
Byte b=120;
Byte b2=120;
System.out.println(b==b2);//永远true 只有一个字节吗
public static Character valueOf(char c) {
return c < 128 ? SMALL_VALUES[c] : new Character(c);
}
public static Byte valueOf(byte b) {
return VALUES[b + 128];
}
(5)Boolean
Boolean b3=true;
Boolean b4=true;
System.out.println(b3==b4);//永远true 装箱还是老样子啊
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
(二)常量池 存放字符串常量和基本类型常量(public static final)。
public class test1
{
/** * @param args */
public static void main(String[] args)
{
String a = "a1";
String b = "a"+ 1;
System.out.println(a==b); }//true}
test2:
public class test2
{
/** * @param args */
public static void main(String[] args)
{
String a = "ab";
String bb = "b";
String b = "a"+ bb; //编译器不克不及断定为常量
System.out.println(a==b); }//false}
test3:
public class test3
{
/** * @param args */
public static void main(String[] args)
{
String a = "ab";
final String bb = "b";
String b = "a"+ bb; //bb加final后是常量,可以在编译器断定b
System.out.println(a==b); }//true}
test4:
public class test4
{
/** * @param args */
public static void main(String[] args)
{
String a = "ab";
final String bb = getBB();
String b = "a"+ bb;//bb是经由过程函数返回的,固然知道它是final的,但不知道具体是啥,要到运行期才知道bb的值
System.out.println(a==b); }//false private static String getBB(){ return "b"; }}
test5:
public class test5
{
/** * @param args */
private static String a = "ab";
public static void main(String[] args)
{
String s1 = "a";
String s2 = "b";
String s = s1 + s2;//+的用法
System.out.println(s == a);
System.out.println(s.intern() == a);//intern的含义 }//flase true}
test6:
public class test6
{
/** * @param args */
private static String a = new String("ab");
public static void main(String[] args)
{
String s1 = "a";
String s2 = "b";
String s = s1 + s2;
System.out.println(s == a);
System.out.println(s.intern() == a);
System.out.println(s.intern() == a.intern()); }//flase false true}
-------------------------------------------------------------------------------------------------------------------------------------------------
String常量池详解:
1.String应用private final char value[]来实现字符串的存储,也就是说String对象创建之后,就不克不及再批改此对象中存储的字符串内容,就是因为如此,才说String类型是不可变的(immutable)。String类有一个特别的创建办法,就是应用""双引号来创建.例如new String("i am")实际创建了2个
String对象,一个是"i am"经由过程""双引号创建的,另一个是经由过程new创建的.只不过他们创建的时代不合,
一个是编译期,一个是运行期!java对String类型重载了+操纵符,可以直接应用+对两个字符串进行连接。运行期调用String类的intern()办法可以向String Pool中动态添加对象。
例1
String s1 = "sss111";
//此语句同上
String s2 = "sss111";
System.out.println(s1 == s2); //成果为true
例2
String s1 = new String("sss111");
String s2 = "sss111";
System.out.println(s1 == s2); //成果为false
例3
String s1 = new String("sss111");
s1 = s1.intern();
String s2 = "sss111";
System.out.println(s1 == s2);//成果为true
例4
String s1 = new String("111");
String s2 = "sss111";
String s3 = "sss" + "111";
String s4 = "sss" + s1;
System.out.println(s2 == s3); //true
System.out.println(s2 == s4); //false
System.out.println(s2 == s4.intern()); //true
成果上方解析,总结如下:
1.零丁应用""引号创建的字符串都是常量,编译期就已经断定存储到String Pool中;
2,应用new String("")创建的对象会存储到heap中,是运行期新创建的;
3,应用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能断定,已经断定存储到String Pool中;
4,应用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
还有几个经常考的口试题:
String s1 = new String("s1") ;
String s2 = new String("s1") ;
上方创建了几个String对象?
答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.(用new创建的每new一次就在堆上创建一个对象,用引号创建的若是在常量池中已有就直接指向,不消创建)
String s1 = "s1";
String s2 = s1;
s2 = "s2";
s1指向的对象中的字符串是什么?
答案: "s1"。(永远不要忘了String不成变的,s2 = "s2";实际上s2的指向就变了,因为你不成以去改变一个String,)
--------------------------------------------------------------------------------------------------------------------------------------------------
String是一个特别的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的情势来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后经由过程符号引用去字符串常量池里找有没有"abc",若是没有,则将"abc"存放进字符串常量池,并令str指向”abc”,若是已经有”abc” 则直接令str指向“abc”。
斗劲类里面的数值是否相等时,用equals()办法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子申明上方的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的体式格式是生成不合的对象。每一次生成一个。
因此用第二种体式格式创建多个”abc”字符串,在内存中其实只存在一个对象罢了. 这种写法有利与节俭内存空间. 同时它可以在必然程度上进步法度的运行速度,因为JVM会主动按照栈中数据的实际景象来决意是否有须要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有须要创建新对象,从而加重了法度的肩负。
另一方面, 要重视: 我们在应用诸如String str = "abc";的格局定义类时,老是想当然地认为,创建了String类的对象str。愁闷陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有经由过程new()办法才干包管每次都创建一个新的对象。
因为String类的immutable性质,当String变量须要经常变换其值时,应当推敲应用StringBuffer类,以进步法度效力。
1. 起首String不属于8种根蒂根基数据类型,String是一个对象。
因为对象的默认值是null,所以String的默认值也是null;但它又是一种特别的对象,有其它对象没有的一些特点。
2. new String()和new String(”")都是申明一个新的空字符串,是空串不是null;
3. String str=”kvill”;String str=new String (”kvill”)的差别
看例1:
String s0="kvill";
String s1="kvill";
String s2="kv" + "ill";
System.out.println( s0==s1 );
System.out.println( s0==s2 );
成果为:
true
true
起首,我们要知成果为道Java会确保一个字符串常量只有一个拷贝。
因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被断定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它本身必然也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中” kvill”的一个引用。所以我们得出s0==s1==s2;用new String() 创建的字符串不是常量,不克不及在编译期就断定,所以new String() 创建的字符串不放入常量池中,它们有本身的地址空间。
看例2:
String s0="kvill";
String s1=new String("kvill");
String s2="kv" + new String("ill");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );
成果为:
false
false
false
例 2中s0还是常量池中"kvill”的应用,s1因为无法在编译期断定,所所以运行时创建的新对象”kvill”的引用,s2因为有后半项目组 new String(”ill”)所以也无法在编译期断定,所以也是一个新创建对象”kvill”的应用;熟悉打听了这些也就知道为何得出此成果了。
4. String.intern():
再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()办法就是扩充常量池的 一个办法;当一个String实例str调用intern()办法时,Java查找常量池中是否有雷同Unicode的字符串常量,若是有,则返回其的引用,若是没有,则在常量池中增长一个Unicode便是str的字符串并返回它的引用;看例3就清楚了
例3:
String s0= "kvill";
String s1=new String("kvill");
String s2=new String("kvill");
System.out.println( s0==s1 );
System.out.println( "**********" );
s1.intern();
s2=s2.intern(); //把常量池中"kvill"的引用赋给s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
System.out.println( s0==s2 );
成果为:
false
**********
false //固然履行了s1.intern(),但它的返回值没有赋给s1
true //申明s1.intern()返回的是常量池中"kvill"的引用
true
最后我再废除一个错误的懂得:有人说,“应用 String.intern() 办法例可以将一个 String 类的保存到一个全局 String 表中 ,若是具有雷同值的 Unicode 字符串已经在这个表中,那么该办法返回表中已有字符串的地址,若是在表中没有雷同值的字符串,则将本身的地址注册到表中”若是我把他说的这个全局的 String 表懂得为常量池的话,他的最后一句话,”若是在表中没有雷同值的字符串,则将本身的地址注册到表中”是错的:
看例4:
String s1=new String("kvill");
String s2=s1.intern();
System.out.println( s1==s1.intern() );
System.out.println( s1+" "+s2 );
System.out.println( s2==s1.intern() );
成果:
false
kvill kvill
true
在这个类中我们没有申明一个”kvill”常量,所以常量池中一开端是没有”kvill”的,调用s1.intern()后就在常量池中新添加了一个”kvill”常量,本来的不在常量池中的”kvill”仍然存在,也就不是“将本身的地址注册到常量池中”了。
s1==s1.intern()为false申明本来的”kvill”仍然存在;s2如今为常量池中”kvill”的地址,所以有s2==s1.intern()为true。
相关推荐
### Java堆、栈和常量池详解 #### Java内存模型概览 在深入探讨Java中的堆、栈以及常量池之前,我们先来简要回顾一下Java内存模型的基本概念。Java程序运行时会使用到不同的内存区域来存储各种类型的数据,这些...
### Java堆、栈和常量池——内存剖析 #### 寄存器 寄存器作为最快的存储区域之一,由编译器自动管理分配与回收,它位于CPU内,用于存储临时变量,例如局部变量和一些操作数。由于寄存器的数量有限且由编译器自动...
如果不存在,则创建一个新的字符串对象并将其放入常量池。这种方式创建的字符串,一旦创建便不会改变,且可以共享。 而使用new关键字创建字符串对象时,如`String str = new String("abc");`,则会在堆内存中创建一...
如果不存在,则创建一个新的字符串对象并将其放入字符串常量池。 - **性能优化**:使用字符串常量池可以显著减少内存中字符串的重复,特别是在大量使用字符串的场景下。例如,在Web开发中,经常需要处理大量的字符...
在编译阶段,所有的字符串文字会被放入常量池,以实现对象的共享,从而节省内存和提高运行效率。比较字符串时,使用`==`会检查两个字符串引用是否指向同一对象,而`equals()`方法会检查字符串内容是否相等。常量池中...
字符串的重复创建会导致内存浪费,因此JVM引入了字符串 intern() 方法,使得字符串对象可以复用已存在于常量池中的实例。当一个新字符串被创建时,JVM会检查常量池中是否存在相同的字符串,如果存在,就直接返回其...
在Java中,内存主要分为四个区域:寄存器、栈、堆和方法区(包括常量池)。以下是这四个区域的详细说明: 1. **寄存器**: 这是计算机硬件的一部分,用于存储非常快速访问的数据。在Java中,寄存器主要由JVM直接管理...
开发者应当充分利用常量池的特性,尤其是对于频繁使用的对象和字符串,合理利用对象池可以显著提高程序运行效率。同时,了解不同类型的包装类是否支持常量池,以及支持的范围,也有助于编写更高效和内存友好的代码。
《JVM调优实战与常量池详解》 在Java开发中,JVM(Java虚拟机)的性能优化是一项至关重要的任务。...同时,了解常量池的工作机制,有助于我们更好地管理字符串对象,减少不必要的内存开销,从而提高整体系统性能。
- **存储内容**:常量池包含代码中定义的各种基本类型和对象型的常量值,还包括以文本形式出现的符号引用,例如类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。 - **存储位置**:常量池存储在...
1. **对象池技术**:对于频繁创建和销毁的对象,可以使用对象池避免频繁的内存分配和回收。 2. **减少对象创建**:尽量复用对象,减少不必要的new操作,例如使用StringBuilder而非String进行字符串拼接。 3. **...
Double和Float类型的包装类并没有实现常量池技术,这意味着每次创建新的Double或Float对象时都会创建新的对象,而不是从常量池中获取对象。 在应用程序中,常量池技术可以被广泛应用于各种场景。例如,在String类...
`new`指令用于在堆上创建一个新的`String`对象,`dup`指令复制栈顶的引用,`ldc`指令再次从常量池获取"haha"的引用,`invokespecial`调用`String`构造器来初始化新对象,最后`astore_1`将新对象的引用存储到变量`s`...
它主要分为Class文件常量池、运行时常量池,全局字符串常量池,以及基本类型包装类对象常量池。 在JAVA语言中,字面量是指在源代码中用来表示固定值的表示法。例如,整数、浮点数、字符串、布尔类型、字符类型等都...
在Java中,有两种创建字符串对象的方式:直接使用双引号声明出来的String对象会直接存储在常量池中。如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern方法会从字符串常量池中查询当前字符...
3. **intern()方法**:Java的`String`类提供了一个`intern()`方法,调用此方法的字符串对象会尝试从字符串常量池中找到相同的值,如果找到则返回该值的引用,否则将此字符串添加到池中并返回其引用。 4. **内存管理...
Java编程语言的基础知识中,数据类型和运行时常量池(Runtime Constant Pool)是两个关键概念。数据类型决定了变量可以存储的值的种类和大小,而运行时常量池则是Java虚拟机(JVM)内存模型中的一个重要组成部分。 ...