博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
读书笔记-String
阅读量:5922 次
发布时间:2019-06-19

本文共 3216 字,大约阅读时间需要 10 分钟。

【String】就是对char[]数组进行封装的对象,由三部分组成:

1, char数组:它是String对象所表示的字符串的超集;

2, 3, offset和count,表示了String对象表示的字符串在char数组中的起始段;

String是特定设计的,包含以下三个特点:

1, 不变性: 不变模式immutable,节省了同步和锁等待的消耗;

2, 针对【常量池】的优化:

变量 内存空间 常量池

String str1 = “abc” ———————>

String str2 = “abc” ———————> abc

String str3 = new String(“abc”) —-> str实例 ———>

注意:str1 == str3.intern()是true;str2, str2直接指向常量池中的”abc”,不拷贝;

3,类的final定义;

String的两个构造方法:

public String(char value[]) {    this.value = Arrays.copyOf(value, value.length); } String(char[] value, boolean share) { this.value = value; }

第一个构造方法会构造全新的char[]数组;

第二个构造方法共享了原来的char[]数组;

【内存泄漏】第二个包可见的共享char[]数组的构造方法会导致内存泄露

这个构造方法是空间换时间的策略(很有可能理解为时间换空间,因为share了空间,但这里大多数情况下是阻止大空间的GC);

调用这个构造方法,会使得原始的char[]数组无法被GC,假如原char[]很大,按新的String对象只引用了其中很小的一部分,这就是subString(begin, end)的潜在风险,因为这个方法使用了这个包可见的构造方法返回了新的共享了旧的char[]数组的String对象:

new String(offset + beginIndex, endIndex-beginIndex, value);

包可见的构造方法,客户代码虽然无法使用,但调用以下方法则间接调用了这个构造方法:

Integer.toString;

Long.toString;

String.concat;

String.replace;

String.subString;

String.toLower;

String.toUpper;

String.valueOf;

比如:

String str = new String(new char[10000000]);

String str2 = str.subString(1, 5);

1000000个字符常驻内存,无法GC,因为5个字符串的使用;

【字符串分割】

String.split提供【正则表达式】分割功能:

“a;b,c:d”.split(“[;|,|:]”);

StringTokenizer是分割字符串的迭代器:

StringTokenizer st = new StringTokenizer(orignalString, “;”);

while(st.hasMoreTokens())

st.nextToken();

用String.indexOf和String.subString来分割字符串:

1234567891011121314
while(true) {    String splitStr = null;    int j = orignalStr.indexOf(';');    if(j < 0) break; splitStr = orignalStr.subString(0, j); orignalStr = orignalStr.subString(j + 1); //更新string }

分割性能:split < StringTokenizer < indexOf&subString


【字符串查找】

indexOf(char c)与charAt(int index)是String互补的方法;

用startWith和endsWith进行字符串;

用charAt实现startWith:

if(origStr.charAt(0) == ‘a’ && origStr.charAt(1) == ‘b’ && origStr.char(2) == ‘c’);

用charAt实现endsWith:

if(origStr.charAt(len - 1) == ‘c’ && origStr.charAt(len - 2) == ‘b’ && origStr.char(len - 3) == ‘a’);

charAt性能高于startWith和endsWith;


【字符串连接 + += concat StringBuilder StringBuffer】

静态字符串(String常量)的连接操作,会在编译期被编译器直接运算优化:

String result = “abc + “and” + “123”; 的性能高于

StringBuilder builder = new StringBuilder();

builder.append(“abc”);

因为静态字符串的+操作在编译期就被运算了,运行期只存在”abcand123”一个字符串,并非:

“abc”, “and”, “123”, “abcand”, “abcand123”;

动态字符串(String变量)的连接操作,会在编译期被编译器转换为StringBuilder实现,循环中的局部变量也不例外:

所以,

String str1 = “abc”;

String str2 = “and”;

String str3 = “append”;

String result = str1 + str2 + str3;

的字节码等同于:

String result = (new StringBuilder(String.valueOf(str1))).append(str2).append(str3).toString();

所以,其实用+操作和StringBuilder的性能是一样的 ;

但编译器把+转换为StringBuilder时不够聪明,经常会过多new StringBuilder的对象:

for(int i = 0; i < 10000; i++)

str = str + i;

会被编译器转换为:

for(int i = 0; i < 10000; i++)

str = (new StringBuilder(String.valueOf(str))).append(i).toString();

所以应该显式使用StringBuilder而不是依靠编译器转换为StringBuilder实现:

StringBuilder sb = new StringBuilder();

for(int i = 0; i < 100000; i++)

sb.append(i);

StringBuffer是线程安全的,理论上性能略低于StringBuilder;

StringBuilder和StringBuffer就是变长的char[]数组,跟所有变长数组一样,指定合适capacity可以节省扩容的消耗,提高性能:

StringBuffer(int capacity) StringBuilder(int capacity);

字符串连接的效率:StringBuilder >> concat > +

转载于:https://www.cnblogs.com/mosthink/p/5288693.html

你可能感兴趣的文章
simhash进行文本查重 Simhash算法原理和网页查重应用
查看>>
python的异常机制使用技巧
查看>>
高速幂取余算法
查看>>
linux c获取mac
查看>>
Learning Lua Programming (2) Lua编程基础
查看>>
C# read weather xml
查看>>
全局变量如果不初始化,则默认为0,编译时编译器不提示“变量未初始化”。...
查看>>
HTML学记笔记
查看>>
CLR线程概览(一)
查看>>
cocos2dx游戏--欢欢英雄传说--添加血条
查看>>
WPF自定义控件(二)の重写原生控件样式模板
查看>>
【转】Flash:同志们,这些知识点你们知道多少?(一些必备的Flash开发知识点)...
查看>>
The N-dimensional array (ndarray)¶
查看>>
3. Spring Boot热部署【从零开始学Spring Boot】
查看>>
JpaSpecificationExecutor接口与自定义 Repository 方法&#x60;
查看>>
Java10来了,来看看它一同发布的全新JIT编译器
查看>>
今年双11,飞猪的“非OTA”之路走得怎么样了?
查看>>
苹果下架APP数量暴增超万款,看看你常用的在列吗?
查看>>
南非总统顾问一句想试试 马云当真了 做了件事你都想不到
查看>>
长虹软服常清雪:赋能数字化转型 看传统企业如何抢占先机
查看>>