자바의 정석 Chapter03 을 참고하여 정리한 포스트입니다.

이전글
자바의 정석 Chapter01
자바의 정석 Chapter02


Chapter 03

1. 연산자 (operator)

1.1 연산자와 피연산자

  • 연산자 : 연산을 수행하는 기호 (+, -,*, / 등)
  • 피연산자 : 연산자의 작업 대상 (변수,상수,리터럴, 수식)

1.2 식과 대입연산자

연산자와 피연산자를 조합하여 계산한다.

1
2
3
x = 5;
y = 4 * x + 3;
System.out.println(y);  //23이 출력된다.

1.3 연산자의 종류

종류 연산자 설명
산술 연산자 + - * / % « » 사칙연산(+, -, *, /)과 나머지 연산(%)
비교 연산자 > < >= <= == != 크고 작음과 같고 다름을 비교
논리 연산자 && || ! & | ^ ~ AND와 OR 으로 조건을 연결
대입 연산자 = 우변의 값을 좌변에 저장
기타 (type) ?: instanceof 형변환 연산자, 삼항 연산자, instanceof 연산자

1.4 연산자의 우선순위와 결합규칙

  1. 산술 > 비교 > 논리 > 대입
  2. 단항(1) > 이항(2) > 삼항(3)
  3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.

1.5 산술 변환(usual arithmetic conversion)

이항 연산자는 두 피연산자의 타입이 일치해야 연산이 가능하므로, 피연산자의 타입이 서로 다르다면 연산 전에 형변환 연산자로 타입을 일치시켜야한다.

1
2
3
4
5
6
int i = 10;
float f = 20.0f;

float result = f + (float)i;   //형변환으로 두 피연산자의 타입을  일치

float result = f + i;   //큰 타입으로 형변환시, 형변환연산자 생략 가능

산술 변환 규칙

  1. 두 피연산자의 타입을 같게 일치시킨다. (보다 큰 타입으로 일치)
  2. 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.

모든 연산에서 ‘산술 변환’이 일어나지만, 쉬프트 연산자(«, »), 증감 연산자(++, --)는 예외이다.


2. 단항 연산자

2.1 증감 연산자 ++ –

타입 설명 사용 예
전위형 값이 참조되기 전에 증가시킨다 j = ++i;
후위형 값이 참조된 후에 증가시킨다 j = i++;


  • 예제 3-1 OperatorEx1.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      class OperatorEx1 {
          public static void main(String args[]) {
              int i = 5;
              i++;    //i = i+1;과 같은 의미이다. ++i;로 바꿔도 결과는 같음
              System.out.println(i);
    
              i = 5;
              ++i;
              System.out.println(i);
          }
      }
    
  • 결과
    1
    2
    
      6
      6
    

    이 경우에는 어떤 수식에 포함된 것이 아니라 단독적으로 사용된 것이지 때문에, 전위형과 후위형의 차이가 없다.
    그러나 다른 수식에 포함되거나 메서드의 매개변수로 사용된 경우, 전위형과 후위형의 결과는 다르다.


  • 예제 3-2 OperatorEx2.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      class OperatorEx2 {
          public static void main(String args[]) {
              int i = 5, j = 0;
    
              j = i++;
              System.out.println("j = i++; 실행 후 i = " + i + ", j = " + j);
    
              j = 5;
              j = 0;
    
              j = ++i;
              System.out.println("j = ++i; 실행 후 i = " + i + ", j = " + j);
          }
      }
    
  • 결과
    1
    2
    
      j = i++; 실행 후 i = 6, j = 5
      j = i++; 실행 후 i = 6, j = 5
    
  • 전위형과 후위형의 증가 순서
    1
    2
    3
    4
    
      j = ++i;    //전위형
    
      ++i;    //증가 후에
      j = i;  //참조하여 대입
    
    1
    2
    3
    4
    
      j = i++;    //후위형
    
      j = i;  //참조하여 대입 후에
      i++;    //증가
    


메서드 호출에 증감연산자 사용 예

  • 예제 3-3 Operator3.java
    1
    2
    3
    4
    5
    6
    7
    8
    
      class OperatorEx3 {
          public static void main(String args[]) {
              int i = 5; j = 5;
              System.out.println(i++);
              System.out.println(++j);
              System.out.println("i = "+ i +", j = "+ j);
          }
      }
    
  • 실행결과
    1
    2
    3
    
      5
      6
      i = 6, j = 6;
    

2.2 부호 연산자 + -

부호 연산자는 boolean형과 char형을 제외한 기본형에서만 사용할 수 있다.

  • 예제 3-4 OperatorEx4.java
    1
    2
    3
    4
    5
    
      class OperatorEx4 {
          public static void main(String[] args) {
    
          }
      }
    

3. 산술 연산자

3.1 사칙 연산자 + - * /

  • 예제 3-5 OperatorEx5.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
      class OperatorEx5 {
          public static void main(String args[]) {
              int a = 10;
              int b = 4;
    
              System.out.pringln("%d + %d =%d\n", a, b, a + b);
              System.out.pringln("%d - %d =%d\n", a, b, a - b);
              System.out.pringln("%d * %d =%d\n", a, b, a * b);
              System.out.pringln("%d / %d =%d\n", a, b, a / b);
              System.out.pringln("%d + %f =%d\n", a, (float)b, a / (float)b);
          }
      }
    
  • 결과

    실행결과
    10 + 4 = 14
    10 - 4 = 6
    10 * 4 = 40
    10 / 4 = 2
    10 / 4.000000 = 2.500000

올바른 연산결과를 얻기 위해서는 두 피연산자 중 어느 한 쪽을 실수형으로 형변환을 해야한다.
크기가 작은 자료형의 변수를 큰 자료현의 변수에 저장할 때는 자동으로 형변환(type conversion, casting) 되지만, 반대로 큰 자료형의 값을 작은 자료형의 변수에 저장하려면 명시적으로 형변환 연산자를 사용해서 변환해주어야 한다.

  • 예제 3-7 OperatorEx7.java
    1
    2
    3
    4
    5
    6
    7
    8
    
      class OperatorEx7 {
          public static void main(String[] args) {
              byte a = 10;
              byte b = 30;
              byte c = (byte)(a * b);
              System.out.pringln(c);
          }
      }
    
  • 결과

    실행결과
    44

위의 예제를 보면 10*30은 300이지만 큰 자료형에서 작은 자료형으로 변환하면 데이터의 손실이 발행하므로 값이 바뀔 수 있다.
300은 byte형의 범위를 넘기 때문에 byte형으로 변환하면 데이터 손실이 발생하여 결국 44가 byte형 변수 c에 저장된다.

  • 예제 3-8 OperatorEx8.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      class OperatorEx8 {
          public static void main(String args[]) {
              int a = 1_000_000;  //1,000,000 1백만
              int b = 2_000_000;  //2,000,000 2백만
    
              long c = a *b;  //a*b = 2,000,000,000,000 ?
    
              System.out.println(c);
          }
      }
    
  • 결과

    실행결과
    -1454759936

위의 결과 값을 담는 변수 c의 자료형이 long(8 byte)이기 때문에 $2*10^12$을 저장하기에 충분하흐로 제대로된 값이 출력될 것 같았지만 결과는 전혀 다른 값이 출력된다.

이유는 int타입과 int타입의 연산결과는 int타입이기 때문이다.
‘a*b’의 결과가 이미 int타입의 값이므로 long형으로 자동 형변환되어도 값은 변하지 않았다.

올바른 결과를 얻드려면 변수 a 또는 b의 타입을 ‘long’으로 형변환해야 한다.

1
long c = (long)a * b;

3.2 나머지 연산자 %

나머지 연산자는 왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자이다.
나머지 연산자는 주로 짝수, 홀수 또는 검사 등에 주로 사용된다.

  • 예제 3-19 OperatorEx19.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      class OperatorEx19 {
          public static void main(String  args[]) {
              int x = 10;
              int y = 8;
    
              System.out.printf("%d을 %d로 나누면, %n", x, y);
              System.out.printf("몫은 %d이고, 나머지는 %d입니다.%n", x / y, x % y);
          }
      }
    
  • 실행결과
    10을 8로 나누면,
    몫은 1이고, 나머지는 2입니다.

  • 예제 3-20 OperatorEx20.java
    1
    2
    3
    4
    5
    6
    7
    
      class OperatorEx20 {
          public static void main(String[] args) {
              System.out.println(-10%8);
              System.out.println(10%-8);
              System.out.println(-10%-8);
          }
      }
    
  • 결과

    실행결과
    -2
    2
    -2

나머지 연산자(%)는 나누는 수로 음수도 허용한다. 그러나 부호는 무시되므로 결과는 음수의 절대값으로 나눈 나머지와 결과가 같다.

피연산자의 부호를 모두 무시하고,나머지 연산을 한 결과에 왼쪽 피연산자(나눠지는 수)의 부호를 붙이면 된다.

4. 비교 연산자

4.1 대소비교 연산자 < > <= >=

비교연산자 연산결과
> 좌변 값이 크면, true 아니면 false
< 좌변 값이 작으면, true 아니면 false
>= 좌변 값이 크거나 같으면, true 아니면 false
<= 좌변 값이 작거나 같으면, true 아니면 false

4.2 등가비교 연산자 == !=

비교연산자 연산결과
== 두 값이 같으면, true 아니면 false
!= 두 값이 다르면, true 아니면 false

문자열의 비교
두 문자열을 비교할 때는, 비교 연산자 “==”대신 equals() 라는 메서드를 사용해야 한다.
equals()는 비교하는 두 문자열이 같으면 true를, 다르면 false를 반환한다.

1
2
3
4
String str = new String("abc");

//equals()는 두 문자열의 내용이 같으면 true, 다르면 false
boolean result = str.equals("abc"); //내용이 같으므로 result에 true가 저장됨

원래 String은 클래스이므로, 아래와 같이 new를 사용해서 객체를 생성해야 한다.

1
2
String str = new String("abc"); //String클래스의 객체를 생성
String str = "abc"; //위의 문장을 간단히 표현

그러나 특별히 String만 new를 사용하지 않고, 위와 같이 간단히 쓸 수 있도록 허용한다.

  • 예제 3-23 OperatorEx23.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    class OperatorEx23 {
      public static void main(String[] args) {
          String str1 = "abc";
          String str2 = new String("abc");
    
          System.out.printf("\"abc\"==\"abc\" ? %b%n", "abc"=="abc");
          System.out.printf(" str1==\"abc\" ? %b%n", str1=="abc");
          System.out.printf(" str2==\"abc\" ? %b%n", str2=="abc");
          System.out.printf("str1.equals(\"abc\") ? %b%n", str1.equals("abc"));
          System.out.printf("str2.equals(\"abc\") ? %b%n", str2.equals("abc"));
          System.out.printf("str2.equalsIgnoreCase(\"ABC\") ? %b%n", str2.equalsIgnoreCase("ABC"));
      }
    }
    
  • 결과

    실행결과
    “abc”==”abc” ? true
    ㅤstr1==”abc” ? true
    ㅤstr2==”abc” ? false
    str1.equals(“abc”) ? true
    str2.equals(“abc”) ? true
    str2.equals(“ABC”) ? false
    str2.equalsIgnoreCase(“ABC”) ? true

str2와 “abc”의 내용이 같은데도 ‘==’로 비교하면, false를 결과로 얻는다.
내용은 같지만 다른 객체이기 때문이다.
그러나 equals()는 객체가 달라도 내용이 같으면 true를 반환한다. 그래서 문자열을 비교할 때는 항상 equals()를 사용해야 한다.
만일 대소문자를 구별하지 않고 비교하고 싶으면, equals() 대신 equalsIgnoreCase()를 사용하면 된다.

5. 논리 연산자

5.1 논리연산자 - &&, ||, !

|| (OR 결합)ㅤㅤ피연산자 중 어느 한 쪽만 true이면 true를 결과로 얻는다.
&& (AND 결합)ㅤㅤ피연산자 양쪽 모두 true이어야 true를 결과로 얻는다.

  • 예제 3-24 OperatorEx24.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    class OperatorEx24 {
      public static void main(String args[]) {
          int x = 0;
          char ch = ' ';
    
          x = 15;
          System.out.printf("x=%2d, 10 < x && x < 20 = %b%n", x, 10 < x && x < 20);
    
          x = 6;
          System.out.printf("x=%2d, x%%2==0 || x%%3==0 && x%%6!=0 = %b%n", x, x%%2==0 || x%%3==0 && x%%6!=0);
          System.out.printf("x=%2d, (x%%2==0 || x%%3==0) && x%%6!=0 = %b%n", x, (x%%2==0 || x%%3==0) && x%%6!=0);
    
          ch = '1';
          System.out.printf("ch='%c', '0'<=ch && ch<='9' = %b%n", ch,'0'<=ch && ch<='9');
    
          ch = 'a';
          System.out.printf("ch='%c', 'a'<=ch && ch<='z' = %b%n", ch, 'a'<=ch && ch<='z');
    
          ch = 'A';
          System.out.printf("ch='%c', 'A'<=ch && ch<='Z' = %b%n", ch, 'A'<=ch && ch<='Z');
    
          ch = 'q';
          System.out.printf("ch='%c', ch=='q' || ch<='Q' = %b%n", ch, ch=='q' || ch<='Q');
            
      }
    }
    
  • 결과

    실행결과
    x=15, 10 < x && x < 20 = true
    x=6, x%2==0 || x%3==0 && x%6!=0 = true
    x=6, (x%2==0 || x%3==0) && x%6!=0 = false
    ch=’1’, ‘0’<=ch && ch<=’9’ = true
    ch=’a’, ‘a’<=ch && ch<=’z’ = true
    ch=’A’, ‘A’<=ch && ch<=’Z’ = true
    ch=’q’, ch==’q’ || ch<=’Q’ = true


  • 예제 3-25 OperatorEx25.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      import java.util.*; //Scanner클래스를 사용하기 위해 추가
    
      class OperatorEx25 {
          public static void main(String args[]) {
              Scanner scanner = new Scanner(System.in);
              char ch = ' ';
    
              System.out.printf("문자를 하나 입력하세요. > ");
    
              String input = scanner.nextLine();
              ch= input.charAt(0);
    
              if('0' <= ch && ch < = '9') {
                  System.out.printf("입력하신 문자는 숫자입니다.%n");
              }
              if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
                  System.out.printf("입력하신 문자는 영문자입니다.%n");
              }
          }   //main
      }
    
  • 결과

    실행결과 1
    문자를 하나 입력하세요. > 7
    입력하신 문자는 숫자입니다.
    실행결과 2
    문자를 하나 입력하세요. > a
    입력하신 문자는 영문자입니다.


논리 부정 연산자 !
피연산자가 true이면 false를, false면 true를 결과로 반환한다.

x !x
true false
false true

5.2 비트 연산자 & | ^ ~ « »

| (OR 연산자)ㅤㅤ피연산자 중 한 쪽의 값이 1이면, 1을 결과로 얻는다. 그 외에는 0을 얻는다.
& (AND 연산자)ㅤㅤ피연산자 양쪽 모두 1이어야만 1을 결과로 얻는다. 그 외에는 0을 얻는다.
^ (XOR 연산자)ㅤㅤ피연산자의 값이 서로 다를 때만 1을 결과로 얻는다. 같을 때는 0을 얻는다.

x y x|y x&y x^y
1 1 1 1 0
1 0 1 0 1
0 1 1 0 1
0 0 0 0 0

비트 전환 연산자 ~

이 연산자는 피연산자를 2진수로 표현했을때, 0을 1로, 1은 0으로 바꾼다.
논리부정 연산자 ‘!’와 유사하다.

x ~x
1 0
0 1

쉬프트 연산자 «»

이 연산자는 피연산자의 각 자리(2진수로 표현 시)를 ‘오른쪽(»)’ 또는 ‘왼쪽(«)’으로 이동(shift)한다고 해서 ‘쉬프트 연산자(shift operator)’라고 이름 붙여졌다.

ex. 10진수 8의2진수를 왼쪽으로 2자리 이동

  1. 10진수 8은 2진수로 ‘00001000’이다.
  2. ‘8 « 2’은 10진수 8의 2진수를 왼쪽으로 2자리 이동시킨다.
    • 0 0ㅤ0 0 1 0 0 0 (빈자리) (빈자리)
  3. 자리이동으로 인해 저장범위를 벗어난 값은 버려지고, 빈자리는 0으로 채워진다.
    • 0 0 1 0 0 0 0 0
  4. ‘8 « 2’의 결과는 2진수로 ‘00100000’이 된다. (10진수로 32)

6. 그 외의 연산자

6.1 조건 연산자 ? :

조건 연산자는 조건식, 식1, 식2 모두 세 개의 피연산자를 필요로 하는 삼항 연산자이며,
삼항연산자는 조건 연산자 하나뿐이다.

조건 연산자는 첫 번째 피연산자인 조건식의 평가결과에 따라 다른 결과를 반환한다.
조건식의 평가결과가 true이면 식1이, false이면 식2가연산결과가 된다.

  • 조건식의 결과가 참(true)일 때 (a)와 거짓(false)일 때 (b)
    1
    2
    3
    4
    
    result = (x > y) ? x : y;
    -> result = (5 > 3) ? 5 : 3;
    -> result (true) ? 5 : 3;   //조건식이 true(참)이므로 연산결과는 5
    -> result = 5;
    
  • 예제 3-32 OperatorEx32.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    class OperatorEx32 {
      public static void main(String args[]) {
          int x, y, z;
          int absX, absY, absZ;
          char signX, signY, signZ;
    
          x =  10;
          y = -5;
          z = 0;
    
          absX = x >= 0 ? x : -x; //x의 값이 음수이면, 양수로 만든다.  
          absY = y >= 0 ? y : -y;
          absZ = z >= 0 ? z : -z;
    
          signX = x > 0 ? '+' : ( x==0 ? ' ' : "-" ); //조건 연산자를 중첩
          signY = y > 0 ? '+' : ( y==0 ? ' ' : "-" );
          signZ = z > 0 ? '+' : ( z==0 ? ' ' : "-" );
    
          System.out.printf("x=%c%d%n", signX, absX);
          System.out.printf("y=%c%d%n", signY, absY);
          System.out.printf("z=%c%d%n", signZ, absZ);
      }
    }
    
  • 결과

    실행결과
    x=+10
    y=-5
    z=0

6.2 대입 연산자 = op=

대입 연산자는 변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장하는데 사용된다.

  • [EX] x = y = 3;
    연산 진행 방향이 오른쪽에서 왼쪽이기 때문에 “x=y=3;”에서 ‘y=3’이 먼저 수행되고 그 다음에 ‘x=y’가 수행된다.
    • (1) y = 3
    • (2) x = 3
    • (3) x = y

lvalue와 rvalue

대입연산자의 왼쪽 피연산자를 ‘lvalue(left value)’이라 하고, 오른쪽 피연산자를 ‘rvalue(right value)’라고 한다.

  • [EX] x = 3;
    • x : lvalue
    • 3 : rvalue

lvalue는 반드시 변수처럼 값을 변경할 수 있는 것이어야 한다.
그래서 리터럴이나 상수같이 값이 저장할 수 없는 것들은 lvalue가 될 수 없다.

1
2
3
4
5
6
int i = 0;
3 =  i + 3; //에러. lvalue가 값을 저장할 수 있는 공간이 아니다.
i + 3 = i;  //에러. lvalue의 연산결과는 리터럴(i+3 -> 0+3 -> 3)

final int MAX = 3;  //변수 앞에 키워드 final을 붙이면 상수가 된다.
MAX = 10;   //에러. 상수(MAX)에 새로운 값을 저장할 수 없다.

복합 대입 연산자

대입 연산자는 다른 연산자(op)와 결합하여 ‘op=’와 같은 방식으로 사용될 수 있다.

  • 예를 들면, ‘i = i + 3;은 ‘i += 3’과 같이 표현될 수 있다.

  • 복합 대입 연산자의 종류

    op= =
    i += 3; i = i + 3;
    i -= 3; i = i - 3;
    i *= 3; i = i * 3;
    i /= 3; i = i / 3;
    i %= 3; i = i % 3;
    i «= 3; i = i « 3;
    i »= 3; i = i » 3;
    i &= 3; i = i & 3;
    i ^= 3; i = i ^ 3;
    i |= 3; i = i | 3;
    i += 10 + j; i = i * (10 + j);

🌞 정보 : 공부 기록용 블로그입니다. 오타나 내용 오류가 있을 경우 알려주시면 감사하겠습니다.

태그:

카테고리:

업데이트:

댓글남기기