1. 简单认识String字符串
通过源码我们可以看出String字符串被final进行修饰,那么也就说明了String字符串不能被继承和重写。
String的特点:不能继承和重写
关于字符串与内存关系:
String str1 = new String("abc"); (1)
String str2 = "abc"; (2)
String str3 = "a" + "bc"; (3)
String str4 = "a" + new String("bc"); (4)
分析:
从1式可以看出:会产生两个内存空间,在堆内存申请一份,然后在常量池里面申请一份,然后栈内存变量str1指向堆内存。
从2式可以看出:str2会在常量池里面找,如果有的话,就不申请内存空间,如果没有的话,需要在常量池申请内存。
从3式可以看出 : jvm对用“+”进行连接的字符串进行了优化,它的思想和str2内容差不多。
从4式可以看出:它进行new操作,然后进行拼接,这样的话申请的内存地址空间是不同的。
常量池:就是在编译器被确定,保存在编译的。class文件中,主要有类,方法,接口的常量组成,以及字符串常量等。常量池还具备动态性,运行期间可以将新的常量放入池中,例如调用String的intern()方法。
从上述我们可以提出问题堆内存的对象和常量池里面的对象有什么关系?
根据上述1式可以看出,应该是把堆内存的内容克隆一份去常量池中。
String常用方法的介绍:
replace方法:
1.把原来字符串变为字符数组
2.判断要替换的字符和新字符是否相等,如果相等就返回原来的内容,不相等,则进行替换操作
3.找到要替换字符的位置
4.然后产生一个新数组,把替换字符位置之前的字母装到这个新数组里面
5.在遍历替换字符位置之后的内容,如果value[i] 和oldchar相等的话,就变为newChar
6.最后把这个字符数组变为字符串
分析:这是jdk1.7源码的内容(为什么在找到替换字符位置时,不直接从这个位置开始进行遍历,在原来数组上进行操作,而要产生一个新数组把原来的内容装起来)
indexof 方法:
indexof参数说明:
Soure | 原始字符串 |
sourceOffset | 原始字符串偏移大小 |
sourceCount | 原始字符串个数 |
target | 目标字符串 |
targetOffset | 目标字符串偏移大小 |
fromIndex | 起始下标 |
1. 用起始下标(fromIndex)和原始字符串大小进行进行比较
2. 取出目标的第一个元素,这个取出时根据targetOffset的下标来取得
3. 用target[targetOffset]的值,在原始字符串找与之对应的值。
4. 如果在原始字符串里面找过一遍没有的话,就返回-1
5. 如果找到的话,就需要记住这个下标的位置 j = i+1
6. 然后用这下标j取出source[j]和taget[targetOffet+1]进行比较,如果符合条件就返回i下标
分析:假设让我们去实现首先取出目标字符串第一个元素,然后用这个元素和原始字符串的每一个进行比较,如果没有找到的话,就返回-1,找到的话,记录目标元素在原始字符串位置,然后从这个元素开始进行逐一比较。,如果目标元素都和原始元素比较结束,并且都符合条件,返回原来保存的下标i。(其实和jdk源码思想大致相同,现在纠结的是,为啥源码里面有这么多参数)
trim方法:
1. 得到开始下标st
2.得到为节点下标leng
3. 得到value[st] 不为空字符串的下标
4. 得到value[length]不为空字符串下标
5.最后用str.substring()进行截取。
分析:假设让我们去做,我们可以提供出几种方式呢
简单说一下String,StringBuffer和StringBuilder之间的区别?
String是字符串常量,StringBuffer和StringBuilder是字符串变量
每一次对字符串常量进行操作时,都会产生新的对象,如果频繁对字符创进行改变,这样会产生对系统的性能的影响。
但是有一个特殊操作,例如 String str = “a” + “b”;有人会说这样并没有频繁产生对象,这是因为常量池对“+”进行特殊处理(如何进行处理,现在还在研究中),但是这样的就比较耗性能,String str1 = “a” String str2 = ’‘b“ String str3 = str1 +str2;
StringBuffer 保证线程安全,那么它使用与多线程环境中
StringBuilder适应单线程环境中字符串缓冲区(这里面的字符串缓冲区如何设计还在研究中)