深入理解String类(重点)

一、想要理解string类,先看源码:

1 public final class String
2     implements java.io.Serializable, Comparable<String>, CharSequence {
3     /** The value is used for character storage. */
4     private final char value[];
5
6     /** Cache the hash code for the string */
7     private int hash; // Default to 0
8     ...
9 }

从上面可以看出

  • String类被final关键字修饰,意味着String类不能被继承,并且它的成员方法都默认为final方法;字符串一旦创建就不能再修改。
  • String类实现了Serializable、CharSequence、 Comparable接口。
  • String实例的值是通过字符数组实现字符串存储的。

二、String 方法

下面是 String 类支持的方法,更多详细,参看 Java String API 文档:

三、字符串常量池

在Java的内存分配中,总共3种常量池,分别是Class常量池、运行时常量池、字符串常量池。

字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性,常量池中一定不存在两个相同的字符串。

 1 public class String1 {
 2     static String a = "AB";
 3     static String b = "AB";
 4     static String c = new String("AB");
 5     static String d = "A"+"B";
 6     static String e = "A";
 7     static String f = "B";
 8     static String g = e+f;
 9     static String h = "A"+f;
10     public static void main(String[] args) {
11         System.out.println(a==b);   //true
12         System.out.println(a==c);   //false
13         System.out.println(a==d);   //true
14         System.out.println(a==g);   //false
15         System.out.println(a.equals(g));    //true
16         System.out.println(a.equals(h));    //true
17         System.out.println(a==h);   //false
18     }
19 }

内存分析如图所示:

四、关于字符串拼接符“+”

把"java"、"language"和"specification"这三个字面量进行"+"操作得到一个"javalanguagespecification" 常量,并且直接将这个常量放入字符串池中,这样做实际上是一种优化,将3个字面量合成一个,避免了创建多余的字符串对象。而字符串引用的"+"运算是在Java运行期间执行的,即str + str2 + str3在程序执行期间才会进行计算,它会在堆内存中重新创建一个拼接后的字符串对象。总结来说就是:字符串常量"+"拼接是在编译期间进行的,拼接后的字符串存放在字符串池中;而字符串引用的"+"拼接运算实在运行时进行的,新创建的字符串存放在堆中。

对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+"love"+"java"; 的字符串相加,在编译期间便被优化成了"Ilovejava"。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。

五、、关于String.intern()

intern方法使用:一个初始为空的字符串池,它由类String独自维护。当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。

它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

String.intern();
再补充介绍一点:存在于.class文件中的常量池,在运行期间被jvm装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,java查找常量池中是否有相同unicode的字符串常量,如果有,则返回其引用,如果没有,则在常量池中增加一个unicode等于str的字符串并返回它的引用。

例1:

 1 /**
 2  * 关于String.intern()
 3  */
 4 public void test11(){
 5     String s0 = "kvill";
 6     String s1 = new String("kvill");
 7     String s2 = new String("kvill");
 8     System.out.println("===========test11============");
 9     System.out.println( s0 == s1 ); //false
10     System.out.println( "**********" );
11     s1.intern(); //虽然执行了s1.intern(),但它的返回值没有赋给s1
12     s2 = s2.intern(); //把常量池中"kvill"的引用赋给s2
13     System.out.println( s0 == s1); //flase
14     System.out.println( s0 == s1.intern() ); //true//说明s1.intern()返回的是常量池中"kvill"的引用
15     System.out.println( s0 == s2 ); //true
16 }

结果:false、false、true、true。

例2:

 1 public class String1 {
 2
 3     public static void main(String[] args) {
 4         /**
 5          *      String a = "AB";
 6          *      String b = "AB";
 7          *      String c = new String("AB");
 8          *      String d = "A"+"B";
 9          *      String e = "A";
10          *      String f = "B";
11          *      String g = e+f;
12          *      String h = "A"+f;
13          *         System.out.println(a==b);   //true
14          *         System.out.println(a==c);   //false
15          *         System.out.println(a==d);   //true
16          *         System.out.println(a==g);   //false
17          *         System.out.println(a.equals(g));    //true
18          *         System.out.println(a.equals(h));    //true
19          *         System.out.println(a==h);   //false
20          */
21             String s1 = "AB";
22             String s2 = new String("AB");
23             String s3 = "A";
24             String s4 = "B";
25             String s5 = "A" + "B";
26             String s6 = s3 + s4;
27             System.out.println(s1 == s2);       //false
28             System.out.println(s1 == s5);       //true
29             System.out.println(s1 == s6);       //false
30             System.out.println(s1 == s6.intern());      //true
31             System.out.println(s2 == s2.intern());      //false  我的理解:左边s2=new String("AB");
32                                                         // 右边s2.intern()和String s2="AB"是一个意思,
33                                                         //所以两边不相等
34         }
35 }

内存分析:

参考大神:https://blog.csdn.net/ifwinds/article/details/80849184

https://www.cnblogs.com/xiaoxi/p/6036701.html

里面更加详细,想理解更深入,可以点击链接!!

原文地址:https://www.cnblogs.com/qiaoxin11/p/12551441.html

时间: 2024-08-30 07:19:02

深入理解String类(重点)的相关文章

jdk源码理解-String类

String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比较简单,由字符串中的字符的ASCII值计算出来. /** * Returns a hash code for this string. The hash code for a * <code>String</code> object is computed as * <block

深入理解String类

1.String str = "eee" 和String str = new String("eee")的区别 先看一小段代码, 1 public static void main(String[] args) { 2 String str1 = "eee"; 3 String str2 = "eee"; 4 String str3 = new String("eee"); 5 System.out.pri

从C# String类理解Unicode(UTF8/UTF16)

上一篇博客:从字节理解Unicode(UTF8/UTF16).这次我将从C# code 中再一次阐述上篇博客的内容. C# 代码看UTF8 代码如下: string test = "UTF-8你"; //把字符转换为 byte[] byte[] bytearray_UTF8 = Encoding.UTF8.GetBytes(test); // byte[] to 16 进制的字符形式 String hexString = BitConverter.ToString(bytearray_

有关C++ std::string 类的类型转换 其他语言永远无法理解的伤

最近做了个项目,C++的MFC窗口程序,一个基于dialog的学生-图书管理系统,有一些感触,最后会放上一些项目截图和部分代码提供大家参考.如果有什么好方法和建议欢迎指导. 强类型,为什么这么伤 我知道强类型是很必要的,但是最近使用的都是一些弱类型的语言,到回来使用C++的时候还真是很不习惯.std::string在学的时候就知道了,好用但还是跟c标准char[]有很大区别的,MFC编程中又加入了没有学过的Cstring和LPSTR.LPWSTR等,下面我就来分享一下一些有关类型转换的感受. 什

String类的深入理解(未完待续)

String不是基本数据类型,String和8种包装类型是不可变类.String和8种基本数据类型采用值传递. 0.不可变类的设计原则 public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];//数组是引用传递 /*

《Java架构筑基》从Java基础讲起——String类深入理解

一. String问题答疑 String字符串是如何设计与实现考量的? String字符串缓存 intern()方法,由永久代移到堆中. String 的演化,Java 9 中底层把 char 数组换成了 byte 数组,占用更少的空间 二. String的创建机理 由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池.其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对

String Buffer和String Builder(String类深入理解)

String在Java里面JDK1.8后它属于一个特殊的类,在创建一个String基本对象的时候,String会向“ 字符串常量池(String constant pool)” 进行检索是否有该数据(字符串)存在,如果存在则向该数据进行实例引用,返回到创建的String对象.所以当创建两个不同名字,相同字符串的常量时,不可能会有两个不同的存储内存. String常量,在JDK1.8后便可以任意修改,不会创建新的内存地址对内存应用的浪费. (常量与常量比较) String de="你好婷婷&quo

String类replaceAll方法正则替换深入分析

作者网址: https://my.oschina.net/shipley/blog/98973 背景:      前几天有人发了一个关于下面问题的贴,对这个有点好奇,故花时间做了点研究.        对单个反斜杠字符串替换成双斜杠的Java实现如下:    String s = "\\";    方法一:String sr1 = s.replaceAll("\\\\", "\\\\\\\\");    方法二:String sr1 = s.re

深入分析Java的String类的方法与特点

字符串是任何编程语言都必须支持的变量类型,有些编程语言是直接提供了原生的变量类型,有些编程语言则使用语法特性以 SDK 的形式提供支持.在Java编程平台中,对字符串的支持使用了后者的形式,就是通过在 JDK中提供一个名为String的类,对应字符串这个变量类型. 源码分析 既然JDK中的String类对应了字符串变量类型,为了熟练地掌握Java中字符串相关的技能,我们必须深入地分析和研究一下这个类.编码界有一句名言叫做 "源码面前,了无秘密",因此,我们第一步就是来看看String类