Java修炼之路——基础篇——String
String
1:字符串的不可变性
什么是不可变对象?不可变对象是指创建后无法变更的对象
String为什么是不可变的?String类为final,并且内部字符数组也为final。所以String对象是不可变对象。
String类为什么要设计为不可变?
主要出于对效率和安全的考量。
当你复制一个对象的时候,如果你知道它是不可变的,那么你只需要复制此对象的引用即可,一般引用会比对象小很多,所以能提高效率;String是不可变的,所以字符串常量池才可以存在,减少很多heap内存的占用;因为String的不可变性,所以在创建的时候hashcode就可以缓存,很适合作为map的key值;
安全方面:不可变对象是线程安全的。在多线程情况下,可变对象的内部状态可能会被其他线程改变,导致不可预期的结果。比如数据库连接,socket连接的IP PORT,类加载器等,都是通过String传参的,如果String是可变的,那会引起很大的安全问题。
2:JDK 6和JDK 7中substring的原理及区别
subString(int beginIndex, int endIndex)方法用来截取字符串
String x = "qwertt";x = x.substring(1,2);System.out.println(x);
结果输出:
w
JDK6中的subString
String类有三个属性:
char[] value:字符数组
int offset:起始位置
int count:字符串长度
对于subString方法,生成的String对象,value相同,只是改变了offset和count。这样会导致一个严重的问题:本来只需要很短的字符串,但是因为指向了一个很长的字符串,导致这个长字符串无法回收,存在内存泄漏的风险。
//JDK 6
String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;
}public String substring(int beginIndex, int endIndex) {//check boundaryreturn new String(offset + beginIndex, endIndex - beginIndex, value);
}
jdk6中,为解决上述问题,一般生成一个新的字符串并引用它:
x = x.substring(x, y) + ""
JDK7中的subString
在jdk7中,对上述问题进行了优化。每次执行subString的时候,都会去生成一个新的char[] ,从而避免了上述问题
jdk7源码如下:
//JDK 7
public String(char value[], int offset, int count) {//check boundarythis.value = Arrays.copyOfRange(value, offset, offset + count);
}public String substring(int beginIndex, int endIndex) {//check boundaryint subLen = endIndex - beginIndex;return new String(value, beginIndex, subLen);
}
3:replaceFirst、replaceAll、replace区别
先看一个示例:
String s = "my.test.txt";
System.out.println(s.replace(".", "#"));
System.out.println(s.replaceAll(".", "#"));
System.out.println(s.replaceFirst(".", "#"));
System.out.println(s.replaceFirst("\\.", "#"));
执行结果:
my#test#txt
###########
#y.test.txt
my#test.txt
原因:
replace方法有两个实现,一个是传入字符,循环匹配;一个是传入字符串,使用Pattern的逐个按字符进行匹配;
replaceFirst和replaceAll是使用Pattern,进行正则表达式的匹配。因为“.”在正则表达式中,表示任一字符,所以出现了“###########”的结果。
附源代码实现(jdk1.8版)
replace():
public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = value.length;int i = -1;char[] val = value; /* avoid getfield opcode */while (++i < len) {if (val[i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0; j < i; j++) {buf[j] = val[j];}while (i < len) {char c = val[i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(buf, true);}}return this;}
replace():
public String replace(CharSequence target, CharSequence replacement) {return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));}
replaceAll():
public String replaceAll(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceAll(replacement);}
replaceFirst():
public String replaceFirst(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceFirst(replacement);}
4:String对“+”的重载、字符串拼接的几种方式和区别
字符串的拼接方式:“+”、StringBuffer、new String().concat、StringBuilder
“+”:底层是使用StringBuilder实现。如:
String s1 = "11";
String s2 = "22";
String s = s1+s2;
System.out.println(s);
其实此段代码基本等价于:
String s1= "11";
String s2= "22";
StringBuilder sb = new StringBuilder();
sb.append(s1);
sb.append(s2);
String str = sb.toString();
System.out.println(str);
在大量使用“+”进行字符串拼接的时候,会产生大量的StringBuilder和String对象,会严重影响效率
concat:
concat其实是申请一个新的数组,进行数组的拷贝,然后用来创建新的String对象。底层是调用:System.arraycopy()
public String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true);}
StringBuffer & StringBuilder
两者调用的父类方法如下,区别在于StringBuffer 方法用了synchronized,是线程安全的
与concat的区别在于:
扩容逻辑不同,concat为需要多少扩多少,StringBuilder等是指数级扩容;
concat每次会生成新的String对象,而StringBuilder不会
public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}
5:String.valueOf和Integer.toString的区别
直接看源代码就好
public static String valueOf(int i) {return Integer.toString(i);
}//对null进行了处理
public static String valueOf(Object obj) {return (obj == null) ? "null" : obj.toString();} public static String toString(int i) {if (i == Integer.MIN_VALUE)return "-2147483648";int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);char[] buf = new char[size];getChars(i, size, buf);return new String(buf, true);}
6:switch对String的支持
Java JDK7中switch添加了对String的支持,之前仅支持(short、int、byte、char),并且底层最终都会转为int类型。那么对于String,是如何支持的呢?
请看以下代码:
public static void test(String status) {switch (status) {case "INIT":System.out.println("INIT"); break;case "PAY_ING":System.out.println("PAY_ING"); break;case "PAY_SUCCESS":System.out.println("PAY_SUCCESS"); break;case "PAY_FAIL":System.out.println("PAY_FAIL"); break;default:System.out.println("default"); break;}}
反编译class文件得到:
public void test(String status){String str;switch ((str = status).hashCode()){case -2113017739:if (str.equals("PAY_FAIL")) break label129; break;case -68158581:if (str.equals("PAY_ING")) break label107; break;case 2252048:if (str.equals("INIT")) break label96; break;case 1643683628:if (!(str.equals("PAY_SUCCESS"))) { break label140:System.out.println("INIT");return;System.out.println("PAY_ING");return;}System.out.println("PAY_SUCCESS");return;label129: System.out.println("PAY_FAIL");label140: break;default:label96: label107: System.out.println("default");}}
虽然看不懂有些带标签的break语句(break label;)但是很明显可以看出来支持String的方式:
将String转为了int类型的hashCode,因为hashCode可能会冲突,又加入了equals判断。
7:字符串池、常量池(运行时常量池、Class常量池)、intern
偷个懒,先放个链接,后续再慢慢完善
https://www.cnblogs.com/tiancai/p/9321338.html
Java修炼之路——基础篇——String相关推荐
- Java修炼之路——基础篇——枚举
枚举的用法 每个枚举变量其实都是枚举类的一个实例. 枚举与单例 各种模式的单例模式,包括枚举实现的单例 //懒汉模式 class SingletonA {private static Singleto ...
- Java修炼之路——基础篇——Java关键字
1:transient 当对象被序列化时,transient阻止其修饰的对象进行序列化:当反序列化时,此对象的值不会被恢复. 2:instanceof 判断引用指向的对象,是不是某个类及其子类的实例对 ...
- Java修炼之路——基础篇——数据类型
基础数据类型: 整型(byte short int long ).浮点型.布尔型.字符型boolean:只表示一位的信息,true,false.默认为false,基本上占一字节char: 16位,2字 ...
- Java修炼之路——基础篇——Java集合类详解2
Set和List区别?Set如何保证元素不重复? Set.List都实现了Collection接口,List是有序的列表,Set是无序的集合(TreeSet有序) List实现类: ArrayList ...
- Java修炼之路——基础篇——Java集合类详解1
SynchronizedList和Vector的区别 java.util.Vector java.util.Collections.$SynchronizedList Vector用同步方法,Sync ...
- Java修炼之路——基础篇——值传递
什么是值传递?引用传递? 值传递:值传递是将变量的一个副本传递到方法中,方法中如何操作该副本,都不会影响原变量的值.引用传递:引用传递是将变量的地址传递到方法中,方法中操作该变量,会对其产生影响. 为 ...
- Java修炼之路——基础篇——平台无关性
Java如何实现平台无关性? 首先说无论是哪种语言,都需要经过操作系统和CPU来完成程序的运行.平台无关性指的是程序不会因为操作系统和处理器的不同而不能运行或者发生运行错误.而不同的CPU和OS组成的 ...
- JAVA学习之路--基础篇三
目录 关于Java中从键盘输入的语句 nextxxx().next().nextLine()的区别 语句 if和if else语句 Switch语句 for语句 while和do..while bre ...
- java程序试岗内容_java程序员修炼之路基础篇四:继承
上一篇文章我跟大家聊了一下"封装",今天我们聊一下同样作为java语言三大特征之一的"继承". 简单说"继承"就是从一个已知类派生出新类的过 ...
最新文章
- Windows客户端C/C++编程规范“建议”——函数
- Titanium开发环境搭建第一个坑
- ETSI MEC — 参考架构模型
- linux vim 到底,真的有(很多)linux大牛用vim写项目吗?
- GO语言打包ICO图标
- windows知识点2
- BZOJ5221[Lydsy2017省队十连测] 偏题
- 如何写一份大家都满意的专利说明书
- vue 滑动置顶功能_CSS3 移动端 滚动置顶 吸顶
- 浅淡 Apache Kylin 与 ClickHouse 的对比
- 如何将电脑设置为定时关机?
- 学习笔记(13):C++编程FFMpeg(QT5+OpenCV)实战--实时美颜直播推流-ffmpegSDK开发环境准备,第一个ffmpeg项目创建...
- IC在測試生產過程的靜電放電(ESD)擊傷及電性過壓(EOS)現象
- 大数据营销模型思路架构
- Unity3D-Baked Lightmapping 示例学习
- SQLServer主从同步配置(Log Shipping方式)
- 互联网公司让行政给员工发中秋节福利,看到预算后:还是别发了
- 关于路由器的一点疑问
- 如何评估流程管理的紧迫度
- 初中数学最全几何模型_初中数学常用几何模型及构造方法大全.doc
热门文章
- 我的世界java版forge怎么用_我的世界电脑版MOD怎么用 我的世界pc版forge怎么安装...
- python列表操作程序_Python列表操作,比较常见的10个问题
- 超1亿人选择朋友圈三天可见,背后的原因值得深思
- 从小一看到数字,脑子里就开始搞颜色......
- 喜报!985大学首次登上Nature封面,这所学校可太不容易了!
- 当身为老师的爸爸上课时......​
- 趣图:BAT程序员的一天对比
- 为什么技术与产品沟通起来总是那么痛苦
- php 建立自己的框架,利用 Composer 一步一步构建自己的 PHP 框架(一)——基础准备...
- 一键对频对讲机好吗_对讲机的基础知识你都知道多少呢?