Java字节基元类型是否有任何实际用途?

时间:2011-07-31 21:31:18

标签: java types byte

出于某种莫名其妙的原因,byte基元类型是用Java签名的。这意味着有效值为-128..127而不是通常的0..255范围,表示一个字节中的8个有效位(没有符号位)。

这意味着所有字节操作代码通常都会进行整数计算,最后屏蔽最后8位。

我想知道是否存在任何现实生活场景,其中Java byte基元类型完全适合,或者它只是一个完全无用的设计决策?


编辑:唯一的实际用例是本机代码的单字节占位符。换句话说,不要将其作为Java代码中的字节进行操作。


编辑:我现在已经看到一个内部紧密循环需要除以7(数字0..32)的位置,因此可以使用字节作为数据类型来完成查找表,以便可以保持较低的内存使用率L1缓存使用情况。这不是指签名/无签名,而是实际使用情况。

10 个答案:

答案 0 :(得分:33)

Josh Bloch最近mentioned in a presentation这是该语言中的错误之一。

我认为这背后的原因是java没有无符号数字类型,byte应符合该规则。 (注意:char是无符号的,但不代表数字)

至于具体问题:我想不出任何一个例子。即使有例子,它们也会少于0..255的那些,并且它们可以使用掩蔽(而不是大多数)来实现

答案 1 :(得分:16)

byte, short, char类型几乎没用,除非在数组中使用以节省空间。

Java JVM 都没有真正支持它们。几乎所有关于它们的操作都会首先将它们提升到intlong。我们甚至不能写像

这样的东西
short a=1, b=2;
a = a + b;  // illegal
a = a << 1; // illegal

那么为什么要对byte, short, char类型的操作进行定义呢?

他们所做的只是偷偷摸摸地扩大转换程序,这会让程序员感到惊讶。

答案 2 :(得分:10)

令人惊讶的是,我上周第一次在Java中使用了byte,所以我确实有一个(虽然不寻常)用例。我正在编写一个native Java function,它允许您在可以由Java调用的库中实现一个函数。需要将Java类型转换为本机语言的类型,在本例中为C

获取字节数组所需的函数,但是(当时完全忘记byte类型)我需要char[]。为C函数生成的签名Java将该参数的类型赋予jcharArray,可以将其转换为一堆jchar s,这些jni.hunsigned short到{{{ 1}}。当然,这不是相同的大小 - 它是2个字节而不是1.这导致了底层代码的各种问题。使Java类型byte[]产生jbyteArray,并且Linux上的jbyte被类型定义为signed char,这是正确的大小

答案 3 :(得分:4)

带有8位带符号样本的数字化声音(或任何其他信号)似乎是我唯一合理的例子。当然,签名字节不需要处理这些信号,可以说Java字节是否“完全适合”。

我个人认为没有签名是不对的。不仅因为对无符号字节/整数的使用更多,而且因为我更喜欢更强大的类型系统。能够指定负数无效并允许编译器检查和违规的运行时异常会很好。

答案 4 :(得分:3)

byte在Java Card的applet开发中有广泛的用途。因为卡片资源有限,所以每一点内存都是宝贵的。顺便说一句,卡处理器在处理整数值方面存在局限性。 int类型支持是可选的,不支持java.lang.String,因此所有整数操作和数据存储都由byteshort变量和数组完成。由于整数文字属于int类型,因此应在整个代码中将它们显式转换为byteshort。与卡的通信通过APDU命令传递给applet,作为byte的数组,应该分解为byte以解码命令类,指令和参数。查看以下代码,您会看到有多少byteshort类型对Java Card开发很重要:

package somepackage.SomeApplet;

import javacard.framework.*;
import org.globalplatform.GPSystem;
import org.globalplatform.SecureChannel;

public class SomeApplet extends Applet {

    // Card status
    private final static byte ST_UNINITIALIZED     = (byte) 0x01;
    private final static byte ST_INITIALIZED       = (byte) 0x02;

    // Instructions & Classes
    private final static byte PROP_CLASS           = (byte) 0x80;     

    private final static byte INS_INIT_UPDATE      = (byte) 0x50;
    private final static byte INS_EXT_AUTH         = (byte) 0x82;

    private final static byte INS_PUT_DATA         = (byte) 0xDA;
    private final static byte INS_GET_RESPONSE     = (byte) 0xC0;
    private final static byte INS_GET_DATA         = (byte) 0xCA;


    private final static short SW_CARD_NOT_INITIALIZED       = (short) 0x9101;  
    private final static short SW_CARD_ALREADY_INITIALIZED   = (short) 0x9102;  

    private final static byte OFFSET_SENT = 0x00;
    private final static byte OFFSET_RECV = 0x01;
    private static short[] offset;

    private static byte[] fileBuffer;
    private static short fileSize = 0;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new SomeApplet( bArray, bOffset, bLength);
    }

    public RECSApplet(byte[] bArray, short bOffset, byte bLength) {
        offset = JCSystem.makeTransientShortArray((short) 2, JCSystem.CLEAR_ON_RESET);
        fileBuffer = new byte[FILE_SIZE];

        byte aidLen = bArray[bOffset];
        if (aidLen== (byte)0){
            register();
        } else {
            register(bArray, (short)(bOffset+1), aidLen);
        }
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }
        byte[] buffer = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive(); 

        byte cla = buffer[ISO7816.OFFSET_CLA];
        byte ins = buffer[ISO7816.OFFSET_INS];
        short lc = (short) (buffer[ISO7816.OFFSET_LC] & 0x00ff); 

        while (len < lc) {
            len += apdu.receiveBytes(len);
        }

        SecureChannel sc = GPSystem.getSecureChannel();
        if ((short)(cla & (short)0x80) == ISO7816.CLA_ISO7816) {
            switch (ins) {
                case INS_PUT_DATA:
                    putData(buffer, ISO7816.OFFSET_CDATA, offset[OFFSET_RECV], len);

                    if ((cla & 0x10) != 0x00) {
                        offset[OFFSET_RECV] += len;
                    } else {
                        fileSize = (short) (offset[OFFSET_RECV] + len);
                        offset[OFFSET_RECV] = 0;
                    }
                    return;

                case INS_GET_DATA:
                case INS_GET_RESPONSE:
                    sendData(apdu);
                    return;
                default:
                    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
            }

        }
        else if ((byte) (cla & PROP_CLASS) == PROP_CLASS) {
            switch (ins) {
                case INS_INIT_UPDATE:
                case INS_EXT_AUTH:
                    apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, sc.processSecurity(apdu));
                    return;
                default:
                    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
            }
        } else
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    }

    // Some code omitted

}

答案 5 :(得分:1)

我认为它是签名的,以便与short和int保持一致。

关于它是否被大量使用,它使“字节数组”的概念成为构造而不是原语。

这就是我的全部。 :)

答案 6 :(得分:1)

在一个字大于8位的机器上,如果你希望将大量适合8位范围的值存储到单个数组中,它会有所帮助,但通常情况下使用它们并不是一个好主意,因为byte实际上是比int更加努力的内存。

请记住,Java是专为非常小的消费设备(机顶盒电视盒)而设计的。我希望如果它在小型8位微处理器上以这种方式使用它会更有用,因为它可以精确地适应字大小,并且可以用于非常小规模的一般“数学”操作。

我能看到让它签名的唯一原因是与int交互的无符号字节可能有点令人困惑 - 但我不相信它比签名的更令人困惑!

答案 7 :(得分:0)

字节大小为8位。字节大小有助于处理输入和输出,同时执行写入文件或从文件读取等功能。考虑一种情况,您希望从键盘或任何文件中读取输入。如果你使用&#34;字节&#34;数据结构,你知道你一次收到一个字符,因为大小是8位。因此,每次收到输入流时,您都知道您实际上一次只接收一个字符。

答案 8 :(得分:-1)

当我为J2ME编写软件和游戏时,我经常使用它。在大多数J2ME设备上,您的资源有限,因此在字节数组中存储级别的映射比将数据存储在int数组中要少得多。

答案 9 :(得分:-3)

我现在正在java中使用字节用于蓝牙android项目。

相关问题