【JavaSE】String类

本文介绍了Java中字符串的基础知识,包括字符串构造方法、长度计算、isEmpty()方法、比较方法如equals()和compareTo(),以及字符串查找、转换、替换和拆分的方法。还详细讲解了String的不可变性,并对比了StringBuilder和StringBuffer的区别,强调了在需要修改字符串时使用StringBuilder的效率优势。
摘要由CSDN通过智能技术生成

目录

前言:

1.1、了解字符串构造方法

1.2、求字符串长度(xxx.length())

1.3、isEmpty()方法

1.4、String对象的比较 

 1.4.1、通过(str1 == str2)来比较,这样比较的是两个引用当中的地址

1.4.2、 boolean equals(Object anObject)方法:比较两个引用所指向的对象里面的内容是否一致

1.4.3、 int compareTo(String s)方法:用来比较两个字符串的大小

 1.4.4、int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写,进行比较

1.5、字符串查找

1.5.1、char  charAt(int index)方法:查找index下标上的字符

1.5.2、int  indexOf(int ch)方法:找字符串中c第一次出现的位置,没有返回-1

 1.5.3、int  indexOf(int ch,int fromIndex)方法:从指定下标(fromIndex)开始查找字符c第一次出现的位置(下标)

1.5.4、 int indexOf(String str)方法:查找字符串中某一串字符串(abcd)出现的位置,返回这个字符串的第一个字母的下标,没有返回-1

 1.5.5、int lastIndexOf(int ch):默认从后往前找,找到返回下标,没找到返回-1

 1.5.6、int lastIndexOf(int ch, int fromIndex)方法:从指定位置(fromIndex)开始找,从后往前字母(a)第一次出现的位置。

1.6、字符串的转换

1.6.1、数字转字符串:xxx.valueOf()

1.6.2、字符串转数字 :Integer.paresInt(str1)

1.6.3、字符串小写转大写:xxx.toUpperCase();

 1.6.4、字符串大写转小写:xxx.toLoweCase();

 1.6.5、字符串转数组:xxx.toCharArray();

 1.6.6、格式化输出

1.7、字符串的替换

1.7.1、替换指定的字母:xxx.replace();

1.7.2、 替换所有指定的内容(xxx.replaceAll)

 1.7.3、替换首个所指的内容(xxx.replaceFirst)

 1.8、字符串的拆分

1.8.1、String[] split(String regex):将字符串全部拆分

1.8.2、 String[] split(String regex, int limit) :将字符串以指定的格式,拆分为limit组

1.8.3、拆分IP地址:有一些特殊字符作为分割符可能无法正常切分,需要加上转义。

1.8.4、多次拆分

 1.9、字符串的截取

1.9.1、String substring(int beginIndex) :从指定位置开始截取所有字符

 1.9.2、String substring(int beginIndex, int endIndex) :截取某个区域内的内容

 1.10、String trim():去掉字符串中的最外侧的空格,保留中间空格

 1.11、字符串的不可变性

 1.12、字符串的修改

2、StringBulider和StringBuffer 

2.1、StringBulider的学习

 2.1.1、StringBuilder类的append方法

 2.1.2、Stringbuilder类当中的方法介绍

 2.2、String、StringBuilder、StringBuffer的区别

2.3、来看一道面试题

2.4、习题


前言:

在c语言中,使用字符串,一般使用字符数组和字符串指针,它没有一个专门的类。而在Java中设计出专门的类,将数据和操作数据的方法放在一个类当中,这样符合Java的面向对象的思想。

🏆创建一个类对最终目的就是实例化对象,所以在学习一个类的时候一定是从它的构造方法开始学起。 


1.1、了解字符串构造方法

String类提供的构造方法有很多,常用的就一下三种:

1️⃣、使用常量串构造

2️⃣、直接newString对象

3️⃣、使用字符数组经行构造

public class Test {
    public static void main(String[] args) {
        //使用常量串构造
        String str1 = "hello";
        System.out.println(str1);
        //直接newString对象
        String str2 = new String("hello");
        System.out.println(str2);
    }
}

String类是引用类型所以这两种写法的本质是一样的区别就是使用常量串简化了直接newString对象。

public class Test {
    public static void main(String[] args) {
        //字符数组
        char[] values = {'a','v','c','d'};
        //这里new String对象,是调用构造方法,将字符数组转化成为字符串。
        String str3 = new String(values);
        System.out.println(str3);
    }
}

 当然,想了解String类更多的构造方法,可以选中String按住Ctrl+点击鼠标左键,然后再点击左下角的Structure,来查看String类的构造方法。

 ❗❗❗【注意】

1、String是引用数据类型,内部并不存储字符串本身,String类有两个成员属性,在创建String类的时候,不论调用有参还是无参构造方法,都会给value属性赋值。

🌈两个成员属性:value  hash

 2、通过调试上述的代码,我们可以看见,字符串结束的时候,并不像C语言一样,使用\0来结束。

 

 上述代码,可以画图理解:


String是一个类,那么就有很多方法,那么现在来了解一下他的方法

1.2、求字符串长度(xxx.length())

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        System.out.println(str1.length());
        //通过调用String类当中的lenght()方法,就可以求出字符串的长度
    }

 相比于数组求长度(array.length)

public class Test {
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        System.out.println(array.length);
}

💥字符串求长度调用的是length()方法,而数组求长度调用的类似于一个属性(array.length),所以在使用的时候要分清是否要加()


1.3、isEmpty()方法

表示判断引用所指向的对象里面的字符串长度是否为0,是,返回true,不是,返回false。

public class Test {
    public static void main(String[] args) {
    String str2 = "";
    System.out.println(str2.length());//0
    //下面两个isEmpty表示的空,是字符串长度为空
    System.out.println(str2.isEmpty());//true
    //null:表示str3指向的引用为空,表示str3不指向任何对象
    String str3 = null;
}

❗❗❗注意:

在Java中“”引起来的也是String类型的对象

// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());

在调用上述两个方法时,一定是一个字符串类型,不一定是一个变量,它也可以是一个常量


1.4、String对象的比较 

字符串的比较有两种情况:

1️⃣相不相同

2️⃣大小

 1.4.1、通过(str1 == str2)来比较,这样比较的是两个引用当中的地址

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "abcd";
        System.out.println(str1 == str2);
        //比较的是两个引用当中的地址,结果一定是错的
    }

1.4.2、 boolean equals(Object anObject)方法:比较两个引用所指向的对象里面的内容是否一致

public class Test {
    public static void main(String[] args) {
        String str1 =  new String("hello");
        String str2 =  new String("hello");
        System.out.println(str1.equals(str2));
    }

✨拓展:equals也可以忽略大小写进行比较内容是否一致

public class Test {   
    public static void main(String[] args) {
        String str1 =  new String("HEllo");
        String str2 =  new String("hello");
        //忽略大小写进行比较内容是否一致,返回true或false
        System.out.println(str1.equalsIgnoreCase(str2));
    }
}

1.4.3、 int compareTo(String s)方法:用来比较两个字符串的大小

compareTo()方法,按字典序进行比较大小

字典序:字符大小的顺序

public class Test {
    public static void main(String[] args) {
        String str1 =  new String("hello");
        String str2 =  new String("abcd");
        //比较两个引用所指向的对象的内容的大小
        System.out.println(str1.compareTo(str2));
    }

当str1>str2时,返回一个正数

当str1<str2时,返回一个负数

当str1=str2时,返回0

str1:调用这个方法的引用,str2:作为参数传给这个方法的引用

这里可以了解一下这个方法的返回值

所以上述代码,比较结果为7,h比a大7,返回了差值。

✨字符串比较存在这样的情况 

public class Test {
    public static void main(String[] args) {
        String str1 =  new String("helloabc");
        String str2 =  new String("hello");
        //比较两个引用所指向的对象的内容的大小
        System.out.println(str1.compareTo(str2));
    }

 

 1.4.4、int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写,进行比较

public class Test {
    public static void main(String[] args) {
        String str1 =  new String("Hello");
        String str2 =  new String("hello");
        //忽略大小写进行比较
        System.out.println(str1.compareToIgnoreCase(str2));
    }


1.5、字符串查找

方法功能
char  charAt(int index)返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
int  indexOf(int ch)返回ch第一次出现的位置,没有返回-1
int  indexOf(int ch,int fromIndex)从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

1.5.1、char  charAt(int index)方法:查找index下标上的字符

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        for (int i = 0; i < str1.length(); i++){
    //将变量i作为charAt()方法的参数,被charAt()方法的index参数接收,每循环一次输出一个字母
            System.out.println(str1.charAt(i));
        }
    }

1.5.2、int  indexOf(int ch)方法:找字符串中c第一次出现的位置,没有返回-1

public class Test {
    public static void main(String[] args) {
        String str1 = "abcabcabcabcde";
        //直接返回c字母在数组中的下标
        System.out.println(str1.indexOf('c'));
    }

 

 1.5.3、int  indexOf(int ch,int fromIndex)方法:从指定下标(fromIndex)开始查找字符c第一次出现的位置(下标)

public class Test {
    public static void main(String[] args) {
        String str1 = "abcabcabcabcde";
        //从指定的下标为6的位置开始找c第一次出现的位置(下标)
        System.out.println(str1.indexOf('c',6));
    }

1.5.4、 int indexOf(String str)方法:查找字符串中某一串字符串(abcd)出现的位置,返回这个字符串的第一个字母的下标,没有返回-1

public class Test {
    public static void main(String[] args) {
        String str1 = "abcabcabcabcde";
        System.out.println(str1.indexOf("abcd"));
    }
}

 1.5.5、int lastIndexOf(int ch):默认从后往前找,找到返回下标,没找到返回-1

public class Test {
    public static void main(String[] args) {
        String str1 = "abcabcabcabcde";
        //查找的时候,是从后往前找,但是返回下标的时候,是从前往后数
        System.out.println(str1.lastIndexOf('a'));
    }
}

 1.5.6、int lastIndexOf(int ch, int fromIndex)方法:从指定位置(fromIndex)开始找,从后往前字母(a)第一次出现的位置。

public class Test {
    public static void main(String[] args) {
        String str1 = "abcabcabcabcde";
        //查找的时候,是从后往前找,但是返回下标的时候,是从前往后数
        System.out.println(str1.lastIndexOf('a',7));
    }


1.6、字符串的转换

1.6.1、数字转字符串:xxx.valueOf()

public class Test{
     public static void main(String[] args) {
        //数字转字符串
         String str1 = String.valueOf(123);
         System.out.println(str1);
     }
}

1.6.2、字符串转数字 :Integer.paresInt(str1)

public class Test{
     public static void main(String[] args) {
         String str2 = "12345";
         //字符串转数字
         int data = Integer.parseInt(str2);
         System.out.println(data);
     }

 以上这两种转换只限定于数字样式的字符串,将字符串和数字之间相互转换,不能字母和数字之间转换,这样编译器会报错。

1.6.3、字符串小写转大写:xxx.toUpperCase();

public class Test{
     public static void main(String[] args) {
         String str1 = "abcd";
         //字符串小写转大写
         System.out.println(str1.toUpperCase());
     }

 1.6.4、字符串大写转小写:xxx.toLoweCase();

public class Test{
     public static void main(String[] args) {
         String str2 = "ABCD";
         //字符串大写转小写
         System.out.println(str2.toLowerCase());
     }

 1.6.5、字符串转数组:xxx.toCharArray();

public class Test{
     public static void main(String[] args) {
         String str1 = "abcdef";
        //字符串转数组,因为toCharArray()方法的返回值是char[]类型,所以用char[]类型的数组接收
         char[] array = str1.toCharArray();
         for (int i = 0; i < array.length; i++) {
             System.out.println(array[i]);
         }
     }
}

 1.6.6、格式化输出

 public class Test{
     public static void main(String[] args) {
         String s = String.format("%d-%d-%d",2022,12,25);
         System.out.println(s);
     }
}


1.7、字符串的替换

1.7.1、替换指定的字母:xxx.replace();

public class Test{
     public static void main(String[] args) {
         String str1 = "aaaaabbbbbddddcccc";
         //将字符串中的a字母全都替换成p
         String ret1 = str1.replace('a','p');
         System.out.println(ret1);
     }
}

1.7.2、 替换所有指定的内容(xxx.replaceAll)

public class Test{
     public static void main(String[] args) {
          String str2 = "abaababababcd";
          String ret2 = str2.replaceAll("ab","ooo");
          System.out.println(ret2);
     }
}

 1.7.3、替换首个所指的内容(xxx.replaceFirst)

public class Test{
     public static void main(String[] args) {
           String str1 = "aaaaabbbbbddddcccc";
           String ret3 = str1.replaceFirst("ab","999");
           System.out.println(ret3);
     }
}

✨ 拓展:上述的replaceAllreplaceFirst方法,也可以将字符串中的某个字符替换成空格,还是某些字符都是可以的。但是replace方法是不能实现

public class Test{
     public static void main(String[] args) {
           String str1 = "aaaaabbbbbddddcccc";
           String ret3 = str1.replaceFirst("ab"," # ");
           System.out.println(ret3);
     }
}

 

🎉🎉总结:由于字符串是不可变对象,所以上述的字符串的替换字符串的转化都没有修改当前的字符串,而是产生一个新的字符串,对其进行修改。 


 1.8、字符串的拆分

字符串的拆分有两种方法:

1.8.1、String[] split(String regex):将字符串全部拆分

public class Test{
     public static void main(String[] args) {
         String str = "how are you";
        //按空格拆分,将拆分后的字符串用字符串数组进行接收
         String[] strs = str.split(" ");
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
         }
     }
}

1.8.2、 String[] split(String regex, int limit) :将字符串以指定的格式,拆分为limit组

public class Test{
     public static void main(String[] args) {
         String str = "how are you";
        //按照空格拆分,拆分成两组
         String[] strs = str.split(" ",2);
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
         }
     }

1.8.3、拆分IP地址:有一些特殊字符作为分割符可能无法正常切分,需要加上转义。

 【注意事项】

  1. 字符"|" ,"*","+"都得加上转义字符,前面加上"\\".
  2. 而如果"\",那么就得写成"\\\\".
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符。

1、 

public class Test{
     public static void main(String[] args) {
         String str = "192.168.1.1";
        //按照.拆分,要添加转义字符\,但是这里添加了两个\,原因在于先将\转义,在转义.
         String[] strs = str.split("\\.");
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
         }
     }

 2、

public class Test{
     public static void main(String[] args) {
         String str = "192\\168\\1\\1";
        //在写字符串的时候,不能单独写一个\,因为这样和后面的数组形成了转义必须写\\
        //按照\拆分,在写的时候,先要将\转义,再转义\\,所以这里就要写\\\\
         String[] strs = str.split("\\\\",2);
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
         }
     }

 3、

public class Test{
     public static void main(String[] args) {
         String str = "192&168@1=1";
        //字符串被多个分割符隔开,想要将字符串按照这些分割符拆分,那么可以使用连字符将这些分隔符写在一起
         String[] strs = str.split("&|@|=");
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
         }
     }
}

 

1.8.4、多次拆分

 public class Test{
     public static void main(String[] args) {
         String str = "name=zhangsan&age=18";
        //这个字符串中有两部分,名字和年龄,先将她两拆分
         String[] strs = str.split("&");
         for (int i = 0; i < strs.length; i++) {
            //拆分成两个数组后,再用=拆分
            String[] string = strs[i].split("=");
            for (String s:string){
                System.out.println(s);
            }
         }
     }
}

 1.9、字符串的截取

1.9.1、String substring(int beginIndex) :从指定位置开始截取所有字符

public class Test{
     public static void main(String[] args) {
        String str = "abcdefgh";
        //从第二个字母开始截取后面所有字母
        String s = str .substring(2);
         System.out.println(s);
     }

 1.9.2、String substring(int beginIndex, int endIndex) :截取某个区域内的内容

public class Test{
     public static void main(String[] args) {
        String str = "abcdefgh";
        //表示包含0下标的字符,不包含6下标的字符
        String s = str .substring(0,6);//他是一个前闭后开区间的写法[)
         System.out.println(s);
     }
}

注意事项:

1、索引从0开始

2、注意前闭后开区间的写法。

3、 字符串的拆分和截取,都不是再原字符串上操作的,都是在新产生的字符串上操作的。


 1.10、String trim():去掉字符串中的最外侧的空格,保留中间空格

public class Test{
     public static void main(String[] args) {
         String str = "   hello  abcd    ";
         System.out.println(str);
        //去掉最外侧的空格,保留中间的空格
         String ret = str.trim();
         System.out.println(ret);
     }
}


 1.11、字符串的不可变性

 public class Test{
     public static void main(String[] args) {
         String str1 = "abcd";
         String str2 = new String("abcd");
         String str3 = "abcd";
         System.out.println(str1 == str2);
         System.out.println(str1 == str3);
     }

 

 ❗❗❗【纠正错误】

上述这副图在这里只是用作理解上述代码中为什么str1==str3,字符串常量池还没有讲解,所以这幅图是错误的,举例来说

1、String str1 = "abc";从下面这副图来看,他创建了一个String对象(value)和一个char数组对象(abc).

 2、String str2 = new String(abc);从下面的图来看,它创建了两个String对象(value)和一个char数组对象(abc);

 这里涉及到常量池的概念,小编还没学习常量池的内容,所以这里就不讲解了。

 字符串为什么有不可变性?

  1. 给String类的引用赋值字符串后,在内存中字符串是以字符数组的形式保存的。
  2. String类当中的value[ ] 属性,是被private修饰的,也就是说value[ ] 是被封装的。
  3. 被封装了之后,因该要设置公开方法get和set方法,来得到value[ ] ,并且可以修改value[ ]所指向的数组中的值。
  4. 但是在String类当中,并没有给出公开的方法让我们得到value[ ]属性。得不到value[ ]引用,所以他指向的数组中的内容不能被修改,所以字符串具有不可变性 。

总结:

1、String类被final修饰,表明该类不能被继承

2、value被final修饰,表明value不能引用其他对象(指向不可变),即不能引用其他字符数组,但是其引用空间中的内容可以修改。

为什么String要设计成不可变的?(不可变对象的好处是什么?)

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

 1.12、字符串的修改

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

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

通过反汇编来看一下,这种方式在中间创建了很多对象

 模拟一下上述反汇编的代码:

public class Test {

    public static void main(String[] args) {
            String str = "hello";
//        这里4句代码相当于上面代码的str += "abc";
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(str);
            stringBuilder.append("abc");
//        这里调用toString方法的作用是,在拼接完成之后,有一个新的String对象
            str = stringBuilder.toString();
            System.out.println(str);
    }
}

那么设想一下,每拼接一次,调用上述的4句代码,那么在代码编写时,写一个循环,那么每循环一次,调用这4句代码,就造成了代码效率非常低下。

总结

所以在循环当中不建议使用+对字符串进行拼接。因为这样的写法,会产生很多的临时对象,造成代码效率低下如果要修改建议尽量使用StringBuffer或者StringBulider


2、StringBulider和StringBuffer 

2.1、StringBulider的学习

由于String的不可更改特性,为了方便字符串的修改,Java中有提供了StringBulider和StringBuffer类这两个类大部分功能时相同的 

  通过上述图片可以看见,StringBuilder类有即有参构造方法,也有无参构造方法

 2.1.1、StringBuilder类的append方法

❓❓那么StringBuilder类对字符串进行拼接,会是什么样的那?

🕖先来看一下append方法的源码:

 🕕利用append方法对字符串进行拼接

public class Test {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("abc");
        System.out.println(stringBuilder);
        stringBuilder.append("123").append(10);
        stringBuilder.append(19.0);
        System.out.println(stringBuilder);//此时不会产生多余的临时对象,
//他永远返回的是当前对象,所有的修改都在当前对象
    }
}

 2.1.2、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(int
offset, String str)
在offset位置插入:八种基类类型 & String类型 & Object类型数据 
StringBuffer
deleteCharAt(int index)
删除index位置字符
StringBuffer delete(int
start, int end)
删除[start, end)区间内的字符
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的方式返回

 ❗❗❗总结:从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改频繁修改字符串可以考虑使用StringBuilder

❗❕❗注意:String和StringBuilder类不能直接转换。如果想要相互转换,可以采用如下原则:

  • String变为StringBuilder:利用StringBuilder的构造方法或append()方法。
  • StringBuilder变为String:调用toString()方法。
 //通过stringBuilder来调用toString方法,达到将StringBuilder类型对象转换为String类型对象
public class Test {
     public static void main(String[] args) {
           StringBuilder stringBuilder = new StringBuilder("abc");
           String ret = stringBuilder.toString();
    }
}
//通过stringBuilder调用构造方法或者append()方法,将String类型转换为StringBuilder类型
public class Test {
    public static void main3(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("abc");
        System.out.println(stringBuilder);
        stringBuilder.append("123");
        System.out.println(stringBuilder);
    }
}

 2.2、String、StringBuilder、StringBuffer的区别

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

2.3、来看一道面试题

以下两串代码分别创建了几个String对象【前提:不考虑常量池之前是否存在】

String str = new String("ab");  // 会创建多少个对象
String str = new String("a") + new String("b");  // 会创建多少个对象

1️⃣第一句:创建了2个对象。

  1. 因为字符串是一个对象,
  2. 而又new了一个对象,所以有两个对象。

2️⃣第二句:创建了5个对象。

  1. 因为字符串是一个对象,
  2. 而又new了两个对象,
  3. 又因为在进行字符串的拼接,这样会创建一个StringBuilder类型的对象,
  4. 在拼接完成之后,又会通过StringBuilder类型的对象调用toString方法,这样又创建了一个String对象。
  5. 又因为问的是创建了几个String对象,所以StringBuilder对象在这里就不算了。
  6. 为什么StringBuilder调用的toString方法创建的对象在这里可以算一个String对象?toString方法创建的对象是String类型的,所以在这里算。

 


2.4、习题

1、字符串中的第一个唯一字符

给定一个字符串s,找到他的第一个不重复的字符,并返回他的索引。如果不存在,则返回-1。

要求:字符串s只包含小写字母。

public class Test {
    public int firstUniqChar(String s) {
        int[] count = new int[26];
        //统计每个字符出现的次数
        for(int i = 0; i < s.length(); ++i){
            char ch = s.charAt(i);
            count[ch - 'a']++;
        }
        //找第一个只出现一次的字符
        for(int i = 0; i < s.length(); ++i){
            char ch = s.charAt(i);
//通过for循环遍历,并且通过if判断每一个字母在上一轮的fou循环中计数的情况(是否只出现过一次,若第一个字母计数>1,那么就判断下一个字母,直到找到计数为一的字母,并返回该字母)
            if(count[ch - 'a'] == 1){//用ch - 'a'用字母的ASCII的减去97,得到字母在数组中的下标。
                return i;
            }
        }
        return -1;
    }

2、最后一个单词的长度

输出一个正数,表示输入字符串最后一个单词的长度。

import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNextLine()){
            String str = in.nextLine();
            int index = str.lastIndexOf(" ");//最后一个空格开始
            String ret = str.substring(index+1);//从最后一个空格+1的位置开始,向后计算字符串的长度
            System.out.println(ret.length());
        }
    }
}

3、检测一个字符串是否为回文字符串

如果在将所有大写字符转换为小写字符,并移除所有非字母数字字符之后短语正着读和反着读都一样。则可认为该短语是一个回文串。

字母和数字都属于数字字符。

要求 :给你一个字符串s,如果他是回文串,返回true;否则,返回false.

public class Test {
     public boolean isPalindrome(String s){
        s = s.toLowerCase();//将大写字母转换为小写
        int left = 0;//从左边开始的下标
        int right = s.length()-1;//从右边开始的下标
        while(left < right){
            while(left < right && !isValidChar(s.charAt(left))){
                left++;
            }
            while(left < right && !isValidChar(s.charAt(right))){//条件是左边下标小于右边下标,并且来两边要是有效字符。
                right -- ;
            }
            //判断如果左边字母不等于右边字母,返回false,两边字母相等,左边向前挪一位,右边向前挪一位。
            //每个字母判断完成之后,都相等,返回true。
            if(s.charAt(left) !=s.charAt(right)){
                return false;
            }else{
                left++;
                right--;
            }
        }
        return true;
    }
    //判断他是否为有效字符
    private boolean isValidChar(char ch){
        if(ch >= '0' && ch <= '9'|| ch <= 'a'&& ch <= 'z'){
        //上边语句可以优化为
        //if(Character.isDigit(ch)||Character.isLetter(ch))
        //isDigit()判断是否为数字  isLetter()判断是否为字母
            return true;
        }
        return false;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值