当前位置: 首页 > 面试题库 >

Java中初始化字符串的大小

轩辕华辉
2023-03-14
问题内容

显然,javac中初始化字符串的大小受到限制。谁能帮助我确定最大限额?

谢谢

编辑:

我们正在构建一个初始化字符串,看起来像这样的“ {1,2,3,4,5,6,7,8
......}”,但理想情况下应包含10,000个数字。当我们为1000执行此操作时,10,000会引发错误,提示代码对于try语句而言太大。

为了产生这种效果,我们使用了一个stringbuilder并在附加值的数组上循环。显然,这是javac中的限制。有人告诉我们,如果以小块形式传递数组,则可以使用调用的方法重建数组。但是,这是不可能的,因为我们无法控制所调用的用户方法。

我想发布代码,但是不能,因为这是大学的项目。我不是在寻找代码解决方案,而只是在理解实际问题所在方面有所帮助。

它的for循环是罪犯

    Object o = new Object() 
    { 
        public String toString() 
        { 
            StringBuilder s = new StringBuilder();
            int length = MainInterfaceProcessor.this.valuesFromData.length;
            Object[] arrayToProcess = MainInterfaceProcessor.this.valuesFromData;

            if(length == 0)
            {
                //throw exception to do
            }
            else if(length == 1)
            {
                s.append("{" + Integer.toString((Integer)arrayToProcess[0])+"}");
            }
            else
            {
                s.append("{" + Integer.toString((Integer)arrayToProcess[0])+","); //opening statement
                for(int i = 1; i < length; i++)
                {
                    if(i == (length - 1))
                    {
                        //last element in the array so dont add comma at the end
                        s.append(getArrayItemAsString(arrayToProcess, i)+"}");
                        break;
                    }       
                    //append each array value at position i, followed
                    //by a comma to seperate the values
                    s.append(getArrayItemAsString(arrayToProcess, i)+ ",");
                }
            }
            return s.toString();
        }
    };
    try 
    {
        Object result = method.invoke(obj, new Object[] { o });

}


问题答案:

字符串文字的长度(即"...")受类文件格式的CONSTANT_Utf8_info结构限制,该结构由该CONSTANT_String_info结构引用。

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

此处的限制因素是length属性,该属性只有2个字节大,即最大值为65535。该数字对应于字符串的已修改UTF-8表示形式中的字节数(实际上几乎是CESU-8,但0字符也以两字节形式表示)。

因此,一个纯ASCII字符串文字最多可以包含65535个字符,而由范围在U + 0800 … U +
FFFF范围内的字符组成的字符串仅占其中的三分之一。并且在UTF-8中编码为代理对的对(即U + 10000到U + 10FFFF)每个占用6个字节。

(因为标识符使用相同的结构,所以标识符(即类,方法和变量名以及它们的类型描述符)具有相同的限制。)

Java语言规范未提及字符串文字的任何限制:

字符串文字包含零个或多个用双引号引起来的字符。

因此,原则上,编译器可以将较长的字符串文字拆分为多个CONSTANT_String_info结构,并在运行时通过串联(和.intern()-ing结果)对其进行重构。我不知道是否有任何编译器实际上正在执行此操作。

它表明该问题与字符串文字无关,而与数组初始化程序有关。

当将一个对象传递给BMethod.invoke(和BConstructor.newInstance相似)时,它可以是BObject(即围绕现有对象的包装,然后将传递包装的对象),String(照原样传递),或者还要别的吗。在最后一种情况下,对象将被转换为字符串(by
toString()),然后将该字符串解释为Java表达式。

为此,BlueJ将把此表达式包装在类/方法中并编译此方法。在该方法中,将数组初始化程序简单地转换为一长串的数组分配…,这最终使该方法比Java方法的最大字节码大小长:

code_length项的值必须小于65536。

这就是为什么它会中断较长数组的原因。

因此,要传递更大的数组,我们必须找到其他方法将它们传递给BMethod.invoke。BlueJ扩展API无法创建或访问包装在BObject中的数组。

我们在聊天中发现的一个想法是:

  1. 在项目内部(或在新项目中,如果他们可以互操作)创建一个新类,如下所示:
    public class IntArrayBuilder {
    private ArrayList<Integer> list;
    public void addElement(int el) {
        list.add(el);
    }
    public int[] makeArray() {
        int[] array = new int[list.size()];
        for(int i = 0; i < array.length; i++) {
           array[i] = list.get(i);
        }
        return array;
    }
    

    }

(这是为了创建一个int[]-如果您还需要其他类型的数组,也可以使其更通用。此外,可以通过使用内部int[]存储来提高效率,随着内部存储的增长而偶尔地扩大它,然后int
makeArray进行最终的arraycopy。这是一个草图,因此这是最简单的实现。)

  1. 在我们的扩展中,创建一个此类的对象,然后通过调用其.addElement方法向该对象添加元素。
    BObject arrayToBArray(int[] a) {
    BClass builderClass = package.getClass("IntArrayBuilder");
    BObject builder = builderClass.getConstructor(new Class<?>[0]).newInstance(new Object[0]);
    BMethod addMethod = builderClass.getMethod("addElement", new Class<?>[]{int.class});
    for(int e : a) {
        addMethod.invoke(builder, new Object[]{ e });
    }
    BMethod makeMethod = builderClass.getMethod("addElement", new Class<?>[0]);
    BObject bArray = (BObject)makeMethod.invoke(builder, new Object[0]);
    return bArray;
    

    }

(为了提高效率,实际上对于每个数组转换,BClass / BMethod对象实际上只能被检索一次并被缓存,而不是一次。)
如果您通过某种算法生成数组内容,则可以在此处进行此生成,而不必先创建另一个包装对象。

  1. 在我们的扩展中,通过传递包装的数组,调用我们实际想用long数组调用的方法:
    Object result = method.invoke(obj, new Object[] { bArray });
    


 类似资料:
  • 问题内容: 我知道对于上面的第3个初始化,字符串对象在字符串池中初始化,而第4个与字符串池无关。 1.和2有 什么区别?如果我将其视为指针变量,它存储的是特定内存地址,而该内存地址从未被JVM或OS使用? 4.和5 之间有区别吗? 当我打印和通过直接和,对,我甚至无法通过compilation.For ,编译OK,我得到“空”,并在控制台窗口中的输出。为什么? @aioobe的答案后编辑:更多问题

  • 在我的应用程序中,一切正常,但我想提高性能并优化我的代码。 这两个哪个更适合 1.initialisation 2.连接

  • 问题内容: 如果String和其他字符串一样是一个类,如何使用双引号将其初始化? 问题答案: Java的设计者决定保留面向对象语言中的原始类型,而不是将所有内容都变成对象,以提高语言的性能。原语存储在调用堆栈中,这需要较少的存储空间,并且操作成本较低。另一方面,对象存储在程序堆中,这需要复杂的内存管理和更多的存储空间。 出于性能原因,Java的String设计为介于基本体和类之间。 例如 注意:

  • 同一类型的扫描仪方法在一个地方工作,但在另一个地方不工作。。。如果这改变了任何答案,我将使用eclipse作为我的代码编辑器。如果不是在这里,所有变量都已在别处声明。 如果有人知道如何解决这个问题,我将永远感激你:) 这一个正在工作: 这个不起作用: 错误消息:

  • 考虑以下初始化: 在g 5.2.0中,编译器对falseString发出警告,而对trueString发出错误。 使用clang 3.6-std=c 11时,编译器会对假字符串和真字符串抛出错误。 Q1)为什么的行为不同,即使两个初始化值是相同的类型()? Q2)哪个编译器是正确的,为什么?标准怎么说? 编辑: 错误:从“bool”到“std::string”(又名“basic\u string”

  • 如果String和其他类一样,那么如何使用双引号初始化它?