String类
我们知道java有八大基本数据类型,其中char是字符型,只能存放单个字符,如果我们想存放一串字符,就需要用到字符串String类型,字符串类型就是一个或多个字符组成的连续序列,程序需要存储的大量文字、字符都会使用字符串进行处理。
字符串String的声明
String 变量名;
字符串两种实例化方式
1.使用字符串常量直接初始化(常用)
String str = "HelloWorld";
2.使用构造方法创建并初始化
String str = new String("HelloWorld");
字符串的拼接
在前面的学习过程中我们经常使用到字符串的拼接输出,例如
System.out.println(name+"正在学习");
我们使用的都是"+"进行拼接,需要记住,字符串类型和所有的基本数据类型拼接都是字符串类型
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
int a = 10;
double b = 20.0;
boolean flag = true;
System.out.println("我们的一串字符串拼接起来变成"+str1+","+str2+","+a+","+b+","+flag);
}
}
代码运行结果:
代码讲解:在上面拼接过程中,如果两边都有字符串,中间夹着一个变量名我们就应该: " "+变量名+" ",
如果变量名是最后一个要拼接的元素,只需要一个"+"即可:" "+变量名
字符串的比较
1."=="比较两字符串的引用地址是否相同
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println(str1==str2);
System.out.println(str1==str3);
}
}
代码运行结果:
代码讲解:
str1与str3不相同的原因:
(1)str1是变量名一定会保存在栈内存,而"Hello"就一定会在“堆内存中”。
(2)使用new创建对象,一定会在堆内存中开辟新的空间
(3)String本身是一个类,所以String类型是引用数据类型,String类的对象是一定可以进行引用传递的,引用传递的结果就是不同的栈内存将会指向同一块堆内存的地址。
(4)栈内存,里面存放的是数值,每一块栈内存只能保存一块堆内存的物理地址数值
不知道大家有没有注意过,bigdodo在给大家画内存空间图的时候,总会将堆内存画得比栈内存大,原因是这样:在栈内存中只存放堆内存的地址数值,而堆内存会存放内容,所以记得“栈小堆大”。
2."equals()"比较两个字符串是否相同,区分大小写
3."equalsIgnoreCase"比较两个字符串是否相同,忽略大小写
代码演示:
package demo;
public class StringDemo {
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
}
}
4."compareTo"比较字符串的大小关系,两个字符串从第一个字符开始相比。
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abd";
System.out.println(str1.compareTo(str2)); //结果: -1
}
}
代码讲解:
结果值为-1,这是因为字符串的大小比较,怎么比?只能通过字符对应的ASCII码的数值,进行比较,而且是从前往后一个一个比较。第一个都是"a",相等,第二个都是"b",相等,第三个,一个是“c”,一个是“d”,我们看下方的ASCII码的十进制,能看到99和100,前和后小了1,所以结果值为-1,大家还可以自己尝试一下别的值进行比较
字符串的的内存分配比较
1.直接赋值法
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
String a = "Hello"; //直接赋值
String b = "Hello"; //直接赋值
String c = b; //引用传递
System.out.println(a==b); //true
System.out.println(a==c); //true
System.out.println(b==c); //true
}
}
代码讲解:
这里bigdodo给大家讲一下什么叫引用传递,我们都记得栈内存中存放的是堆内存的地址数值信息,也就是说,b = "Hello",中b存放的其实是个数值,是"Hello"所在堆内存空间的地址,所以当String c = b;引用传递,就是让c也指向了b所执行的物理地址数值
我们来个图再理解一下
我们可以看到"Hello"这个字符串,在String a = "Hello";的时候就一直在堆内存中占着一块地,如果只用直接赋值,和引用传递,并没有创建新的"Hello"字符串。
2.构造方法实例化
String str = new String("Hello");
内存空间图
代码讲解:我们能够看到,在new的时候,会先创建一个字符串"Hello",然后当做参数,再传给new出来的堆空间中,这样使用一次new,在堆空间中会出现两个"Hello",其中一个是垃圾
字符串一旦声明不可以改变
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
String str = "Hello"; //直接赋值
str+="World";
str = str + "!!!";
System.out.println(str);
}
}
代码运行结果
HelloWorld!!!
代码讲解:上述采用了字符串的拼接,看似结果是一个字符串,其实不是,我们来看一下内存空间
我们可以看到看似是一个字符串,完全拼接后,我们需要的只有一个字符串,却产生了4个字符串垃圾。如果一旦修改的数据量很大,而且对内存开销有要求,显然这种形式是不合理的,java还给我们提供了一个StringBuffer类让我们进行字符串打的大量修改操作
StringBuffer类
同样可以用来使用字符串类型,String类型的大多数方法,同样可以使用,同时还提供了一些自己的方法。
StringBuffer专门用来对字符串的增删改查,对字符串的增删改查,而不会创建新的对象,对内存消耗上会比String类型小很多
我们来演示一下StringBuffer的一些方法:
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
StringBuffer sbf=new StringBuffer("Hello");
sbf.append("World!!!");//类似字符串的拼接
sbf.insert(0,"abc");//在开头位置插入abc
sbf.delete(0,5);//删除下标从0到5且不包含5的字符 [0,5)
String str = sbf.toString(); //确定sbf字符串修改完成后还能转换成String类型
System.out.println(str);
}
}
我们来对String类型,和StringBuffer类型,对字符串修改的时候,效率进行个比较
代码演示:
package demo;
public class StringDemo {
public static void main(String[] args) {
int n = 100000;
long start = System.currentTimeMillis(); //获取当前系统时间(单位:毫秒)
StringBuffer buf = new StringBuffer();
for (int i = 0; i < n; i++)
buf.append("abc");
long end = System.currentTimeMillis();
System.out.println("StringBuffer用时:"+(end-start)+"毫秒");
start = System.currentTimeMillis(); //获取当前系统时间(单位:毫秒)
String str = "";
for (int i = 0; i < n; i++)
str += "abc";
end = System.currentTimeMillis();
System.out.println("String用时:"+(end-start)+"毫秒");
}
}
代码运行结果:
代码讲解:我们可以看到,在效率上,同样执行100000次的操作,StringBuffer的执行效率是String类型的1195.5倍。这在对后期数据库操作的情况下,差距会更加的大。
总结点评:String类和StringBuffer类型的学习,主要是要知道它们在内存空间中都是怎么分配的,如果记住了,对String类型的学习帮助会很大,虽然StringBuffer类型在字符串的修改上执行效率比String类型高很多,但我们一般编程中都是使用String类型,因为我们很少会操作上万次的字符串的修改,为此,bigdodo还专门去做了实验,使用这两个类型进行10次的字符串修改,出来的时间都是0ms,整的bigdodo还以为自己写错了代码,而实际上,这两个类型在修改次数少的时候,效率都还是很高的,效率差可以完全忽略。