String
创建字符串
创建字符串常见3中方式
- 直接赋值
String str = "Hello";
- new对象赋值
String str2 = new String("Hello");
- 数组转换字符串
char[] array = {
'H', 'e', 'l','l','o'};
String str3 = new String(array);
三种赋值的内存结构
字符串的比较
那么这个代码的结果时怎样的呢?
String str = "Hello";
String str2 = new String("Hello");
char[] array = {
'H', 'e', 'l','l','o'};
String str3 = new String(array);
System.out.println(str == str2);
System.out.println(str == str3);
System.out.println(str2 == str3);
其实根据上面的结构图不难看出,每个引用都是不相同的,引用所指向的地址不同,则指向的不是同一对象。
由此可见:
String 使用 “ == ”比较并不是在比较字符串内容, 而是比较两个引用是否是指向同一个对象
同理也可以判断这些输出结果
String str1 = "abcde";
String str2 = new String("abcde");
System.out.println(str1 == str2); //false
String str3 = "abc" + "de"; //编译时 就进行了拼接,变为"abcde"
System.out.println(str3 == str1); //true
String str4 = new String("abc") + new String("de");
System.out.println(str1 == str4); //false;
String str5 = new String("abc") + "de";
System.out.println(str5 == str1); //false
System.out.println(str4 == str5); //false
equals方法
“==”号是用来比较两个对象是否相同,那么如果想比较对象里的内容是否相同,该怎么办呢?
String中有equals方法,可以比较两者里的内容是否相等
扫描二维码关注公众号,回复:
13035398 查看本文章
String a = new String("123");
String b = "123";
System.out.println(a.equals(b)); //true
字符串常量池
String类的两种实例化操作, 直接赋值和 new 一个新的 String
1. 直接赋值
String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true
可以发现此时并没有开辟新的堆内存空间,那是因为
在JVM底层实际上会自动维护一个对象池(字符串常量池)
- 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
- 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用
- 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用
2. 采用构造方法
String str = new String("hello") ;
这样的做法有两个缺点:
- 如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间(字符串常量 “hello” 也是一个匿名对象, 用了一次之后就不再使用了, 就成为垃圾空间, 会被 JVM 自动回收掉)
- 字符串共享问题. 同一个字符串可能会被存储多次, 比较浪费空间
但是我们可以使用 String 的 intern方法来手动把 String 对象加入到字符串常量池中
// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); //false
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2); //true
总结:解释String类中两种对象实例化的区别
- 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用
- 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池
理解字符串不可变
字符串是一种不可变对象. 它的内容不可改变
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
这样一个代码虽然能执行处一个正确的结果,但是!!!
其内存发生了巨大的变化,如下图
因为字符串是不可变的,所以它会拼接出很多用不到的内存,最后只用到最后拼接好的字符串,从而导致浪费内存
那么如果实在需要修改字符串, 例如, 现有字符串 str = “Hello” , 想改成 str = “hello” , 该怎么办?
- 借助原字符串, 创建新的字符串
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
// 执行结果 hello
- 使用 “反射” 这样的操作可以破坏封装, 访问一个类内部的 private 成员(这里就不详细赘述了)
字符,字节,字符串
1、字符与字符串
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String(char value[]) | 构造 | 将字符数组的所有内容变为字符串 |
2. | public String(char value[], int offset, int count) | 构造 | 将部分字符数组中的内容变为字符串 |
3. | public char charAt(int index) | 普通 | 取得指定索引位置的字符,索引从0开始 |
4. | public char[] toCharArray() | 普通 | 将字符串变为字符数组返回 |
- public String(char value[])----(字符数组)
将字符数组的所有内容变为字符串
char[] value = {
'h','e','l','l','o'};
String a = new String(value);
System.out.println(a); //hello
- public String(char value[], int offset, int count)----(字符数组,区间首位置,区间尾位置)
char[] value = {
'h','e','l','l','o'};
String a = new String(value,1,3);
System.out.println(a); //ell
- public char charAt(int index)----(下标位置)
String b = "hello";
System.out.println(b.charAt(1)); //e
- public char[] toCharArray()
String b = "hello";
char[] c = b.toCharArray();
System.out.println(Arrays.toString(c)); //[h, e, l, l, o]
2、字节与字符串
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String(byte bytes[]) | 构造 | 将字节数组变为字符串 |
2. | public String(byte bytes[], int offset, int lengrh) | 构造 | 将部分字节数组中的内容变为字符串 |
3. | public byte[] getBytes() | 普通 | 将字符串以字节数组的形式返回 |
4. | public byte[] getBytes(String charsetName) throw unsupportedEncodingException | 普通 | 编码转换处理 |
- String(byte bytes[])----(字节数组)
byte[] d = {
97,98,99,100};
String e = new String(d);
System.out.println(e); //abcd
- String(byte bytes[], int offset, int lengrh)—(字节数组,区间首位置,区间尾位置)
byte[] d = {
97,98,99,100};
String e = new String(d,1,2);
System.out.println(e); //bc
- byte[] getBytes()
String f = "abcde";
byte[] g = f.getBytes();
System.out.println(Arrays.toString(g)); //[97, 98, 99, 100, 101]
- public byte[] getBytes(String charsetName) throw unsupportedEncodingException
可以通过不同的编码格式来转换对应的字节值
String h = "xing";
try {
byte[] bytes = h.getBytes("utf8"); //编码格式,还可以写gbk等
} catch (UnsupportedEncodingException e) {
e.printStackTrace(); //[97, 98, 99, 100, 101]
}
3、总结
- byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用.更适合针对二进制数据来操作.
- char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
字符串常见操作
1、字符串比较
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public boolean equals(Object anObject) | 普通 | 区分大小写比较 |
2. | public boolean equalsIanoreCase(String anoterString) | 普通 | 不区分大小写比较 |
3. | public int compareTo(String anotherString) | 普通 | 比较两个字符串大小关系 |
- public boolean equals(Object anObject) ----(比较的对象)
String a = "abcd";
String b = "abcd";
System.out.println(a.equals(b)); //true
- public boolean equalsIanoreCase(String anoterString)----(比较的对象)
String a = "AbCd";
String b = "abcd";
System.out.println(a.equalsIgnoreCase(b)); //true
- public int compareTo(String anotherString)----(比较的对象)
String a = "abcd";
String b = "abcd";
System.out.println(a.compareTo(b)); //相同返回 0
String c = "abcde";
String d = "abcd";
System.out.println(c.compareTo(d)); //a > b 返回大于0的数,此例子返回1
String e = "abcd";
String f = "abcdfg";
System.out.println(e.compareTo(f)); //a < b 返回小于0的数,此例子为-2
2、字符串查找
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public boolean contains(CharSequence s) | 普通 | 判断一个子字符是否存在 |
2. | public int indexOf(String str) | 普通 | 从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1 |
3. | public int indexOf(String str, int fromIndex) | 普通 | 从指定位置开始查找子字符串位置 |
4. | public int lastIndexOf(String str) | 普通 | 由后向前查找子字符串位置 |
5. | public int lastIndexOf(String str, int fromIndex) | 普通 | 从指定位置有后向前查找 |
6. | public boolean startsWith(String prefix) | 普通 | 判断是否以指定字符串开头 |
7. | public boolean startsWith(String prefix, int toffset) | 普通 | 从指定位置开始判断是否以指定字符串开头 |
8. | public boolean endsWith(String suffix) | 普通 | 判断是否以指定字符串结尾 |
- public boolean contains(CharSequence s)----(查找的字符串接口)
String a = "abcdef";
String b = "bcd";
String c = "dcb";
System.out.println(a.contains(b)); //true
System.out.println(a.contains(c)); //false
- public int indexOf(String str)----(查找的字符串)
String a = "abcdef";
String b = "bcd";
String c = "dcb";
System.out.println(a.indexOf(b)); //有,返回第一个字母下标 1
System.out.println(a.indexOf(c)); //无,返回-1
- public int indexOf(String str, int fromIndex)----(查找的字符串,开始位置下标)
String a = "abcdef";
String b = "cd";
System.out.println(a.indexOf(b,2)); //有,返回第一个字母下标 2
System.out.println(a.indexOf(b,3)); //从fromIndex往后找,没找到,返回-1
- public int lastIndexOf(String str)----(查找的字符串)
String c = "abababeee";
System.out.println(c.lastIndexOf("ab")); //从后往前,第一个ab在四号下标,返回4
- public int lastIndexOf(String str, int fromIndex)----(查找的字符串,开始位置下标)
String c = "abababeee";
System.out.println(c.lastIndexOf("ab",3)); //从fromIndex往前,第一个ab在二号下标,返回2
- public boolean startsWith(String prefix)----(查找的字符串)
String d = "beatuiful";
System.out.println(d.startsWith("bea")); //是"bea"开头,返回true
- public boolean startsWith(String prefix, int toffset)----(查找的字符串,开始位置下标)
String d = "beatuiful";
System.out.println(d.startsWith("atu",2)); //从toffset下标开始,是"atu"开头,返回true
- public boolean endsWith(String suffix)
String d = "beatuiful";
System.out.println(d.endsWith("ful")); //从后往前,最后是"ful"结尾,返回true
3、字符串替换
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String replaceAll(String regex,String replacement) | 普通 | 替换所有指定内容 |
2. | public String replaceFirst(String regex, String replacement) | 普通 | 替换首个内容 |
- public String replaceAll(String regex,String replacement)----(子字符串,想要替换的字符串)
String f = "abababababcde";
String h = f.replaceAll("ab", "hh");
System.out.println(h); //hhhhhhhhhhcde
- public String replaceFirst(String regex, String replacement)----(子字符串,想要替换的字符串)
String f = "abababababcde";
String h = f.replaceFirst("ab", "hh");
System.out.println(h); //只替换第一次出现的,返回hhababababcde
4、字符串拆分
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String[] split(String regex) | 普通 | 将字符串全部拆分 |
2. | public String[] split(String regex, int limit) | 普通 | 将字符串部分拆分,该数组长度就是limit极限 |
- public String[] split(String regex)
String str = "hello world hello xingxing" ;
String[] result = str.split(" ") ; //按空格拆分
System.out.println(Arrays.toString(result)); //[hello, world, hello, xingxing]
- public String[] split(String regex, int limit)
String str = "hello world hello xingxing" ;
String[] result = str.split(" ",3) ;
System.out.println(Arrays.toString(result)); //最多数组空间为3,所以为[hello, world, hello xingxing]
5、字符串截取
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String substring(int beginIndex) | 普通 | 从指定索引截取到结尾 |
2. | public String substring(int beginIndex, int endIndex) | 普通 | 截取部分内容 |
- public String substring(int beginIndex) ----(起始位置下标)
String str = "helloworld" ;
System.out.println(str.substring(5)); //world
- public String substring(int beginIndex, int endIndex)----(起始位置下标,结束位置下标)
String str = "helloworld" ;
System.out.println(str.substring(0, 5)); //hello
6、其他操作方法
NO. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1. | public String trim() | 普通 | 去掉字符串中的左右空格,保留中间空格 |
2. | public String toUpperCase() | 普通 | 字符串转大写 |
3. | public String toLowerCase() | 普通 | 字符串转小写 |
4. | public native String intern() | 普通 | 字符串入池操作 |
5. | public String concat(String str) | 普通 | 字符串连接,等同于“+”,不入池 |
6. | public int length() | 普通 | 取得字符串长度 |
7. | public boolean isEmpty() | 普通 | 判断是否为空字符串,但不是null,而是长度为0 |
- public String trim()
String str = " hello world " ;
System.out.println(str.trim()); //去掉了首尾空格hello world
- public String toUpperCase()
String str = "hello world" ;
System.out.println(str.toUpperCase()); //HELLO WORLD
- public String toLowerCase()
String str = "HELLO WORLD" ;
System.out.println(str.toLowerCase()); //hello world
- public native String intern()
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2); //true
- public String concat(String str)----(想要拼接的字符串)
String a = "hello";
String b = "world";
System.out.println(a.concat(b)); //helloworld
- public int length()
String a = "hello";
System.out.println(a.length()); //5
- public boolean isEmpty()
String str1 = ""; //str1指向的对象为空
System.out.println(str1.isEmpty()); //true
String str2 = null; //str2不指向任何对象
System.out.println(str2.isEmpty()); //空指针异常
StringBuffer 和 StringBuilder
String 和 StringBuffer 、StringBuilder的区别
- 后两者包含了一些String没有的方法,比如reverse方法
- 后两者是可变的,String是不可变的。String每次拼接,都会产生新的对象。后两者每次的拼接都返回的是this
- StringBuilder StringBuilder区别:
StringBuilder和String出现在单线程情况下
StringBuffer因为有synchronized关键字,所以一般出现在多线程情况下。 - StringBuilder和String之间的区别:
String的拼接+ 会被优化,优化为StringBuilder . append了
在循环当中,不可以使用String直接进行拼接,这样会产生大量的临时对象,包括优化后的StringBuilder对象
StringBuffer sb = new StringBuffer();
sb.append("Hello").append("World");
System.out.println(sb);