Java冷知识

一 方法参数不能超过 255 个

一般我们工作中,一个方法超过 5 个参数的都很少见。超过 10 个的估计是刚毕业的实习生干的,超过 255 个的更是没试验过。

/**
 * @author Xiao Lou
 */
public class ParamsExceed255 {
    public static void main(String[] args) {
        System.out.println("我出错了");
    }
    public void test(
            int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9,
            int p10, int p11, int p12, int p13, int p14, int p15, int p16, int p17, int p18, int p19,
            int p20, int p21, int p22, int p23, int p24, int p25, int p26, int p27, int p28, int p29,
            int p30, int p31, int p32, int p33, int p34, int p35, int p36, int p37, int p38, int p39,
            int p40, int p41, int p42, int p43, int p44, int p45, int p46, int p47, int p48, int p49,
            int p50, int p51, int p52, int p53, int p54, int p55, int p56, int p57, int p58, int p59,
            int p60, int p61, int p62, int p63, int p64, int p65, int p66, int p67, int p68, int p69,
            int p70, int p71, int p72, int p73, int p74, int p75, int p76, int p77, int p78, int p79,
            int p80, int p81, int p82, int p83, int p84, int p85, int p86, int p87, int p88, int p89,
            int p90, int p91, int p92, int p93, int p94, int p95, int p96, int p97, int p98, int p99,
            int p100, int p101, int p102, int p103, int p104, int p105, int p106, int p107, int p108, int p109,
            int p110, int p111, int p112, int p113, int p114, int p115, int p116, int p117, int p118, int p119,
            int p120, int p121, int p122, int p123, int p124, int p125, int p126, int p127, int p128, int p129,
            int p130, int p131, int p132, int p133, int p134, int p135, int p136, int p137, int p138, int p139,
            int p140, int p141, int p142, int p143, int p144, int p145, int p146, int p147, int p148, int p149,
            int p150, int p151, int p152, int p153, int p154, int p155, int p156, int p157, int p158, int p159,
            int p160, int p161, int p162, int p163, int p164, int p165, int p166, int p167, int p168, int p169,
            int p170, int p171, int p172, int p173, int p174, int p175, int p176, int p177, int p178, int p179,
            int p180, int p181, int p182, int p183, int p184, int p185, int p186, int p187, int p188, int p189,
            int p190, int p191, int p192, int p193, int p194, int p195, int p196, int p197, int p198, int p199,
            int p200, int p201, int p202, int p203, int p204, int p205, int p206, int p207, int p208, int p209,
            int p210, int p211, int p212, int p213, int p214, int p215, int p216, int p217, int p218, int p219,
            int p220, int p221, int p222, int p223, int p224, int p225, int p226, int p227, int p228, int p229,
            int p230, int p231, int p232, int p233, int p234, int p235, int p236, int p237, int p238, int p239,
            int p240, int p241, int p242, int p243, int p244, int p245, int p246, int p247, int p248, int p249,
            int p250, int p251, int p252, int p253, int p254
    ) {
        System.out.println("我有 255 个参数");
    }
}

上面的代码,虽然 idea 工具不会报错,但是在编译时就会出错!
Java参数过多
上面的代码直接无法编译(也就不会生成对应的 class 文件),编译期会报错.其中,第 9 行第 17 列也就是 test 方法名的位置。这说明编译阶段限制了尺寸。
如果我们把形参减少一个,上面这段代码就能通过编译了。

二 字符串长度限制

如果你不细心,工作多年的你可能还真不知道,Java 中字符串到底能有多长。
首先,一段字符串,我们在 Java 中想要获取它的长度信息,可以使用.length()函数。通过调用得知,length()返还的是一个 int 值。这说明,在 Java 中,一个字符串最长应该是不能超过 int 的。

2^31-1 =214748364716-bit Unicodecharacter

2147483647 * 16 = 3435973835234359738352 / 8 = 4294967294 (Byte)
4294967294 / 1024 = 4194303.998046875 (KB)
4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)
4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)

计算下来,约有 4G 的容量。
但在实际测试过程中,你会发现,字符串常量长度之要超过 65534 个字符,就会在编译期报错。

public static void main(String[] args) {
    String s = "a...a";// 共65534个a
    System.out.println(s.length());

    String s1 = "a...a";// 共65535个a
    System.out.println(s1.length());
}

上面的代码,会在String s1 = “a…a”;// 共65535个a处编译失败:

✗ javac StringTest.java
StringTest.java:11: 错误: 常量字符串过长

这长度还没超过 2147483647 呢?怎么就无法使用了?

实际上,String 内部是以 char 数组的形式存储,数组的长度是 int 类型,那么 String 允许的最大长度就是 Integer.MAX_VALUE 了。又由于 java 中的字符是以 16 位存储的,因此大概需要 4GB 的内存才能存储最大长度

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

上面的CONSTANT_Utf8_info结构中有u2 length;表明了该类型存储数据的长度。 u2 是无符号的 16 位整数,因此理论上允许的的最大长度是2^16=65536。而 java class 文件是使用一种变体 UTF-8 格式来存放字符的,null 值使用两个字节来表示,因此只剩下65536 - 2 = 65534个字节。关于这一点,在the class file format spec中也有明确说明:

The length of field and method names, field and method descriptors, and other constant string values is limited to 65535 characters by the 16-bit unsigned length item of the CONSTANTUtf8info structure (§4.4.7). Note that the limit is on the number of bytes in the encoding and not on the number of encoded characters. UTF-8 encodes some characters using two or three bytes. Thus, strings incorporating multibyte characters are further constrained.

所以,在 Java 中,字符串的实际最大长度是不能超过 65534 的。
但是,如果你真的有字符串长度要超过 65534,该怎么办呢?
聪明的人,估计已经想到了,既然是编译期报的错,那我就绕过编译期。且是字符串常量池有限制,那我也想办法饶过它,这样就能突破 65534 的限制了。
下面给一个简单的 demo 解除 65534 的限制。

StringBuilder sb = new StringBuilder();
sb.append("String");
sb.append(",String");
String str = sb.toString();
String [] parts = str.split(",");
System.out.println(parts.length);

实际上,不少 json 框架采用这种做法,突破字符串长度限制,做大 JSON 解析。

总结

关于这一小节,我们做一个简单的总结。

String 的长度是有限制的。
编译期的限制:字符串的UTF8编码值的字节数不能超过65535,字符串的长度不能超过65534。
运行时限制:字符串的长度不能超过2^31-1,占用的内存数不能超过虚拟机能够提供的最大值。
另外,本文的理论是基于 Java8 的。JDK9 以后对 String 的存储进行了优化。底层不再使用 char 数组存储字符串,而是使用 byte 数组。这样对于 LATIN1 字符的字符串可以节省一倍的内存空间。

单个 Java 方法长度限制
单个 Java 方法不能超过 65535 字节。我相信大部分 Java 程序员都没有遇到过这个错误:The code of method xxx() is exceeding the 65535 bytes limit。

一般使用 jsp,包含大量 html 代码时,才有可能遇到这个异常。

其他的情况,只有你遇到超大的方法体才回出现这个异常。一个方法的代码量要在几千几万行左右才回出现。这样的方法真是大的可怕,反正我是写不出来。

单个 Java 文件长度限制
一般的,一个 Java 类可以写多少行,几乎没人知道,因为没试验过。

实际上,Java 对单个类文件时有长度限制的。单个 Java 文件常量个数上限是 65536。超过这个数字会报:Too many constants, the constant pool for XXX would exceed 65536 entries。

这是因为.class文件头 4 个字节的模数(magic number)是小写的0xca,0xfe,0xba,0xbe。0xCA,0xFE,0xBA,0xBE连起来就是 cafebabe,这就是 Class 文件的魔数。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值