zoukankan      html  css  js  c++  java
  • java字符串String的intern()方法,举例说明

    参考

    1.  new String都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。
    2. 通过字面量赋值创建字符串(如:String str=”twm”)时,会先在常量池中查找是否存在相同的字符串,若存在,则将栈中的引用直接指向该字符串;若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
    3. 常量字符串的“+”操作,编译阶段直接会合成为一个字符串。如string str=”JA”+”VA”,在编译阶段会直接合并成语句String str=”JAVA”,于是会去常量池中查找是否存在”JAVA”,从而进行创建或引用。
    4. 对于final字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
      final String str1=”ja”;
      final String str2=”va”;
      String str3=str1+str2;
      在编译时,直接替换成了String str3=”ja”+”va”,根据第三条规则,再次替换成String str3=”JAVA”
    5. 常量字符串和变量拼接时(如:String str3=baseStr + “01”;)会调用stringBuilder.append()在堆上创建新的对象。
    6. JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。

    例子:

    package util;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.math.BigInteger;
    import java.util.Arrays;
    public class Main20210907{
    	public static void main(String[] args) {
    
    //		一次
    		fun1();
    		System.out.println();
    		fun2();		
    		System.out.println();
    		fun3();
    		System.out.println();
    		fun4(1);
    		System.out.println();
    		fun5();
    	}
    	public static void fun1() {
    		System.out.println("fun1");
    		String s1 = new String("str"); //等价于两句String s0="str";String s1 = new String(s0);第一句作用:常量池中检查,没有,把常量对象"str"放进常量池中;第二句作用:new String必然会在jvm堆中创建了一个实例
    		s1.intern();//从字符串常量池中查询当前字符串是否存在,存在不作处理
    		String s2 = "str";//在常量池中已有常量"str",s2拿过来
    		System.out.println(s1==s2);//所以为false,因为s1为new的新的实例,s2取得常量池中的常量
    		System.out.println(s1.intern()==s2);//true
    	}
    	
    	public static void fun2() {
    		System.out.println("fun2");
    		String s1 = new String("a")+new String("bc");//会把常量"a"和"bc"放进常量池,"abc"不会放进常量池
    		s1.intern();//检查常量池是否有字符串"abc",常量池不存在"abc",所以(jdk1.6将"abc"复制到常量池,jdk1.7将"abc"的引用放入常量池)
    		/**
    		 * JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,
    		 * 区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
    		 * 简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
    		 */
    		String s2 = "abc";//检查常量池有字符串"abc",返回它的引用
    		System.out.println(s1==s2); //true
    		System.out.println(s1.intern()==s2);//true
    	}
    	
    	public static void fun3() {
    		System.out.println("fun3");
    		String s0="def"; //常量池加入"def"
    		String s1 = new String("d")+new String("ef"); //常量池加入"d"和"ef"
    		s1.intern();//常量池存在"def"(s0),所以不做操作(导致s2与s1不等)
    		String s2 = "def";//常量池存在s0="def"
    		System.out.println(s1==s2); //false
    	}
    	public static void fun4(int flag) {
    		System.out.println("fun4");
    		String h="h", ij="ij";//"h"和"ij"都加入常量池
    		String s1 = h+ij;//会调用stringBuilder.append()在堆上创建新的对象”hij“。
    //		情况一
    		if (flag==1) {
    			String s2 = "hij";//检查常量池 不存在,于是加入“hij”
    			System.out.println(s1==s2); //false
    		}else {
    			s1.intern();//检查常量池不存在"hij",所以(jdk1.6将"hij"复制到常量池,jdk1.7将"hij"的引用放入常量池)
    			String s2 = "hij";//检查常量池,存在“hij”
    			System.out.println(s1==s2); //true
    		}
    
    	}
    	
    	public static void fun5() {
    		System.out.println("fun5");
    		final String k="k", lm="lm";//"k"和"lm"都加入常量池(final修饰)
    		String s1 = k+lm;//直接替换成了String s1=”k”+”lm”,再根据常量字符串的“+”操作,编译阶段直接会合成为一个字符串。所以再次替换为String s1="klm","klm"也纳入常量池;
    		String s2 = "klm";//检查常量池,存在“klm”
    		System.out.println(s1==s2); //true
    	}
    }
    

      

  • 相关阅读:
    【Java123】JDBC数据库连接池建立
    【招聘123】Some good open positions
    [Java123]Gradle
    4_3:流程控制:循环练习
    4_3:流程控制:while + do while + continue + break
    4_2:流程控制:[ for循环 ] + 断点调试
    4_1:流程控制:分支结构:[ if else ] + [ 三元表达式 ] + [ switch case ]
    3:运算符 + 运算符优先级 [ 逻辑短路 ]
    2_3:变量:[ 类型之间转换 ]
    2_2:变量:[ 五种简单数据类型 ]
  • 原文地址:https://www.cnblogs.com/sunupo/p/15249566.html
Copyright © 2011-2022 走看看