Java基础系列3: String类型的分析
本文是作者的读书笔记和心得整理,部分内容来源于网络,如有侵权,请联系作者。
初始化
String类有11种构造方法,提供不同的参数来初始化.
String类的对象是不可变的,一旦创建就不可改变
这里要理解以下,比如:
str1='a'
str1='b'
这是允许的,但是字符串’a’并没有被改变,只不过是str1这个指针现在指向了’b’这个对象.
如果需要修改可以使用StringBuffer或者StringBuilder类
5大常用方法:length(),substring(),charAt(),indexOf(),lastIndexOf()
==运算符和.equals之间的区别
==运算符判断的是地址,而不同的初始化函数出来的地址是不同的.
而equals函数判断的是内容. 如以下代码所示:
package com.mpp.string; public class StringDemo5 { public static void main(String[] args) {
String str1 = "mpp";
String str2 = "mpp";
String str3 = new String("mpp");
System.out.println(str1.equals(str2)); //true 内容相同
System.out.println(str1.equals(str3)); //true 内容相同
System.out.println(str1==str2); //true 地址相同
System.out.println(str1==str3); //false 地址不同
}
}
字符串拼接
Java中的拼接是使用转换成StringBuffer对象再转换回来这种方式来实现的.所以最好不要使用拼接,会有大量的中间变量
StringBuffer这个类是线程安全的,所有的修改数据的方法都有synchronized关键字,但是效率比较低
StringBuilder是线程不安全的,所以他比较快.
注意最好在StringBuffer声明的时候就限定好capacity,避免扩容,开销比较大.
delete的本质是把其余字符重新拷贝到字符数组.
String和JVM
这里直接引用别人的定义来解释这4个名次:
Java栈(线程私有数据区):
每个Java虚拟机线程都有自己的Java虚拟机栈,Java虚拟机栈用来存放栈帧,每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
Java堆(线程共享数据区):
在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配。
方法区(线程共享数据区):
方法区在虚拟机启动的时候被创建,它存储了每一个类的结构信息,例如运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容、还包括在类、实例、接口初始化时用到的特殊方法。在JDK8之前永久代是方法区的一种实现,而JDK8元空间替代了永久代,永久代被移除,也可以理解为元空间是方法区的一种实现。
常量池(线程共享数据区):
常量池常被分为两大类:静态常量池和运行时常量池。
静态常量池也就是Class文件中的常量池,存在于Class文件中。
运行时常量池(Runtime Constant Pool)是方法区的一部分,存放一些运行时常量数据。
字符串常量池:
字符串常量池存在运行时常量池之中(在JDK7之前存在运行时常量池之中,在JDK7已经将其转移到堆中)。
字符串常量池的存在使JVM提高了性能和减少了内存开销。
使用字符串常量池,每当我们使用字面量(String s=”1”;)创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就将此字符串对象的地址赋值给引用s(引用s在Java栈中)。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中,并将此字符串对象的地址赋值给引用s(引用s在Java栈中)。
使用字符串常量池,每当我们使用关键字new(String s=new String(”1”);)创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么不再在字符串常量池创建该字符串对象,而直接堆中复制该对象的副本,然后将堆中对象的地址赋值给引用s,如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中,然后在堆中复制该对象的副本,然后将堆中对象的地址赋值给引用s。