一、String的两种实例化方式
1.直接赋值(用的最多,也最推荐)
2.通过构造方法
String str = "HelloWorld";//推荐使用
String str2 = new String("HelloWorld");
二、字符串相等比较
如果现在有两个int型变量,判断其相等可以使用“==”完成。如果说现在在String类对象上使用“==”?
class Test{
public static void main(String[] args) {
String str1 = "Hello";
String str = new String("Hello");
System.out.println(str == str1);
}
}
//输出false
现在两个字符串内容相同,而使用“==“得到的结果却是false,说明两个字符串不同嘛。为什么会这样?
其实"=="本身是进行数值比较的,如果现在用于对象比较,那么所比较的是两个对象所保存的内存地址数值,而并没有比较对象的内容。在内存中就是这样的:
那么要想比较内容,则必须采用String类提供的equals方法。
class Test{
public static void main(String[] args) {
String str1 = "Hello";
String str = new String("Hello");
System.out.println(str.equals(str1));
}
}
//输出true
三、字符串常量是String类的匿名对象。
简单来说就是这样
class Test{
public static void main(String[] args) {
String str = new String("Hello");
System.out.println("Hello".equals(str));
}
}
"Hello"本身就是一个对象,可以通过"."来调用String类中的方法。比如上面的"Hello".equals(str)。
tips:在进行指定内容比较时,将指定内容(字符串常量)写前面,避免空指针异常(NullPointerException)
String str = null;
System.out.println(str.equals("Hello"));
上面的代码中假设str要用户输入,而用户没有输入,则一定会出现Exception in thread "main" java.lang.NullPointerException,即空指针异常。正确的写法如下:
String str = null;
System.out.println("Hello".equals(str));
四、String的两种实例化方式的比较
1.直接赋值法
看这样一段代码
class Test{
public static void main(String[] args) {
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
}
}
/**输出
* true
* true
* true
*/
内存分析
好像和前面说的不一样啊,为什么现在并没有开辟新的堆内存空间呢?这是因为String类的设计使用了共享设计模式
在jvm底层自动维护一个字符串对象池(对象数组),如果采用直接赋值的模式进行String类的对象实例化操作,此对象将自动保存到对象池中,如果下次继续采用直接赋值的模式声明String对象,先去对象池中找是否有指定内容,如果有,直接引用;如果没有,开辟新的空间而后将其保存到对象池中以供下次使用。
2.采用构造方法
String str = new String("hello") ;
通过分析可知,如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间。除了这
一缺点之外,也会对字符串共享产生问题。
// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); // false
这也就是为什么"=="可以比较都是直接赋值的的字符串而不能比较一个直接赋值一个由构造方法赋值的字符串的原因
在String类中也提供了方法手动进行入池操作public String intern() ;
class Test{
public static void main(String[] args) {
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
}
}
//输出true
总结:
1. 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
2. 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern()
方法手工入池。
五、字符串常量不可变更
字符串一旦定义不可改变。所有的语言对于字符串的底层实现,都是字符数组,数组的最大缺陷就是长度固定。在定义字符串常量时,它的内容不可改变。有人会说,我这样写不就是增加了字符串的长度了吗?
class Test{
public static void main(String[] args) {
String str = "hello" ;
str += "world";
System.out.println(str);
}
}
//输出helloworld
我们分析一下,之前说了字符串常量是String类的匿名对象,上面的代码中"world"就已经是一个对象了,在内存中已经分配了空间,进行“+”操作后,则内存又开辟了一个空间来存放"helloworld",然后将str指向这个空间。表面上看起来是str字符串变长了,实际上是str的指向变更了。无论是“hello”还是“world”字符串常量都没有变更过。
可以发现字符串上没有发生任何变化,但是字符串对象的引用一直在改变,而且会形成大量的垃圾空间。正是因为
String的特点,所以如下代码不应该在你的开发中出现:
String str = "hello" ;
for(int x = 0 ; x<1000 ; x++) {
str += x ;
}
System.out.println(str)
如果有很多用户都使用了同样的操作,那么产生的垃圾数量就相当可观了。
使用字符串的原则
- 字符串使用就采用直接赋值。
- 字符串比较就使用equals()实现。
- 字符串别改变太多。
六、字符与字符串
字符串就是一个字符数组,所以在String类里面支持有字符数组转换为字符串以及字符串变为字符的操作方法。
1.字符数组转为字符串
class Test{
public static void main(String[] args) {
char[] c = new char[]{'h','e','l','l','o'};
String str = new String(c);
System.out.print(str);//hello
}
}
2.将字符串按照索引转换成单个字符
public char charAt(int index) :取得指定索引位置的字符
class Test{
public static void main(String[] args) {
String str = "Hello";
System.out.print(str.charAt(0));// H
}
}
3.将字符串转为字符数组
public char[] toCharArray();
class Test{
public static void main(String[] args) {
String str = "Hello";
char[] c = str.toCharArray();
for (char temp:c){
System.out.print(temp + ",");//H,e,l,l,o,
}
}
}
七、字节与字符串
1.字节数组转字符串
class Test{
public static void main(String[] args) {
byte[] data = new byte[]{70,72,73,74,75};//字符串转字节数组
String str = new String(data);
System.out.print(str);//FHIJK
}
}
2.将部分字节数组中的内容转成字符串
class Test{
public static void main(String[] args) {
//String str = "Hello";
byte[] data = new byte[]{70,72,73,74,75};//字符串转字节数组
String str = new String(data,1,3);
System.out.print(str);//HIJ
}
}
3.字符串转字节数组
class Test{
public static void main(String[] args) {
String str = "Hello";
byte[] data = str.getBytes();//字符串转字节数组
for (byte temp : data) {
System.out.print(temp + ",");//72,101,108,108,111,
}
}
}
八、字符串比较
equals()区分大小写的比较
equalsIgnoreCase() 不区分大小写的比较
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2));//false
System.out.println(str1.equalsIgnoreCase(str2));//true
}
}
2.比较两个字符串的关系
public int compareTo(String anotherString)
public class Test {
public static void main(String[] args) {
String str1 = "h";
String str2 = "H";
System.out.println(str1.compareTo(str2));//32
}
}
compareTo()的返回值有如下3种类型:
1. 相等:返回0.
2. 本字符串小于目标字符串:返回内容小于0
3. 本字符串大于目标字符串:返回内容大于0
通过分析可见这个返回值是2个字符串ASCII码的差值,而且从前向后比遇见第一个不同的字符就返回不会再往后进行,即
"abc".compareTo("ABC") 的返回值也是32
九、字符串查找——从一个完整的字符串中判断指定内容是否存在
1.判断指定字符串是否存在
public boolean contains(CharSequence s)
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
String str2 = "Hello";
System.out.println(str1.contains(str2));//true
}
}
2.判断是否以指定字符串开头
public boolean startsWith(String prefix)
public boolean startsWith(String prefix, int toffset):从指定位置判断是否以指定字符串开头
3.判断是否以指定字符串结尾
public boolean endsWith(String suffix)
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
String str2 = "Hello";
System.out.println(str1.startsWith(str2));//true
System.out.println(str1.startsWith("llo",2));//true
System.out.println(str1.endsWith("dd"));//false
}
}
十、字符串替换
public String replaceAll(String regex, String replacement):替换所有的指定内容
public String replaceFirst(String regex, String replacement):替换首个内容
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
System.out.println(str1.replaceAll("l","*"));//He**o Wor*d
System.out.println(str1.replaceFirst("l","#"));//He#lo World
}
}
十一、字符串拆分——可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
public String[] split(String regex):将字符串全部拆分
public String[] split(String regex, int limit) :将字符串拆分成数组长度为limit的子字符串数组
注意:特殊字符需要使用“\\”转义后拆分
eg:\\.
public class Test {
public static void main(String[] args) {
String str1 = "192###168#0#1";
for (String temp :
str1.split("#")) {
System.out.print(temp + ",");//192,,,168,0,1,
}
System.out.println();
for (String temp :
str1.split("#",2)) {
System.out.print(temp + ",");//192,##168#0#1,
}
}
}
多次拆分
public class Test {
public static void main(String[] args) {
String str = "张三:30|李四:40";
String[] temp = str.split("\\|");
for(int i = 0;i<temp.length;i++){
String name = temp[i].split(":")[0];
String age = temp[i].split(":")[1];
System.out.print("name:"+name);
System.out.println(" age:"+age);
}
}
}
/**输出
* name:张三 age:30
* name:李四 age:40
*/
十二、字符串截取
public String substring(int beginIndex):从指定索引截取到结尾
public String substring(int beginIndex, int endIndex):从指定索引截取部分内容
public class Test {
public static void main(String[] args) {
String str = "Hello World";
System.out.println(str.substring(3));//lo World
System.out.println(str.substring(3,7));//lo W
}
}
十三、字符串其他操作方法
1.去除字符串左右空格
public String trim();
2.字符串转大小写(全部大小写)
public String toUpperCase();字符串转大写
public String toLowerCase();字符串转小写
例:把单词首字母大写
public class Test {
public static void main(String[] args) {
String str = "hello";
System.out.println(str.substring(0,1).toUpperCase() + str.substring(1));
//输出Hello
}
}
3.判断字符串是否为空
public boolean isEmpty();(判断“”,不判断null)
判断空字符串完整写法
if(str == null || str.isEmpty())
要先判断str是否等于null,如果等于null后面的就不要判断了,2句话不能写反,如果str是null,先执行后面的会产生空指针异常