• java中字符串常量,堆栈的区别和字符串函数intern(),String s=new String(“abc”)中abc在内存的分配


    转自:http://txy821.iteye.com/blog/760957

    java.lang.String的intern()方法 
    "abc".intern()方法的返回值还是字符串"abc",表面上看起来好像这个方法没什么用处。但实际上,它做了个小动作: 
    检查字符串池里是否存在"abc"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会把"abc"添加到字符串池中,然后再返回它的引用。

    我们做个测试:

    Java代码  收藏代码
    1. String str1 = "a";   
    2. String str2 = "bc";   
    3. String str3 = "a"+"bc";   
    4. String str4 = str1+str2;   
    5.      
    6. System.out.println(str3==str4);   
    7. str4 = (str1+str2).intern();   
    8. System.out.println(str3==str4);   

    输出的结果将会是: 
    false 
    true 
    JDK的api文档是这么解释的: 
    ======================================================================= 
    返回字符串对象的规范化表示形式。 
    一个初始时为空的字符串池,它由类 String 私有地维护。 
    当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。 
    它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。 
    所有字面值字符串和字符串赋值常量表达式都是内部的。字符串字面值在《Java Language Specification》的 §3.10.5 中已定义。 

    返回: 
    一个字符串,内容与此字符串相同,但它保证来自字符串池中。 
    =======================================================================

    字符串字面池指的是常量池.

    字符串对象的创建方式有两种

    如下:

    String s1 = new String("");   //第一种

    String s2 = "";               //第二种

    第一种始终不会入池的.

    第二种要看情况而定(等号右边如果是常量则入池,非常量则不入池)

    例:

    String s3 = "a" + "b"; //"a"是常量,"b"是常量,常量+常量=常量,所以会入池.

    String s4 = s1 + "b";   //s1是变量,"b"是常量,变量+常量!=常量,所以不会入池.

    一旦入池的话,就会先查找池中有无此对象.如果有此对象,则让对象引用指向此对象;如果无此对象,则先创建此对象,再让对象引用指向此对象.

    例:

    String s5 = "abc"; //先在池中查找有无"abc"对象,如果有,则让s5指向此对象;如果池中无"abc"对象,则在池中创建一个"abc"对象,然后让s5指向该对象.
    补充一下:

    看了字节码后,发现
    String str ="a"+"b";
    完全等同于
    String str="ab";
    ----------------------
    附加一个小实例:
    Java代码  收藏代码
    1. public class Mud {  
    2. public static String hello(String[] strs, String s2) {  
    3.         strs[0] = "<" + strs[0] + ">";  
    4.         s2.toUpperCase();  
    5. return s2;  
    6.     }  
    7. /** 
    8.      * @param args 
    9.      */  
    10. public static void main(String... args) {  
    11.         String a = new String("t");  
    12.         String[] b = new String[] { "t" };  
    13.         String c = a.intern();  
    14. if (a.equals(b[0])) {  
    15.             System.out.print("1");  
    16.         }  
    17. if (b[0] == c) {  
    18.             System.out.print("2");  
    19.         }  
    20. if (a == c) {  
    21.             System.out.print("3");  
    22.         }  
    23.         a = hello(b, c);  
    24.         System.out.print(a);  
    25.         System.out.print(b[0]);  
    26.         System.out.print(c);  
    27.     }  
    28. }  

     String s=new String(“abc”)中abc在内存的分配

      之前看到好几篇博客说这样创建对象时候是先在常量池中创建abc,然后在堆中创建对象s,然后s指向常量池中的abc。其中牛客上有一题如下:

     

     很多解释都也是这么说的,但是如果说是先在常量池中创建了“abc”在堆里只是引用,那为何下面代码返回的是false

             String s1=new String("abc");
    		String s2="abc";
    		System.out.println(s1==s2);
    

      按照上面解释,new对象也会在常量池中创建对象,那执行了后第二条的s2也会引用new出来的“abc”,这样一来应该相等才对啊。

    后来看到的解释说:应该是AC,即是堆和字符串常量池中,当你new String("abc")时,其实会先在字符串常量区生成一个abc的对象,然后new String()时会在堆中分配空间,然后此时会把字符串常量区中abc复制一个给堆中的String,故abc应该在堆中和字符串常量区。

    所以:初步认为new出来的对象会在常量池中生成“abc”,然后复制一份到堆中。即s1是指向堆中的”abc“,而s2是指向常量池中的abc。s1.intern()函数是指向s1在字符串常量区生成的“abc”

                    String s1=new String("abc");
    		String s2="abc";
    		String s3=s1.intern();
    		System.out.println(s1==s3);
    		System.out.println(s1==s2);
    		System.out.println(s3==s2);                    
    

      打印结果为:

    false
    false
    true

    正好验证上面的结论。

     栈与堆的区别转自:http://droidyue.com/blog/2014/12/07/differences-between-stack-and-heap-in-java/ 

    Java中的堆和栈的区别

    DEC 7TH, 2014

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先出(Last In First Out)的顺序的数据结构,这就是java.util.Stack。这种情况下,不免让很多人更加费解前面的问题。事实上,堆和栈都是内存中的一部分,有着不同的作用,而且一个程序需要在这片区域上分配内存。众所周知,所有的Java程序都运行在JVM虚拟机内部,我们这里介绍的自然是JVM(虚拟)内存中的堆和栈。

    区别

    java中堆和栈的区别自然是面试中的常见问题,下面几点就是其具体的区别

    各司其职

    最主要的区别就是栈内存用来存储局部变量和方法调用。
    而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

    独有还是共享

    栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
    而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

    异常错误

    如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
    而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。

    空间大小

    栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。
    你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。

    这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。

  • 相关阅读:
    Springboot整合MongoDB的Docker开发,其它应用也类似
    Docker可视化工具Portainer
    Mac上使用Docker Desktop启动Kubernetes,踩坑后终于搞掂
    Docker入门——理解Docker的核心概念
    删库吧,Bug浪——我们在同一家摸鱼的公司
    一键下载网页所有图片,把美丽存下来
    序列推荐(transformer)
    [论文笔记] An introduction to ROC analysis
    【推荐算法工程师技术栈系列】分布式&数据库--tensorflow
    [论文翻译]Practical Diversified Recommendations on YouTube with Determinantal Point Processes
  • 原文地址:https://www.cnblogs.com/bokeofzp/p/4799274.html
Copyright © 2020-2023  润新知