String
- String的常见创建方式
- 字符串比较
- ==比较
- equals比较
- 字符常量池
- 字符串不可变
- 字符、字节与字符串
- 字符与字符串
- 字节与字符串
- 字符串常见的操作
- 字符串比较
- 字符串查找
- 字符串替换
- 字符串拆分
- 字符串截取
- 其他常用的方法
- String、StringBuffer 和 StringBuilder
- String、StringBuffer 和 StringBuilder之间的转换
- String、StringBuffer 和 StringBuilder之间的区别
Sting类不管在任何一个语言中都是非常重要的,我们在很多地方都会使用它,我们需要熟练掌握。
String的常见创建方式
//方式一
String str1="hello";
//方式二
String str2=new String("hello");
//方式三
char[] ch={'h','e','l','l','o'};
String str3=new String(ch);
三种方式在内存中的分布如图
字符串比较
==比较
比较两个引用是否是指向同一个对象
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 执行结果
true
str1 和 str2 是指向同一个对象的. 此时如 “Hello” 这样的字符串常量是在 字符串常量池 中
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 执行结果
false
通过 String str1 = new String(“Hello”); 这样的方式创建的 String 对象相当于再堆上另外开辟了空间来存储"Hello" 的内容, 也就是内存中存在两份 "Hello
总结:
String 使用 == 比较并不是在比较字符串内容, 而是比较两个引用是否是指向同一个对象
equals比较
Java 中要想比较字符串的内容, 必须采用String类提供的equals方法
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// 或者这样写也行
// System.out.println(str2.equals(str1));
// 执行结果
true
equals 使用注意事项
现在需要比较 str 和 “Hello” 两个字符串是否相等, 我们该如何来写呢?
String str = null;
// 方式一
System.out.println(str.equals("Hello")); // 执行结果 抛出 java.lang.NullPointerException 异
常
// 方式二
System.out.println("Hello".equals(str)); // 执行结果 false
我们更推荐使用 “方式二”. 一旦 str 是 null, 方式一的代码会抛出异常, 而方式二不会(“Hello” 这样的字面值常量, 本质上也是一个 String 对象, 完全可以使用 equals 等 String 对象的方法)
字符常量池
String类的设计使用了共享设计模式(可以理解为现在的共享单车,如果我们想用的话就在外面直接扫一辆单车直接用就行了(从常量池中取),不用我们再买一辆新的自行车(自己new一个新的对象赋值),大大方便了我们的使用)
在JVM底层实际上会自动维护一个对象池(字符串常量池)
- 如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.
- 如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用。
- 如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用
我们一般采取直接赋值的方式创建 String 对象
字符串不可变
字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 但是 String 类并没有提供 set 方法之类的来修改内部的字符数组.
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果
hello world!!!
形如 += 这样的操作, += 之后 str 打印的结果确实是变了, 但是不是 String 对象本身发生改变, 而是 str 引用到了其他的对象。
那么如果实在需要修改字符串, 例如, 现有字符串 str = “Hello” , 想改成 str = “hello” , 该怎么办?
- 1)常见办法: 借助原字符串, 创建新的字符串
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
// 执行结果
hello
- 2)反射
使用 “反射” 这样的操作可以破坏封装, 访问一个类内部的 private 成员
为什么 String 要不可变?(不可变对象的好处是什么?)
- 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了.
- 不可变对象是线程安全的.
- 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中
字符、字节与字符串
字符与字符串
字符串内部包含一个字符数组,String 可以和 char[] 相互转换.
常用的一些方法
- toCharArray()将此字符串转换为新的字符数组并返回
- charAt() 截取一个字符
- String()数组转字符串
- valueOf(char[])数组转字符串
- copyValueOf(char[])数组转字符串
字节与字符串
字节常用于数据传输以及编码转换的处理之中,String 也能方便的和 byte[] 相互转换(一般在网络方面使用)
常用的一些方法
- getBytes()将字符串以字节数组的形式返回
- getBytes(String charsetName)throws UnsupportedEncodingException编码转换处理
字符串常见的操作
这里我只列举了一点点,详情的话大家可以参考这位博主的文章java String类的常用方法
字符串比较
- equals()和equalsIgnoreCase() 比较两个字符串(ignore不区分大小写)
- compareTo()和compareToIgnoreCase() 比较字符串
字符串查找
- 字符串查找,最好用最方便的就是contains()
- startsWith()方法判断是否以指定字符开头
- endWith()方法决定是否以指定字符结尾
- indexOf() 查找字符或者子串第一次出现的地方。
- lastIndexOf() 查找字符或者子串最后一次出现的地方
字符串替换
- replaceAll() 替换所有指定内容
- replaceFirst()替换首个内容
注意事项: 由于字符串是不可变对象 , 替换不修改当前字符串, 而是产生一个新的字符串
字符串拆分
- split(String regex)将字符串全部拆分
- split(String regex,int limit)将字符串部分拆分,切分该数组长度的就是limit的最大值
拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {
System.out.println(s);
}
注意事项:
- 字符" | “,” * “,”+“都得加上转义字符,前面加上”\ ".
- 而如果是"\ “,那么就得写成”\".
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
多次拆分
String str = "name=zhangsan&age=18" ;
String[] result = str.split("&") ;
for (int i = 0; i < result.length; i++) {
String[] temp = result[i].split("=") ;
System.out.println(temp[1]);
}
运行结果
zahngsan
18
split(String regex,int limit)
String str = "aaaaaa=bbbbbb=cccccc=ddddd" ;
String[] strings=str.split("=",2);
for(int i=0;i<strings.length;i++) {
System.out.println(strings[i]);
}
运行结果为
aaaaaa
bbbbbb=cccccc=ddddd
limit给2的话数组的长度便会是2(会切分为两部分)
字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下
- String substring(int beginIndex)从指定索引截取到结尾 String
- substring(int beginIndex,int endInx)截取部分内容
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));
输出结果
world
hello
注意事项:
- 索引从0开始
- 注意左闭右开的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
其他常用的方法
- String trim()去掉字符串中的左右空格,保留中间的空格
- String toUpperCase()字符串转大写
- String toLowerCase()字符串转小写
- public native String intern()字符串入池
- String concat(String str)字符串连接,等同于“+‘’ 但不入池
- int length()取字符串的长度
- boolean isEmpty()判断是否为空字符串,但不是null,而是长度为0
String、StringBuffer 和 StringBuilder
首先来回顾下String类的特点:
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
String、StringBuffer 和 StringBuilder之间的转换
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:(String和StringBuilder类似)
- String变为StringBuffer:利用StringBuffer的构造方法或append()方法
StringBuffer定义了三个构造函数:
StringBuffer()
StringBuffer(int size)
StringBuffer(String str)
StringBuffer(CharSequence chars) - StringBuffer变为String:调用toString()方法
String、StringBuffer 和 StringBuilder之间的区别
String 和 StringBuilder StringBuffer 区别:
- 后两者包含了一些String没有的方法 比如reverse方法
- 后两者是可变的,String是不可变的。String的每次拼接,都会产生新的对象,后两者每次的拼接都返回的是this
- StringBuilder 之间 StringBuffer 区别:
StringBuilder和String 出现在单线程情况下
StringBuffer因为有synchronized关键字 所以一般出现多线程情况下。
- StringBuilder和 String之间有啥区别!!
String的拼接 + 会被优化 优化为StringBuilder . append了 !!!
在循环当中 不可以使用String直接进行拼接 这样会产生大量的临时对象(包括优化之后StringBuilder对象)