java中的String可以有多长?

2023-05-16

参考链接:     https://www.cnblogs.com/ibelieve618/p/6380328.html

https://www.cnblogs.com/htyj/p/8337209.html     https://blog.csdn.net/qq_36761831/article/details/99943600?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-0&spm=1001.2101.3001.4242

结论:

1、在编译期以字面量(字面量就是数据/数值,例如:1234,true,”abc”,’中’)形式放在java内存的栈中,以字节的个数代表String的长度,如果是拉丁字母,最长为65534(因为javac源码有个异常,不能为65535),如果含有中文(中文在utf-8中一般占三个字节),差别比较大,最大为65535。

2、存储的是数组和对象,凡是new建立的都是在堆中,理论上String最大长度为Integer.MAX_VALUE(2^31-1),但是有些VMs(虚拟机)需要保留一些空间给头信息,所以此时最大为Integer.MAX_VALUE-8,随意堆上的String的长度尽量小于Integer.MAX_VALUE-8。

 

概念:

栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

 堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。

 

那么String在栈和堆中都是以什么样的形式存在呢?

例如:关于String str = "abc"的内部工作。
Java内部将此语句转化为以下几个步骤: 
(1)先定义一个名为str的对String类的对象引用变量:String str; 
(2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着在栈中创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。 
(3)将str指向对象o的地址。 
值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用! 
为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。 
            String str1 = "abc"; 
            String str2 = "abc"; 
            System.out.println(str1==str2); //true 
注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。 
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。 
我们再来更进一步,将以上代码改成: 
            String str1 = "abc"; 
            String str2 = "abc"; 
            str1 = "bcd"; 
            System.out.println(str1 + "," + str2); //bcd, abc 
            System.out.println(str1==str2); //false 
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。 
事实上,String类被设计成为不可改变(final)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。 
再修改原来代码: 
            String str1 = "abc"; 
            String str2 = "abc"; 
            str1 = "bcd"; 
            String str3 = str1; 
            System.out.println(str3); //bcd 
            String str4 = "bcd"; 
            System.out.println(str1 == str4); //true 
str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。 
我们再接着看以下的代码。 
            String str1 = new String("abc"); 
            String str2 = "abc"; 
            System.out.println(str1==str2); //false 
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。 
            String str1 = "abc"; 
            String str2 = new String("abc"); 
            System.out.println(str1==str2); //false 
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。 
以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。 
6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型包装类都不能更改其内部的值。 
7. 结论与建议: 
(1)我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。 
(2)使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。 
(3)当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。 
(4)由于String类的final性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

 

 

正文:如下图,两者的String长度最长都是多少呢?

栈内存中:

当我们使用字符串字面量直接定义String的时候,是会把字符串在常量池中存储一份的。那么上面提到的65534其实是常量池的限制。常量池中的每一种数据项也有自己的类型。Java中的UTF-8编码的Unicode字符串在常量池中以CONSTANT_Utf8类型表示。

我们使用字面量定义的字符串在字节码class文件中,是使用CONSTANTUtf8info存储的,而CONSTANTUtf8info中有u2 length;表明了该类型存储数据的长度。u2是无符号的16位整数,因此理论上允许的的最大长度是2^16=65536。所以u1的bytes理论上最多能存储65536个字节(下文解释其实不是65536)。其运行时加载到jvm内存的方法区中的常量池内,(如果常量池太小,longString放不下就会出现oom,常量池大小可以控制,一般不会出现常量池太小的问题)

  
 

但是在测试时发现,传入65535个a会报错Error:java:constant string too long,查看编译器源码(javac源码)发现如下代码,所以这是编译器源码的一个bug,对于拉丁字符(Latin)由于一个字符占用一个字节,就会触发下图的代码,导致最多能存储65534个字节。

如果存储的字符串含有中文,中文在utf-8中一般占据三个字节,所以不会触发上图的方法,而是先将中文转成utf-8的编码,如下图。此时的代码就是正确的,最多能存储65535个字节。

所以在栈内存中String的长度总结如下:

 

 

堆内存

new的String存放在堆内存中,在读取文件时,其实就是new 一个String,这个String的背后其实就是一个char的数组,这个数组的大小受虚拟机指令newArray的限制,这个newArray接受的是一个整型的参数,理论上最大为Integer.MAX_VALUE,但是有些VMs(虚拟机)需要保留一些空间给头信息,所以此时最大为Integer.MAX_VALUE-8,随意堆上的String的长度尽量小于Integer.MAX_VALUE-8。

 

总结:

 

 

本章回顾:

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java中的String可以有多长? 的相关文章

随机推荐

  • 安卓利用tensorflow-lite使用yolov5训练的模型

    前言 作为使用yolov5后一次简单的尝试 准备工作 通过yolov5训练出自己所需要的模型查看模型训练教程将模型通过tensorflow的python版转换 xff0c 使用yolov5 6 1以上版本安卓端引入tensorflow远端依
  • 多个生产者一个消费者的单线程处理队列

    之前其他博主那里看到的例子 xff0c 很值得参考 span class token comment lt summary gt span span class token comment 队列处理 span span class toke
  • No plugin found for prefix install in the current project解决方案

    No plugin found for prefix install in the current project解决方案 maven 使用的setting配置文件为默认配置文件 xff0c 未修改 xff0c 运行install时报如下错
  • ubuntu 16和ubuntu20如何直接使用root登录系统

    之前Ubuntu14好像还可以直接选择用户名为root进行root登陆 xff0c 后面的版本好像就不行了 xff0c 不能选择root登陆了 没有root权限 xff0c 操作的时候好多情况都需要切换root权限进行操作 xff0c 这样
  • Kali 安装vnc

    1 安装tightvnc apt install tightvncserver apt install tightvnc java 通过浏览器java访问需要安装tightvnc java 2 启动VNC服务 span class toke
  • 通俗易懂的zookeeper选举机制

    目前网络上已有很多文章讲解了zookeeper的选举机制 xff0c 但都比较抽象难懂 xff0c 于是写下此文 xff0c 用最通俗易懂的语言阐述zookeeper的选举机制 xff0c 希望能帮助大家理解 zookeeper的选举机制一
  • mybatis IncompleteElementException:Could not find result map java.lang.String

    MyBatis项目中在查询数据库时遇到org apache ibatis builder IncompleteElementException Could not find result map java lang String 原因了把r
  • 【JAVA】-判断链表是否包含环

    目录 一 问题二 解题思路三 解题代码 一 问题 判断链表是否包含环 二 解题思路 判断链表是否包含环属于经典问题了 xff0c 解决方案也是用快慢指针 xff1a 每当慢指针 slow 前进一步 xff0c 快指针 fast 就前进两步
  • FTPClient 中文目录、中文文件名乱码、上传文件失败 解决方法

    FTPClient上传中文目录 中文文件名乱码问题解决方法 本文使用的FTP工具包为 apache的 commons net 起因 xff1a 今天在做FTP上传时一直上传文件上传不了 xff0c xff08 代码是跑通了 xff0c 但是
  • maven idea设置查找依赖优先从本地仓库获取

    第一步 xff1a 在这个settings里面 xff0c 设置默认的 第二步设置参数 DarchetypeCatalog 61 internal
  • Android集成OpenCV(NDK)

    1 下载OpenCv的动态库 so OpenCv官网 这边下载的是4 6 0 2 解压opencv 4 6 0 android sdk zip 复制目录opencv 4 6 0 android sdk OpenCV android sdk
  • Win10 重装系统备忘

    文章目录 一 美化工具1 Dism 43 43 很方便的简化 34 资源管理器 34 xff0c 比网上的教程方便很多 还有右键菜单等等 2 StartIsBack 可以吧 34 Win10菜单栏 34 xff08 屏幕下面那一横排 xff
  • ubuntu无法打开terminal

    我是在将系统显示设置为中文显示后 xff0c 重启无法打开终端的 xff0c 可以按照下面的链接进行修改 http blog csdn net u010395144 article details 52794947
  • MariaDB用法——增删改查

    数据库四大护法 增insert 删delete 改update 查select 设置禁用mysql删除语句 xff0c 防止操作者误删数据 mysql secure installation mysql基础安全设置 xff0c 设置密码 c
  • 女生学Java好不好就业?看看学完Java的你就业道路有多广?

    技能总在将学未学时最为美好 xff0c 高薪可期 Java xff0c 这门于 1995 年正式发布的老牌编程语言 xff0c 在每年 Github 的开发者报告统计出来之时 xff0c 总居前三高位不下 xff0c 成为使用人数最多的编程
  • Spring MVC 执行流程详解

    一 Spring MVC 执行流程 客户端的所有请求都会交给前端控制器DispatcherServlet来处理 xff0c DispatcherServlet会负责调用系统的其他模块来完成用户请求的处理 xff1b 即用户发送的请求会先从D
  • 程序员5大热门发展行业,就业迷茫的同学注意啦!

    信息化时代 xff0c 程序员成为各行业中的香饽饽岗位 xff0c 发展空间大 xff0c 薪资福利高 xff0c 因此最近几年转向程序员岗位的小伙伴越来越多 xff0c 不过因为这种 青睐 xff0c 使得程序员岗的竞争也越发大了 xff
  • 非常易懂且全面的计算机科学概论知识总结

    计算机科学概论 xff08 美 xff09 布鲁克希尔 这本书非常推荐大家去读一下 xff0c 作者用非常浅显易懂的语言让你能够对计算机领域有一个全面的认识和了解 xff0c 我在研一时候读的 xff0c 这本书让我受益匪浅 xff0c 对
  • Java 进口管制限制解除

    版权声明 xff1a 本文为博主原创文章 xff0c 遵循 CC 4 0 BY SA 版权协议 xff0c 转载请附上原文出处链接和本声明 由于国外的进出口限制 xff0c 对Java密码算法体系进行了一些限制 xff0c 为了解除限制 x
  • java中的String可以有多长?

    参考链接 xff1a https www cnblogs com ibelieve618 p 6380328 html https www cnblogs com htyj p 8337209 html https blog csdn ne