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

问题描述 投票:56回答:10

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

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

我想知道是否有任何真实生活场景,Java byte原始类型完全适合或者它只是一个完全无用的设计决策?


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


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

java types byte
10个回答
10
投票

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

该函数需要一个字节数组,但(当时完全忘记了byte类型)我需要一个char[]。为C函数生成的签名Java将该参数的类型赋予jcharArray,它可以转换为一堆jchars,它们在jni.h中被定义为unsigned short。当然,这不是相同的大小 - 它是2个字节而不是1.这导致了底层代码的各种问题。制作Java类型byte[]导致了jbyteArray,而Linux上的jbyte被定义为signed char,这是正确的大小


-3
投票

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


33
投票

乔希布洛赫最近mentioned in a presentation认为这是该语言的错误之一。

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

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


16
投票

byte, short, char类型大多无用,除非在数组中使用以节省空间。

Java或JVM都没有任何真正的支持。几乎所有关于它们的操作都会首先将它们推广到intlong。我们甚至无法写出类似的东西

short a=1, b=2;
a = a + b;  // illegal
a = a << 1; // illegal

那么为什么甚至会对byte, short, char类型的定义操作感到麻烦呢?

他们所做的只是偷偷摸摸地扩大转换程序,这会给程序员带来惊喜。


4
投票

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

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


3
投票

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

}

1
投票

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

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

这就是我的全部。 :)


1
投票

在一个字大于8位的机器上,如果你希望将大量适合8位范围的值存储到单个数组中,这有点有用,但通常使用它们不是一个好主意,否则因为一个字节实际上是内存比int更多的努力。

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

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


0
投票

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


-1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.