- 一、JDK中String的声明
- 二、创建字符串的四种方式
- 三、字符串的字面量
- 四、字符串常量池
- 4.1手工入池方法
- 五、字符串的不可变性
- 六、修改字符串内容
- 6.1 通过反射破坏数组的封装(了解,不推荐)
- 6.2 使用StringBuilder或StringBuffer类(重点)
- 七、字符串的常用 *** 作
- 7.1 字符串的比较
- 7.2 字符和字符串的相互转换(重要)
- 7.3 字节与字符串的相互转换
- 7.4 字符串的查找
- 7.5字符串替换 *** 作
- 7.6 字符串的拆分 *** 作
- 7.7 字符串截取
- 7.8 其他 *** 作
二、创建字符串的四种方式
- String继承的接口 :
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
- 为什么String类被final修饰?
被final修饰的类无法被继承,String类不存在子类。保证所有用JDK的人,用到的String类就一个,就不会造成子类行为不一致的问题。
否则,所有子类都能使用String的方法,都能自己设计一套equals方法等。这样无法一致性。会造成这个程序能用,下个程序不能用的情况,会产生很多版本。
直接赋值
通过构造方法产生对象
通过字符数组产生对象
通过String静态方法valueOf(任意数据类型),转换为字符串
public class StringTest {
public static void main(String[] args) {
//第一
String str = "hello";
//第二
String str2 = new String("hello");
//第三
char[] data = new char[]{'a','b','c'};
String str3 = new String(data);
//第四
String str4 = String.valueOf(10);
}
}
三、字符串的字面量
定义:直接写出来的数值称为字面量
10 —— int字面量
10.1 —— double字面量
true —— boolean字面量
“abc” —— String字面量 ->String是个引用类型,就是一个字符串对象
public static void main(String[] args){
String str = "hello";
String str1 = str;
str1 = "hello world";
System.out.println(str);
}
输出:
hello
str和str1是两个对象,开辟了两块内存空间
下面来看一个代码
public static void main(String[] args) {
String userName = null;
System.out.println(userName.equals("张三")); //1
System.out.println("张三".equals(userName)); //2
}
1 输出:NullPointerException
2 输出:false
四、字符串常量池牵扯到用户输入就一定要做判空处理。
要比较的内容本身就是字符串的字面量,一定不是空对象。所以要把比较的内容放在euqals的前面,就可以方便处理userName为空的问题。
看一个代码
public static void main(String[] args) {
String str = "hello";
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println(str == str1); //1
System.out.println(str1 == str2); //2
System.out.println(str3 == str4); //3
}
输出:
true
true
false
"=="比较的是两个对象的地址,1,2代码返回的是true,说明这三个对象指向的是同一块内存。3是false,说明这两个对象属于不同的内存空间,new一个对象就开辟了一块内存,所以毋庸置疑这两个对象肯定不是一个内存空间的。
结论:当使用直接赋值法产生字符串对象时,JVM会维护一个字符串的常量池,若对象在堆中还不存在,则产生一个新的字符串对象加入字符串的常量池中
当继续使用直接赋值法产生字符对象时,JVM发现该引用指向的内容在常量池中已经存在了,此时不在新建字符串对象,而是复用已有对象。
大多数"池"—— 都是共享设计模式的思想,目的是为了节省空间,节约资源
内存图
String类提供的intern方法
源码如下:
public native String intern();
用法:
调用intern方法会将当前字符串引用指向的对象保存到字符串常量池中。
- 若当前常量池中已经存在了该对象,则不在产生新的对象,返回常量池中的String对象地址
- 若当前常量池中不存在该对象,则将该对象入池,返回入池后的地址。
一道考试题
public static void main(String[] args) {
String str1 = new String("hello"); //1
str1.intern(); //2
String str2 = "hello"; //3
System.out.println(str1 == str2); //4
}
输出:
false
- new一个对象,在堆中产生一块空间。hello是字符串字面量,也是一个对象,便在常量池中存放一份。str1指向的是堆内存中的hello,而不是常量池中的hello
- 由于常量池中已经存在hello对象,则不再产生新的对象。
- str2指向的是常量池中的hello
- 两个不是一个地址,所以返回false
如何让结果返回true呢?
public static void main(String[] args) {
String str1 = new String("hello"); //1
str1 = str1.intern(); //2
String str2 = "hello"; //3
System.out.println(str1 == str2); //4
}
输出:
true
当常量池中已经存在hello时,代码2会返回常量池中的String对象地址,被str1接收,所以str1也指向了常量池中的hello。结果返回true。
再看一道题
public static void main(String[] args) {
char[] data = new char[]{'a', 'b', 'c'};
String str1 = new String(data);
str1.intern();
String str2 = "abc";
System.out.println(str1 == str2);
}
输出:
true
字符数组data在堆中开辟空间。若当前常量池中不存在该对象,则将该对象入池,返回入池后的地址。str2发现常量池中已有“abc”,直接复用。结果就相等。
内存图
五、字符串的不可变性字符串不可变指的是字符串的内容不可变。字符串对象一旦产生并赋值就不能改其内容。而字符串引用是可变的,它可以按需指向各个字符串。
六、修改字符串内容 6.1 通过反射破坏数组的封装(了解,不推荐)提问:为什么字符串对象内容无法修改而其他类的对象可以修改内容?
因为字符串实际上时一个字符数组,字符串保存的值是实在数字中保存的。以下是String源码
//The value is used for character storage. private final char value[];
他是一个私有权限,对外部隐藏,并且没有提供getter和setter方法,外部拿不到value数组,所以字符串的内容无法修改。
public class StringChange {
public static void main(String[] args) throws Exception {
String str = "hello";
Class<String> cls = String.class;
//获取value成员属性
Field field = cls.getDeclaredField("value");
//设置成可更改的,破坏封装
field.setAccessible(true);
//在String类外部通过反射拿到value数组
char[] value = (char[]) field.get(str);
value[0] = 'H';
System.out.println(str);
}
}
输出:
Hello
6.2 使用StringBuilder或StringBuffer类(重点)
若需要经常使用字符串的拼接,使用StringBuilder类的append方法。
这个类可以修改字符串对象的内容。
StringBuilder和StringBuffer的使用方法完全一样
StringBuilder类目的是为了解决字符串拼接的问题。StringBuilder类的对象是可以修改内容的。
StringBuilder和String时两个独立的类
StringBuilder类和String类的转换
- StringBuilder -> String : 调用这个类的toString方法
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
stringBuilder.append("world");
//修改成String类型
String str = stringBuilder.toString();
System.out.println(str);
//查看数据类型
System.out.println(str.getClass().getName());
}
输出:
helloworld
java.lang.String
利用StringBuilder的toSting方法将其转换成Sting类型
- String -> StringBuilder: 使用StringBuilder的构造方法或者append方法
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello"); //1
stringBuilder.append("world"); //2
System.out.println(stringBuilder);
//查看数据类型
System.out.println(stringBuilder.getClass().getName());
}
输出:
helloworld
java.lang.StringBuilder
1 将hello字符串字面量转换成StringBuilder类
2 将world字符串字面量转换成StringBuilder类
StringBuilder的常用方法
- 字符串的反转:reverse()
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("hello");
stringBuilder.append("world");
System.out.println(stringBuilder);
stringBuilder.reverse();
String str = stringBuilder.toString();
System.out.println(str);
}
输出:
helloworld
dlrowolleh
- 字符串添加:append()
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("hello");
stringBuilder.append("world");
System.out.println(stringBuilder);
}
输出:
helloworld
- 删除指定范围的字符:delete(int start,int end)——左闭右开区间
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("hello");
stringBuilder.append("world");
stringBuilder.delete(5,10);
System.out.println(stringBuilder);
}
输出:
hello
- 字符串插入:insert(int start,value)
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("hello");
stringBuilder.append("world");
//在索引为5的位置插入28
stringBuilder.insert(5,28);
System.out.println(stringBuilder);
}
输出
hello28world
StringBuilder,StringBuffer和String类的区别
- String的对象无法修改,其他两个对象内容可以修改
- StringBuffer是线程安全的 *** 作,性能较差;StringBuilder是线程不安全的 *** 作,性能较高。
String类的所有针对字符串的 *** 作方法都不会修改原字符串,而是产生了一个新的字符串
7.1 字符串的比较方法名称 | 作用 |
---|---|
public boolean equals(Object anObject) | 区分大小写的比较 |
public boolean equalsIgnoreCase(String anotherString) | 不区分大小写的比较 |
public int compareTo(String anotherString) | 比较两个字符串大小的关系 |
String实现了Comparable这个接口,覆写了compareTo方法,返回ASCII码的差值
按照“字典序”排列字符串,就是按照字符串的ASCII码大小排序
public static void main(String[] args) {
String str1 = "abc";
String str2 = "Abc";
System.out.println(str1.compareTo(str2));
}
输出:
32
7.2 字符和字符串的相互转换(重要)
方法名称 | 作用 |
---|---|
public Sting(char value[]) | 将字符数组中的所有内容变为字符串 |
public String(char value[], int offest, int count) | 将部分字符数组中的内容变为字符串 |
public char charAt(int index) | 取得指定索引位置,从索引0开始 |
public char[] toCharArray() | 将字符串变为字符数组返回 |
字符数组转换为字符串,通过String类的构造方法
public static void main(String[] args) {
char[] data = new char[]{'a','b','c'};
String str = new String(data);//全部转换
String str1 = new String(data,1,2);//部分转换
System.out.println(str);
System.out.println(str1);
}
输出:
abc
bc
字符串转为字符数组的两种方式
public static void main(String[] args) {
String str = "hello";
//取出字符串中索引为1位置的值
char ch = str.charAt(1);
System.out.println(ch);
//将字符串转为字符数组
char[] data = str.toCharArray();
data[0] = 'H';
System.out.println(data);
System.out.println(str);
}
输出:
e
Hello
hello
修改字符数组中值对原字符串无影响。这里是产生了一个新的字符数组,将字符串的内容复制到字符数组中。字符串不可变性
一个小题目:如何判断一个输入的字符串是由纯数字组成,若是返回true,不是返回false
public boolean isNumber(String str) {
//将字符串转为字符数组
char[] data = str.toCharArray();
//循环遍历字符数组,找反例
for (char c : data) {
if (c < '0' || c > '9'){
return false;
}
}
return true;
}
7.3 字节与字符串的相互转换
方法名称 | 作用 |
---|---|
public String(byte byte[]) | 将字节数组变为字符串 |
public String(byte bytes[],int offest,int length) | 将部分字节数组中的内容变为字符串 |
public byte[] getBytes() | 将字符串以字节数组的形式返回 |
public byte[] getBytes(String charsetName) throws UnsupportedEncondingException | 编码转换 |
字节数组转字符串调用字符串的构造方法就可以,与字符数组转字符串类似。
按照ASCII码值转为字符串
public static void main(String[] args) {
byte[] data = new byte[]{97,98,99};
String str = new String(data);//全部转换
System.out.println(str);
String str1 = new String(data,1,2);//部分转换
System.out.println(str1);
}
字符串转为字节数组
- 按照当前默认的字符编码转为字节数组
- 按照指定的编码格式转为字节数组
public void main(String[] args){
String str = "你好";
byte[] data = str.getBytes(); //默认编码
byte[] data1 = str.getBytes("gbk"); //指定编码
System.out.println(Arrays.toString(data));
System.out.println(Arrays.toString(data1));
}
输出:
[-28, -67, -96, -27, -91, -67]
[-60, -29, -70, -61]
7.4 字符串的查找
方法名称 | 作用 |
---|---|
public boolean contains(CharSquence s) | 判断一个子字符串是否存在 |
public boolean startsWith(String prefix, int toffset) | 从指定位置开始判断是否以指定字符串开头 |
public boolean endsWith(String suffix) | 判断是否以指定字符串结尾 |
public static void main(String[] args) {
String str = "hello world";
//判断是否包含字串
System.out.println(str.contains("world"));
//是否以指定字符串开头
System.out.println(str.startsWith("hello"));
System.out.println(str.startsWith("hello1"));
//是否以指定字符串结尾
System.out.println(str.endsWith("world"));
System.out.println(str.endsWith("world1"));
}
输出:
true
true
false
true
false
7.5字符串替换 *** 作
public static void main(String[] args) {
String str = "helloworld";
//替换所有的指定内容
System.out.println(str.replaceAll("l","_"));
//替换首个内容
System.out.println(str.replaceFirst("l","_"));
System.out.println(str);
}
输出:
he__owor_d
he_loworld
helloworld
7.6 字符串的拆分 *** 作
public static void main(String[] args) {
String str = "Hello world Hello you";
//按照"_"拆封字符串
String[] data1 = str.split("-");
System.out.println(Arrays.toString(data1));
System.out.println(data1.length);
// 按照空格将str拆分,拆分后的字符串数组长度为2
String[] data2 = str.split(" ",2);
System.out.println(Arrays.toString(data1));
System.out.println(Arrays.toString(data2));
System.out.println(data2.length);
}
输出:
[Hello world Hello you]
1
[Hello world Hello you]
[Hello, world Hello you]
2
当按照指定的格式分割字符串得到了一个空数组,说明这个格式是特殊字符,需要转义处理
public static void main(String[] args) {
String str = "192.168.1.1";
String[] data = str.split("\.");
System.out.println(Arrays.toString(data));
}
输出:
[192, 168, 1, 1]
当指定的拆分格式在原字符串中不存在,就会输出原字符串
public static void main(String[] args) {
String str = "Hello,Wolrld";
String[] data = str.split("-");//不存在
System.out.println(Arrays.toString(data));
}
输出:
[Hello,Wolrld]
7.7 字符串截取
方法名称 | 描述 |
---|---|
public String substring(int beginIndex) | 从指定索引截取到结尾 |
public String subSting(int beginIndex,int endIndex) | 截取部分内容 |
public static void main(String[] args) {
String str = "HelloWolrd";
System.out.println(str.substring(5));
//前闭后开区间
System.out.println(str.substring(0,5));
}
输出:
Wolrd
Hello
7.8 其他 *** 作
方法名称 | 描述 |
---|---|
public String trim() | 去掉字符串中的左右空格,保留中间空格 |
public String toUpperCase() | 字符串转大写 |
public String toLowerCase() | 字符串转小写 |
public int length() | 取得字符串的长度 |
public boolean isEmpty() | 判断是否为空字符串,但不是null,只能判断长度是否为0 |
public static void main(String[] args) {
String str = " hello world ";
// 只会去掉str的左右空格,保留中间的空格
System.out.println(str.trim());
System.out.println(str.toUpperCase());
System.out.println("HELLO".toLowerCase());
// 5
System.out.println("hello".length());
}
输出:
hello world
HELLO WORLD
hello
5
写一个方法将字符串首字母大写
public static String firstUpper(String str) {
//判空
if (str == null || str.isEmpty()){
return null;
}
//字符串只有一个元素
if (str.length() == 1){
return str.toUpperCase();
}
//截取 + 大写
return str.substring(0,1).toUpperCase();
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)