版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2025年高频string类面试题及答案String为什么设计成不可变类?底层如何保证不可变性?String被设计为不可变类主要基于以下原因:一是线程安全,多个线程同时访问时无需额外同步;二是支持字符串常量池优化,相同字面量仅存储一次,节省内存;三是缓存哈希值,String的hashCode()方法会缓存计算结果,不可变性保证了哈希值不会重复计算。底层实现上,JDK8及之前String内部使用`finalchar[]value`存储字符,JDK9起改为`finalbyte[]value`(配合`coder`字段标识编码,LATIN1或UTF16),数组被final修饰确保引用不可变,且String类自身被声明为`final`禁止继承,所有修改操作(如concat、substring)均返回新的String对象,而非修改原对象,从根本上保证了不可变性。String、StringBuilder、StringBuffer的核心区别是什么?各自适用场景?三者均用于处理字符串,但特性差异显著:String是不可变类,所有修改操作提供新对象;StringBuilder是可变类,非线程安全,内部通过`char[]`(或`byte[]`)扩容实现高效拼接;StringBuffer同样可变,但方法使用`synchronized`修饰,保证线程安全。适用场景:少量字符串操作选String;单线程下大量拼接选StringBuilder(性能最高);多线程环境下的拼接操作选StringBuffer(需牺牲部分性能换取线程安全)。字符串拼接有哪些方式?性能差异如何?常见拼接方式包括:1.`+`运算符:编译时自动优化为StringBuilder(JDK5+),但循环中每次`+`会提供新的StringBuilder实例,导致额外开销;2.`StringBuilder.append()`:手动控制拼接,预分配容量时性能最优(减少扩容次数);3.`String.concat()`:底层通过`Arrays.copyOf`复制字符数组,仅适合短字符串拼接(每次拼接提供新数组,长字符串效率低);4.`String.format()`:支持格式化,但内部通过`newStringBuilder`实现,性能低于直接使用StringBuilder;5.`Joiner`(Guava)或`String.join()`(JDK8+):适合多元素按分隔符拼接(如集合转字符串)。性能排序(从高到低):StringBuilder(预分配容量)>String.concat(短字符串)>`+`(非循环场景)>String.format()>StringBuffer(多线程同步开销)。`equals()`和`==`在比较字符串时的区别?`==`比较的是对象的内存地址(引用是否相同),而`equals()`比较的是字符串内容(String重写了Object的equals方法)。例如:`Strings1="abc";Strings2="abc";``s1==s2`为true(指向常量池同一对象);`Strings3=newString("abc");``s1==s3`为false(s3在堆中新建对象),但`s1.equals(s3)`为true(内容相同)。需注意,若未重写equals方法的类(如自定义类),`==`和`equals()`行为一致(均比较引用)。`intern()`方法的作用是什么?JDK6与JDK7+的实现有何差异?`intern()`的核心作用是将字符串对象放入字符串常量池,并返回池中的引用。JDK6中,常量池位于永久代(PermGen),调用`intern()`时若池不存在该字符串,会复制原字符串的字符到永久代并返回其引用;JDK7+常量池移至堆内存,若池不存在该字符串,直接存储原字符串的引用(而非复制字符),此时原字符串和池中的字符串共享同一字符数组。例如:`Strings=newString("123");ern();`JDK6中,池会新建"123"对象;JDK7+中,池直接引用堆中的s对象(若池原本无"123")。这一变化减少了内存复制,避免永久代内存溢出问题。字符串常量池的存储位置在JVM不同版本中如何变化?JDK6及之前,字符串常量池存储于方法区的永久代(PermGen),受限于永久代大小(默认仅几十MB),大量字符串字面量易导致`OutOfMemoryError:PermGenspace`;JDK7中,常量池从永久代迁移至堆内存(Heap),与普通对象一样受堆内存管理;JDK8起,永久代被元空间(Metaspace)替代,但字符串常量池仍保留在堆中,元空间仅存储类元信息等,此举避免了永久代的内存限制问题,提高了大字符串场景的稳定性。`substring(intbeginIndex,intendIndex)`在JDK6和JDK7+中的实现差异?JDK6中,substring返回的新String与原String共享`char[]value`数组(通过`newString(offset+beginIndex,endIndexbeginIndex,value)`构造),仅修改`offset`和`count`字段。这一设计可能导致内存泄漏:若原字符串很大,仅需其中一小部分子串,原字符串的`value`数组仍会被子串引用无法回收。JDK7+中,substring会新建一个`char[]`数组,复制原数组中需要的字符(`Arrays.copyOfRange(value,beginIndex,endIndex)`),子串与原字符串不再共享底层数组,避免了内存泄漏问题,但增加了复制开销(对大字符串更友好)。如何判断两个字符串是否为旋转字符串(如"abcd"和"cdab")?旋转字符串指将原字符串的前k个字符移到末尾形成的新字符串。判断方法:若字符串s1和s2是旋转关系,则s2一定是s1+s1的子串,且两者长度相同。例如:`s1="abcd";s2="cdab";``s1+s1="abcdabcd"`,包含s2("cdab"),且长度相等,故为旋转字符串。代码实现:```javapublicstaticbooleanisRotation(Strings1,Strings2){if(s1==null||s2==null||s1.length()!=s2.length())returnfalse;return(s1+s1).contains(s2);}```如何高效判断字符串是否包含重复字符?方法一(通用):使用HashSet存储已出现的字符,遍历字符串时检查是否已存在,存在则返回true。时间复杂度O(n),空间复杂度O(1)(字符集有限时,如ASCII最多256个字符)。方法二(位运算,仅适用于小写字母):用int变量的每一位表示字符是否出现(a对应第0位,b对应第1位...),遍历字符时计算`1<<(c'a')`,若与当前掩码有交集则重复。代码示例:```javapublicstaticbooleanhasDuplicate(Strings){intmask=0;for(charc:s.toCharArray()){intbit=1<<(c'a');//假设仅小写字母if((mask&bit)!=0)returntrue;mask|=bit;}returnfalse;}```如何实现字符串反转?要求至少写出三种方法。方法一(迭代交换):将字符串转为字符数组,首尾指针交换直至中间。```javapublicstaticStringreverse1(Strings){if(s==null)returnnull;char[]arr=s.toCharArray();inti=0,j=arr.length1;while(i<j){chartemp=arr[i];arr[i]=arr[j];arr[j]=temp;i++;j--;}returnnewString(arr);}```方法二(递归):递归截取首尾字符,中间部分反转后拼接。```javapublicstaticStringreverse2(Strings){if(s.length()<=1)returns;returns.charAt(s.length()-1)+reverse2(s.substring(0,s.length()-1));}```方法三(StringBuilder):直接调用`reverse()`方法(最简洁)。```javapublicstaticStringreverse3(Strings){returnnewStringBuilder(s).reverse().toString();}```正则表达式在String中的常见应用场景及注意事项?常见场景包括:1.`split(Stringregex)`:按正则分割字符串(如`"a,b;c".split("[,;]")`得到`["a","b","c"]`);2.`replaceAll(Stringregex,Stringreplacement)`:替换所有匹配正则的子串(如`"12a34b".replaceAll("\\d","")`得到"ab");3.`matches(Stringregex)`:判断字符串是否完全匹配正则(如`.matches("^1[3-9]\\d{9}$")`验证手机号)。注意事项:正则中的特殊字符(如`.^$+?()[{\|`)需转义(加`\\`);贪婪匹配(默认)可能匹配最长子串,非贪婪匹配(`?`修饰)匹配最短(如`"aab".replaceAll("a.?b","x")`得到"x");大字符串匹配时需注意正则复杂度(如避免指数级匹配的正则模式)。String的`hashCode()`方法如何实现?设计时为何选择31作为乘数?String的hashCode()计算公式为:`hash=s[0]31^(n-1)+s[1]31^(n-2)+...+s[n-1]`,其中s[i]是字符的ASCII值,n是字符串长度。选择31的原因:一是31是质数,减少哈希冲突(质数的乘积更分散);二是31可被JVM优化为位运算(`31i=(i<<5)i`),计算效率更高。例如,`"abc"`的hashCode计算为:`'a'31²+'b'31+'c'=97961+9831+99=93217+3038+99=96354`。处理大字符串(如1GB)时,如何优化内存使用?优化策略包括:1.避免不必要的字符串拼接:优先使用`StringBuilder`并预分配足够容量(`newStringBuilder(initialCapacity)`),减少扩容次数;2.利用`substring`的JDK7+特性:避免JDK6中共享数组导致的内存泄漏;3.使用`intern()`共享字符串:若大量重复字符串,通过intern()将其存入常量池,减少重复存储(需评估常量池内存压力);4.流式处理:读取大字符串时按块读取(如使用`BufferedReader.readLine()`),避免一次性加载到内存;5.避免使用`String.getBytes()`提供大字节数组:改用`InputStream`或`ByteBuffer`逐块处理;6.使用`CharBuffer`(NIO):直接操作堆外内存,减少GC压力。如何正确处理字符串中的转义字符(如反斜杠、双引号)?转义字符需通过转义符`\`处理,具体规则:反斜杠`\`需表示为`\\`(Java字符串中`\`是转义符,需用`\\`表示一个实际反斜杠);双引号`"`在双引号字符串中需表示为`\"`(如`Strings="他说:\"你好\"";`);正则中的特殊字符(如`.`)需用`\\.`匹配字面量`.`;若需处理任意特殊字符,可使用`Pattern.quote(Strings)`方法,将字符串转为正则字面量(如`Pattern.quote("a.b")`提供`\Qa.b\E`,匹配"a.b"本身)。示例:解析JSON字符串时,需将双引号转义为`\"`,反斜杠转义为`\\`,否则会导致解析错误。KMP算法的核心思想是什么?如何实现字符串匹配?KMP算法通过预处理模式串提供部分匹配表(next数组),避免主串指针回溯,将时间复杂度优化到O(n+m)(n为主串长度,m为模式串长度)。next数组存储的是模式串前缀和后缀的最长公共长度。实现步骤:1.构建next数组:遍历模式串,计算每个位置i的最长公共前后缀长度;2.匹配过程:主串指针i和模式串指针j同时移动,若字符不匹配则j回退到next[j-1],直到j=0或匹配;若j等于模式串长度,说明匹配成功。代码示例(构建next数组):```javapublicstaticint[]buildNext(Stringpattern){intm=pattern.length();int[]next=newint[m];next[0]=0;for(inti=1,len=0;i<m;){if(pattern.charAt(i)==pattern.charAt(len)){next[i++]=++len;}elseif(len>0){len=next[len1];}else{next[i++]=0;}}returnnext;}```匹配逻辑:```javapublicstaticintkmp(Stringtext,Stringpattern){int[]next=buildNext(pattern);inti=0,j=0;while(i<text.length()){if(text.charAt(i)==pattern.charAt(j)){i++;j++;if(j==pattern.length())returnij;//返回匹配起始位置}elseif(j>0){j=next[j1];}else{i++;}}return-1;//未匹配}```String对象在堆和字符串常量池中的存储关系是怎样的?字符串字面量(如`Strings="abc";`):编译时存入常量池(JDK7+在堆中),运行时若常量池已有该字符串,则s直接指向池中的对象;`newString("abc")`:在堆中创建新的String对象,同时检查常量池是否有"abc"。若没有,先在常量池创建"abc"对象(JDK6复制字符数组,JDK7+引用堆对象),然后堆中的String对象的`value`数组指向常量池的字符数组(JDK6)或直接存储字符数组(JDK7+);动态提供的字符串(如`Strings="a"+"b";`):编译时优化为`"ab"`,存入常量池;拼接变量(如`Stringa="a";Strings=a+"b";`):编译时提供StringBuilder,运行时拼接后通过`toString()`提供新的String对象(在堆中,不一定进入常量池,除非调用intern())。为什么String常被用作HashMap的key?主要原因:1.不可变性:String的不可变性保证了hashCode()在对象创建后不会改变,避免HashMap中键的哈希值变化导致的索引错误(若键可变,修改后可能无法找到原存储位置);2.高效的hashCode()和equals():String重写了这两个方法,hashCode()基于字符内容计算(缓存结果),equals()直接比较字符数组,保证了哈希表的查找效率;3.广泛的使用场景:字符串是最常见的键类型(如配置项、标识符等),设计为key符合实际需求。如何统计字符串中各字符的出现次数(区分大小写和空格)?方法:使用HashMap<Character,Integer>遍历字符串,统计每个字符的出现次数。代码示例:```javapublicstaticMap<Character,Integer>countChar(Strings){Map<Character,Integer>map=newHashMap<>();for(charc:s.toCharArray()){map.put(c,map.getOrDefault(c,0)+1);}returnmap;}```若需按顺序输出(如字母顺序),可将键存入TreeSet后遍历;若字符集有限(如ASCII),可用数组替代HashMap(更高效):```javapublicstaticint[]countAscii(Strings){int[]count=newint[256];//ASCII共256个字符for(charc:s.toCharArray()){count[c]++;}returncount;}```处理超长字符串时,可能遇到哪些性能瓶颈?如何解决?瓶颈及解决方案:1.内存占用过高:超长字符串一次性加载到内存易导致OOM。解决:流式处理(按行/块读取)、使用`java.util.stream.Stream`逐元素处理;2.GC压力大:大量临时String对象被创建,触发频繁GC。解决:复用StringBuilder实例、避免不必要的对象创建(如循环中使用`newStringBuilder`
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 山东省青岛市城阳区2026届英语高三上期末学业水平测试模拟试题含解析
- 2026届陕西省汉中市南郑区龙岗学校高三生物第一学期期末学业水平测试模拟试题含解析
- 2026届河南省南阳市达标名校高二上数学期末监测试题含解析
- 2026届上海市宝山区行知实验生物高一第一学期期末学业质量监测试题含解析
- 2026届甘肃省白银市数学高二上期末学业水平测试试题含解析
- 2026年中核凯利深圳核能服务股份有限公司福清分公司招聘备考题库带答案详解
- 2026年上海交大长兴海洋实验室海洋智能MEMS传感器研究中心招聘专职工程人员备考题库参考答案详解
- 2026年上海当代艺术博物馆公开招聘工作人员备考题库(第二批)及1套参考答案详解
- 2026年南通市邮政管理局招聘辅助人员备考题库完整参考答案详解
- 2026年中能化备考题库与发展战略研究中心招聘备考题库附答案详解
- 2024年四川省内江市中考物理试卷附答案
- 钢铁购销简单合同范本
- TSG特种设备安全技术规范TSGD-202工业管道安全技术规程
- 2024年4月自考00612日本文学选读试题
- 《海上风电场工程岩土试验规程》(NB/T 10107-2018)
- 地产公司设计部工作总结
- 《期权基础知识》课件
- 新年团建室内活动策划
- 2023秋季学期国开思政课《思想道德与法治》在线形考(专题检测1-7)试题及答案
- EPC工程总承包项目设计及施工的配合制度
- DB21∕T 3358-2020 电梯再生制动系统要求及试验方法
评论
0/150
提交评论