【0基础学Java第十课】-- 认识String类

10. 认识String类

  • 10.1 String类的重要性
  • 10.2 常用方法
    • 10.2.1 字符串构造
    • 10.2.2 String对象的比较
    • 10.2.3 字符串查找
    • 10.2.4 转化
    • 10.2.5 字符串替换
    • 10.2.6 字符串拆分
    • 10.2.7 字符串截取
    • 10.2.8 字符串的不可变性
    • 10.2.9 字符串修改
  • 10.3 StringBuilder和StringBuffer
    • 10.3.1 StringBuilder的介绍
    • 10.3.2 面试题:
  • 10.4 String类oj

10.1 String类的重要性

在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类
另外在开发和校招笔试中,字符串也是常客,比如:

  • 字符串转整形数字
  • 字符串相加

而在面试中经常被提问:
String、StringBuff和StringBuilder之间的区别等。

10.2 常用方法

10.2.1 字符串构造

常用的三种构造方法:

    public static void main(String[] args) {//使用常量串构造String str = "hello";System.out.println(str); // 调用println中print里面再调用write方法来打印//直接newString对象String str2 = new String("world");System.out.println(str2);//使用字符数组进行构造char[] array = {'h','e','l','l','o'};String str3 = new String(array);System.out.println(str3);}

其他方法需要使用可以去查看Java在线文档:链接: String官方文档

注意:

  1. String是引用类型,内部并不存储字符串本身,比如在String类的是实现源码,String类实例变量如下:
    在这里插入图片描述
    字符串实际保存在char类型的数组,即value去引用里面的数组内容,而s3这个引用 指向了s1这个引用 指向的对象如下:
    在这里插入图片描述
    public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("world");String s3 = s1;System.out.println(s3);}
  1. 在Java中 “” 引起来也是String类型对象,如:
    public static void main(String[] args) {String str4 = "";System.out.println("输出:"+str4);System.out.println(str4.length());System.out.println(str4.isEmpty());//为空 则为true,但这里的空不是nullString str5 = null;System.out.println(str5.isEmpty());//报错:NullPointerException 所以null 和 ""不一样}

10.2.2 String对象的比较

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

  1. == 比较是否引用同一个对象
    注意对于内置类型,双等号比较的是变量中的值;对于引用类型,==比较的是引用中的地址。
    public static void main(String[] args) {int a = 10;int b = 20;int c = 10;// 对于基本类型变量,==比较两个变量中存储的值是否相同System.out.println(a == b); // falseSystem.out.println(a == c); // true// 对于引用类型变量,==比较两个引用中的地址String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("world");String s4 = s1;System.out.println(s1 == s2); // falseSystem.out.println(s2 == s3); // falseSystem.out.println(s1 == s4); // true}
  1. boolean equals(Object anObject) 方法:按照字典序比较
    字典序:字符大小的顺序
    String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照
    如下规则进行比较,比如: s1.equals(s2)
    public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("world");System.out.println(s1.equals(s2)); //String类重写了父类Object中equals方法}

而父类Object中equals方法如下:

    public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

另外:

    public static void main(String[] args) {String s3 = "hello";String s4 = "hello";System.out.println(s3==s4); // trueSystem.out.println(s3.equals(s4)); // true}

在这里插入图片描述

  1. int compareTo(String s) 方法
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("abc");String s4 = new String("abcdef");System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1System.out.println(s1.compareTo(s3)); // 相同输出 0System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:

  • 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
  • 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
  1. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较:
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("ac");String s3 = new String("ABc");String s4 = new String("abcdef");System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}

10.2.3 字符串查找

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

    public static void main(String[] args) {String s1 = new String("hello");//返回字符串对应下标的字符char ch = s1.charAt(1);System.out.println(ch); //e//返回对应字符出现的下标位置 从头开始一个一个找 没有返回-1int index = s1.indexOf('l');System.out.println(index); //2// 从指定位置(3)开始找某个字符出现的位置   没有返回-1int index2 = s1.indexOf('l',3);System.out.println(index2); //3// 字符串查找 从一个字符串找另一个字符串   没有返回-1int index3 = s1.indexOf("llo");System.out.println(index3); //2int index4 = s1.indexOf("llo",3);System.out.println(index4); //-1//从后往前找,返回ch第一次出现的位置,没有返回-1int index5 = s1.lastIndexOf('l');System.out.println(index5); //3// 从指定位置开始找,从后往前找ch第一次出现的位置,没有返回-1int index6 = s1.lastIndexOf('l',2);System.out.println(index6); // 2// 字符串也可以从后往前同理}

10.2.4 转化

结论:字符串的改变 都是产生了新的对象
1.数值和字符串转化:String.valueOf()方法,里面可以是整数,double,boolean等:
在这里插入图片描述

    public static void main(String[] args) {//把整数  转化为  字符串String str = String.valueOf(123);System.out.println(str); //这个过程  可以理解为序列化String str1 = String.valueOf(new Student("张三",12));System.out.println(str1); //上面重写一下toString方法来变成想要的形式  姓名:张三  年龄:12//包装类:首先是一个类 其次 类中拥有更多的方法 使用起来非常方便//把字符串变成整型int a = Integer.parseInt("123");System.out.println(a);  //123//变成double  变成什么类型就是 该包装类.parse类型double d = Double.parseDouble("99.99");System.out.println(d);  //99.99}

2.大小写转换:toUpperCase(),变小:toLowerCase()

    public static void main(String[] args) {//结论:字符串的改变 都是产生了新的对象//转化成大写的时候,产生了一个新的对象String str = "hello";String ret = str.toUpperCase();System.out.println(ret);  //HELLOSystem.out.println(str);String str2 = "HELLO";String ret2 = str2.toLowerCase();System.out.println(ret2); // hello}

3.字符串转数组

    public static void main(String[] args) {String str = "hello";char[] chars = str.toCharArray();for (char ch:chars) {System.out.println(ch);}

4.格式化

    public static void main(String[] args) {String s = String.format("%d-%d-%d",2019,9,14);System.out.println(s); //2019-9-14}

10.2.5 字符串替换

    public static void main(String[] args) {String str = "abcdabcddef";// 字符替换 把a替换成AString ret = str.replace('a','A');System.out.println(ret);// 字符串替换  把ab替换成AB String ret2 = str.replace("ab","AB");System.out.println(ret2);}

10.2.6 字符串拆分

.split(“切割符”,限制数) 拆分为几部分的数组接收:

    public static void main(String[] args) {String str = "name=zhagnsan&age=10";String[] ret = str.split("&");for (int i = 0; i < ret.length; i++) {System.out.println(ret[i]);//name=zhagnsan//age=10}//可以加限制分割为几部分String str2 = "hello world hello bit";String[] ret2 = str2.split(" ",2);for (int i = 0; i < ret2.length; i++) {System.out.println(ret2[i]);    //hello//world hello bit}String str3 = "192.168.1.1";String[] ret3 = str3.split("\\.");for (int i = 0; i < ret3.length; i++) {System.out.println(ret3[i]);//192//168//1//1}

注意

  1. 字符"|“,”*“,”+“都得加上转义字符,前面加上”\" .
  2. 而如果是"" ,那么就得写成"\\" .
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
    public static void main(String[] args) {//正则表达式的分割String str = "192\\168\\1\\1";String[] ret = str.split("\\\\");for (int i = 0; i < ret.length; i++) {System.out.println(ret[i]);//192//168//1//1}// 俩个分割符String str2 = "name=zhagnsan&age=10";String[] ret2 = str2.split("=|&");for (int i = 0; i < ret2.length; i++) {System.out.println(ret2[i]);//name//zhagnsan//age//10}
  1. 多次拆分:
    public static void main(String[] args) {//实现多次分割String str = "name=zhagnsan&age=10";String[] ret = str.split("&");// [0] name=zhagnsan  [1]  age=10for (String x:ret) {String[] s = x.split("=");for (String ss:s) {System.out.println(ss);//name//zhagnsan//age//10}}}

10.2.7 字符串截取

从一个完整的字符串之中截取出部分内容。可用方法如下:
String substring(int beginIndex) 从指定索引截取到结尾
String substring(int beginIndex, int endIndex) 截取部分内容
trim() 截取字符串两边的空格 保留中间空格

    public static void main(String[] args) {String str = "abcdef";//从指定截取到结尾String ret = str.substring(3);System.out.println(ret);   //def//截取部分内容  [a,b) 在Java中一般是左闭有开String ret2 = str.substring(2,5);   //cdeSystem.out.println(ret2);//trim() 截取字符串两边的空格  保留中间空格String str3 = "    abcde fefef  f     ";String ret3 = str3.trim();System.out.println(ret3);   //abcde fefef  f}

10.2.8 字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,对字符串的改变操作都会产生新的对象。

在被private修饰封装起来的value[] 拿不到value里面的内容,而且也没有提供get 和set方法。
在这里插入图片描述

    public static void main15(String[] args) {final char[] value = {'a','b','c','d'};value[0] = 'g';//修改对象 0 下标内容//value = new char[10];//指向新的对象}

final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内
容是可以修改的。

public static void main(String[] args) {final int array[] = {1,2,3,4,5};array[0] = 100;System.out.println(Arrays.toString(array));// array = new int[]{4,5,6}; // 编译报错: 无法为最终变量array分配值//可以修改值但是不能修改数组的指向
}

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

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

10.2.9 字符串修改

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

    public static void main15(String[] args) {//String s = "hello";//s += " world";  // s指向了新的指向//System.out.println(s); // 输出:hello world//相当于下面:String s = "hello";StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(s);s = stringBuilder.toString();System.out.println(s);System.out.println(stringBuilder);}

在这里插入图片描述

但是这种方式不推荐使用,因为其效率非常低,中间创建了好多临时对象。

    public static void main(String[] args) {StringBuilder stringBuilder = new StringBuilder("abcdef");stringBuilder.reverse();System.out.println(stringBuilder);}public static void main17(String[] args) {long start = System.currentTimeMillis();StringBuffer sbf = new StringBuffer("");for(int i = 0; i < 100000; ++i){sbf.append(i);}long end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();StringBuilder sbd = new StringBuilder();for(int i = 0; i < 100000; ++i){sbd.append(i);}end = System.currentTimeMillis();System.out.println(end - start);start = System.currentTimeMillis();//获取当前系统的时间戳String s = "";for(int i = 0; i < 100000; ++i){//以后不能在循环当中 这样去拼接字符串s += i;}end = System.currentTimeMillis();System.out.println(end - start);}

10.3 StringBuilder和StringBuffer

10.3.1 StringBuilder的介绍

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大
部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其他可以点击链接: stringBuilder在线文档

    public static void main(String[] args) {//StringBuilder StringBuffer 是一个可变的对象 返回的是this 也就是当前对象// 使用多线程情况下 synchronized 执行一个append方法时得先执行完才能执行其他方法// 但是频繁得上锁 和 解锁是需要耗费系统的资源StringBuffer stringBuffer = new StringBuffer("aaaa");stringBuffer.append("111");System.out.println(stringBuffer); //aaaa111StringBuilder stringBuilder = new StringBuilder("abcdef");stringBuilder.append("123");stringBuilder.append("456").append("789");stringBuilder.reverse(); // 逆置字符串System.out.println(stringBuilder);  //987654321fedcba}
  • 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的方式返回
    public static void main(String[] args) {StringBuilder sb1 = new StringBuilder("hello");StringBuilder sb2 = sb1;// 追加:即尾插-->字符、字符串、整形数字sb1.append(' '); // hellosb1.append("world"); // hello worldsb1.append(123); // hello world123System.out.println(sb1); // hello world123System.out.println(sb1 == sb2); // trueSystem.out.println(sb1.charAt(0)); // 获取0号位上的字符 hSystem.out.println(sb1.length()); // 获取字符串的有效长度14System.out.println(sb1.capacity()); // 获取底层数组的总大小sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123System.out.println(sb1);System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置sb1.deleteCharAt(0); // 删除首字符sb1.delete(0,5); // 删除[0, 5)范围内的字符String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回System.out.println(str);sb1.reverse(); // 字符串逆转str = sb1.toString(); // 将StringBuffer以String的方式返回System.out.println(str);}

总结:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可
以修改
频繁修改字符串的情况考虑使用StringBuilder
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

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

10.3.2 面试题:

  1. String、StringBuffer、StringBuilder的区别
  • String的内容不可修改,StringBuffer和StringBuilder的内容可以修改
  • StringBuffer和StringBuilder大部分功能是相似的
  • StringBuffer采用同步处理,属于多线程安全操作;而StringBuilder未采用同步操作,属于线程不安全操作
  1. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】

10.4 String类oj

  1. 链接: 第一个只出现一次的字符
    public int firstUniqChar(String s) {//1.定义一个计数数组int[] count = new int[26];//2.遍历字符串 记录次数for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);count[ch-'a']++;}//3.再次遍历原字符串for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if (count[ch -'a'] == 1) {return i;}}return -1;}
  1. 链接: 字符串最后一个单词的长度
  • 使用split方法分割空格后的字符串
    public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseString s = in.nextLine();String[] ret = s.split(" ");System.out.println(ret[ret.length-1].length());}}
  • 使用lastIndexOf方法找到空格的位置,然后substring截取空格+1之后的字符串
    public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseString s = in.nextLine();int index = s.lastIndexOf(" ");String str = s.substring(index+1);int len = str.length();System.out.println(len);}}
  1. 链接: 检测字符串是否为回文
    public boolean isPalindrome(String s) {s = s.toLowerCase();int left = 0;int right = s.length()-1;while(left < right) {//1.left走到合法字符底下while(left<right && !isCharacterNum(s.charAt(left))) {left++;}//2.right走到合法字符底下while(left<right && !isCharacterNum(s.charAt(right))) {right--;}if(s.charAt(left) == s.charAt(right)) {left++;right--;} else {return false;}}return true;}private boolean isCharacterNum(char ch) {// if(ch >= 'a' && ch <= 'z' || ch >='0' && ch <= '9') {//     return true;// }// return false;if(Character.isDigit(ch) || Character.isLetter(ch)) {return true;}return false;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/190970.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

制作翻页电子相册,这个工具你必须了解!

电子相册作为一种很有纪念意义的载体&#xff0c;无论是生日、旅行、结婚、毕业纪念等等&#xff0c;可以应用在很多场合当中&#xff0c;如何制作呢&#xff1f; 而对于不会制作电子相册的人来说&#xff0c;使用套用模板是最直接快速的方式了。所以&#xff0c;推荐大家使用…

关于SPJ表的数据库作业

打字不易&#xff0c;且复制且珍惜 建表 use 库名;create table S( --供应商 SNO char(6) not null, SNAME char(10) not null, STATUS INT, CITY char(10), primary key(SNO));create table P( --零件 PNO char(6) not null, PNAME char(12)not null, COLOR char(4), WEIGHT…

小命令,大世界

Linux是一个大系统&#xff0c;功能丰富&#xff0c;好比是一台巨型机器&#xff0c;而命令&#xff0c;就是这台机器的操作台。要想控制好这台机器&#xff0c;用好这台机器&#xff0c;就得会看仪表&#xff0c;会操作各种按钮。《Linux常用命令自学手册》就是介绍如何操作这…

1334. 阈值距离内邻居最少的城市/Floyd 【leetcode】

1334. 阈值距离内邻居最少的城市 有 n 个城市&#xff0c;按从 0 到 n-1 编号。给你一个边数组 edges&#xff0c;其中 edges[i] [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边&#xff0c;距离阈值是一个整数 distanceThreshold。 返回能通过某些路径…

无重复最长字符串(最长无重复子字符串),剑指offer,力扣

目录 原题&#xff1a; 力扣地址&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 难度算中下吧&#xff0c;这个总体不算很难&#xff0c;而且滑动窗口&#xff0c;以及哈希都比较常见 审题目事例提示&#xff1a; 解题思路&#xff08;…

纯CSS自定义滚动条样式

.my-carousel{height: 474px;overflow-y: auto; } /*正常情况下滑块的样式*/ .my-carousel::-webkit-scrollbar {width: 5px; } .my-carousel::-webkit-scrollbar-thumb {border-radius: 8px;background-color: #ccc; } .my-carousel::-webkit-scrollbar-track {border-radius:…

Linux上编译和安装SOFA23.06

前言 你可以直接使用编译安装好的SOFA版本Installing from all-included binaries (v23.06.00)&#xff1a; 如果你想自己编译&#xff0c;可以看我下面写的内容&#xff0c;不过绝大多数是从官网来的&#xff0c;如果和官网有出入&#xff0c;建议还是以官网为准。 在Linux下…

多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测

多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-BiGRU-Attention粒子群优化双向门控循环单元融合注意力机制的多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 …

springBoot 配置druid多数据源 MySQL+SQLSERVER

1:pom 文件引入数据 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency>…

深入理解Linux网络笔记(六):深度理解TCP连接建立过程

本文为《深入理解Linux网络》学习笔记&#xff0c;使用的Linux源码版本是3.10&#xff0c;网卡驱动默认采用的都是Intel的igb网卡驱动 Linux源码在线阅读&#xff1a;https://elixir.bootlin.com/linux/v3.10/source 5、深度理解TCP连接建立过程 1&#xff09;、深入理解liste…

【算法基础】筛质数

文章目录 问题描述解决方法朴素筛法线性筛法 问题描述 给定一个正整数 n n n&#xff0c;请你求出 1 ∼ n 1∼n 1∼n 中质数的个数。 输入格式 共一行&#xff0c;包含整数 n。 输出格式 共一行&#xff0c;包含一个整数&#xff0c;表示 1∼n 中质数的个数。 数据范围 …

代码随想录二刷 | 数组 | 数组理论基础

代码随想录二刷 &#xff5c; 数组 &#xff5c; 数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。可以通过下标索引的方式获取到下标对应的数据。 数组的下标都是从0开始的 数组内存空间的地址是连续的 因为数组的在内存空间的地址是连续的&#xff0c;所以我们…