String 字符串
String类 是被 final关键字 声明的,因此它不可被继承。 String 字符串是引用类型,底层用 char 数组实现的。String 字符串的特点:
1.字符串不可变,它们的值在创建后不能被更改。
2.虽然String 的值是不可变的,但是可以被共享 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )。
String 字符串解析:
1.通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,即使内容相同,但地址值不同。
2.以“”方式给出的字符串,JVM会将其存放在 字符串常量池 中维护。
3.且若多个“”方式给出的字符序列(顺序及大小写)相同,JVM只会建立一个String 对象。
为什么 String 字符串 不适用于 大量 字符串 拼接 操作?
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,对内存空间的极大浪费。
String 字符串的 + 操作(字符串 拼接 操作)其本质是创建了 StringBuilder 对象进行 append() 操作,然后将拼接后的 StringBuilder 对象用 toString() 方法处理成 String 对象。
在 Java 中无论使用何种方式进行字符串连接,实际上都使用的是 StringBuilder。
我们知道,在Java中有两种创建字符串对象的方式:
- 采用字面值的方式赋值。
- 采用new关键字 新建一个字符串对象。
String str = new String(
"abc")创建了几个对象?
创建2个对象。
第一个对象是”abc”字符串 存储 在字符串常量池中;
第二个对象在JAVA Heap堆 中 new 的 String 对象
String str = "a" + "b" + "c" 创建了几个对象?
创建1个对象。
因为 赋值符号右边的"a"、"b"、"c"都是常量
String str = new String("a") + new String("b")创建了几个对象?
创建6个对象。
对象1:new StringBuilder()
对象2:new String("a")
对象3:常量池的 a
对象4:new String("b")
对象5:常量池的 b
对象6:toString中会创建一个 new String("ab")
String str= "abc";
final String finalStr = "abc";//final修饰的是常量
String str1 = "abc01";
String str2 = "abc" + "01";
String str3 = str + "01";
String str4 = finalStr + "01";
String str5 = new String("abc01").intern();
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
System.out.println(str1 == str4); // true //final修饰的是常量
System.out.println(str1 == str5); // true
String、StringBuffer 和 StringBuilder 的区别
1)、可变不可变
String:字符串常量,在修改时不会改变自身;若修改,等于重新生成新的字符串对象。StringBuffer:字符串变量,在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对象;使用场景:对字符串经常改变情况下,主要方法:append(),insert()等。2)、线程是否安全
String:对象定义后不可变,线程安全。StringBuffer:是线程安全的(对调用方法加入synchronized同步锁),执行效率较慢,适用于多线程下操作字符串缓冲区大量数据。StringBuilder:是线程不安全的,StringBuilder 效率高于 StringBuffer,适用于单线程下操作字符串缓冲区大量数据。3)、共同点
StringBuilder 与 StringBuffer 有公共父类 AbstractStringBuilder(抽象类)。StringBuilder、StringBuffer 的方法都会调用 AbstractStringBuilder 中的公共方法,只是StringBuffer 会在方法上加 synchronized 关键字,进行同步。最后,如果程序不是多线程的,那么使用 StringBuilder 效率高于 StringBuffer。
String | 不可变字符串 | 线程安全 | 每次new 都是生成新的String对象 | 不适用于 大量 字符串 拼接 操作,影响内存性能 |
StringBuffer | 可变字符串 | 线程安全 | StringBuffer 执行效率慢 | 适用于多线程下操作字符串缓冲区大量数据 |
StringBuilder | 可变字符串 | 线程不安全 | StringBuilder 执行效率高 | 适用于单线程下操作字符串缓冲区大量数据 |
常量
用final修饰的成员变量表示常量,值一旦给定就无法改变!
final修饰的变量分别表示三种类型的常量:静态变量、实例变量 和 局部变量。
Java中的常量池,实际上分为两种形态:静态常量池 和 运行时常量池。
1)静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
2)运行时常量池,则是JVM虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
常量池(Constant Pool)
常量池,也叫 Class 常量池(常量池==Class常量池,Class Constant Pool)。Java文件被编译成 Class文件,Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池,每个class文件都有一个class常量池。常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种 字面量 (Literal)和 符号引用(SymbolicReferences)。
字面量 包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
符号引用 包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。
运行时常量池(Runtime Constant Pool)
运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会 将Class文件常量池里的内容转移到运行时常量池里(运行时常量池也是每个类都有一个)。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中
字符串常量池(String Constant Pool)
字符串常量池又称为:字符串池,全局字符串池,英文也叫String Constant Pool。
字符串常量池是全局的,JVM中独此一份,因此也称为全局字符串常量池。
String的String Pool是一个固定大小的
Hashtable
,默认值大小长度是1009。在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要讨论的核心:字符串常量池。字符串常量池由String类私有的维护
class常量池 是在编译的时候每个class都有的. 在编译阶段,存放的是常量的 符号引用 。 [在class文件中]
字符串常量池 在每个VM中只有一份,存放的是字符串常量的 引用值 。 [在堆中]
运行时常量池 是在类加载完成之后,将每个class常量池 中的符号引用值转存到 运行时常量池 中,也就是说,每个class都有一个 运行时常量池 ,类在 解析阶段 ,将 符号引用 替换成 直接引用 ,与 字符串常量池 中的引用值保持一致。[在方法区]