java中的String定义的字面量最大长度是多少

 更新时间:2019年12月25日 09:53:36   作者:蓝色土耳其18  
这篇文章主要介绍了java中的String定义的字面量最大长度是多少,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

java的String对象底层是有字符数组存储的,理论上char[]  最大长度是int的最大值,实际

思路:

首先,String字面常量是由String类来维护的,并且在编译时就可以确定(具体请参考String常量池)。因而,如果String字面常量存在一个最大的长度(目前暂且假设),而我们使用的字面常量又超过了这个极限,那么,在编译期间,编译器就能够给出错误信息。因此,我们可以使用IO流生成Java文件,文件的内容就是声明一个String对象,然后使用字面常量赋值,根据动态编译结果,调整字面常量的长度,最后得出字面常量的最大长度值

根据以下代码得出结论(代码来自书《Java深入解析:透析Java本质的36个话题 》):

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
 
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
 
public class LiteralLength {
 
 public static void main(String[] args) throws Exception {
 String fileName = "D:/Literal.java";
 StringBuilder prefix = new StringBuilder();
 prefix.append("public class Literal{ String s = \"");
 int low = 0;
 int high = 100_0000;
 int mid = (low + high)/2;
 StringBuilder literal = new StringBuilder(high);
 
 int result;
 
 String ch = "A";
 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 //自定义错误输出流 取代System的err
 OutputStream err = new OutputStream() {
  
  @Override
  public void write(int b) throws IOException {
  
  
  }
 };
 
 int max = 0;
 for (int i = 0; i < mid; i++) {
  literal.append(ch);
 }
 while(low <= high){
  StringBuilder fileContent 
        = new StringBuilder(literal.length() + prefix.length() * 2);
  fileContent.append(prefix);
  fileContent.append(literal);
  fileContent.append("\";}");
  FileWriter w = new FileWriter(fileName);
  BufferedWriter bw = new BufferedWriter(w);
  bw.write(fileContent.toString());
  bw.close();
  w.close();//生成java文件
  result = compiler.run(null, null, err, fileName);
  
  //代码点的数量
  int codePointCount = literal.codePointCount(0, literal.length());
  if(result == 0){//0表示没有编译错误
  low = mid + 1;
  mid = (low + high)/2;
  max = codePointCount;
  for (int i = codePointCount; i < mid; i++) {
   literal.append(ch);
  }
  System.out.println("长度" + max 
            + "编译成功,增加长度至" + mid);
  
  }else{
  //编译错误,说明字面量太长
  high = mid - 1;
  mid = (low + high)/2;
  System.err.println("长度" + codePointCount 
            + "编译失败,减少长度至" + mid);
  int start = ch.length() == 1? mid : mid *2;
  literal.delete(start, literal.length());
  }
 }
 err.close();
 System.out.println("最大字面量长度:" + max);
 
 
 }
}

 输出结果:

长度500000编译失败,减少长度至249999
长度249999编译失败,减少长度至124999
长度124999编译失败,减少长度至62499
长度62499编译成功,增加长度至93749
长度93749编译失败,减少长度至78124
长度78124编译失败,减少长度至70311
长度70311编译失败,减少长度至66405
长度66405编译失败,减少长度至64452
长度64452编译成功,增加长度至65428
长度65428编译成功,增加长度至65916
长度65916编译失败,减少长度至65672
长度65672编译失败,减少长度至65550
长度65550编译失败,减少长度至65489
长度65489编译成功,增加长度至65519
长度65519编译成功,增加长度至65534
长度65534编译成功,增加长度至65542
长度65542编译失败,减少长度至65538
长度65538编译失败,减少长度至65536
长度65536编译失败,减少长度至65535
长度65535编译失败,减少长度至65534
最大字面量长度:65534 

但是若 修改代码

String ch = "α";

结论 : 最大字面量长度:32767

若  String ch = "字";

最大字面量长度:21845

在class文件中,使用CONSTANT_Utf8_info表来存放各种常量字符串,包括String字面常量,类或接口的全限定名,方法及变量的名称、描述符等。CONSTANT_Utf8_info表的结构如表 所示。

从表3-1可知,CONSTANT_Utf8_info表使用2字节来表示字符串的长度,因此,bytes数组的最大长度为216−1,即65535字节。可是,为什么4个字符(“A”、“á”、“字”与“㊣”)的运行结果各不相同呢?原因在于,在CONSTANT_Utf8_info表中,从“\u0001”~“\u007f”,bytes使用1字节来表示,空字符(null,即“\u0000”)和从“\u0080”~“\u07ff”,使用2字节来表示,从“\u0800”~“\uffff”,使用3字节来表示,而对于增补字符,即代码点范围在“U+10000”~“U+10FFFF”之间的字符,使用6字节来表示。也可以这样认为,增补字符是使用一个代理对来表示的,而代理对的取值范围为“\ud800”~“\udfff”,这些字符都在“\u0800”~“\uffff”之间,每个代理字符使用3字节表示,共6字节。上述的存储是在class文件中的实现,不要与Java程序中的字符相混淆,对于Java程序来说,“A”、“á”、“字”都使用一个char类型变量表示,即2字节,而“[插图]”(增补字符)使用两个char类型变量表示,即4字节。

String字面常量的最大长度与String在内存中的最大长度是不一样的,后者的最大长度为int类型的最大值,即2147483647,而前者根据字符(字符Unicode值)的不同,最大长度也不同,最大长度为65534(可手动修改class文件,令输出结果为65535)。

String字面常量的最大长度是由CONSTANT_Utf8_info表来决定的,该长度在编译时确定,如果超过了CONSTANT_Utf8_info表bytes数组所能表示的上限,就会产生编译错误。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • idea compile项目正常启动项目的时候build失败报“找不到符号”等问题及解决方案

    idea compile项目正常启动项目的时候build失败报“找不到符号”等问题及解决方案

    这篇文章主要介绍了idea compile项目正常,启动项目的时候build失败,报“找不到符号”等问题,这种问题属于lombok编译失败导致,可能原因是依赖jar包没有更新到最新版本,需要的朋友可以参考下
    2023-10-10
  • java使用PageInfo的list通用分页处理demo

    java使用PageInfo的list通用分页处理demo

    这篇文章主要为大家介绍了java使用PageInfo的list通用分页处理demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2023-12-12
  • Java中的BlockingQueue接口源码解析

    Java中的BlockingQueue接口源码解析

    这篇文章主要介绍了Java中的BlockingQueue接口源码解析,BlockingQueue接口表示阻塞队列,是Java并发包中阻塞队列的接口定义规范,阻塞队列意味着对于该队列的操作是线程安全的,当多个线程存放元素进入队列或者从队列中取出元素都是线程安全的,需要的朋友可以参考下
    2023-11-11
  • SpringBoot集成quartz实现定时任务

    SpringBoot集成quartz实现定时任务

    这篇文章主要介绍了如何使用SpringBoot整合Quartz,并将定时任务写入库中(持久化存储),还可以任意对定时任务进行如删除、暂停、恢复等操作,需要的可以了解下
    2023-09-09
  • 如何在springboot中引入参数校验

    如何在springboot中引入参数校验

    一般我们判断前端传过来的参数,需要对某些值进行判断,是否满足条件,而springboot相关的参数校验注解,可以解决我们这个问题,本文给大家介绍如何在springboot中引入参数校验,感兴趣的朋友一起看看吧
    2023-12-12
  • java打包解包操作小结

    java打包解包操作小结

    使用别人的jar包程序,需要修改其中的相关参数然后重新打包,在此记录一下打包和解包过程,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • Java如何打印完整的堆栈信息

    Java如何打印完整的堆栈信息

    这篇文章主要为大家介绍了Java如何打印完整的堆栈信息示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 重写Java中的equals方法介绍

    重写Java中的equals方法介绍

    这篇文章主要介绍了重写Java中的equals方法介绍,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • SpringCloud Ribbon负载均衡工具使用

    SpringCloud Ribbon负载均衡工具使用

    Ribbon是Netflix的组件之一,负责注册中心的负载均衡,有助于控制HTTP和TCP客户端行为。Spring Cloud Netflix Ribbon一般配合Ribbon进行使用,利用在Eureka中读取的服务信息,在调用服务节点时合理进行负载
    2023-02-02
  • Java-文件File简单实用方法(分享)

    Java-文件File简单实用方法(分享)

    下面小编就为大家带来一篇Java-文件File简单实用方法(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08

最新评论