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

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

类和接口的全限定名;

字段的名称和描述符;

方法和名称和描述符。

java常量池技术

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

常量池的好处

常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。

节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。

节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。

public static void main(String[] args) {

String str1 = new String("wwe");

String str2 = new String("wwe");

System.out.println(str1 == str2);

System.out.println(str1.intern() == str2.intern());

Integer a1 = 1; Integer a2 = new Integer(1); System.out.println(a1.equals(a2)); System.out.println(a1 instanceof Integer);}

输出:false true true true

1.false 。 String str1 = new String("wwe"); String str2 = new String("wwe"); System.out.println(str1 == str2);类中的 ‘==’ 比较的是内存地址,通过new生成的对象会在堆中创建一个新的对象,内存地址明显不同。

2.trueSystem.out.println(str1.intern() == str2.intern());。String.intern(),比较的是常量池中的值。当常量池中不存在“wwe”时,会在常量池中新建一个常量。若存在,则直接返回该常量。

源码介绍如下:

/**

* Returns a canonical representation for the string object.

*

* A pool of strings, initially empty, is maintained privately by the

* class {@code String}.

*

* When the intern method is invoked, if the pool already contains a

* string equal to this {@code String} object as determined by

* the {@link #equals(Object)} method, then the string from the pool is

* returned. Otherwise, this {@code String} object is added to the

* pool and a reference to this {@code String} object is returned.

*

* It follows that for any two strings {@code s} and {@code t},

* {@code s.intern() == t.intern()} is {@code true}

* if and only if {@code s.equals(t)} is {@code true}.

*

* All literal strings and string-valued constant expressions are

* interned. String literals are defined in section 3.10.5 of the

* The Java™ Language Specification.

*

* @return a string that has the same contents as this string, but is

* guaranteed to be from a pool of unique strings.

*/

public native String intern();

一道思考题 new String("wwe").equals("11去去去") 创建了几个对象

这里创建了1或2 个对象。如果常量池不存在“11去去去”则需要创建一个对象。

3.true System.out.println(a1.equals(a2)); 以下是interger类型的equals函数,不同的复合类是不一样的

/**

* Compares this object to the specified object. The result is

* {@code true} if and only if the argument is not

* {@code null} and is an {@code Integer} object that

* contains the same {@code int} value as this object.

*

* @param obj the object to compare with.

* @return {@code true} if the objects are the same;

* {@code false} otherwise.

*/

public boolean equals(Object obj) {

if (obj instanceof Integer) {

return value == ((Integer)obj).intValue();

}

return false;

}

4.true。 System.out.println(a1 instanceof Integer);

用来在运行时指出对象是否是特定类的一个实例

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));i1=i2 truei1=i2+i3 truei1=i4 falsei4=i5 falsei4=i5+i6 true40=i5+i6 true

Integer i1=40;Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。Integer i1 = new Integer(40);这种情况下会创建新的对象。语句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);//falseString str1 = "str";String str2 = "ing";String str3 = "str" + "ing";String str4 = str1 + str2;System.out.println("string" == "str" + "ing");// trueSystem.out.println(str3 == str4);//falseString str5 = "string";System.out.println(str3 == str5);//true

"abcd"是在常量池中拿对象,new String("abcd")是直接在堆内存空间创建一个新的对象。只要使用new方法,便需要创建新的对象。连接表达式 +,只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入常量池中。对于字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,其属于在运行时创建的字符串,具有独立的内存地址,所以不引用自同一String对象。

关注头条号每天分享java知识,欢迎留言评论转发私信回复“555”赠送一些Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式资料

查看原文 >>
相关文章