草庐IT

StringBuilder,Stringbuffer和String相关面试笔试

bit me 2023-12-01 原文

String类中的重点

✌🏼一.StringBuilder和StringBuffer介绍

由于String的不可更改特性,在我们想要改变字符串的时候,都是在new的对象上进行改变,并没有改变字符串本身,为了能在字符串本身上进行的修改,不用创建大量临时对象,Java中提供StringBuilderStringBuffer

  1. 先来看看Stringbuffer的源码实现,以及栈和堆的内存分配:


    可以看到stringBuffer一直都在内部进行操作,而不是在常量池里面,所以只会返回内部的内容,新加入的内容都会进入内部和常量池中,从而不需要创建大量临时对象来接收新的内容

  2. 我们再看一看Stringbuilder的源码实现,它的栈和堆的内存分配和Stringbuffer是一样的

    我们可以发现在StringBuffer的源码实现比StringBuilder实现里面多了synchronized,synchronized代表线程安全,StringBuffer是线程安全的,StringBuilder不是线程安全的

线程安全是啥呢,线程安全指的是内存的安全在每个进程的内存空间中都会有一块特殊的公共区域,通常称为堆(内存)。进程内的所有线程都可以访问到该区域,这就是造成问题的潜在原因。

所以线程安全指的是,在堆内存中的数据由于可以被任何线程访问到,在没有限制的情况下存在被意外修改的风险。即堆内存空间在没有保护机制的情况下,对多线程来说是不安全的地方,因为你放进去的数据,可能被别的线程“破坏”。

在一段函数执行的过程中,具有线程安全的代码不会被外界所影响,相当于把这段函数锁在一个空间里,当函数执行完毕之后,锁就开了

例如人们上厕所,当第一个人进去上厕所之后,后面的人排队上厕所,当你不锁门的情况下,后面的人就可能会进来,干扰到你,但是当你反锁了门锁之后,后面的人就不能随意进出了,就对你不会有影响,所以在这里的门锁就和我们的线程安全类似,当你具备线程安全后就不用担心被别的线程所干扰了

但是我们这里就会产生一个疑问了,既然StringBuffer比StringBuilder安全,那为什么还需要StringBuilder呢?
线程安全会频繁的加锁和释放锁会消耗系统的资源,而在有些情况下,是不需要线程安全的,所以这时候就用StringBuilder更好,总之得看情况而定

举例我们字符串的拼接

String str = "abc";
str = str + "123";
System.out.println(str);

在字节码文件里我们可以看到new了一个StringBuilder对象,字符串的拼接也用append的方法来写的,并且调用优化了toString方法
相同情况下,多次拼接就会多次new StringBuilder对象,使得内部执行异常繁琐,多个对象是的程序运行不能最大化执行代码,我们就必须要使用StringBuilder来优化了

String str = "abc";
for (int i = 0; i < 10; i++) {
	str = str +i;
}
System.out.println(str);

优化后的代码

String str = "abc";
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < 10; i++) {
	sb.append(i);
}
System.out.println(sb.toString());

优化后的代码就只有一个StringBuilder对象,极大的提升了代码的性能,有人会说为什么不用Stringbuffer,在这里没有涉及到线程,用了会浪费资源,所以这两种方法各有优势,使用得看情况而论

🤞🏼 二.相关面试

  1. String、StringBuffer、StringBuilder的区别
    ①String的内容不可修改,StringBuffer与StringBuilder的内容可以修改
    ②StringBuffer与StringBuilder大部分功能是相似的
    ③StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

  2. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】

String str = new String("ab");

String str1 = new String("a") + new String("b");

第一个str创建了两个对象,第一个对象是字符串"ab",属于常量池里面的,第二个对象是new了一个对象,里面有value和hash

第二个str创建了六个对象,第一个对象是字符串"a",第二个对象是字符串"b",第三个对象是a new的一个对象,里面有value和hash,第四个对象是b new的一个对象,里面有value和hash,第五个对象是第三第四个对象合起来创建的一个Stringbuilder对象,第六个对象就是Stringbuilder的toString方法生成的一个String对象

  1. 请解释String类中两种对象实例化的区别

JDK1.8中

  1. String str = “hello”;

只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象

  1. String str = new String(“hello”);

会开辟两块堆内存空间,字符串"hello"保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值。

  1. String str = new String(new char[]{‘h’, ‘e’, ‘l’, ‘l’, ‘o’});

现在在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中(常量池没有东西,只有双引号的内容才会在常量池里面)

🤙🏼三.String类oj笔试

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

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

思路:

  1. 先根据题目要求列式,字符串为空和长度为0的情况下,返回-1
  2. 因为我们想知道这个字符是不是只出现了一次,所以我们得遍历一次统计出每个字符出现的个数
  3. 再次遍历,从左往右遍历的时候输出统计后第一个只出现了一次的字符
public int firstUniqChar(String s) {
        //对参数进行判断
        if(s == null || s.length() == 0){
            return -1;
        }

        int[] array = new int[26];//0

        for(int i = 0;i < s.length();i++){//先遍历一次数组,把每个元素出现的次数都记录下来
            char ch = s.charAt(i);
            array[ch-'a']++;
        }

        for(int i = 0;i < s.length();i++){//再次遍历数组,从左往右,输出记录后第一个只出现了一次的字符
            char ch = s.charAt(i);
            if(array[ch-'a'] == 1){
                return i;
            }
        }
        return -1;
    }
  1. 字符串最后一个单词的长度

计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)

思路:

  1. 我们先输入一串字符串
  2. 合理利用字符串截取里面的库函数,从后往前找到第一个空格,然后返回第一个空格后面的一串字符,在这里需要提醒的是,用下角标找到第一个空格的时候,下角标需要往后挪一位,空格位不算字符
 public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while(scan.hasNextLine()){
            String str = scan.nextLine();
            int index = str.lastIndexOf(" ");
            String ret = str.substring(index+1);
            System.out.println(ret.length());
        }

    }
  1. 验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串 s,如果它是回文串 ,返回 true ;否则,返回 false 。

思路:

  1. 先按照题目要求规范字母大小写,都换成小写
  2. 定义最左边和最右边的元素下角标,为了依次进行向中心挪动对比做准备
  3. 考虑下标合法性以及字符合理性:左边下角标要小于右边下角标,i下标或者j下标所对应的是数字或字母,
  4. 判断对应i和j下标的元素是否相同
private boolean isCharacter(char ch){
        if (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9'){//判断字符合理性
            return true;
        }
        return false;
    }

    public boolean isPalindrome(String s){
        //1.把所有的字符变成小写的
        s = s.toLowerCase();
        int i = 0;
        int j = s.length()-1;
        while(i < j){//i和j的下标要合法
            while(i < j && !isCharacter(s.charAt(i))){//此处不用if是因为在第一个字母或数字之前可能会有空格
                i++;//i下标就是一个合法的数字字符或字母
            }
            while(i < j && !isCharacter(s.charAt(j))){//判断j是不是合法的数字字符或字母
                j--;//j下标就是一个合法的数字字符或字母
            }
            if(s.charAt(i) != s.charAt(j)){//当两边字母或数字不一样的时候,返回false
                 return false;
            }else {
                i++;
                j--;
            }
        }
        return true;
    }

有关StringBuilder,Stringbuffer和String相关面试笔试的更多相关文章

  1. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  2. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  3. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  4. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  5. ruby-on-rails - 在具有 ActiveRecord 条件的相关模型中按字段排序 - 2

    我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我

  6. ruby - 使用指向 ruby​​ 可执行文件的符号链接(symbolic link)时查找相关库 - 2

    假设您有一个可执行文件foo.rb,其库bar.rb的布局如下:/bin/foo.rb/lib/bar.rb在foo.rb的header中放置以下要求以在bar.rb中引入功能:requireFile.dirname(__FILE__)+"../lib/bar.rb"只要对foo.rb的所有调用都是直接的,这就可以正常工作。如果你把$HOME/project和符号链接(symboliclink)foo.rb放入$HOME/usr/bin,然后__FILE__解析为$HOME/usr/bin/foo.rb,因此无法找到bar.rb关于foo.rb的目录名.我意识到像ruby​​gems这

  7. ruby - json 没有将 String 隐式转换为 Integer (TypeError) - 2

    玩转ruby​​,我已经:#!/usr/bin/ruby-w#WorldweatheronlineAPIurlformat:http://api.worldweatheronline.com/free/v1/weather.ashx?q={location}&format=json&num_of_days=1&date=today&key={api_key}require'net/http'require'json'@api_key='xxx'@location='city'@url="http://api.worldweatheronline.com/free/v1/weather.

  8. ruby - 类型错误 : can't convert String into Integer - 2

    我有代码:classScenedefinitialize(number)@number=numberendattr_reader:numberendscenes=[Scene.new("one"),Scene.new("one"),Scene.new("two"),Scene.new("one")]groups=scenes.inject({})do|new_hash,scene|new_hash[scene.number]=[]ifnew_hash[scene.number].nil?new_hash[scene.number]当我启动它时出现错误:freq.rb:11:in`[]'

  9. ruby - 为什么 String::sub!() 会更改 Ruby 中克隆对象的原始对象? - 2

    我的Ruby代码中有一个看起来有点像这样的结构Parameter=Struct.new(:name,:id,:default_value,:minimum,:maximum)稍后,我使用创建了这个结构的一个实例freq=Parameter.new('frequency',15,1000.0,20.0,20000.0)在某些时候,我需要这个结构的精确副本,所以我调用newFreq=freq.clone然后,我更改newFreq的名称newFreq.name.sub!('f','newF')奇迹般地,它也改变了freq.name!像newFreq.name='newFrequency'这样

  10. HarmonyOS原子化服务开发相关术语 - 2

    术语中文解释Ability原子化服务帮助用户完成任务的原子化服务,和用户的意图进行关联。Fulfillment服务履行通过图标,卡片,语音等形式呈现用户意图。开发者通过接口的方式,处理用户意图,返回内容。Intent意图用于表达用户想要达成的目标或完成的任务。HUAWEIAssistant智能助手“无微不智”的个人助手,通过不断的学习用户的使用习惯,不断的为用户提供贴心的精准的便捷的个性化服务。AISearch全局搜索用户可快速搜索关键词,与之匹配的原子化服务则会出现在搜索结果中。SmartService智慧服务用户订阅原子化服务,在到达特定触发条件(时间、地点、事件)后,卡片推送至用户智能助

随机推荐