你所认识的String
概述
String作为非基本数据类型,Java开发中使用频率最高的一种数据类型之一,对于字符号的操作也很频繁,在使用的同时我们是否注意到了一下问题?
问题
- String a = new String("xxx")创建了多少个对象?
- String a = "xxx"创建了多少个对象?
- 为什么要用StringBuilder来代替"+"?
- 为什么String作为方法参数,在方法内部修改,不会影响原来的值?
- 字符串相等的问题?
- 如何正确的操作字符串?
如上问题我们是否都清晰明了,接下来结合示例来了解以上问题,同时让我们更加清晰的认识String
问题一
String a = new String("xxx") 复制代码该语句创建了2个对象,首先new会在堆中创建了一个对象用来存放"xxx",然后变量a指向刚才创建的对象,紧接着会在常量池中查看是否存在该字符串,如果没有,创建"xxx"字符串
问题二
String a = "xxx" 复制代码该语句创建了一个对象,会在常量池中查看是否存在"xxx"这个字符串,如果存在,则直接指向,如果不存在,则需要创建"xxx"字符串,然后指向
问题三
源代码
public class StringAppendTest {public static void main(String[] args) {String str = "abc";for (int i = 0; i < 10000; i++) {str += "def";}} } 复制代码反编译之后代码
package com.primary.example.string;public class StringAppendTest {public StringAppendTest(){}public static void main(String args[]){String str = "abc";for(int i = 0; i < 10000; i++)str = (new StringBuilder()).append(str).append("def").toString();} } 复制代码在线反编译地址:在线反编译,记得Decompiler类型选择JAD
如上代码展示可以看出来,"+"最终会被反编译成创建StringBuilder对象,然后调用append()方法,最终调用toString
如果是一条语句使用"+"拼接完全没有问题,如果在循环中使用的话就会不断的创建对象,影响性能。
问题四
示例代码1
public void test2() {Student student = new Student();student.setId(10001);student.setName("jack");System.out.println("before change,student:" + student);changeStudent(student);System.out.println("after change,student:" + student); }private void changeStudent(Student student) {student.setName("lucky"); } 复制代码打印结果1
before change,student:Student(id=10001, name=jack) after change,student:Student(id=10001, name=lucky) 复制代码示例代码2
public void test4() {String str = "jack";System.out.println("before change,str:" + str);changeStr(str);System.out.println("after change,str:" + str); }/*** 通过查看String的源码,可以看到里面定义的char[]是final,也就是不可变的* 每次对字符串的操作都相当于new String()操作* @param str*/ private void changeStr(String str) {str = "smile"; } 复制代码打印结果1
before change,str:jack after change,str:jack 复制代码如上展示,示例1传对象在方法内部的修改会影响外部,示例2传对象在方法内部修改却没有影响外部,同样是对象,示例1和示例2却得到不一样的效果?
示例1由于传递的是地址值,调用changeStudent()的时候,形参根据地址值找到student对象,然后对其修改,由于形参和实参指向的是同一个对象,所以方法内部的修改会影响到外部
实例2传递的也是地址值,但是由于String类型是不可变的,每一次赋值都相当于重新创建一个对象,所以内部的修改不影响外部
String内部字符数组的定义
private final char value[]; 复制代码问题五
示例1
public void test1() {String str1 = "123";String str2 = "123";System.out.println(str1 == str2); } 复制代码结果1
true 复制代码示例2
public void test2() {String str1 = "123";String str2 = "12" + "3";System.out.println(str1 == str2); } 复制代码结果2
true 复制代码示例3
public void test3() {String str1 = "123";String temp = "3";String str2 = "12" + temp;System.out.println(str1 + "=====" + str2);System.out.println(str1 == str2); } 复制代码结果3
false 复制代码示例4
public void test4() {String str1 = "123";final String temp = "3";String str2 = "12" + temp;System.out.println(str1 == str2); } 复制代码结果4
true 复制代码示例5
public void test5() {String str1 = "123";final String temp = getTemp();String str2 = "12" + temp;System.out.println(str1 == str2); }public String getTemp() {return "3"; } 复制代码结果5
false 复制代码结果是不是很惊讶?为什么值一样却不相等?首先"=="比较的是地址,equals()方法比较的是内容,但是由于每个类的equals()方法不一样,所以需要看具体的实现
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false; } 复制代码可以看到String的equals()方法首先比较地址是否一样,如果不一样再比较内容是否一样
然后再回到上面"=="比较的问题,我们首先要明白一个观点就是,Java中的常量是在编译期间已经确定好的,无法确定的就会在堆中
示例1在编译期间可以确定
示例2在编译期间也可以确定
示例3在编译期间无法确定,由于存在变量,变量只有在运行的时候才能确定
示例4在编译期间可以确定,虽然有变量,但是声明为常量,常量一旦定义就无法修改,所以编译时是可以确定的
示例5在编译期间无法确定,由于调用了方法,在运行的时候才能知道方法的返回值
问题六
来看看我们对字符串的操作
str.length(); str.substring() str.indexOf() if (null != str && str != "") {} 复制代码替代方案
StringUtils.length("xxx"); StringUtils.substring("xxx", 0, 5); StringUtils.indexOf("xxx", 1); if (StringUtils.isBlank("xxx")) {} 复制代码我们完全可以使用Apache的工具类来操作,首先是方便,其次是可以避免NullPointerException异常,进入工具类的方法实现,可以看到,首先会对我们传入的字符串进行null判断,从而避免异常
以上都是个人理解,如有错误,欢迎指定,让我提早走向光明
转载于:https://juejin.im/post/5c94addcf265da60df410a20
总结
以上是生活随笔为你收集整理的你所认识的String的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: glide 下载golang.org包问
- 下一篇: uva 815之理解诡异的海平线题目之不