Java的String解密

字符串运行时常量池的所在地

JDK1.6之前,字符串常量池还未与其它常量池分离,都位于永久代中(方法区的实现方式),JDK1.7虽然还未废除永久代,但此时字符串常量池和静态变量已经离开了常量池,去了堆中。JDK1.8已经废除常量池,取而代之的是元空间(元空间不再位于虚拟机中,而是处于本地内存中),其它常量池和类信息都去了元空间,而字符串常量、静态变量、Class对象存在堆中。

String类型的各种初始化方式的不同之处

内容

方式一:String a = “aaa” ;
方式二:String b = new String(“aaa”);
方式三: String d3=new String (“aa”); String d4=“a”+d3;
方式四: String d = “aa” + “a”;

前两种方式都能创建字符串对象,但方式一要比方式二更优。因为当常量池中已经有了"aaa”实例,方式一不会再使用内存,而方式二还是会在堆中开辟一个新的内存来创建一个新对象,增加了内存消耗。方式三字符串的+操作其本质是创建了StringBuilder对象进行append操作,然后将拼接后的StringBuilder对象用toString方法处理成String对象,toString方法处理过程相当于new了一个新的对象,但无论常量池中是否有"aaa"字面量,都不会将该对象的内容加到常量池中。在常量池中没有"aaa"字面量时,方式四会直接在常量池创建"aaa"的实例。若已有,则返回该字面量的引用。

1.当常量池中没有"aaa"的实例
方式一会在常量池中创建一个“aaa”的实例,而方式二会new一个对象存放在堆内存中,并且还会在常量池中创建一个"aaa"的实例。方式一创建一个实例,方式二创建了两个实例。方式三会在堆中创建一个"aaa"的对象,但不会在常量池中创建实例。方式四只在常量池中创建一个"aaa"的实例。

2.常量池中已经有”aaa”
通过方式一创建对象,程序运行时会在常量池中查找”aaa”字符串,将找到的”aaa”字符串的地址赋给a。通过方式二创建对象,无论常量池中有没有”aaa”字符串,程序都会在堆内存中开辟一片新空间存放新对象。方式三会在堆中创建一个"aaa"的对象,不会在常量池中创建该字面量实例。方式四会得到"aaa"字面量的引用,不会重新创建实例。

示例

 String   a="11";                //只在常量池中产生字面量
 String   a1=new String("11");   //这个过程会在堆中产生一个对象,因为常量池中已有"11"实例,所以不会再在常量池中生成"11"实例
 String   a2="11";               //与a一样,都指向常量池中"11"的实例
 System.out.println(a==a1);      //不相等,因为a1指向堆,a指向堆中的常量池
 System.out.println(a==a2);      //相等,都指向常量池中"11"的字面量

String拼接的示例

 String d = "44" + "44";//这种方式直接在常量池创建"4444"的示例,并返回对字面量的引用
 String d1 = "4444";   //因为常量池已有"4444"的字面量,直接返回对该字面量的引用
 String d2 = new String("4444"); //堆中创建对象,池中不创建实例
 String d3=new String ("44"); 
 String d4="44"+d3;//区别与d,该方式在堆中创建一个新的对象,不管常量池中是否有"4444"的实例,都不会在常量池中创建实例
 System.out.println(d == d1);//true,都指向常量池
 System.out.println(d == d2);//false 一个指向常量池,一个指向堆
 System.out.println(d == d4);//false 一个指向常量池,一个指向堆
 System.out.println(d2== d4);//false 指向堆中不同的对象

String类型对象的intern()方法详解

1.这个方法是常量池动态性的重要体现,在运行期间将新的变量放入常量池中。当字符串对象执行intern()方法之后,若常量池中已有该字符串的实例,则返回常量池中常量的引用,如无,则将堆中对象的引用存到常量池中,并返回该引用。(在jdk1.7之前的做法是将堆中的数据复制一份到常量池中,并返回常量池字面量的引用,1.7以及之后为了节约内存,改为将堆中该对象的引用存到常量池中,返回该引用)

下面是常量池没有该字符串常量的示例

String s = new String("11") + new String("11");  
//上面这个代码只生成了“11”这个字面量,而没有生成"1111"的字面量,在堆中生成了内容为"1111"的对象
s.intern();  
//s.intern()执行过程,会去常量池是否有"1111"这个字面量,若有,则返回常量池的地址,没有,则会把堆中“1111”对象地址存到常量池中,并返回这个对象地址,这里是没有,所以返回对象地址。
String s1 = "1111";
System.out.println(s == s1);
//s1定义的时候发现常量池中有了"1111"的对象的引用地址,所以没有返回"1111"这个字面量,而是拿到了这个引用地址。所以这里结果是true

下面是常量池有该字符串常量的示例

 //印证,我先创建字面量
 String c3="3333";
 String c= new String("33") + new String("33");  //只生成了“11”这个字面量
 c.intern();    //因为已经有了字面量,所以执行intern函数返回的是对字面量的引用
 String c1 = "3333";
 String c2=new String("3333");
 System.out.println(c== c1); 
//c指向堆中内容为"3333"的对象,c1指向常量池,所以false
 System.out.println(c3==c1);
  //因为c3初始化时,常量池已经有了"3333"的实例,所以c1其实和c3都指向常量池中该实例,所以为true

字符串的反转方法

  1. StringBuilder类型的reverse();

  2. 通过Stirng中的charAt方法获取每一个字符然后通过字符拼接

  3. 通过toCharArray方法将字符串转换成数组再反转

  4. 递归

String与其它类型的转换的通用方法

String转其它类型----调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型。

  //String类型转成其它类型
        String str="222";
        Integer inte=Integer.parseInt(str);
        Integer inte1=Integer.valueOf(str);
        System.out.println(inte instanceof  Integer); //true
        System.out.println(inte1 instanceof  Integer);//true

其它类型转String----一种方法是将基本数据类型与空字符串("")连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf()方法返回相应字符串。还有一种是使用toString方法

  //其它类型转换成String类型
        Integer in=123;
        String str1=in.toString();
        String str2=String.valueOf(in);
        String str3=""+in;
        System.out.println(str1 instanceof String); //true
        System.out.println(str2 instanceof String); //true
        System.out.println(str3 instanceof String); //true
    
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值