기본 유형 '짧은'-Java로 캐스팅


78

shortJava 의 기본 유형 에 대한 질문이 있습니다 . JDK 1.6을 사용하고 있습니다.

다음이있는 경우 :

short a = 2;
short b = 3;
short c = a + b;

컴파일러는 컴파일을 원하지 않습니다. "int에서 short로 변환 할 수 없습니다"라고 말하고 캐스트를 만들 것을 제안합니다 short.

short c = (short) (a + b);

정말 작동합니다. 하지만 내 질문은 왜 내가 캐스트해야하나요? a와 b의 값은 범위에 있습니다 short-짧은 값의 범위는 {-32,768, 32767}입니다. 나는 또한 작업을 수행하고 싶을 때 캐스트해야합니다-, *, / (다른 사람을 확인하지 않았습니다).

기본 유형에 대해 동일한 작업을 수행하면 intaa + bb를 int. 다음은 잘 작동합니다.

int aa = 2;
int bb = 3;
int cc = aa +bb;

나는 short 타입의 두 변수를 추가해야하는 클래스를 디자인하면서 이것을 발견했고 컴파일러는 내가 캐스트를 만들기를 원했다. 유형의 두 변수를 사용하여이 작업을 수행하면 int캐스트 할 필요가 없습니다.

작은 말 : primitive type에서도 같은 일이 발생합니다 byte. 따라서 이것은 작동합니다.

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

그러나 이것은 아닙니다 :

byte a = 2;
byte b = 3;
byte c = a + b;

를 들어 long, float, double,과 int, 캐스트 할 필요가 없습니다. shortbyte값에 대해서만 .

답변:


64

짧은 C #에 설명 된대로 (하지만 Java와 같은 다른 언어 컴파일러에도 해당)

short에서 int, long, float, double 또는 decimal로 미리 정의 된 암시 적 변환이 있습니다.

더 큰 스토리지 크기의 비 리터럴 숫자 유형을 short로 암시 적으로 변환 할 수 없습니다 (정수 유형의 스토리지 크기는 Integral Types Table 참조). 예를 들어 다음 두 개의 짧은 변수 x 및 y를 고려하십시오.

short x = 5, y = 12;

다음 할당 문은 할당 연산자의 오른쪽에있는 산술 표현식이 기본적으로 int로 평가되기 때문에 컴파일 오류가 발생합니다 .

short z = x + y;   // Error: no conversion from int to short

이 문제를 해결하려면 캐스트를 사용하십시오.

short z = (short)(x + y);   // OK: explicit conversion

그러나 대상 변수의 저장소 크기가 같거나 저장소 크기가 더 큰 다음 문을 사용할 수 있습니다.

int m = x + y;
long n = x + y;

좋은 후속 질문은 다음과 같습니다.

"대입 연산자의 오른쪽에있는 산술 표현식이 기본적으로 int로 평가되는 이유"?

첫 번째 답변은 다음에서 찾을 수 있습니다.

정수 상수 폴딩 분류 및 공식 검증

산술 표현식이 평가되어야 정수 자바 언어 사양을 정의는 정수 번호는 어떻게 표현하고 정확하게하는 방법 . 이 프로그래밍 언어는 인터넷의 분산 응용 프로그램에서 사용되도록 설계 되었기 때문에 Java의 중요한 속성입니다. Java 프로그램은이를 실행하는 대상 기계와 독립적으로 동일한 결과를 생성하는 데 필요합니다 .

반대로 C (및 널리 사용되는 명령형 및 객체 지향 프로그래밍 언어의 대부분)는 더 조잡하고 많은 중요한 특성을 열어 둡니다. 이 부정확 한 언어 사양의 의도는 분명합니다. 동일한 C 프로그램은 대상 프로세서에 내장 된 산술 연산을 사용하여 소스 프로그램의 정수 산술을 인스턴스화하여 16 비트, 32 비트 또는 64 비트 아키텍처에서 실행되어야합니다. 이는 사용 가능한 기계 작업을 직접 사용할 수 있기 때문에 훨씬 더 효율적인 코드로 이어집니다. 정수 계산이 "충분히 작은"숫자만을 처리하는 한, 불일치는 발생하지 않습니다.

이러한 의미에서 C 정수 산술은 프로그래밍 언어 사양에 의해 정확하게 정의되지 않고 대상 시스템을 결정함으로써 만 완전히 인스턴스화되는 자리 표시 자입니다.

Java는 정수가 표현되는 방법과 정수 산술이 계산되는 방법을 정확하게 정의합니다.

      Java Integers
--------------------------
Signed         |  Unsigned
--------------------------
long  (64-bit) |
int   (32-bit) |
short (16-bit) |  char (16-bit)
byte  (8-bit)  |

Char는 유일한 부호없는 정수 유형입니다. 그 값은 유니 코드 문자를 나타냅니다. from \u0000~ \uffff, 즉 0 ~ 2 16 -1.

정수 연산자에 long 유형의 피연산자가 있으면 다른 피연산자도 long 유형으로 변환됩니다. 그렇지 않으면 연산이 int 유형의 피연산자에 대해 수행되고 필요한 경우 더 짧은 피연산자가 int로 변환됩니다 . 변환 규칙이 정확하게 지정됩니다.

[이론 컴퓨터 과학의 전자 노트 82 No. 2 (2003)
Blesner-Blech-COCV 2003 : Sabine GLESNER , Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Germany]


또한 다음 T a, b; a += b과 동일합니다 T a, b; a = (T) (a + b). 컴파일러가 추가 한 캐스트를 확인하십시오.
wchargin 2013 년

17

편집 : 좋아, 이제 우리는 그것이 Java라는 것을 알고 있습니다 ...

Java 언어 사양의 섹션 4.2.2는 다음과 같이 설명합니다.

Java 프로그래밍 언어는 정수 값에 대해 작동하는 여러 연산자를 제공합니다.

[...]

  • int 또는 long 유형의 값이되는 숫자 연산자 :
  • [...]
  • 더하기 연산자 + 및-(§15.18)

  • (정수형에 적용) 더하기 연산자는 오직 결과 - 즉, C 번호처럼 int또는 long당신이에 할당 캐스트해야하는 이유 인 short변수입니다.

    원래 답변 (C #)

    C #에서 (언어를 지정하지 않았으므로 추측합니다) 기본 형식에 대한 유일한 추가 연산자는 다음과 같습니다.

    int operator +(int x, int y);
    uint operator +(uint x, uint y);
    long operator +(long x, long y);
    ulong operator +(ulong x, ulong y);
    float operator +(float x, float y);
    double operator +(double x, double y);
    

    이는 C # 3.0 사양, 섹션 7.7.4에 있습니다. 또한 소수점 더하기가 정의됩니다.

    decimal operator +(decimal x, decimal y);
    

    (열거 추가, 문자열 연결 및 대리자 조합도 여기에서 정의됩니다.)

    보시다시피 short operator +(short x, short y)연산자가 없으므로 두 피연산자가 암시 적으로 int로 변환되고 int 형식이 사용됩니다. 이는 결과가 "int"유형의 표현식이므로 캐스트해야 함을 의미합니다.


    7.7.4 섹션에 연결하기 위해 msdn.microsoft.com/en-us/library/aa691375(VS.71).aspx 를 추가 할 수 있습니다.
    VonC

    예, C # 3.0 사양의 간단한 하이퍼 링크 버전 이 없다는 것은 유감입니다 . MSDN 버전은 너무 고통 스럽습니다. IMO :(
    Jon Skeet

    이제 우리는 그것이 Java라는 것을 알고 있으므로 uint 또는 ulong이 없습니다. Java가 BigInteger 및 / 또는 BigDecimal에 대해 연산자 +를 오버로드하는지 여부를 기억할 수 없습니다
    finnw

    아직 0 ?! 어서 ... +1, 사양을 올바르게 언급했습니다;) 내 답변에서 내 후속 질문을 살펴보고 해당 주제에 대한 통찰력이 있는지 확인해 주시겠습니까? (예 : "왜 기본적으로 int가 있습니까?" ")
    VonC


    16

    C # 및 Java에서 할당 오른쪽의 산술 표현식은 기본적으로 int로 평가됩니다. 그렇기 때문에 int에서 short 로의 암시 적 변환이 없기 때문에 short로 다시 캐스팅해야합니다.


    8

    "기본적으로 왜 int"질문에 대한 답변이없는 경우 ...

    첫째, "기본값"은 실제로 적절한 용어가 아닙니다 (충분히 가깝지만). VonC에서 언급했듯이 int와 long으로 구성된 표현식은 긴 결과를 갖습니다. 그리고 int / logs 및 double로 구성된 연산은 두 배의 결과를 갖습니다. 컴파일러는 결과에서 더 큰 범위 및 / 또는 정밀도를 제공하는 모든 유형으로 표현식의 용어를 승격합니다 (대형 long을 double로 변환하면 정밀도가 손실되지만 부동 소수점 유형은 정수보다 더 큰 범위 및 정밀도를 갖는 것으로 간주됩니다).

    한 가지주의 할 점은이 프로모션이 필요한 조건에 대해서만 발생한다는 것입니다. 따라서 다음 예에서 하위 표현식 5/4는 정수 값만 사용하고 전체 표현식이 double을 포함하더라도 정수 수학을 사용하여 수행됩니다. 결과가 예상과 다릅니다 ...

    (5/4) * 1000.0
    

    좋아요, 왜 byte와 short가 int로 승격됩니까? 저를 백업 할 언급이없는 것은 실용성 때문입니다. 바이트 코드 수가 제한되어 있습니다.

    이름에서 알 수 있듯이 "바이트 코드"는 단일 바이트를 사용하여 작업을 지정합니다. 예를 들어 , 두 개의 int를 추가하는 iadd . 현재 205 개의 opcode가 정의 되어 있으며 정수 수학은 변환 연산자를 계산하지 않고 각 유형에 대해 18 개 (즉, 정수와 long 사이의 합계 36 개)를 사용합니다.

    짧고 바이트에 각각 고유 한 opcode 세트가 있으면 241이되어 JVM의 확장 기능이 제한됩니다. 내가 말했듯이 이것에 대한 저를 뒷받침하는 언급은 없지만 Gosling 등이 "사람들이 실제로 반바지를 얼마나 자주 사용합니까?"라고 말한 것 같습니다. 반면에 byte를 int로 승격하면 다음과 같은 그다지 멋진 효과가 발생합니다 (예상 답변은 96, 실제 값은 -16).

    byte x = (byte)0xC0;
    System.out.println(x >> 2);
    

    예상되는 대답은 48입니다.
    mafu

    @mafu 그렇습니다. 그래서 >>캐스트 int?? 그러나 그 효과는 Z80에서 SRA(오른쪽 산술 시프트) 라고 불리는 것 입니다. 이는 바이트의 비트를 오른쪽으로 1 자리로 이동하고 맨 오른쪽을 잃고 맨 왼쪽을 복제합니다 (따라서 부호있는 바이트를 2로 나눔). SRL(시프트 오른쪽 논리), 왼쪽에 0 비트를 남깁니다 (부호없는 바이트를 2로 나누는 것과 동일). 이것이 "예상 답변"의 기반입니다.
    Heimdall

    5

    어떤 언어를 사용하고 있습니까?

    많은 C 기반 언어에는 수학적 표현이 int 이상의 크기로 수행된다는 규칙이 있습니다. 이 때문에 두 개의 short를 추가하면 결과는 int 유형이됩니다. 이로 인해 캐스트가 필요합니다.


    2

    Java는 항상 계산에 최소 32 비트 값을 사용합니다. 이는 Java가 도입되었을 때 1995 년에 일반적이었던 32 비트 아키텍처 때문입니다. CPU의 레지스터 크기는 32 비트이고 산술 논리 장치는 CPU 레지스터 길이의 2 개 숫자를 허용했습니다. 따라서 CPU는 이러한 값에 최적화되었습니다.

    이것이 바로 산술 연산을 지원하고 32 비트 미만의 모든 데이터 유형이 계산에 사용되는 즉시 int (32 비트)로 변환되는 이유입니다.

    요약하자면 주로 성능 문제로 인해 호환성을 위해 유지되고 있습니다.


    1

    Java에서 다음과 같은 모든 숫자 표현식 :

    anyPrimitive zas = 1;
    anyPrimitive bar = 3;
    ?? x = zas  + bar 
    

    x는 항상 최소한 int가되거나 덧셈 요소 중 하나가 long이면 long이됩니다.

    하지만 몇 가지 어려운 점이 있습니다.

    byte a = 1; // 1 is an int, but it won't compile if you use a variable
    a += 2; // the shortcut works even when 2 is an int
    a++; // the post and pre increment operator work
    

    1

    AFAIS, 아무도 final그 사용법에 대해 언급하지 않았습니다 . 당신이 당신의 마지막 예제를 수정하고 변수 a와 b 정의하면 final 변수를 다음 컴파일러입니다 보장 자신의 합계 값 (5), 유형의 변수에 할당 할 수있는 byte정밀도의 손실없이. 이 경우 컴파일러는 a와 b의 합을 c에 할당하는 것이 좋습니다. 수정 된 코드는 다음과 같습니다.

    final byte a = 2;
    final byte b = 3;
    byte c = a + b;
    

    정확히. final byte a = (byte) (new Random().nextInt(4));그리고 Incompatible types그것은 다시 못생긴 머리를 키운다. 최종성뿐만 아니라 유형에 맞는 값으로 컴파일 할 수 있습니다.
    LAFK는 Reinstate Monica

    Herbert Schildt에게 불만을 전하십시오. 그의 생각입니다. @LIttleAncientForestKami
    SNR

    특히 Shildt조차도 javac에 대해 도움을 줄 수 없기 때문에 @snr이 하나 있으면 좋을 것입니다. ;-) 귀하의 말 final 은 컴파일러보장 한다는 것을 의미 하며 충분하지 않을 수 있습니다. 당신의 예를 그대로 사용하면 모든 것이 훌륭하고 멋집니다. 그러나 교체 시도 b = 3와 함께 b = (byte)(new Random().nextInt(4)). 호환되지 않는 유형이 돌아 왔고 a + b는 다시 캐스팅해야합니다. 답변에 추가 할 수 있습니다.
    LAFK는 분석 재개 모니카 말한다

    1

    "int"(Boolean 제외)보다 작은 데이터 유형은 암시 적으로 "int"로 변환됩니다.

    귀하의 경우 :

    short a = 2;
    short b = 3;
    short c = a + b;
    

    (a + b)의 결과는 암시 적으로 int로 변환됩니다. 그리고 지금 당신은 그것을 "short"에 할당하고 있습니다. 그래서 당신은 오류가 발생합니다.

    short, byte, char-이 모든 것에 대해 동일한 오류가 발생합니다.


    0

    지적되지 않은 것을 추가하고 싶습니다. Java는 변수 (2 및 3)에 지정한 값을 고려하지 않습니다.

    짧은 a = 2; 짧은 b = 3; 짧은 c = a + b;

    자바가 아는 한이 작업을 수행 할 수 있습니다.

    짧은 a = 32767; 짧은 b = 32767; 짧은 c = a + b;

    short 범위를 벗어난 경우 결과가 short 이상이지만 int 이하인 것은 "가능"하기 때문에 결과를 int로 자동 상자에 넣습니다. 기본적으로 대부분의 사람들은 2,147,483,647 이상 또는 -2,147,483,648 이하의 값을 하드 코딩하지 않기 때문에 Int가 "기본값"으로 선택되었습니다.


    말도 안 돼요. 두 개의 int MAXVALUE를 추가 할 수 있고 LHS가 길지 않아도되기 때문입니다.
    Gordon
    당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
    Licensed under cc by-sa 3.0 with attribution required.