수색…


소개

Java 프로그래밍 언어의 연산자 는 하나, 둘 또는 세 개의 피연산자에 대해 특정 연산을 수행 한 다음 결과를 반환하는 특수 기호입니다.

비고

연산자 는 Java 프로그램이 하나, 둘 또는 세 개의 피연산자 에 대해 연산 을 수행하도록 지시하는 기호 (들)입니다. 연산자와 피연산자가 표현식을 구성합니다 (표현식 항목 참조). 연산자의 피연산자는 그 자체가 표현식입니다.

이 주제에서는 Java에 의해 정의 된 40 가지의 다른 연산자를 설명합니다. 별도의 표현식 항목에서 설명합니다.

  • 연산자, 피연산자 및 기타 요소가 표현식으로 결합되는 방식,
  • 표현식 평가 방법 및
  • 표현식 입력, 변환 및 표현식 평가 작동 방식

문자열 연결 연산자 (+)

+ 기호는 Java의 세 가지 고유 연산자를 의미 할 수 있습니다.

  • + 앞에 피연산자가 없으면 단항 Plus 연산자입니다.
  • 피연산자가 두 개인 경우 두 피연산자가 모두 숫자입니다. 다음은 이진 덧셈 연산자입니다.
  • 두 개의 피연산자가 있고 그 중 적어도 하나가 String 이면 이진 연결 연산자입니다.

간단한 경우 Concatenation 연산자는 두 개의 문자열을 조인하여 세 번째 문자열을 제공합니다. 예 :

String s1 = "a String";
String s2 = "This is " + s1;    // s2 contains "This is a String"

두 피연산자 중 하나가 문자열이 아닌 경우 다음과 같이 String 으로 변환됩니다.

  • 형식이 기본 유형 인 피연산자는 boxed 값에서 toString() 을 호출하여 변환 됩니다 .

  • 형식이 참조 형식 인 피연산자는 피연산자의 toString() 메서드를 호출하여 변환됩니다. 피연산자가 null 이거나 toString() 메서드가 null 반환하면 문자열 리터럴 "null" 이 대신 사용됩니다.

예 :

int one = 1;
String s3 = "One is "  + one;         // s3 contains "One is 1"
String s4 = null + " is null";        // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
                                      // "{} is [I@xxxxxxxx"

s5 예제에 대한 설명은 배열 유형의 toString() 메소드가 java.lang.Object 에서 상속되고, 동작은 유형 이름과 객체의 ID 해시 코드로 구성된 문자열을 생성하는 것입니다.

Concatenation 연산자는 표현식이 상수 표현 인 경우를 제외하고는 새 String 객체를 만들도록 지정됩니다. 후자의 경우, 표현식은 컴파일 유형에서 평가되고 런타임 값은 문자열 리터럴과 동일합니다. 즉, 다음과 같이 긴 문자열 리터럴을 분할 할 때 런타임 오버 헤드가 없습니다.

String typing = "The quick brown fox " +
                "jumped over the " +
                "lazy dog";           // constant expression

최적화 및 효율성

위에서 언급했듯이 상수 표현식을 제외하면 각 문자열 연결 표현식은 새로운 String 객체를 만듭니다. 다음 코드를 고려하십시오.

public String stars(int count) {
    String res = "";
    for (int i = 0; i < count; i++) {
        res = res + "*";
    }
    return res;
}

위의 메서드에서 루프의 각 반복은 이전 반복보다 한 문자 더 긴 새 String 을 만듭니다. 각 연결 복사 피연산자 문자열의 모든 문자는 새로운 형성하는 String . 따라서 stars(N) 은 :

  • N 새로운 String 객체를 생성하고 마지막 객체를 제외한 모든 객체를 버린다.
  • N * (N + 1) / 2 자 복사 및
  • O(N^2) 바이트의 가비지를 생성합니다.

이것은 큰 N 대해 매우 비쌉니다. 실제로 루프에서 문자열을 연결하는 코드는이 문제가 발생할 수 있습니다. 이를 작성하는 더 좋은 방법은 다음과 같습니다.

public String stars(int count) {
    // Create a string builder with capacity 'count' 
    StringBuilder sb = new StringBuilder(count);
    for (int i = 0; i < count; i++) {
        sb.append("*");
    }
    return sb.toString();
}

이상적으로는 StringBuilder 의 용량을 설정해야하지만 실용적이지 않은 경우 클래스는 자동으로 작성자가 문자를 보유하는 데 사용하는 대체 배열을 확장 합니다. (참고 : 구현 지수 보조 배열 확장이 전략은 문자로 복사의 양을 유지한다. O(N) 이 아닌 O(N^2) ).

어떤 사람들은이 패턴을 모든 문자열 연결에 적용합니다. 그러나 JLS를 사용 하면 Java 컴파일러가 단일 표현식 내에서 문자열 연결을 최적화 할 수 있으므로이 작업은 불필요합니다. 예 :

String s1 = ...;
String s2 = ...;    
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";

일반적으로 바이트 코드 컴파일러에 의해 다음과 같이 최적화됩니다.

StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();

(JIT 컴파일러는 s1 또는 s2null 될 수 없다고 추측 할 수 있다면 더 이상 최적화 할 수 있습니다.) 그러나이 최적화는 단일 표현식 내에서만 허용됩니다.

즉, 문자열 연결의 효율성에 대해 염려하는 경우 :

  • 루프 (또는 이와 유사한)에서 반복 연결을 수행하는 경우 손으로 최적화하십시오.
  • 단일 연결 식을 직접 최적화하지 마십시오.

산술 연산자 (+, -, *, /, %)

Java 언어는 정수 및 부동 소수점 값에 대한 산술 연산을 수행하는 7 개의 연산자를 제공합니다.

  • + 연산자가 두 개 있습니다.
    • 이진 더하기 연산자는 하나의 숫자를 다른 숫자에 더합니다. (문자열 연결을 수행하는 바이너리 + 연산자도 있지만 별도의 예에서 설명합니다.)
    • 단항 플러스 연산자는 숫자 프로모션을 트리거하는 것과 별개의 기능을 수행합니다 (아래 참조)
  • 두 가지가 있습니다 - : 연산자
    • 이진 빼기 연산자는 다른 숫자에서 하나의 숫자를 뺍니다.
    • 단항 마이너스 연산자는 피연산자를 0에서 뺀 것과 같습니다.
  • 이진 곱하기 연산자 (*)는 한 숫자에 다른 숫자를 곱합니다.
  • 이진 나누기 연산자 (/)는 한 숫자를 다른 숫자로 나눕니다.
  • 2 진 나머지 1 연산자 (%)는 한 숫자를 다른 숫자로 나눌 때 나머지를 계산합니다.

이것은 종종 "모듈러스"연산자로 잘못 언급됩니다. "Remainder"는 JLS에서 사용하는 용어입니다. "계수"와 "나머지"는 같은 것이 아닙니다.

피연산자 및 결과 유형 및 숫자 승격

연산자는 숫자 피연산자가 필요하며 숫자 결과를 생성합니다. 피연산자 유형은 java.lang 에서 정의 된 임의의 원시 숫자 유형 (즉, byte , short , char , int , long , float 또는 double )이거나 숫자 래퍼 유형 일 수 있습니다. ie ( Byte , Character , Short , Integer , Long , Float 또는 Double .

결과 유형은 다음과 같이 피연산자 또는 피연산자 유형에 따라 결정됩니다.

  • 피연산자 중 하나가 double 또는 Double 이면 결과 유형은 double 입니다.
  • 그렇지 않으면 피연산자 중 하나가 float 또는 Float 이면 결과 유형은 float 입니다.
  • 그렇지 않으면, 피연산자 중 하나가 long 또는 Long 이면 결과 유형은 long 입니다.
  • 그렇지 않은 경우 결과 유형은 int 입니다. 여기에는 byte , short , char 피연산자와`int.

연산의 결과 유형에 따라 산술 연산이 수행되는 방식과 피연산자가 처리되는 방식이 결정됩니다

  • 결과 유형이 double 이면 피연산자가 double 으로 승격되고 연산은 64 비트 (배정 밀도 이진) IEE 754 부동 소수점 산술을 사용하여 수행됩니다.
  • 결과 유형이 float 이면 피연산자가 float 로 승격되고 연산은 32 비트 (단 정밀도 2 진수) IEE 754 부동 소수점 산술을 사용하여 수행됩니다.
  • 결과 유형이 long 경우, 피연산자는 long 으로 승격되고 연산은 64 비트 부호있는 2의 보수 2 진 정수 산술을 사용하여 수행됩니다.
  • 결과 유형이 int 이면 피연산자가 int 로 승격되고 연산은 32 비트 부호있는 2의 보수 2 진 정수 연산을 사용하여 수행됩니다.

프로모션은 다음 두 단계로 수행됩니다.

  • 피연산자 유형이 래퍼 유형 인 경우, 피연산자 값은 해당 프리미티브 유형의 값에 unboxed 됩니다.
  • 필요한 경우 기본 유형이 필수 유형으로 승격됩니다.
    • int 또는 long 으로 정수를 승격하는 것은 손실이 적습니다.
    • double 하는 float 프로모션은 손실이 적습니다.
    • 부동 소수점 값으로 정수를 승격하면 정밀도가 떨어질 수 있습니다. 변환은 IEE 768 "가장 가까운 값으로 반올림"의미론을 사용하여 수행됩니다.

분열의 의미

해당 / 오퍼레이터는 좌측 피연산자 분할 n (배당) 및 오른쪽 피연산자 d (제수) 및 결과 생성 q (몫).

Java 정수부는 0을 반올림합니다. JLS 섹션 15.17.2 에서는 Java 정수부의 동작을 다음과 같이 지정합니다.

피연산자 nd 대해 생성 된 몫은 |d ⋅ q| ≤ |n| 를 만족하면서 가능한 한 크기가 큰 정수 값 q 입니다. |d ⋅ q| ≤ |n| . 또한, q|n| ≥ |d|nd 같은 부호를 가지고 있지만, q 부정적인 경우 |n| ≥ |d| nd 는 반대 기호를가집니다.

몇 가지 특수한 경우가 있습니다.

  • nMIN_VALUE 이고 제수가 -1 인 경우 정수 오버플로가 발생하고 결과는 MIN_VALUE 입니다. 이 경우에는 예외가 발생하지 않습니다.
  • d 가 0이면, ArithmeticException이 발생합니다.

Java 부동 소수점 분할은 더 많은 첨단 사례를 고려해야합니다. 그러나 기본 아이디어는 결과 qd . q = n 를 만족시키는 데 가장 가까운 값이라는 것입니다 d . q = n .

부동 소수점 나누기는 절대로 예외를 발생시키지 않습니다. 대신, 0으로 나누는 연산은 INF 및 NaN 값을 생성합니다. 아래를보십시오.

나머지의 의미

C 및 C ++과 달리 Java의 나머지 연산자는 정수 및 부동 소수점 연산 모두에서 작동합니다.

정수 경우에, 결과 a % b 숫자로 정의되고 r 되도록 (a / b) * b + r 동일하다 , a / , *+ 해당 자바 정수 연산자이다. 이것은 b 가 0 일 때를 제외하고 모든 경우에 적용됩니다. 이 경우, 나머지는 ArithmeticException 됩니다.

위의 정의에서 a % ba 가 음수 인 경우에만 음수가 될 수 있고 a 가 양수인 경우에만 양수가 될 수 있습니다. 게다가, a % b 의 크기는 b 의 크기보다 항상 작습니다.

부동 소수점 나머지 연산은 정수의 경우를 일반화 한 것입니다. a % b 의 결과는 나머지 r 은 수학적 관계 r = a - (b ⋅ q) 의해 정의됩니다. 여기서 :

  • q 는 정수이고,
  • a / b 가 음수 일 때만 음수이고 a / b 가 양수이면 양수이고
  • 그것의 크기는 ab 의 진정한 수학적 지수의 크기를 초과하지 않고 가능한 한 크다.

부동 소수점 나머지는 b 가 0 일 때와 같이 경계 케이스에서 INFNaN 값을 생성 할 수 있습니다. 아래를보십시오. 예외는 발생하지 않습니다.

중요 사항:

% 로 계산 한 부동 소수점 나머지 연산의 결과는 IEEE 754에 정의 된 나머지 연산으로 생성 된 결과 와 다릅니다 . IEEE 754 나머지는 Math.IEEEremainder 라이브러리 메소드를 사용하여 계산할 수 있습니다.

정수 오버플로

Java 32 및 64 비트 정수 값은 부호가 있고 2의 보수 쌍성 표현을 사용합니다. 예를 들어, 숫자 범위는 (32 비트) int -2 31 에서 +2 31 - 1로 나타낼 수 있습니다.

두 개의 N 비트 정수 (N == 32 또는 64)를 더하거나 뺄 때, 연산 결과가 너무 커서 N 비트 정수로 나타낼 수 없습니다. 이 경우 연산은 정수 오버플 로를 발생시키고 결과는 다음과 같이 계산 될 수 있습니다.

  • 수학 연산은 전체 수의 중간 2의 보수 표현을 제공하기 위해 수행됩니다. 이 표현은 N 비트보다 클 것입니다.
  • 중간 표현의 하위 32 또는 64 비트가 결과로 사용됩니다.

정수 오버플로는 어떤 상황에서도 예외가 발생하지 않는다는 점에 유의해야합니다.

부동 소수점 INF 및 NAN 값

Java는 floatdouble 대해 IEE 754 부동 소수점 표현을 사용합니다. 이러한 표현에는 실수의 도메인 외부에있는 값을 나타내는 몇 가지 특별한 값이 있습니다.

  • "무한"또는 INF 값은 너무 큰 숫자를 나타냅니다. +INF 값은 너무 크고 양수 인 숫자를 나타냅니다. -INF 값은 너무 크고 음수 인 숫자를 나타냅니다.
  • "무기한"/ "숫자가 아님"또는 NaN은 의미없는 작업으로 인해 발생하는 값을 나타냅니다.

INF 값은 오버플로를 일으키는 부동 연산 또는 0으로 나누는 부동 소수점 연산에 의해 생성됩니다.

NaN 값은 0을 0으로 나누거나 0을 나머지로 계산하여 생성됩니다.

놀랍게도 예외를 트리거하지 않고 INF 및 NaN 피연산자를 사용하여 산술을 수행 할 수 있습니다. 예 :

  • + INF와 유한 값을 추가하면 + INF가됩니다.
  • + INF 및 + INF를 추가하면 + INF가됩니다.
  • + INF 및 -INF를 추가하면 NaN이 제공됩니다.
  • INF로 나누면 +0.0 또는 -0.0이됩니다.
  • 하나 이상의 NaN 피연산자가있는 모든 연산은 NaN을 제공합니다.

상세한 내용은 JLS 15 의 관련 조항을 참조하십시오. 이것은 주로 "학문적 인"점에 유의하십시오. 일반적인 계산의 경우 INF 또는 NaN 은 무언가 잘못되었음을 의미합니다. 예를 들어 불완전하거나 잘못된 입력 데이터가 있거나 계산이 잘못 프로그래밍 된 경우.

평등 연산자 (==,! =)

==!= 연산자는 피연산자가 같은지 여부에 따라 true 또는 false 평가되는 이진 연산자입니다. == 오퍼레이터 제공 true 피연산자가 동일한 경우와 false 그렇지. != 연산자는 피연산자가 같으면 false 반환하고 그렇지 않으면 true 반환합니다.

이러한 연산자는 프리미티브 및 참조 형식의 피연산자로 사용할 수 있지만 동작이 크게 다릅니다. JLS에 따르면 실제로 세 가지 별개의 연산자 집합이 있습니다.

  • 부울 ==!= 연산자.
  • 숫자 ==!= 연산자.
  • 참조 ==!= 연산자.

그러나 모든 경우에 ==!= 연산자의 결과 유형은 boolean 입니다.

숫자 ==!= 연산자

== 또는 != 연산자의 피연산자 중 하나 (또는 ​​둘다)가 원시 숫자 유형 ( byte , short , char , int, long , float 또는 double )이면 연산자는 숫자 비교입니다. 두 번째 피연산자는 원시 숫자 유형이거나 박스형 숫자 유형이어야합니다.

다른 숫자 연산자의 동작은 다음과 같습니다.

  1. 피연산자 중 하나가 박스형이면 unbox입니다.
  2. 현재 피연산자 중 하나가 byte , short 또는 char 이면 int 로 승격됩니다.
  3. 피연산자의 유형이 동일하지 않으면 "더 작은"유형의 피연산자가 "더 큰"유형으로 승격됩니다.
  4. 비교는 다음과 같이 수행됩니다 :
    • 승격 된 피연산자가 int 또는 long 이면 값이 동일한 지 확인하기 위해 테스트됩니다.
    • 승격 된 피연산자가 float 또는 double 경우 :
      • 0의 두 가지 버전 ( +0.0-0.0 )은 동일한 것으로 처리됩니다
      • NaN 값은 다른 것과 같지 않은 것으로 간주됩니다.
      • 다른 값은 IEEE 754 표현이 동일하면 동일합니다.

참고 : ==!= 을 사용하여 부동 소수점 값을 비교할 때는주의해야합니다.

부울 ==!= 연산자

두 피연산자가 모두 boolean 이거나 boolean 이고 BooleanBoolean 이면이 연산자는 부울 ==!= 연산자입니다. 동작은 다음과 같습니다.

  1. 피연산자 중 하나가 Boolean 이면 unbox입니다.
  2. 박스 화되지 않은 피연산자가 테스트되고 부울 결과는 다음 진리표에 따라 계산됩니다
에이 A == B A! = B
그릇된 그릇된 참된 그릇된
그릇된 참된 그릇된 참된
참된 그릇된 그릇된 참된
참된 참된 참된 그릇된

진실 값에 ==!= 거의 사용하지 않는 것이 두 가지 "함정"입니다.

참조 ==!= 연산자

두 피연산자가 모두 객체 참조 인 경우 ==!= 연산자는 두 피연산자 가 동일한 객체를 참조 하는지 테스트 합니다 . 이것은 종종 당신이 원하는 것이 아닙니다. 두 객체가 같은 인지 테스트하려면 대신 .equals() 메소드를 사용해야합니다.

String s1 = "We are equal";
String s2 = new String("We are equal");

s1.equals(s2); // true

// WARNING - don't use == or != with String values
s1 == s2;      // false

경고 : 대부분의 경우 ==!= 을 사용하여 String 값을 비교하는 것은 올바르지 않습니다 . http://www.ripting.com/java/example/16290/pitfall--using-to-compare-strings을 참조 하십시오 . 유사한 문제는 프리미티브 래퍼 유형에도 적용됩니다. http://www.riptutorial.com/java/example/8996/pitfall--using-to-compare-primitive-wrappers-objects-such-as-integer를 참조 하십시오 .

NaN 에지 케이스 정보

JLS 15.21.1 은 다음과 같이 명시하고 있습니다 :

두 피연산자가 모두 NaN 이면 == 의 결과는 false 이지만 != 의 결과는 true 입니다. 실제로, 테스트 x != x 것입니다 true 의 값의 경우에만 x 있다 NaN .

이 동작은 (예 : 대부분의 프로그래머에게) 예기치 않은 결과입니다. NaN 값이 자신과 같은지 테스트하는 경우 대답은 "아니요!"입니다. 즉, ==NaN 값에 대해 반사적 이지 않습니다.

그러나 이것은 Java "oddity"가 아니며 IEEE 754 부동 소수점 표준에 지정되어 있으며 대부분의 최신 프로그래밍 언어에서 구현됩니다. (자세한 정보는 http://stackoverflow.com/a/1573715/139985를 참조 하십시오 ... 이것은 "결정이 내려 졌을 때 방안에 있었던"사람이 작성한 것임을 나타냅니다!)

증가 / 감소 연산자 (++ / -)

변수는 각각 ++-- 연산자를 사용하여 1 씩 증가 또는 감소 할 수 있습니다.

++-- 연산자가 변수를 따르는 경우이를 후행 증가후행 감소 라고합니다.

int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again

++-- 연산자가 변수 앞에 오는 경우 연산은 각각 사전 증가사전 감소 라고합니다.

int x = 10;
--x; // x now equals 9
++x; // x now equals 10

연산자가 변수 앞에 오는 경우 표현식의 값은 증가 또는 감소 된 후 변수의 값입니다. 연산자가 변수를 따르는 경우 표현식의 값은 증가 또는 감소되기 전의 변수 값입니다.

int x=10;

System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10

사후 증가 또는 감소를 덮어 쓰지 않도록주의하십시오. 이것은 in / decremented 변수 자체에 재 할당 된 표현식의 끝에서 post-in / decrement 연산자를 사용하는 경우 발생합니다. in / decrement는 효과가 없습니다. 왼쪽의 변수가 올바르게 증가하더라도 그 값은 식의 오른쪽에서 이전에 평가 된 결과로 즉시 덮어 쓰기됩니다 :

int x = 0; 
x = x++ + 1 + x++;      // x = 0 + 1 + 1 
                        // do not do this - the last increment has no effect (bug!) 
System.out.println(x);  // prints 2 (not 3!) 

옳은:

int x = 0;
x = x++ + 1 + x;        // evaluates to x = 0 + 1 + 1
x++;                    // adds 1
System.out.println(x);  // prints 3 

조건부 연산자 (? :)

통사론

{조건 - 평가} ? {statement-executed-true} : {statement-executed-on-false}

구문에서 볼 수 있듯이 조건 연산자 (Ternary Operator 1 이라고도 함)는 ? (물음표) 및 : 콜론) 문자를 사용하여 가능한 두 가지 결과의 조건부 표현식을 활성화합니다. 조건에 따라 두 값 중 하나를 반환하기 위해 더 긴 if-else 블록을 대체하는 데 사용할 수 있습니다.

result = testCondition ? value1 : value2

같음

if (testCondition) { 
    result = value1; 
} else { 
    result = value2; 
}

"testCondition이 true이면 result를 value1로 설정하십시오. 그렇지 않으면 result2를 value2로 설정하십시오. ".

예 :

// get absolute value using conditional operator 
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"

같음

// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
    absValue = -a;
} else {
    absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"

일반적인 사용법

조건부 할당 (조건부 할당 (null check)과 같은)을 위해 조건부 연산자를 사용할 수 있습니다.

String x = y != null ? y.toString() : ""; //where y is an object

이 예제는 다음과 같습니다.

String x = "";

if (y != null) {
    x = y.toString();
}

조건 연산자가 두 번째로 낮은 우선 순위를 가지므로 할당 연산자 위에는 조건 을 사용할 필요가 거의 없지만 다른 연산자와 결합 할 경우 전체 조건 연산자 구조 주위에 괄호가 필요합니다.

// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7

// parenthesis required
7 * (a > 0 ? 2 : 5)

조건부 연산자 중첩은 세 번째 파트에서 수행 할 수도 있습니다. 세 번째 파트에서는 ​​체인화 또는 switch 문처럼 작동합니다.

a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
    "a, b, and c are false"

//Operator precedence can be illustrated with parenthesis:

a ? x : (b ? y : (c ? z : w))

각주:

1 - Java 언어 스펙Java Tutorial 모두 ( ? : :) 연산자를 조건부 연산자로 호출합니다. 이 자습서에서는 Java에 의해 정의 된 유일한 (현재) 유일한 삼항 연산자이므로 "삼항 연산자"라고도합니다. "조건부 연산자"용어는 C 및 C ++ 및 동등한 연산자가있는 다른 언어와 일관됩니다.

비트 연산자와 논리 연산자 (~, &, |, ^)

Java 언어는 정수 또는 부울 피연산자에 대해 비트 또는 논리 연산을 수행하는 4 개의 연산자를 제공합니다.

  • 보수 ( ~ ) 연산자는 하나의 피연산자 비트를 비트 또는 논리 반전하는 단항 연산자입니다. JLS 15.15.5를 참조하십시오 . .
  • AND ( & ) 연산자는 두 개의 피연산자의 비트 또는 논리 "and"를 수행하는 이진 연산자입니다. JLS 15.22.2를 참조하십시오 . .
  • OR ( | ) 연산자는 2 개의 피연산자의 비트 또는 논리 "포함 또는"을 수행하는 2 진 연산자입니다. JLS 15.22.2를 참조하십시오 . .
  • XOR ( ^ ) 연산자는 두 개의 피연산자의 비트 또는 논리 "배타적 논리합"을 수행하는 이항 연산자입니다. JLS 15.22.2를 참조하십시오 . .

피연산자가 부울 값 일 때이 연산자가 수행하는 논리적 연산은 다음과 같이 요약 할 수 있습니다.

에이 ~ A A & B A | 비 A ^ B
0 0 1 0 0 0
0 1 1 0 1 1
1 0 0 0 1 1
1 1 0 1 1 0

정수 피연산자의 경우 위의 표는 개별 비트에 대해 수행되는 작업을 설명합니다. 연산자는 실제로 모든 32 또는 64 비트의 피연산자 또는 피연산자를 병렬로 연산합니다.

피연산자 유형 및 결과 유형.

피연산자가 정수인 경우 일반적인 산술 변환이 적용됩니다. 비트 연산자의 일반적인 사용 사례


~ 연산자는 부울 값을 뒤집거나 정수 피연산자의 모든 비트를 변경하는 데 사용됩니다.

& 연산자는 정수 피연산자의 비트 중 일부를 "마스킹"하는 데 사용됩니다. 예 :

int word = 0b00101010;
int mask = 0b00000011;   // Mask for masking out all but the bottom 
                         // two bits of a word
int lowBits = word & mask;            // -> 0b00000010
int highBits = word & ~mask;          // -> 0b00101000

| 연산자는 두 피연산자의 진리 값을 결합하는 데 사용됩니다. 예 :

int word2 = 0b01011111; 
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask);   // -> 0b01011110

^ 연산자는 비트 전환 또는 "뒤집기"에 사용됩니다.

int word3 = 0b00101010;
int word4 = word3 ^ mask;             // -> 0b00101001

비트 연산자의 사용에 대한 예는 비트 조작 (Bit Manipulation)을 참조하십시오.

운영자 Instanceof

이 연산자는 객체가 특정 클래스 / 인터페이스 유형인지 여부를 확인합니다. instanceof 연산자는 다음과 같이 작성됩니다.

( Object reference variable ) instanceof  (class/interface type)

예:

public class Test {

   public static void main(String args[]){
      String name = "Buyya";
      // following will return true since name is type of String
      boolean result = name instanceof String;  
      System.out.println( result );
   }
}

이렇게하면 다음 결과가 생성됩니다.

true

이 연산자는 비교 대상이 오른쪽에있는 유형과 호환되는 할당 인 경우 계속 true를 반환합니다.

예:

class Vehicle {}

public class Car extends Vehicle {
   public static void main(String args[]){
      Vehicle a = new Car();
      boolean result =  a instanceof Car;
      System.out.println( result );
   }
}

이렇게하면 다음 결과가 생성됩니다.

true

할당 연산자 (=, + =, - =, * =, / =, % =, << =, >> =, >>> =, & =, | = 및 ^ =)

이 연산자의 왼손 피연산자는 최종 변수가 아니거나 배열의 요소 여야합니다. 오른손 피연산자는 왼손 피연산자와 양립 할 수 있어야합니다. 즉, 유형이 동일해야하거나 오른쪽 피연산자 유형이 복싱, 언 박싱 또는 확장의 조합으로 왼쪽 피연산자 유형으로 변환 가능해야 함을 의미합니다. 자세한 것은, JLS 5.2를 참조 해주세요 .

"operation and assign"연산자의 정확한 의미는 JLS 15.26.2 에서 다음과 같이 지정됩니다.

E1 op= E2 형식의 복합 할당 표현식은 E1 = (T) ((E1) op (E2)) 와 동일합니다. 여기서 TE1 이 한 번만 평가된다는 점을 제외하고 E1 의 유형입니다.

최종 할당 전에 암시 적 타입 캐스트가 있음에 유의하십시오.

1. =

간단한 대입 연산자 :는 오른손 피연산자의 값을 왼쪽 피연산자에 대입합니다.

예 : c = a + b 의 값을 추가한다 a + b 의 값 c 및에 할당 c

2. +=

"add and assign"연산자 : 오른손 피연산자의 값을 왼쪽 피연산자의 값에 더하고 그 결과를 왼쪽 피연산자에 대입합니다. 왼손 피연산자가 String 유형 인 경우이 연산자는 "연결 및 할당"연산자입니다.

예 : c += ac = c + a 와 대략 동일 c = c + a

3. -=

"빼기 및 대입"연산자 : 왼쪽 피연산자의 값에서 오른쪽 피연산자의 값을 빼고 왼쪽 피연산자에 결과를 대입합니다.

예 : c -= ac = c - a 와 대략 동일 c = c - a

4. *=

"곱하기 및 대입"연산자 : 오른쪽 피연산자의 값에 왼쪽 피연산자의 값을 곱하고 그 결과를 왼쪽 피연산자에 대입합니다. .

예 : c *= ac = c * a 와 대략 동일 c = c * a

5. /=

"나누기 및 대입"연산자 : 오른손 피연산자의 값을 왼손 피연산자의 값으로 나눠 결과를 왼손 피연산자에 대입합니다.

예 : c /*= ac = c / a 와 대략 동일 c = c / a

6. %=

"modulus and assign"연산자는 왼쪽 피연산자의 값에 따라 오른쪽 피연산자 값의 모듈러스를 계산하고 결과를 왼쪽 피연산자에 대입합니다.

예 : c %*= ac = c % a 와 대략 같습니다 c = c % a

7. <<=

"left shift and assign"연산자.

예 : c <<= 2c = c << 2 와 대략 동일합니다.

>>=

"산술 오른쪽 쉬프트 및 할당"연산자.

예 : c >>= 2c = c >> 2 와 대략 같습니다.

9. >>>=

"논리 오른쪽 시프트 및 할당"연산자.

예 : c >>>= 2c = c >>> 2 와 대략 동일합니다.

10. &=

"비트와 and 할당"연산자.

예 : c &= 2c = c & 2 와 대략 동일합니다.

11. |=

"비트 별 및 대입"연산자입니다.

예 : c |= 2c = c | 2 와 거의 같습니다. c = c | 2

12. ^=

"bitwise exclusive or and assign"연산자입니다.

예 : c ^= 2c = c ^ 2 와 대략 동일합니다.

조건부 및 조건부 또는 연산자 (&& 및 ||)

Java는 boolean 유형의 하나 또는 두 개의 피연산자를 취해 boolean 결과를 생성하는 조건부 및 조건부 또는 연산자를 제공합니다. 이것들은:

  • && - 조건부 AND 연산자,

  • || - 조건부 OR 연산자. <left-expr> && <right-expr> 의 평가는 다음 의사 코드와 동일합니다 :

    {
       boolean L = evaluate(<left-expr>);
       if (L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return false;
       }
    }
    

<left-expr> || <right-expr> 의 평가 <left-expr> || <right-expr> 은 다음 의사 코드와 동일합니다.

    {
       boolean L = evaluate(<left-expr>);
       if (!L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return true;
       }
    }

위의 의사 코드에서 볼 수 있듯이 단락 회로 연산자의 동작은 if / else 문을 사용 if 것과 같습니다.

예 - 표현식에서 가드로 && 사용

다음 예제는 && 연산자에 대한 가장 일반적인 사용 패턴을 보여줍니다. 이 두 버전의 메소드를 비교하여 제공된 Integer 가 0인지 테스트하십시오.

public boolean isZero(Integer value) {
    return value == 0;
}

public boolean isZero(Integer value) {
    return value != null && value == 0;
}

대부분의 경우 첫 번째 버전이 작동하지만 value 인수가 null 인 경우 NullPointerException 이 발생합니다.

두 번째 버전에서는 "가드"테스트를 추가했습니다. value != null && value == 0 표현식의 value != null 은 먼저 value != null 테스트 value != null 수행하여 평가됩니다. null 테스트가 성공하면 (즉, true 평가되는 true ) value == 0 표현식이 평가됩니다. null 테스트가 실패하면 value == 0 의 평가는 건너 뛰고 (단락됩니다), 우리 NullPointerException 얻지 못합니다 .

예 - 값 비싼 계산을 피하기 위해 && 사용

다음 예제는 상대적으로 값 비싼 계산을 피하기 위해 && 를 사용하는 방법을 보여줍니다.

public boolean verify(int value, boolean needPrime) {
    return !needPrime | isPrime(value);
}

public boolean verify(int value, boolean needPrime) {
    return !needPrime || isPrime(value);
}

첫 번째 버전에서 | 항상 평가 될 것이므로 (비싼) isPrime 메서드는 불필요하게 호출됩니다. 두 번째 버전에서는 || 를 사용하여 불필요한 호출을 방지합니다. | 대신 | .

시프트 연산자 (<<, >> 및 >>>)

Java 언어는 32 비트 및 64 비트 정수 값에서 비트 시프 팅을 수행하는 세 가지 연산자를 제공합니다. 이들은 모두 이항 연산자이고 첫 번째 피연산자는 시프트 될 값이고 두 번째 피연산자는 얼마나 멀리 이동해야 하는지를 나타냅니다.

  • << 또는 왼쪽 시프트 연산자는 첫 번째 피연산자에 의해 주어진 값을 두 번째 피연산자에 의해 주어진 비트 위치 수만큼 왼쪽으로 시프트합니다. 오른쪽 끝의 빈 위치는 0으로 채워집니다.

  • '>>'또는 산술 시프트 연산자는 첫 번째 피연산자에 의해 주어진 값을 두 번째 피연산자에 의해 주어진 비트 위치의 수만큼 오른쪽 으로 시프트합니다. 왼쪽 끝의 빈 위치는 가장 왼쪽 비트를 복사하여 채 웁니다. 이 프로세스를 부호 확장이라고 합니다.

  • '>>>'또는 논리 오른쪽 시프트 연산자는 첫 번째 피연산자에 의해 주어진 값을 두 번째 피연산자에 의해 주어진 비트 위치의 수만큼 오른쪽 으로 시프트합니다. 왼쪽 끝의 빈 위치는 0으로 채워집니다.

노트:

  1. 이 연산자는 int 또는 long 값을 첫 번째 피연산자로 필요로하며 첫 번째 피연산자와 같은 형식의 값을 생성합니다. (시프트 결과를 byte , short 또는 char 변수에 할당 할 때는 명시 적 형식 캐스팅을 사용해야합니다.)

  2. byte , char 또는 short 인 첫 번째 피연산자와 함께 시프트 연산자를 사용하는 경우 int 로 승격되고 연산은 int 생성합니다.

  3. 두 번째 피연산자는 시프트 양을 제공하기 위해 연산 비트 수를 모듈로 감소시킵니다. mod 수식 개념 에 대한 자세한 내용은 Modulus 예제를 참조하십시오.

  4. 연산에 의해 왼쪽 또는 오른쪽 끝에서 벗어난 비트는 무시됩니다. Java는 원시적 인 "회전"연산자를 제공하지 않습니다.

  5. 산술 시프트 연산자는 2의 제곱으로 (2의 보수) 숫자를 나누는 것과 같습니다.

  6. 왼쪽 시프트 연산자는 a (2의 보수)에 2의 거듭 제곱을 곱한 것과 같습니다.

다음 표는 세 ​​개의 시프트 연산자의 효과를 보여줍니다. (숫자는 가상화를 돕기 위해 이진 표기로 표현되었습니다.)

피연산자 1 피연산자 2 << >> >>>
0b0000000000001011 0 0b0000000000001011 0b0000000000001011 0b0000000000001011
0b0000000000001011 1 0b0000000000010110 0b0000000000000101 0b0000000000000101
0b0000000000001011 2 0b0000000000101100 0b0000000000000010 0b0000000000000010
0b0000000000001011 28 0b1011000000000000 0b0000000000000000 0b0000000000000000
0b0000000000001011 31 0b1000000000000000 0b0000000000000000 0b0000000000000000
0b0000000000001011 32 0b0000000000001011 0b0000000000001011 0b0000000000001011
... ... ... ... ...
0b1000000000001011 0 0b1000000000001011 0b1000000000001011 0b1000000000001011
0b1000000000001011 1 0b0000000000010110 0b1100000000000101 0b0100000000000101
0b1000000000001011 2 0b0000000000101100 0b1110000000000010 0b00100000000000100
0b1000000000001011 31 0b1000000000000000 0b1111111111111111 0b0000000000000001

비트 조작 에서 시프트 연산자 사용자의 예가 있습니다.

람다 연산자 (->)

Java 8 이후부터 람다 연산자 ( -> )는 람다 식을 도입하는 데 사용되는 연산자입니다. 다음 예에서 볼 수 있듯이 두 가지 공통적 인 구문이 있습니다.

Java SE 8
  a -> a + 1              // a lambda that adds one to its argument
  a -> { return a + 1; }  // an equivalent lambda using a block.

람다 표현식은 익명 함수, 또는 함수 인터페이스 를 구현하는 익명 클래스의 인스턴스를보다 정확하게 정의합니다.

(이 예제는 완성을 위해 여기에 포함되어 있습니다. 완전한 처리 방법에 대해서는 Lambda Expressions 항목을 참조하십시오.)

관계 연산자 (<, <=,>,> =)

< , <= , >>= 연산자는 숫자 유형 비교를위한 이진 연산자입니다. 연산자의 의미는 예상대로입니다. 예를 들어, abbyte , short , char , int , long , float , double 또는 해당하는 박스형 중 하나로 선언 된 경우 :

- `a < b` tests if the value of `a` is less than the value of `b`. 
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`. 
- `a > b` tests if the value of `a` is greater than the value of `b`. 
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`. 

이러한 연산자의 결과 유형은 모든 경우에 boolean 입니다.

관계 연산자를 사용하여 숫자를 다른 유형과 비교할 수 있습니다. 예 :

int i = 1;
long l = 2;
if (i < l) {
    System.out.println("i is smaller");
}

관계 연산자는 한쪽 또는 양쪽 숫자가 박스형 숫자 유형의 인스턴스 일 때 사용할 수 있습니다. 예 :

Integer i = 1;   // 1 is autoboxed to an Integer
Integer j = 2;   // 2 is autoboxed to an Integer
if (i < j) {
    System.out.println("i is smaller");
}

정확한 동작은 다음과 같이 요약됩니다.

  1. 피연산자 중 하나가 박스형이면 unbox입니다.
  2. 현재 피연산자 중 하나가 byte , short 또는 char 이면 int 로 승격됩니다.
  3. 피연산자의 유형이 동일하지 않으면 "더 작은"유형의 피연산자가 "더 큰"유형으로 승격됩니다.
  4. 결과는 int , long , float 또는 double 값에 대해 비교가 수행됩니다.

부동 소수점 숫자가 포함 된 관계형 비교에주의해야합니다.

  • 부동 소수점 숫자를 계산하는 표현식은 종종 컴퓨터 부동 소수점 표현의 정밀도가 제한되어 있기 때문에 반올림 오류가 발생합니다.
  • 정수 유형과 부동 소수점 유형을 비교할 때 부동 소수점으로 정수를 변환하면 반올림 오류가 발생할 수도 있습니다.

마지막으로 Java는 위에서 나열한 유형 이외의 다른 유형의 관계 연산자를 사용하는 것을 조금 지원합니다. 예를 들어 이러한 연산자를 사용하여 문자열, 숫자 배열 등을 비교할 수 없습니다 .



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow