热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

byte数组转字符串_Java基础之字符串及——String

Java基础之字符串操作——String字符串什么是字符串?如果直接按照字面意思来理解就是多个字符连接起来组合成的字符序列。为了更好的理解以上的理论,我
15cd0e04845567e8cad9ac453dee76ec.png

Java基础之字符串操作——String

字符串

什么是字符串?如果直接按照字面意思来理解就是多个字符连接起来组合成的字符序列。为了更好的理解以上的理论,我们先来解释下字符序列,字符序列:把多个字符按照一定的顺序排列起来;而字符序列就是作为字符串的内容而存在的。所以可以把字符串理解为:把多个字符按照一定的顺序排列起来而构成的排列组合。

如果还是不好理解,没有关系,我还有法宝。我们可以用烤串来比喻说明,可以把字符串看作是烤串,烤串上的每一块肉都相当于是一个字符。把一块块肉按照肥瘦相间的顺序排列并串起来便成了我们吃的烤串,同理,把多个字符按照一定的顺序“串”起来就构成了字符串。

字符串的分类,字符串分为可变的字符串不可变的字符串两种;这里的不可变与可变指的是字符串的对象还是不是同一个,会不会因为字符串对象内容的改变而创建新的对象。

  • 不可变的字符串:当字符串对象创建完毕之后,该对象的内容(上述的字符序列)是不能改变的,一旦内容改变就会创建一个新的字符串对象;Java中的String类的对象就是不可变的。
  • 可变的字符串:StringBuilder类和StringBuffer类的对象就是可变的;当对象创建完毕之后,该对象的内容发生改变时不会创建新的对象,也就是说对象的内容可以发生改变,当对象的内容发生改变时,对象保持不变,还是同一个。

String 类

String类表示不可变的字符串,当前String类对象创建完毕之后,该对象的内容(字符序列)是不变的,因为内容一旦改变就会创建一个一个新的对象。

String对象的创建:

  1. 方式一:通过字面量赋值创建,String s1 = “laofu”; 需要注意这里是双引号:“”,区别与字符char类型的单引号:‘’;
  2. 方式二:通过构造器创建, String s2 = new String(“laofu”);

以上两种创建方式的对象在JVM中又是如何分布的呢? 分别有什么区别呢?

下面就来一一解密:

方式一和方式二在JVM中又是如何分布?

63b50f78ae25918b2f22fae1b3a90b18.png

字符串对象在JVM中的分布

上图中的常量池:用于存储常量的地方内存区域,位于方法区中。常量池又分为编译常量池运行常量池两种:

  • 编译常量池:当把字节码加载斤JVM的时候,其中存储的是字节码的相关信息(如:行号等)。
  • 运行常量池:其中存储的是代码中的常量数据。

方式一和方式二有何不同?

方式一:String s1 = “laofu”; 有可能只创建一个String对象,也有可能创建不创建String对象;如果在常量池中已经存在”laofu”,那么对象s1会直接引用,不会创建新的String对象;否则,会先在常量池先创建常量”laofu”的内存空间,然后再引用。

方式二:String s2 = new String(“laofu”); 最多会创建两个String对象,最少创建一个String对象。可使用new关键字创建对象是会在堆空间创建内存区域,这是第一个对象;然后对象中的字符串字面量可能会创建第二个对象,而第二个对象如方式一中所描述的那样,是有可能会不被创建的,所以至少创建一个String个对象。

字符串的本质,字符串在底层其实就是char[],char表示一个字符,比如:

String str = "laofu"; 等价于 char[] cs = new char[]{'l','a','o','f','u'};

1495c6ed2f0843c3db5b842f0dabae36.png

字符串在底层其实就是char[]

String对象的空值:

  1. 对象引用为空,即:String s1 = null; 此时s1没有初始化,也在JVM中没有分配内存空间。
  2. 对象内容为空字符串, 比如:String s2 = “”; 此时对象s2已经初始化,值为“”,JVM已经为其分配内存空间。

字符串的比较:使用“==”和“equals”会有不同效果,详情在之前的文章中分享过:Java面向对象之类、对象、static成员#对象比较操作

  1. 使用”==”号:用于比较对象引用的内存地址是否相同。
  2. 使用equals方法:在Object类中和”==”号相同,但在自定义类中,建议覆盖equals方法去实现比较自己内容的细节;由于String类覆盖已经覆盖了equals方法,所以其比较的是字符内容。
57f5ecc9dc29b740693d15d714fc4cc7.png

String equals方法的实现细节

所以可以这样来判断字符串非空:

  1. 对象引用不能为空:s1 != null;,
  2. 字符内容不能为空字符串(“”):“”.equals(s1);

如果上述两个条件都满足,说明字符串确实为空!

字符串拼接:Java中的字符串可以通过是“+”实现拼接,那么代码中字符串拼接在JVM中又是如何处理的呢?我们通过一个例子说明:通过比较拼接字符串代码编译前后的代码来查看JVM对字符串拼接的处理。

6d4dc8a016407d96d874d52f783a4f44.png

字符串拼接的JVM实现

通过上述例子不难发现,JVM会对字符串拼接做一些优化操作,如果字符串字面量之间的拼接,无论有多少个字符串,JVM都会一样的处理;如果是对象之间拼接,或者是对象和字面量之间的拼接,亦或是方法执行结果参与拼接,String内部会使用StringBuilder先来获取对象的值,然后使用append方法来执行拼接。由此可以总结得出:

  1. 使用字符串字面量创建的字符串,也就是单独使用""引号创建的字符串都是直接量,在编译期就会将其存储到常量池中;
  2. 使用new String("")创建的对象会存储到堆内存中,在运行期才创建;
  3. 使用只包含直接量的字符串连接符如"aa" + "bb"创建的也是直接量,这样的字符串在编译期就能确定,所以也会存储到常量池中;
  4. 使用包含String直接量的字符串表达式(如"aa" + s1)创建的对象是运行期才创建的,对象存储在堆中,因为其底层是创新了StringBuilder对象来实现拼接的;

5. 无论是使用变量,还是调用方法来连接字符串,都只能在运行期才能确定变量的值和方法的返回值,不存在编译优化操作。

String 的常用API

这里列举了一些常用String API,更多的可以查阅jdk使用手册,做Java一定得学会查阅jdk手册。

7bcdfbf5eec3bc1ddc2e6bd7c4b1bb43.png

jdk 手册

String 的创建和转换:

  • byte[] getBytes():把字符串转换为byte数组。
  • char[] toCharArray():把字符串转换为char数组。
  • String(byte[] bytes):把byte数组转换为字符串。
  • String(char[] value):把char数组转换为字符串。

获取字符串信息

  • int length() :返回此字符串的长度。
  • char charAt(int index) :返回指定索引处的 char 值。
  • int indexOf(String str) :返回指定字符串在此字符串中首次(从最左边算起)出现处的索引。
  • int lastIndexOf(String str) :返回指定字符串在此字符串中最后(最右边算起)出现处的索引。

字符串比较判断

  • boolean equals(Object anObject): 将此字符串与指定的对象比较。
  • boolean equalsIgnoreCase(String anotherString): 将此 String 与另一个 String 做忽略大小写的比较。
  • boolean contentEquals(CharSequence cs): 将此字符串与指定的 CharSequence 比较,比较的是内容;ps:String类是现实了CharSequence(字符序列)接口的。

字符串大小写转换:调用方法的字符串就是当前字符串

  • String toUpperCase(): 把当前字符串转换为大写
  • String toLowerCase(): 把当前字符串转换为小写

StringBuilder/StringBuffer

先来分别使用String/StringBuilder/StringBuffer来拼接30000次字符串,对比各自损耗的时间,经过测试发现:

String做字符串拼接的时候,耗时最高,性能极低,原因是String内容是不可变的,每次内容改变都会在内存中创建新的对象。

性能最好的是StringBuilder,其次是StringBuffer,最后是String。StringBuilder和StringBuffer区别并不是很大,也有可能是测试次数还不够吧。感兴趣的小伙伴可以增加拼接次数来看看。代码很简单,就不展示出来了。

所以在开发中拼接字符串时,优先使用StringBuffer/StringBuilder,不到万不得已,不要轻易使用String。

StringBuilder以及StringBuffer的区别

StringBuffer和StringBuilder都表示可变的字符串,两种’的功能方法都是相同的。但唯一的区别:

  • StringBuffer:StringBuffer中的方法都使用了synchronized修饰符,表示同步操作,在多线程并发的时候可以保证线程安全,但在保证线程安全的时候,对其性能有一定影响,会降低其性能。
  • StringBuilder:StringBuilder中的方法都没有使用了synchronized修饰符,线程不安全,正因为如此,其性能较高。

对并发安全没有很高要求的情况下,建议使用StringBuilder,因为其性能很高。像这样的情况会较多些。使用StringBuilder无参数的构造器,在底层创建了一个长度为16的char数组:

0423675475706950ddfa5b3bb974942c.png

StringBuilder 无参构造器

此时该数组只能存储16个字符,如果超过了16个字符,会自动扩容(创建长度更大的数组,再把之前的数组拷贝到新数组),此时性能极低;如果事先知道大概需要存储多少字符,可以通过构造器来设置字符的初始值:

9ed08e0e5d075f0a136f51499221dd44.png

设置初始值的StringBuilder构造器

//创建一个长度为80的char数组.new StringBuilder(80);

StringBuilder的常用方法:

  • append(Object val):追加任意类型数据到当前StringBuilder对象中。
  • StringBuilder deleteCharAt(int index) :删除字符串中指定位置的字符。

完结。

虽然老夫不正经,但老夫一身的才华



推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • Java面试题系列:将面试题中比较经典和核心的内容写成系列文章持续在公众号更新,可巩固基础知识,可梳理底层原理,欢迎大家持续关注【程序新视界】。本篇为面试题系列第2篇。常见面试问 ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了在Java中检查字符串是否仅包含数字的方法,包括使用正则表达式的示例代码,并提供了测试案例进行验证。同时还解释了Java中的字符转义序列的使用。 ... [详细]
  • Spring Batch中多线程配置及实现例子
    本文介绍了在Spring Batch中开启多线程的配置方法,包括设置线程数目和使用线程池。通过一个示例演示了如何实现多线程从数据库读取数据并输出。同时提到了在多线程情况下需要考虑Reader的线程安全问题,并提供了解决方法。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 本文介绍了禅道作为一款国产开源免费的测试管理工具的特点和功能,并提供了禅道的搭建和调试方法。禅道是一款B/S结构的项目管理工具,可以实现组织管理、后台管理、产品管理、项目管理和测试管理等功能。同时,本文还介绍了其他软件测试相关工具,如功能自动化工具和性能自动化工具,以及白盒测试工具的使用。通过本文的阅读,读者可以了解禅道的基本使用方法和优势,从而更好地进行测试管理工作。 ... [详细]
author-avatar
情非不得以1_810
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有