Java常用类实战 上(字符传类的分析和使用)
今天学习完JAVA常用类实战这节课的第一章字符串类的分析和使用,学习完这章,我掌握了一下两点内容,分别是String类、StringBuffer和StringBuil类。
一.String类分析
String类是我们之前经常用但是没具体讲解过这个类具体知识点以及如何使用这个类,那么接下来我们就系统的学习学习这个类。先对String类进行一定的分析,总结一下主要知识点。
- String类的底层使用char数组保存数据
- String是一个final类,不能被继承
- String是一个不可变类,生成对象后,内容不能发生变化
- String类中的所有返回String类型对象的成员方法都会返回一个新的String类型对象
二.String类的比较
String类重写了equals()方法,用来比较两个字符串的内容是否相同。与之类似的是"==",这个也是比较是否相同的,只不过和equals()比较的东西不同,"=="比较的是两个String类型对象的地址是否相同。
案例代码如下:
public class StringDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = new String("123");
String s2 = new String("123");
System.out.println(s1==s2);
String s3 = "234";
String s4 = "456";
System.out.println(s3==s4);
System.out.println(s1.equals(s2));
}
}
三.字符串类实例化机制
和其他自己创建的类一样,String类也要创建对象实例,那接下来我们学学Java是如何创建String对象的。
Java创建String对象有两种方式
- 创建的时候,JVM会现在字符串常量池中找是否有该对象,如果有,直接返回该字符串对象的地址,如果没有,就在常量池中创建该对象并返回地址
//第一种方式
String s1 = "123";
2. 创建的时候,也会先查找常量池中是否有该字符串,如果有,就在堆中复制该对象,并且把堆里面的对象地址传给变量;如果不存在,就会在堆中和常量池中各自创建给字符串对象,并且返回堆中对象的地址,就是创建了两个对象存储在了两个地方
//第二种方式
String s2 = new String("123");
//只在常量池中创建对象,创建了一个对象
String s1 = "123";
//在常量池和堆中各创建一个对象,一共有两个
String s2 ="123”;
四.字符串的维护和参数传递
String类的"+"和concat()都可以将两个字符串拼接起来,形成新的字符串。但是两个有区别,区别就是"+"可以将字符串与非字符串拼接到一起,而concat()只能将字符串和字符串连接。案例代码如下:
public class StringDemo2 {
public static void main(String[] args) {
String s1 = "123";
System.out.println(s1+123);
System.out.println(s1.concat("123"));
}
}
String的参数传递:先看一下代码
public static void main(String[] args) {
String s1 = new String("123");
show(s1);
System.out.println(s1);
}
public static void show(String s) {
s = "234";
}
}
看看这个代码输出结果是123还是234呢?是123,接下来聊聊为什么是123,说说这个传参的过程。
- 我们在main函数中创建了一个新的对象123,然后把它的地址传给了s1,所以现在s1存储的是123在堆中的地址
- 调用show()方法,并且把s1传进去,形参s复制了实参s1的值,也就是s1存储的地址,现在s指向的也是123所在的堆中的地址。
- 进入show方法后执行s="234",就是把234这个对象分配给s,s中存储的地址是234的地址。但这个操作对实参s1没有影响,s1存储的还是234的地址。
- show()结束后,形参s消失,对象234因为没有引用指向它,所以会被垃圾回收机制回收。
- 打印s1还是123
五.字符串的常用API方法
String类的常用方法:
- equals():用来比较两个字符串的内容是否相同
- charAt():返回指定索引处的字符
- contains():判断字符串中是否包含另一个字符串
- indexOf():返回第一次出现某个字符串的索引
- isEmpty():判断字符串是否为空字符
- split():按照指定格式拆分字符串,返回字符串数组
- trim():去掉字符串开头和结尾的空格
- toCharArray():将字符串转换为字符数组
- replace():替换字符串中的某个字符或字符串,全部替换
- length():返回字符串的长度
案例代码如下:
import java.util.Arrays;
public class StringDemo4 {
public static void main(String[] args) {
String s = "hello world";
System.out.println(s.charAt(1));//e
System.out.println(s.contains("e"));
System.out.println(s.indexOf("e"));//如果找不到,返回-1
System.out.println(s.isEmpty());//false
String[] ss = s.split(" ");//以空格为标志拆分字符串
System.out.println(Arrays.toString(ss));
System.out.println(s.trim());
char[] sss = s.toCharArray();
System.out.println(Arrays.toString(sss));
System.out.println(s.replace("l", "e"));
System.out.println(s.lastIndexOf("l"));//9 返回最后出现的索引
}
}
六.StringBuffer类
StringBuffer又称为可变字符序列,线程安全的可变字符序列。它是一个类似于String的字符串缓冲区,无法修改,但是可以通过调用某些方法来更改该序列的内容和长度。可以把StringBuffer想象成一个容器,这个容器中包含了很多字符串,并且可以对这些字符串进行操作。StringBuffer是同步安全的,这个后续会讲,跟多线程共享资源要保证同步安全是一个道理
public class StringDemo4 {
public static void main(String[] args) {
//创建空对象的StringBuffer
StringBuffer sb = new StringBuffer();
System.out.println(sb);
System.out.println(sb.capacity());//输出容器的大小 缓冲区默认为16
System.out.println(sb.length());//输出对象的长度
//创建指定容量的字符串缓冲区
StringBuffer sb2 = new StringBuffer(50);
System.out.println(sb2);
System.out.println(sb2.capacity());
System.out.println(sb2.length());
//创建指定字符串内容的字符串缓冲区
StringBuffer sb3 = new StringBuffer("hello");
System.out.println(sb3);
System.out.println(sb3.capacity());//默认是16,现在hello长度是5,容量也就加到21了
System.out.println(sb3.length());
}
//StringBuffer是一个可变字符串序列,容量和长度都可以变
}
七.StringBuilder类
StringBuil和StringBuffer类似,都是字符串缓冲区,非同步安全
package com.huawei.string;
/*
* StringBuilder 也是字符串缓冲区,不同步。如果要比较两个StringBuilder实例是否相同,要转换成String类
*/
public class StringDemo5 {
public static void main(String[] args) {
String str = new String("abc");
StringBuilder stringBuilder = new StringBuilder(str);
System.out.println("使用带参的构造方法生成字符串缓冲区"+stringBuilder);//拿到了abc,因为字符串缓冲区里存放的abc
//利用空构造方法创建StringBuilder对象
StringBuilder builder = new StringBuilder();
System.out.println("空参构造的字符串缓冲区"+builder);
//StringBuilder没有重写equals() 如果必须比较StringBuilder内容是否相同,那就必须把StringBuilder转换成String
String s1 = builder.toString();
StringBuilder builder2 = new StringBuilder();
System.out.println("空参构造的字符串缓冲区"+builder2);
String s2 = builder2.toString();
//先直接比较两个StringBuilder的实例
System.out.println(builder.equals(builder2));//false,这两个实例里面都没有内容,应该是一样的,但是输出是false,所以要想比较,就一定要转换成String
System.out.println(s1.equals(s2));//true
}
}
现在我们来总结一下String,StringBuffer,StringBuilder的区别:
- String内容是可变的
- StringBuffer和StringBuilder的内容是可变的
- StringBuffer是同步的,数据安全但是效率低
- StringBuilder不是同步的,数据不安全但是效率高
通过下面代码结果可以知道,sb的值一直是小于1000,而sb1的值始终为1000,所以StringBuild是不同步的
public class Test {
StringBuilder sb = new StringBuilder();
StringBuffer sb1 = new StringBuffer();
public Test() {
//创建线程组来管理线程
ThreadGroup group = new ThreadGroup("testGroup");
//创建线程类对象
MyThread at = new MyThread();
//开启100个线程
for(int i=0;i<1000;i++) {
Thread th = new Thread(group,at,String.valueOf(i));
th.start();
}
while(group.activeCount()>0) {//此方法返回活动线程的当前线程的线程组中的数量
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(sb.length());
System.out.println(sb1.length());
}
class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sb.append("1");
sb1.append("1");
}
}
public static void main(String[] args) {
new Test();
//StringBuilder达不到1000,不同步,StringBuffer一直是1000,是同步的
}
}
八.总结
学完这些内容我掌握了String类的一些知识点
- 点赞
- 收藏
- 关注作者
评论(0)