String类

认识String类

在C语言中已经涉及到了字符串,但是在C语言中要表示字符串只能使用字符数组或者字符指针,而在Java中String是字符串类型,在C语言当中是没有字符串类型的,String类型是一种引用数据类型,内部并不存储字符串本身。java当中没有说字符串结尾是\0的说法,C语言之所以有这种说法,是因为C需要用这个字符去判断结尾。

String类的基本用法

字符串构造

String类提供的构造方式非常多,常用的有以下三种:

public class Test {
    public static void main(String[] args) {
        //使用常量串构造
        String s1 = "onward and upward";
        System.out.println(s1);

        //直接new String对象
        String s2 = new String("onward and upward");
        System.out.println(s2);

        //使用字符数组进行构造
        char[] array = {'o','n','w','a','r','d'};
        String s3 = new String(array);
        System.out.println(s3);
    }
    //结果为:
    //onward and upward
    //onward and upward
    //onward
}

注意:

  1. String类型是引用类型,内部并不存储字符本身,在String类的实现源码中,String类实例变量如下:
    在这里插入图片描述
public class Test {
    public static void main(String[] args) {
        //s1和s2引用的是不同对象,s1和s3引用的是同一对象
        String s1 = "hello";
        String s2 = new String("World");
        String s3 = s1;

        System.out.println(s1.length());    //获取字符串长度,长度为5
        System.out.println(s1.isEmpty());   //如果字符串长度为0,则返回true,否则返回false
    }
}

在这里插入图片描述

  1. 在java中用""引起来的也是String类型对象。
public class Test {
    public static void main(String[] args) {
        System.out.println("hello".length());    //获取字符串长度,长度为5
    }
}

String对象的比较

字符串的比较是常见的操作之一,比如字符串排序,java中总共提供了4种方式:

  1. == 比较是否引用同一个对象
    注意:对于内置类型, == 比较的是变量中的值;对于引用类型==比较的是引用中的地址。
public class Test {
    public static void main(String[] args) {
        //对于基本类型变量,==比较的是两个变量中存储的值是否相同
        int a = 10;
        int b = 20;
        int c = 10;
        System.out.println(a == b);
        System.out.println(a == c);

        //对于引用数据类型,==比较的是两个引用变量引用的是否为同一个对象
        String s1 = new String("onward and upward");
        String s2 = new String("onward and upward");
        String s3 = new String("never give up");
        String s4 = s1;
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s1 == s4);
    }
    //结果为:
    //false
    //true
    //false
    //false
    //true
}
  1. boolean equals(Object anObject)方法:按照字典序比较
    字典序:字符大小的顺序
    String类重写了Object中的equals方法,Object中的equals默认按照==比较,string重写equals方法后,按照如下规则进行比较:
public boolean equals(Object anObject) {
        //1.先检测this和anObject是否为同一个对象比较,如果是返回true
        if(this == anObject){
            return true;
        }

        //2.检测anObject是否为String类型的对象,如果是则继续比较,否则返回false
        if(anObject instanceof String){
            //将anObject向下转型为String类型对象
            String anotherString = (String)anObject;
            int n = value.length();

            //3.this 和 anObject 两个字符串的长度是否相同,是继续比较,否则返回false
            if(n == anotherString.value.length){
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;

                //4.按照字典顺序,从前往后逐个字符进行比较
                while(n-- != 0){
                    if(v1[i] != v2[i]){
                        return false;
                    }
                    i++;
                }
                return true;
            }
        }
        return false;
    }
public class Test {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("Hello");

        //s1,s2,s3 引用的是三个不同的对象,因此 == 比较结果全为false
        System.out.println(s1 == s2);   //false
        System.out.println(s1 == s3);   //false
        System.out.println(s2 == s3);   //false

        //equals比较:String对象中的逐个字符
        //虽然s1与s2引用的是不同的对象,但是两个对象放置的内容相同,因此输出true
        //s1与s3引用的是不同的对象,而且两个对象中的内容不同,因此输出false
        System.out.println(s1.equals(s2));  //true
        System.out.println(s1.equals(s3));  //false
    }
}
  1. int compareTo(String s)方法:按字典序进行比较
    与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型,具体比较方式:
  • 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
  • 如果前k个字符相等(k为两个字符串长度的最小值),返回值两个字符串长度的差值
public class Test {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abcdf");
        String s4 = new String("abc");

        System.out.println(s1.compareTo(s2));   //不同输出字符差值为 -1
        System.out.println(s1.compareTo(s3));   //前个k个字符完全相同,输出长度差值 -2
        System.out.println(s1.compareTo(s4));   //相同输出 0
    }
}
  1. int compareToIngoreCase(String str)方法:与compareTo方式相同,但是忽略大小写比较
public class Test {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abcdf");
        String s4 = new String("Abc");

        System.out.println(s1.compareTo(s2));   //不同输出字符差值为 -1
        System.out.println(s1.compareTo(s3));   //前个k个字符完全相同,输出长度差值 -2
        System.out.println(s1.compareTo(s4));   //大小写不相同输出 32

        System.out.println(s1.compareToIgnoreCase(s2));   //不同输出字符差值为 -1
        System.out.println(s1.compareToIgnoreCase(s3));   //前个k个字符完全相同,输出长度差值 -2
        System.out.println(s1.compareToIgnoreCase(s4));   //忽略大小写,相同输出 0
    }
}

字符串查找

字符串查找也是字符串中非常常见的操作,String类提供的常用查找方法是:

方法功能
char charAt(int index)返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
int indexOf(int ch)返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, intfromIndex)从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str)返回str第一次出现的位置,没有返回-1
int indexOf(String str, int fromIndex)从fromIndex位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf(int ch)从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex))从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
int lastIndexOf(String str))从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int fromIndex)从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1
public class Test {
    public static void main(String[] args) {
        String s = new String("never give up");
        System.out.println(s.charAt(3));            //'e'
        System.out.println(s.indexOf('e'));         // 1
        System.out.println(s.indexOf('e',5));       // 9
        System.out.println(s.indexOf("ve"));        // 2
        System.out.println(s.indexOf("ve",5));      // 8
        System.out.println(s.lastIndexOf('e'));     // 9
        System.out.println(s.lastIndexOf('e',5));   // 3
        System.out.println(s.lastIndexOf("ve"));    // 8
        System.out.println(s.lastIndexOf("ve",5));  // 2
    }
}

转化

  1. 数值和字符串转化
    序列化:把对象变成字符串
    反序列化:把字符串变成对象
public class Test {
    public static void main(String[] args) {
        //数值转字符串
        String s1 = String.valueOf(1234);
        String s2 = String.valueOf(12.34);
        String s3 = String.valueOf(true);
        String s4 = String.valueOf(new Student("张三",18));
        System.out.println(s1);     //1234
        System.out.println(s2);     //12.34
        System.out.println(s3);     //true
        System.out.println(s4);     //Student@41629346,若要输出具体内容,需要在Student类中重写toString方法

        //字符串转数字
        //注意:Integer、Double是java中的包装类型
        int data1 = Integer.parseInt("1234");
        double data2 = Double.parseDouble("12.34");
        System.out.println(data1);  //1234
        System.out.println(data2);  //12.34
    }
}
  1. 大小写转换
public class Test {
    public static void main(String[] args) {
        String s1 = new String("forward");
        String s2 = new String("FORWARD");
        //小写转大写
        System.out.println(s1.toUpperCase());   //FORWARD
        //大写转小写
        System.out.println(s2.toLowerCase());   //forward
    }
}
  1. 字符串转数组
public class Test {
    public static void main(String[] args) {
        String s = "onward";
        //字符串转数组
        char[] ch = s.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            System.out.print(ch[i]);
        }
        System.out.println("");
        //数组转字符串
        String s2 = new String(ch);
        System.out.println(s2);
    }
    //结果为:
    //onward
    //onward
}
  1. 格式化
public class Test {
    public static void main(String[] args) {
        String s = String.format("%d-%d-%d",2024,9,9);
        System.out.println(s);      //2024-9-9
    }
}

字符串替换

使用一个指定的新的字符串替换已有的字符串数据,可用的方法如下:

方法功能
String replaceAll(String regex, String replacement)替换所有的指定内容
String replaceFirst(String regex, String replacement)替换首个内容
public class Test {
    public static void main(String[] args) {
        String s = new String("never give up");
        System.out.println(s.replaceAll("e","-"));      //n-v-r giv- up
        System.out.println(s.replaceFirst("e","-"));    //n-ver give up
    }
}

字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
可以用的方法如下:

方法功能
String[] split(String regex)将字符串全部拆分
String[] split(String regex, int limit)将字符串以指定的格式,拆分为limit组
public class Test {
    public static void main(String[] args) {
        String s = new String("onward and upward never give up");
        String[] result = s.split(" ");
        for(String str : result){
            System.out.println(str);
        }
    }
    //结果为:
    //onward
    //and
    //upward
    //never
    //give
    //up
}
public class Test {
    public static void main(String[] args) {
        String s = new String("onward and upward never give up");
        String[] result = s.split(" ",4);
        for(String str : result){
            System.out.println(str);
        }
    }
    //结果为:
    //onward
    //and
    //upward
    //never give up
}

拆分是特别常用的操作,还有些特殊字符作为分隔符可能无法区分,需要加上转义。
例如:拆分IP地址

public class Test {
    public static void main(String[] args) {
        String s = new String("192.168.1.1");
        String[] result = s.split("\\.");
        for(String str : result){
            System.out.println(str);
        }
    }
    //结果为:
    //192
    //168
    //1
    //1
}

注意:

  • 字符 “|” , “*” , “+” 都得加上转义字符,前面加上"\\"
  • 而如果是 ‘\’,那么就得写成’\\\\’
  • 如果一个字符串中有多个分隔符,可以用“|”作为连字符
public class Test {
    public static void main(String[] args) {
        String s = new String("name=zhangsan&&age=18");
        String[] result = s.split("=|&&");
        for(String str : result){
            System.out.println(str);
        }
    }
    //结果为:
    //name
    //zhangsan
    //age
    //18
}
public class Test {
    public static void main(String[] args) {
        String s = new String("name=zhangsan&&age=18");
        String[] result = s.split("&&");
        for (int i = 0; i < result.length; i++) {
            String[] temp = result[i].split("=");
            System.out.println(temp[0] + "=" + temp[1]);
        }
    }
    //结果为:
    //name=zhangsan
    //age=18
}

字符串截取

从一个完整的字符串之中截取部分内容,可用方法:

方法功能
String substring(int beginIndex)从指定索引截取到结尾
String substring(int beginIndex, int endIndex)截取部分内容
public class Test {
    public static void main(String[] args) {
        String s = new String("never give up");
        System.out.println(s.substring(5));
        System.out.println(s.substring(0,5));
        //结果为:
        // give up
        //never
    }
}

注意:

  • 索引从0开始
  • 注意前闭后开,substring(0,5)表示包含0号下标的字符,不包含5号下标。

其他操作方法

方法功能
String trim()去掉字符串中的左右空格,保留中间空格
String toUpperCase()字符串转大写
String toLowerCase()字符串转小写
public class Test {
    public static void main(String[] args) {
        String s = "   onward and upward   ";
        System.out.println("[" + s + "]");
        System.out.println("[" + s.trim() + "]");
    }
    //结果为:
    //[   onward and upward   ]
    //[onward and upward]
}

trim()会去掉字符串开头和结尾的空白字符(空格,制表符,换行符)

public class Test {
    public static void main(String[] args) {
        String s = "永不言弃 never give up";
        System.out.println(s.toUpperCase());
        System.out.println(s.toLowerCase());

    }
    //结果为:
    //永不言弃 NEVER GIVE UP
    //永不言弃 never give up
}

这两个函数只转换字母

字符串的不可变性

String是一种不可变对象,字符串中的内容是不可改变的,字符串不可被修改,是因为:

  1. String类在设计时就是不可改变的,String类实现描述中已说明了
    在这里插入图片描述
    Strings是不可改变的,它们的内容在创建好之后就不能被修改。
    在这里插入图片描述
    String类中的实际字符保存在内部维护的value字符数组中,该图可以看出:
  • String类被final修饰,表明该类不能被继承
  • value被final修饰,表明value自身的值不能被修改,既不能引用其他字符数组,但是其引用空间中的内容可以被修改。
  • 但是因为这个数组是被private修饰的,所以在类外是不可以使用和修改的。
public class Test {
    public static void main(String[] args) {
        final int[] array = {1,2,3,4,5};
        array[0] = 2;
        System.out.println(Arrays.toString(array));
        //array = new int[]{10,20,30,40,50};    //编译报错,无法为最终变量array分配值
    }
    //结果为:
    //[2, 2, 3, 4, 5]
}
  1. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

为什么String要设计成不可变的

  • 方便实现字符串对象池,如果String可变,那么对象池就需要考虑写时拷贝的问题
  • 不可变对象是线程安全的
  • 不可变对象更方便缓存 hash code,作为 key时可以更高效的保存到HashMap中

字符串修改

尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新的对象,效率非常低下。

public class Test {
    public static void main(String[] args) {
        String s = "hello";
        s += " world";
        System.out.println(s);  //hello world
    }
}

这种方式不推荐使用,因为其效率非常低,中间创建了好多临时对象。所以可以借助StringBuffer和StringBuilder来修改。

StringBuffer和StringBuilder

由于String的不可更改性,为了方便字符串的修改,java中又提供了StringBuffer和StringBuilder类,这两个类大部分功能是相同的,我们先了解StringBuilder类的一些方法,其他若需要可以参阅链接: StringBuilder在线文档

方法功能
StringBuff append(String str)在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量
char charAt(int index)获取index位置的字符
int length()获取字符串的长度
int capacity()获取底层保存字符串空间总的大小
void ensureCapacity(int mininmumCapacity)扩容
void setCharAt(int index,char ch)将index位置的字符设置为ch
int indexOf(String str)返回str第一次出现的位置
int indexOf(String str, int fromIndex)从fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str)返回最后一次出现str的位置
int lastIndexOf(String str,int fromIndex)从fromIndex位置开始找str最后一次出现的位置
StringBuff insert(intoffset, String str)在offset位置插入:八种基类类型 & String类型 & Object类型数据
StringBuffer deleteCharAt(int index)删除index位置字符
StringBuffer replace(int start, int end, String str)将[start, end)位置的字符替换为str
String substring(int start)从start开始一直到末尾的字符以String的方式返回
String substring(int start,int end)将[start, end)范围内的字符以String的方式返回
StringBuffer reverse()反转字符串
String toString()将所有字符按照String的方式返回
public class Test {
    public static void main(String[] args) {
        StringBuilder sb1 = new StringBuilder("hello");
        StringBuilder sb2 = sb1;
        //追加:即尾插->字符、字符串、整型数字
        sb1.append(' ');    //hello
        sb1.append("world");    //hello world
        sb1.append(123);    //hello world123
        System.out.println(sb1);    //hello world123
        System.out.println(sb1 == sb2); //true
        System.out.println(sb1.charAt(0));  //获取0号位上的字符 h
        System.out.println(sb1.length());   //获取字符串的有效长度 14
        System.out.println(sb1.capacity()); //获取底层数组的总大小
        sb1.setCharAt(0,'H');   //设置指定位置的字符 Hello world123
        sb1.insert(14," never give up hello"); //在任意位置插入,Hello world123 never give up hello
        System.out.println(sb1);
        System.out.println(sb1.indexOf("Hello"));   //获取Hello第一次出现的位置 0
        System.out.println(sb1.lastIndexOf("hello"));   //获取hello最后一次出现的位置 29
        sb1.deleteCharAt(0);    //删除首字符 
        System.out.println(sb1);    //ello world123 never give up hello
        sb1.delete(0,5);    //删除[0,5)范围内的字符
        System.out.println(sb1);    //world123 never give up hello

        String str = sb1.substring(0,5);    //截取[0,5)区间中的字符以String的方式返回
        System.out.println(str);    //world
        sb1.reverse();  //字符串逆转
        str = sb1.toString();   //将StringBuilder以String的方式返回
        System.out.println(str);    //olleh pu evig reven 321dlrow
    }
}

上述例子我们可以看出String和StringBuilder的最大区别是String的内容无法修改,而StringBulider的内容可以修改,频繁修改字符串的情况可以考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换,如果要想互相转换,可以采用如下原则:

  • String变为StringBuilder:利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String:调用toString()方法

思考:String、StringBuilder、StringBuffer的区别?

  • String的内容不可以修改,StringBuilder和StringBuffer的内容可以修改
  • StringBuffer与StringBuilder的大部分功能是相似的
  • StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。

String类oj

  1. 第一个只出现的字符
    给定一个字符串 s ,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
    示例 :
    输入: s = “leetcode”
    输出: 0
//通过一个整型数组来记录其次数,题目规定只出现小写字母。所以减掉'a',保证数组长度为26个字母,合理利用空间,遍历整个字符串字符出现一次在数组相应位置加一,最后再次遍历字符串来找第一个在数组中值为1的下标
class Solution {
    public int firstUniqChar(String s) {
        int[] temp = new int[26];
        for (int i = 0; i < s.length(); i++) {
            temp[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < s.length(); i++) {
            if(temp[s.charAt(i) - 'a'] == 1){
                return i;
            }
        }
        return -1;
    }
}
  1. 字符串最后一个单词的长度
    计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)
    示例
    输入:hello nowcoder
    输出:8
    说明:最后一个单词为nowcoder,长度为8
解法1import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        //循环输入
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            //获取一行单词
            String str = in.nextLine();
            //字符串切割然后求长度
            String[] strs = str.split(" ");
            int result = strs[strs.length - 1].length();
            System.out.println(result);
        }
    }
}
解法2import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        //循环输入
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            //获取一行单词
            String str = in.nextLine();
            //1.找到最后一个空格
            int index = str.lastIndexOf(" ");
            
            //2.获取最后一个单词:从最后一个空格位置+1开始,一直截取到结尾
            String lastStr = str.substring(index + 1);
            
            //3.打印最后一个单词的长度
            System.out.println(lastStr.length());
        }
    }
}
  1. 验证回文串
    如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个回文串 。
    字母和数字都属于字母数字字符。
    给你一个字符串 s,如果它是回文串 ,返回 true ;否则,返回 false 。
    示例 :
    输入: s = “A man, a plan, a canal: Panama”
    输出:true
    解释:“amanaplanacanalpanama” 是回文串。
class Solution {
    //判断字符是否是字母或数字
    public boolean isNumAndCharacter(char ch){
        if(Character.isDigit(ch) || Character.isLetter(ch)){
            return true;
        }
        return false;
    }
    public boolean isPalindrome(String s) {
        int left = 0;
        int right = s.length() - 1;
        //将大小写进行统一
        s = s.toLowerCase();
        while(left < right){
        	//从左侧找到第一个有效字符
            while(left < right && !isNumAndCharacter(s.charAt(left))){
                left++;
            }
            //从右侧找到第一个有效字符
            while(left < right && !isNumAndCharacter(s.charAt(right))){
                right--;
            }
            //若相同继续left往后right往前继续进行对比,若不等,则返回false
            if (s.charAt(left) == s.charAt(right)){
                left++;
                right--;
            }else{
                return false;
            }
        }
        //走到最后相遇,还没提前返回false,则是回文,返回true
        return true;
    }
}
  1. 字符串相加
    给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
    你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
    示例 :
    输入:num1 = “11”, num2 = “123”
    输出:“134”
class Solution {
    public String addStrings(String num1, String num2) {
        StringBuilder ret = new StringBuilder();
        int i = num1.length() - 1;
        int j = num2.length() - 1;
        int sum;    //每位的求和
        int carry = 0;  //进位
        while(i >= 0 || j >= 0){
            int addNum1 = (i < 0) ? 0 : num1.charAt(i) - '0';
            int addNum2 = (j < 0) ? 0 : num2.charAt(j) - '0';
            sum = addNum1 + addNum2 + carry;
            carry = sum / 10;
            i--;
            j--;
            ret.append(sum % 10);
        }
        if(carry == 1){
            ret.append(1);
        }
        return ret.reverse().toString();
    }
}

关于String类的内容我们先了解到这,后续我们在继续深入了解和学习,希望这篇文章能对大家有所帮助,共勉!!!

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值