为什么Java不尊重给定的数组长度?

时间:2015-08-08 13:45:00

标签: java arrays

我在这段代码中看到了问题:

template <typename F, typename A>
auto functional_map(F func, const std::vector<A>& v)
    -> std::vector<typename std::decay<decltype(func(v[0]))>::type>
{
    using B = typename std::decay<decltype(func(v[0]))>::type;
    std::vector<B> result(v.size());
    for (int i = 0; i < (int)v.size(); ++i)
    {
        result[i] = func(v[i]);
    }
    return result;
}

数组是6个字节。如果我从长度为6的字符串中获取字节,我将获得更多字节。那么所有这些字节将如何进入这个数组呢?但这很有效。此外,buf.length显示该数组的长度,因为它是字符数组而不是那些字节。 之后,我意识到了

byte[] buf = new byte[6];
buf = "abcdef".getBytes();
System.out.println(buf.length);

6并不重要,即我可以放0或1或2左右,代码将起作用(buf.length显示给定字符串的长度不是数组 - 我认为是第二个问题或差异)。< / p>

这个问题与Why does Java's String.getBytes() uses “ISO-8859-1”不同,因为它至少有一个方面:变量分配疏忽(getBytes()返回新数组),即它不能完全解决我的问题。

3 个答案:

答案 0 :(得分:6)

这不是变量赋值的工作方式

认为将6字节数组分配给变量将限制分配给同一变量的任何其他数组的长度,这表明对变量是什么以及它们如何工作的基本缺乏理解。

真的想一想为什么你认为将变量赋值给固定长度的数组会限制分配给另一个长度数组的长度吗?

字符串是Java中的Unicode

Java中的字符串是Unicode,内部表示为UTF-16,这意味着它们在内存中每个字符为2或4个字节。 当它们转换为字节数组时,表示字符串的字节数由转换为byte[]时使用的编码确定。

将字符串转换为数组时,请始终指定适当的字符编码,以获得所需的内容。

但即使这样,UTF-8也不能保证每个字符只有单个字节,而ASCII将无法表示非ASCII个Unicode字符。

字符编码很棘手

无处不在的互联网编码标准UTF-8它将在99.9999999%的情况下更正,在这些情况下,它不会将UTF-8转换为正确的编码是微不足道的,因为UTF-8是在每个工具链中得到很好的支持。

学会制作所有内容final,您将会更轻松,更少时间地混淆。

import com.google.common.base.Charsets;

import javax.annotation.Nonnull;
import java.util.Arrays;

public class Scratch
{
    public static void main(final String[] args)
    {
        printWithEncodings("Hello World!");
        printWithEncodings("こんにちは世界!");
    }

    private static void printWithEncodings(@Nonnull final String s)
    {
        System.out.println("s = " + s);
        final byte[] defaultEncoding = s.getBytes(); // never do this, you do not know what you will get!
        // for ASCII characters the first three will all be the same single byte representations
        final byte[] iso88591Encoding = s.getBytes(Charsets.ISO_8859_1);
        final byte[] asciiEncoding = s.getBytes(Charsets.US_ASCII);
        final byte[] utf8Encoding = s.getBytes(Charsets.UTF_8);
        final byte[] utf16Encoding = s.getBytes(Charsets.UTF_16);

        System.out.println("Arrays.toString(defaultEncoding) = " + Arrays.toString(defaultEncoding));
        System.out.println("Arrays.toString(iso88591) = " + Arrays.toString(iso88591Encoding));
        System.out.println("Arrays.toString(asciiEncoding) = " + Arrays.toString(asciiEncoding));
        System.out.println("Arrays.toString(utf8Encoding) = " + Arrays.toString(utf8Encoding));
        System.out.println("Arrays.toString(utf16Encoding) = " + Arrays.toString(utf16Encoding));
    }
}

结果

s = Hello World!
Arrays.toString(defaultEncoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(iso88591) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(asciiEncoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(utf8Encoding) = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
Arrays.toString(utf16Encoding) = [-2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33]
s = こんにちは世界!
Arrays.toString(defaultEncoding) = [-29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, -29, -127, -81, -28, -72, -106, -25, -107, -116, 33]
Arrays.toString(iso88591) = [63, 63, 63, 63, 63, 63, 63, 33]
Arrays.toString(asciiEncoding) = [63, 63, 63, 63, 63, 63, 63, 33]
Arrays.toString(utf8Encoding) = [-29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, -29, -127, -81, -28, -72, -106, -25, -107, -116, 33]
Arrays.toString(utf16Encoding) = [-2, -1, 48, 83, 48, -109, 48, 107, 48, 97, 48, 111, 78, 22, 117, 76, 0, 33]

始终指定Charset编码!

.bytes(Charset)始终是将String转换为字节的正确方法。使用您需要的任何编码。

Internally supported encodings for JDK7

答案 1 :(得分:3)

new byte[6];无效,因为数组引用buf正在通过引用"abcdef".getBytes();返回的数组进行更新。

答案 2 :(得分:2)

那是因为String.getBytes()返回一个完全不同的数组对象,然后将其分配给buf。您可以轻松完成此任务:

byte[] buf = "abcdef".getBytes();
System.out.println(buf.length);