美文网首页
常量池和基本类型、引用类型

常量池和基本类型、引用类型

作者: wangsg先生 | 来源:发表于2018-03-26 18:11 被阅读0次

    一、常量池

            常量池:一块在Class文件结构中,用于存放常量的数据区域。一旦该Class被加载,该常量池将会load进入方法区中的运行时常量池。

            运行时常量池:并不常态。它具有动态的属性,除了预置入Class文件的常量外,它还能将运行期产生的常量存储其中。

            常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从常量池中取一个出来(如果池中没有则创建一个),则在需要重复创建相等变量时节省了很多时间。

    二、基本类型

            对于int num=0的存储,都将是变量num和数值0开辟一个固定内存空间,所以才会有声明时,最大值和最小值的限制(很尬,这居然是今天才理解到)。至于存储的区域,需要分以下种情况:

            1.1、当在方法中赋值时,存储在该方法的栈帧中;   

            1.2、当i为实例的成员变量时,存储在堆中;    

            1.3、当num为实例的静态成员,存储在方法区中;    

            1.4、当num为final常量,存储在运行时常量池中。

    三、引用类型

            Object obj = new Object(),将是变量obj和对象Object的地址引用开辟一个固定的内存空间,存储在分情况的内存区域中。

    总结:基本类型变量=数值,引用类型变量=对象地址

    四、由以上总结,我们能解决一下几个面试经常遇到的问题。

            3.1、java传参什么时候值传递、什么时候引用传递呢?

                例子如:mr.method(int myNum, Object myObj);    void method(int num, Object obj){}

                对于变量myNum,因为基本类型的它存储的是数值,所以传递的是值;对于变量myObj,因为引用类型的它存储的是地址引用,所以传递的是引用。

                至于为什么要区分这个,那是因为,如果只是简单的值传递,那么方法体内任何对参数num的操作,均不会影响到myNum。但如果是引用从传递,那么变量obj将获取到的myObj的引用地址,意味着变量myObj将Object实例对象的控制权交付给变量obj。所以,变量obj任何的操作,都将影响到暂时失去对Object对象控制权的变量myObj。

            3.2、双等号==的含义

                基本数据类型之间应用双等号,比较的是他们的数值。

                引用类型之间应用双等号,比较的是他们在内存中的存放地址。


    五、基本类型和常量池技术

        java中基本类型的包装类的大部分都实现了常量池技术,

           5.1、 其中Byte,Short,Integer,Long,Character,Boolean,这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,只有超出此范围才会去创建新的对象。

            5.2、两种浮点数类型的包装类Float,Double并没有实现常量池技术。

            5.3、Integer比较更丰富的一个例子

            对结果解释:语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。(Java自动拆箱与装箱传送门)


    六、String类和常量池技术

            6.1、字符串何时出现在常量池中

                主要使用方法有两种:

                first:直接使用双引号声明出来的String对象会直接存储在常量池中。

                second:如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中

            6.1、连接表达式 +

            (1)只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。

            (2)对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。

            6.2、String str = new String("xyz");        **创建了几个对象? **

               采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用str,这样,str就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给str引用,这样,str指向了堆中创建的这个"xyz"字符串对象。所以得分情况,才知道要创建几次。

    6.3、java.lang.String.intern()

            对于结果是不是很惊讶。intern()只是执行顺序变了一下,结果就不一样啦。欲知所以然,且容先生步步分析。

            jdk1.7中定义,intern()方法只是将第一次出现的字符串实例的地址引用,记录在常量池中。常量池会建立其索引,索引key代表“str01”,value代表“str1指向的对象的地址引用”。

            于是开始分析:步骤01:根据6.1中的总结,还会在常量池中创建三个String对象,分别是对象“str”、对象“01”。且建立其引用的索引表。同时还会在堆中创建对象“str”、对象“01”和对象“str01”,并将对象“str01”地址引用赋值给变量str1;

             步骤02:变量str2获取“str01”在常量池中存储的value,注意此时的引用指向常量池中”str01“对象;

            步骤03:根据jdk1.7,intern()方法的定义。字符串“str01”已经在常量池中存在,所以并不会操作。如需返回,返回值是常量池中索引表的地址引用;

            步骤04:根据3.2双等号的结论。变量str2和str1,比较的是引用。此时,str1指向堆中对象“str01”,而str2指向常量池中对象“str01”.故为false;

            步骤06:因为变量str3指向的堆对象“str02”还未在常量池中出现过。所以,常量池会建立字符串“str02”和堆对象“str02”的引用的索引;

            步骤07:变量str4获取”str02“在常量池中存储的value,注意此时的引用指向堆中的”str02“对象.

    【温馨提示,根据步骤,画张对象创建过程图,效果杠杠的好哟哟哟】



            我是先生,找寻着那位迷路的Miss。最后,愿各位javaer,合上电脑的刹那,有着侠客收剑入鞘的骄傲!

    相关文章

      网友评论

          本文标题:常量池和基本类型、引用类型

          本文链接:https://www.haomeiwen.com/subject/jhplcftx.html