首页 > 编程语言 >Java----字符串(String)

Java----字符串(String)

时间:2024-09-09 15:53:36浏览次数:13  
标签:lang abc java String Utf8 ---- 字符串 Java

一、什么是字符串?

定义:字符串是一个多个字符的序列

在java中用char数组来表示字符串,我们可以从源码看到:java对char数组进行了封装,并用String类型来表达字符串,也就是说java程序中所有字符串的文字都被成为此类的对象。

#java 8源码
/** The value is used for character storage. */
private final char value[];

看了字符串的定义之后,让我们来看一下

1.字符串的赋值方式?

2.两种赋值方式的区别

3.解释为什么String是不可变的?

二、赋值方式

1.直接赋值

        顾名思义,直接赋值就如下所示:

String s1="abc";

2.new

String s2=new String("abc");

可以看到这两种方式,都可以创建一个字符串,那么我们现在来解释一下两种赋值方式的区别。

区别:直接赋值会创建一个对象或者不创建对象,而new的方式至少会创建一个都对象。

        在说明这个区别之前,我们要了解几个概念:

        1.堆内存:存储对象或者数组,new来创建的,都存在堆内存中。

        2.栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行。

        3.常量池:我们在开发中,会经常大量使用String类型,java对其进行了性能优化。

看下面一段代码:

String a1=new String("dog");

String a2=new String("dog");

System.out.println(a1==a2); //运行结果false

这段代码可以看出,按照常规方式创建字符串对象的时候,即使字符串内容完全一致,也会创建多个对象,想象一下如果要使用几万个字符串,都要创建对象的话,那么会极大的浪费资源,所以就引入了字符串常量池这个概念:

当我们用字面量创建字符串时,字符串常量池会将其对象引用进行保存,后面如果创建重复的字面量,就会直接将字符串常量池的引用进行返回。


public class demo11 {
    public static void main(String[] args) {
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);//结果为true
    }
}

上图中代码可以看出对s1和s2使用直接赋值的方式,字面量都是"abc"。直接赋值时,系统都会检查该字符串在串池是否存在,不存在的话则创建新的,存在的话,可以看到字符串常量值"abc"的地址值返回。这也就解释了直接赋值的方式会创建一个或者不会创建对象。

那么对于new的方式,直接看内存原理图和代码就很好理解了。

public class demo98{
    public static void main(String[] args) {
          String s1=new String("abc");
          String s2=new String("abc");
          System.out.println(s1==s2);//运行结果为false

    }
}

        从内存图可以看出,当s1创建字符串对象时,发现常量池中并没有”abc"这个字符串这个对象,它就会在常量池中创建一个对象还会在堆上创建一个字符串s1并指向常量池,而且将s1的地址值返回,这时就是创建了两个对象。当s2创建对象的时候,也会去检查常量池中是否有该字符串,若有的话,直接在堆中创建一个新的String对象,这个对象也会指向常量池中的"abc",然后把这个新的String的地址返回,这时就是创建了一个对象。

那么,可能有人会说,常量池到底有没有我们也不知道啊,你这样说,也没有依据啊,那我们就来看一下字节码文件,通过javap -v demo98.class进行编译查看结果

Constant pool:
   #1 = Methodref          #8.#21         // java/lang/Object."<init>":()V
   #2 = Class              #22            // java/lang/String
   #3 = String             #23            // abc
   #4 = Methodref          #2.#24         // java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #27.#28        // java/io/PrintStream.println:(Z)V
   #7 = Class              #29            // stringDemo/demo98
   #8 = Class              #30            // java/lang/Object
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               main
  #14 = Utf8               ([Ljava/lang/String;)V
  #15 = Utf8               StackMapTable
  #16 = Class              #31            // "[Ljava/lang/String;"
  #17 = Class              #22            // java/lang/String
  #18 = Class              #32            // java/io/PrintStream
  #19 = Utf8               SourceFile
  #20 = Utf8               demo98.java
  #21 = NameAndType        #9:#10         // "<init>":()V
  #22 = Utf8               java/lang/String
  #23 = Utf8               abc
  #24 = NameAndType        #9:#33         // "<init>":(Ljava/lang/String;)V
  #25 = Class              #34            // java/lang/System
  #26 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;
  #27 = Class              #32            // java/io/PrintStream
  #28 = NameAndType        #37:#38        // println:(Z)V
  #29 = Utf8               stringDemo/demo98
  #30 = Utf8               java/lang/Object
  #31 = Utf8               [Ljava/lang/String;
  #32 = Utf8               java/io/PrintStream
  #33 = Utf8               (Ljava/lang/String;)V
  #34 = Utf8               java/lang/System
  #35 = Utf8               out
  #36 = Utf8               Ljava/io/PrintStream;
  #37 = Utf8               println
  #38 = Utf8               (Z)V

 我们可以看到,常量池会把abc存进去,供之后复用。

        到这里,还有一个问题就是那么String为什么是不可变的呢?

        首先,从前面的知识我们知道,当对一个字符串进行直接赋值时,它会到常量池先去查找这个字符串,如果没有,则会创建一个新的字符串对象,并将其返回,而不是在原来的基础上进行修改。

        其次,从原码的角度解释:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

final:

        .final修饰的变量表示变量的值不可改变,被final修饰过的变量就是常量

        .final修饰方法表示此方法不可以被重写

        .find修饰类表示此类不能被继承

1.第一点:可以看到String这个类被final修饰,表示该类不能被继承,从而杜绝了子类覆盖父类行为的过程

2.第二点:就是String字符串底层存储的实现也是用char value[]这个数组,这个数组也被final修饰,但是只说明它不能指向新的数组,不代表数组本身的数据不可被改变,真正不可变的原因是他还被private修饰,并且String并没有暴露提供任何修改字符数组的方法。

综上两点,说明String时不可变的。

        

标签:lang,abc,java,String,Utf8,----,字符串,Java
From: https://blog.csdn.net/qq_44766305/article/details/141997945

相关文章

  • 计算机毕业设计python企业人事员工考勤管理系统 8bqti
    目录技术栈和环境说明具体实现截图系统设计技术路线解决的思路python-flask核心代码部分展示python-django核心代码部分展示django项目结构讲解研究方法研究目的可行性分析论证源码获取技术栈和环境说明本系统以Python开发语言开发,MySQL为后台数据库,采用DJANGO/flas......
  • 使用yolov8识别+深度相机+机械臂实现垃圾分拣机械臂(代码分享)
    文章目录垃圾分拣机械臂视频演示程序主代码完整代码链接垃圾分拣机械臂视频演示点击查看使用YoloV8做的目标检测,机械臂手眼标定使用Aruco的方式,通过深度相机获取三维坐标,与机械臂坐标系之间的转化,得到抓取的坐标深度相机是dabaipro机械臂自己打印程序主代码imp......
  • 使用SSE发送和接收流式数据
    背景早期去玩了一下各个Ai厂商的免费额度(主要是国内的),虽然不是很给力,但是还是蛮好玩的。建立长连接我们通常使用WebSocket,而对于流式数据发送,只需要服务器返回数据,而不需要客户端发送数据的情况下,SSE是一个不错的选择。介绍SSE(Server-SentEvents)。数据格式大致如下,如果不写......
  • 计算机毕业设计python助农捐赠服务平台的设计与实现 0k7459
    目录技术栈和环境说明具体实现截图系统设计技术路线解决的思路python-flask核心代码部分展示python-django核心代码部分展示django项目结构讲解研究方法研究目的可行性分析论证源码获取技术栈和环境说明本系统以Python开发语言开发,MySQL为后台数据库,采用DJANGO/flas......
  • 在连通无向图中寻找正反向各通过每条边一次的路径(中国邮递员问题)
    在连通无向图中寻找正反向各通过每条边一次的路径(中国邮递员问题)引言问题定义算法思路具体步骤第一步:找出所有奇度顶点第二步:将奇度顶点配对,并添加最短路径第三步:构造欧拉回路伪代码C语言实现引言在图论中,中国邮递员问题(ChinesePostmanProblem,CPP)......
  • frp 内网穿透
     用的frp0.36_2版本#[common]isintegralsection[common]#AliteraladdressorhostnameforIPv6mustbeenclosed#insquarebrackets,asin"[::1]:80","[ipv6-host]:http"or"[ipv6-host%zone]:80"#Forsingle"bind_a......
  • java 多态
    面向对象三大特性:封装、继承、多态,今天我们来讲解多态定义:同类型的对象表现出不同的形态    这听起来有点抽象,我们举个具体的例子:    假设你开了一家宠物店,提供宠物寄养的服务,于是你规定可以给寄养所有的波斯猫,附近的居民都把宠物寄养在这里://参数是哈......
  • 21.多表查询
    多表关系一对多(多对一)多对多一对一一对多案例:部门与员工关系:一个部门对应多个员工,一个员工对应一个部门实现:在多的一方建立外键,指向一的一方的主键多对多案例:学生与课程关系:一个学生可以选多门课程,一门课程也可以供多个学生选修实现:建立第三张中间表,中间表至少包含两......
  • 计算机毕业设计nodejs+vue+express高校学生摄影社团管理系统 2ix7i
    目录技术栈具体实现截图系统设计解决的思路nodejs类核心代码部分展示可行性论证研究方法操作可行性源码获取技术栈该系统将采用B/S结构模式,开发软件有很多种可以用,本次开发用到的软件是vscode,用到的数据库是MySQL,为了更加便捷地使用数据库,用到了MySQL的可视化工具SQ......
  • Rancher 与 Kubernetes(K8s)的关系
    1. 简介1.1Kubernetes作为容器编排平台        Kubernetes是一个开源平台,用于自动化部署、扩展和管理容器化的应用。它提供了容器调度、自动伸缩、健康检查、滚动更新等功能。        例子:假设您有一个微服务架构的应用程序,需要运行在多个节点上,并且......