>

Java에서 비트 조작을 배우고 있습니다. 그래서 바이너리 문자열을 정수 바이트로 변환하고 짧게 변환하고 있습니다. 여기 내 프로그램이 있습니다 :-

byte sByte,lByte; // 8 bit
short sShort,lShort; // 16 bit
int sInt,lInt; // 32 bit
sByte= (byte)(int)Integer.valueOf("10000000", 2); //Smallest Byte
lByte= (byte) ~sByte;
sShort= (short)(int)Integer.valueOf("1000000000000000", 2); //Smallest Short
lShort = (short) ~sShort;
sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"10000000\" \"8 bit\" byte=>"+sByte+"\t~byte=>"+lByte);
System.out.println("\"1000000000000000\" \"16 bit\" short=>"+sShort+"\t~short=>"+lShort);
System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);

바이트와 쇼트는 변환되고 정수가 변환되지 않는 동안 가장 작은 바이트와 가장 작은 쇼트 값을 제공합니다.

다음과 같은 NumberFormatException이 발생합니다 :-

Exception in thread "main" java.lang.NumberFormatException: For input string: "10000000000000000000000000000000"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:583)
    at java.lang.Integer.valueOf(Integer.java:740)
    at com.learnjava.BitsManipulation.start(BitsManipulation.java:14)
    at com.learnjava.learnjava.main(learnjava.java:9)

그리고 그 3 개의 정수 변환 라인을 언급하면 ​​:-

//    sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
//    lInt= (int)~sInt;
//    System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);

출력이 나옵니다 :-

"10000000" "8 bit" byte=>-128   ~byte=>127
"1000000000000000" "16 bit" short=>-32768   ~short=>32767

괜찮습니다 .32 길이의 문자열 길이를 두 번 확인했으며 정수는 32 비트 Java에서 32 비트입니다.이 경우에는 작동하지 않아야합니다.

32 길이 문자열에서 0 또는 1을 제거하거나 1을 0으로 바꾸면 다음과 같이 작동합니다 .-

sInt = (int) (int)Integer.valueOf("00000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"00000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);

sInt = (int) (int)Integer.valueOf("1000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"1000000000000000000000000000000\" \"31 bit\" int=>"+sInt+"\t~int=>"+lInt);

출력은 다음과 같습니다 :-

"00000000000000000000000000000000" "32 bit" int=>0  ~int=>-1
"1000000000000000000000000000000" "31 bit" int=>1073741824  ~int=>-1073741825

나는 이것에 대해 혼란스러워하고있다. 왜이 문제에 대한 NumberFormatException 및 해결책이 발생하는지 이유를 알려주십시오.


  • 답변 # 1

    빠른 답변 :

    Integer.parseInt () 메소드 (Integer.valueOf ()에 의해 호출되는 메소드)는 부호있는 숫자를 처리하도록 설계되지 않았기 때문에 숫자가 음수인지를 알려야합니다. 빼기를 추가하여 코드를 "고정":

    Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
    System.out.println(sInt); // prints -2147483648
    
    
    <시간>

    긴 답변 :

    스택 트레이스는 어디에서 문제가 발생했는지 알아낼 수있는 곳을 알려줍니다. Integer.valueOf () 메소드는 Integer.parseInt ()를 호출하여 583 행에서 NumberFormatException을 발생시킵니다. openjdk에서 Integer 클래스의 코드를 찾을 수 있습니다.

    public static int parseInt(String s, int radix) throws NumberFormatException {
        int result = 0;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;
        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);
            }
            multmin = limit / radix;
            while (i < len) {
                digit = Character.digit(s.charAt(i++),radix);
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                result -= digit;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }
    
    

    설명을 위해 현재 예제에서 실행하지 않는 코드 부분을 제거했습니다. 한도는 -2147483647 (MIN_VALUE 이상)입니다. 마찬가지로, multmin은 -1073741823입니다. 루프의 첫 번째 반복에서 결과는 0이므로 result * radix는 0이고 숫자는 1 (문자열의 첫 번째 숫자)이므로 결과 숫자는 -1입니다. 두 번째 반복에서 숫자는 0이되지만 결과 * 기수는 -2입니다. 세 번째 반복에서 -4, -8 등을 얻습니다. 결과가 -1073741824와 같아 질 때까지 계속됩니다. 이는 한계보다 1이 적습니다.

    이제이 방법으로 숫자에 부호 (+ 또는-)를 추가했는지 확인합니다. 흥미롭게도, 빼기를 더하면 한계가 MIN_VALUE로 설정됩니다. 따라서 직관적으로, 빼기 (-)를 추가하여 코드를 간단히 "고정"할 수 있습니다.

    Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
    System.out.println(sInt); // prints -2147483648
    
    
    <시간>

    다시 말하면, 당신은 거기에서 이상한 캐스팅을합니다. 대신 :

    sByte= (byte)(int)Integer.valueOf("10000000", 2);
    
    

    글을 쓸 수 있어야합니다 :

    sByte = Byte.valueOf("10000000", 2);
    
    

    실제로는 할 수 없기 때문에 "해야한다"고 말합니다. 또 다른 예외가 발생합니다! 이는 Byte.valueOf () 메서드가 Integer.valueOf () 메서드를 간단하게 호출 한 다음 Byte에 응답을 캐스팅하기 때문입니다. 그리고 정수의 10000000은 000 ... 00010000000 = 128이므로 바이트에 비해 너무 크다는 것을 알려줍니다.

    후아! 그렇다면 왜 이상한 캐스팅 트릭이 작동합니까? "자동 오버플로"라는 것이 있습니다. Java는 필자가 바이트에 숫자 128을 필사적으로 맞추기를 원한다는 것을 알고 있습니다. 가능한 한 많은 수를 넣을 수 있고 (127) 나머지 1을 추가하여 맨 아래로 감싸서 -128로 남겨 둡니다. . 나는 이것이 자동 오버플로가 설계된 것이라고 가정하지만, 그것에 따라 분명히 나쁜 생각입니다. 라인에서 일어나는 일을 설명하려면 :

    sByte= (byte)(int)Integer.valueOf("10000000", 2);
    Integer a = Integer.valueOf("10000000", 2);
    System.out.println(a);        // 128
    int b = (int)a;
    System.out.println(b);        // 128
    byte sByte = (byte)b;
    System.out.println(sByte);    // -128
    
    

    따라서 부호있는 숫자에 parseInt () 또는 valueOf ()를 사용하지 마십시오.

관련 자료

  • 이전 "javafx 응용 프로그램 스레드"스레드 예외 javalangruntimeexception : javalangreflectinvocationtargetexception
  • 다음 odoo 110에서 새 javascript 파일을 추가하고 웹/로그인로드시 스크립트를 호출하려면 어떻게해야합니까?