String类
源于Java中的一个类java.lang.String
- String类表示字符串类型,属于引用类型,不属于基本类型
- Java中用双引号括起来的都是String类的对象
- Java中String类对象用双引号括起来的均为不可变对象,其中的字符串都是不能改变的
- jdk规定用双引号括起来的字符串对象都是存储在方法区的常量池当中的,但是通过构造方法创建字符串对象的时候,就不是在常量池中了,new对象产生的对象是在堆中
我们先看看内存中的字符串对象的存在形式:
String s1="abcdef";
s1是一个对象的引用变量地址,“abcdef”是一个字符串对象
当我们进行字符串的拼接操作时,原来的字符串对象是不可以改变的,改变的是新产生的新的字符串,重新将字符串对象的地址赋给引用变量
String s2=s1+"xy";
当我们new String()的时候,在堆内存中开辟空间
String s3=new String(“xy”);
但是我们说过,直接双引号括起的字符串是在常量池中的,不可以改变的,但是我们new出来的对象实在堆中的,所以:
String s3是指向了堆中存在的对象,保存它的引用地址
我们需要注意”abcdef” “xy” “abcdefxy”在方法区的常量池中每个字符串只有一个,因为字符串的值是不可改变的,可以改变的是变量地址的指向,也就是说s1,s2,s3的指向可以改变,但是不代表字符串的值可以改变
String类的构造方法(简单的罗列几个常用的,剩下的很多看文档吧)
String s1=new String("hello");
String s2="hello";
String s3=new String(new byte[]{97,98,99});
String s4=new String(new char[]{'a','b','c'});
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
String的方法:
String str=new String("abcde");
//charAt 根据索引返回字符 从零开始
System.out.println(str.charAt(3)); //d
//contains方法,判断源字符串中是否包含传入的参数字符串
System.out.println(str.contains("de"));//true
System.out.println(str.contains("ed"));//false
//endsWith方法判断是否以规定的字符串结尾
System.out.println(str.endsWith("de"));//true
System.out.println(str.endsWith("ed"));//false
=====================================================================================
//比较两个字符串相等 不应使用== 应该用equals方法
System.out.println("abc".equals("abc"));//true
System.out.println("abc"=="abc");//true
System.out.println("abc".equals("bca"));//false
System.out.println("abc".equals("a"));//false
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2));//true
可以看出,我们new 对象的时候 尽管我们构造字符串时候的传入“abc“是相同的,但是我们new出来的对象地址是不一样的,不是同一个对象,然而我们希望相同字符串的对象应该是相等的,所以我们只能用equals比较两个字符串是否内容相等,我们使用==只能比较两个字符串对象的引用地址是否相同但是无法比较两个字符串的内容
compareTo方法
返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的ASCII差值,如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方结束。
• 如果参数字符串等于此字符串,则返回值 0;
• 如果此字符串小于字符串参数,则返回一个小于 0 的值;
• 如果此字符串大于字符串参数,则返回一个大于 0 的值。
• 参数字符串是调用字符串的前缀的话,则返回长度差值
String str="abcd";
String str2="abc";
String str3="bc";
System.out.println(str.compareTo(str2)); //1 是前缀返回字符串的两个长度差
System.out.println(str.compareTo("abcd")); //0 完全匹配
System.out.println(str.compareTo(str3)); //-1 非前缀 第一个字符就不同 返回两字符的差值
System.out.println(str2.compareTo(str3)); //-1 非前缀从开始字符比较 不同返回ASCII的差值
equalsIgnoreCase方法:
String str="abcd";
//忽略大小写比较字符串是否相等
System.out.println(str.equalsIgnoreCase("AbcD"));//true
getBytes方法 将字符串转为byte数组
String str="abcd";
byte[] s=str.getBytes();
for (int i = 0; i < s.length; i++) {
System.out.println(s[i]);
}
indexOf方法
判断子字符串或者字符在当前字符串中第一次出现的索引
String str="abcd";
System.out.println(str.indexOf("bc")); //1
System.out.println(str.indexOf("b")); //1
System.out.println(str.indexOf('b')); //1
isEmpty方法
判断字符串是否为空 空格也算字符串的一部分
只包含空格的串 不等同于空串
空串什么都没有 没有空格
仅仅包含空格的串不是空串
String str=" ";
System.out.println(str.isEmpty()); //false
String str2="";
System.out.println(str2.isEmpty());//true
length方法
注意面试重点:
数组的长度length和字符串的length不同
数组长度length属性
字符串获取长度 length()方法
String s1="abc";
System.out.println(s1.length()); //3
int[] arr=new int[]{1,2,3};
System.out.println(arr.length); //3
replace方法
替换源字符串中的某些字符
String str="baidu.con";
String s = str.replace("baidu", "love");
System.out.println(str); //baidu.con
System.out.println(s); //love.con
substring方法
截取子串
当我们传入一个参数的时候,默认从该索引处截取到最后
传入两个参数,左闭右开从开始索引到结束索引-1的位置处
String str="baidu.con";
System.out.println(str.substring(3,5)); //du 截取索引3开始4结束不包括5索引处的字符
System.out.println(str.substring(3)); //du.con
toCharArray()方法
将字符串转为char型数组
public static void main(String[] args) {
String str="baidu.con";
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
}
字符串大小写转换 toLowerCase toUpperCase
String str="baidu.con";
String up = str.toUpperCase();
System.out.println(up);
String low = up.toLowerCase();
System.out.println(low);
trim去除前后空格
String str=" baidu.con ";
String s = str.trim();
System.out.println(s);
System.out.println(str);
结果:
ValueOf将非字符串转为字符串
valueOf是String类的静态方法,直接类名调用就可
public static void main(String[] args) {
String s = String.valueOf(true);
System.out.println(s);
//我们输出其所属类名
System.out.println(s.getClass().getName());
}
结果:
下面我们来研究一下这个String.valueOf方法:
首先我们看一下各种参数的Stirng.valueOf的源码
我们从源码中可以看出来所有的传入参数最终都是转为类的toString 方法转为字符串。
也就是说我们传入参数后所有的参数都以变成字符串类型返回.
当我们传入一个对象的时候
import java.util.Arrays;
import java.util.Stack;
class person{
private String name;
int age;
public person() { }
public person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class stringArgs {
public static void main(String[] args) {
String s = String.valueOf(new person("xiaohong",12));
System.out.println(s);
}
}
我们重写了person类的toString 方法,当我们调用String.valueOf的时候传入一个对象作为参数我们可以看源代码
底层中自动调用了该对象的toString方法转为字符串,但是我们当删除掉person类的toString 方法时,我们可以看到结果:
输出的是object类的默认toString方法的返回,是对象的类名@内存地址的形式返回,所以当我们在自定义的类中重写toString方法时,底层转为字符串对象的时候才会调用重写的toString否则调用的永远是Object类的tostring方法
我们再来研究一下这个System.out.println(s);
当我们给println方法的参数传入一个对象的时候,会自动调用valueOf方法,但是我们从上面可以看到,而valueOf又会在源码中看到:
valueof方法会自动调用toString方法,最终返回的是传入的对象参数的toString方法,所以当我们System.out.println(s);进行控制台输出的时候,一切都是转为字符串的形式进行的输出
即:我们从控制台输出的一切内容都是转化为字符串的形式进行输出的