Java의 정석: CHAPTER 03 연산자(Operator)

mucha·2023년 4월 16일

Java의 정석

목록 보기
3/6
post-thumbnail

CHAPTER 03 연산자(Operator)

1. 연산자(operator)


1.1 연산자와 피연산자

연산자(operator): 연산을 수행하는 기호(+, -, *, / 등)
피연산자(operand): 연산자의 작업 대상(변수, 상수, 리터럴, 수식)
연산자는 피연산자로 연산을 수행하고 나면 항상 결과값을 반환.

1.2 식(式)과 대입연산자

식: 연산자와 피연산자를 조합하여 계산하고자하는 바를 표현한 것.
식을 계산하여 결과를 얻는 것을 ‘식을 평가한다’고 한다.
대입 연산자: = 변수와 같이 값을 저장할 수 있는 공간에 결과를 저장하기 위해 필요한 연산자.

// y: 변수
// =: 대입 연산자
// *, x: 연산자
// 4, 3: 피연산자 
y = 4 * x + 3;

1.3 연산자의 종류

종류연산자설명
산술 연산자+ - * / % << >>사칙 연산과 나머지 연산
비교 연산자> < >= <= == !=크고 작음과 같고 다름을 비교
논리 연산자&&
대립 연산자=우변의 값을 좌변에 저장
기타(type) ?: instanceof형변환 연산자, 삼항 연산자, instanceof연산자

피연산자의 개수에 의한 분류
삼항 연산자: 피연산자의 개수가 세 개. ?: 하나만 존재.
연산자를 기능별, 피연산자의 개수별로 나누어 분류하는 이유 → 연산자의 우선순위 때문

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

식에 사용된 연산자가 둘 이상인 경우, 연산자의 우선순위에 의해서 연산순서가결정.

연산자의 결합규칙
1. 산술 > 비교 > 논리 > 대입. 대입은 제일 마지막에 수행.
2. 단항(1) > 이항(2) > 삼항(3). 단항 연산자의 우선순위가 이항 연산자보다 높음.
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽.

종류결합 규칙연산자우선순위
단항 연산자++ — + - ~ ! (type)높음
산술 연산자* / &
산술 연산자+ -
산술 연산자<< >>
비교 연산자< > <= >= instanceof
비교 연산자== !=
논리 연산자&
논리 연산자^
논리 연산자|
논리 연산자&&
논리 연산자||
삼항 연산자?:
대입 연산자= += -= *= /= %= <<= >>= &= ^= |=낮음

1.5 산술 변환(usual arithmetic conversion)

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

int i = 10;
float f = 20.0f;

float result = f + (float)i;

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

2. 단항 연산자


2.1 증감 연산자

증가 연산자(++): 피연산자의 값을 1 증가시킴.
감소 연산자(—): 피연산자의 값을 1 감소시킴.
전위형(prefix): 피연산자의 왼쪽에 위치.
후위형(postfix): 피연산자의 오른쪽에 위치.

class OperatorEx2 {
	public static void main(String args[]) {
		int i=5, j=0;

		j = i++;
		System.out.println("j=i++; 실행 후, i=" + i +", j="+ j);
		// i = 6, j = 5

		i=5;        // 결과를 비교하기 위해, i와 j의 값을 다시 5와 0으로 변경
		j=0;

		j = ++i;
		System.out.println("j=++i; 실행 후, i=" + i +", j="+ j);
		//i = 6, j = 6
	}
}

전위형은 변수의 값을 먼저 증가시킨 후에 변수의 값을 읽음.
후위형은 변수의 값을 먼저 읽어온 후에 값을 증가.
식에 두 번 이상 포함된 변수에 증감연산자를 사용하는 것은 피해야 함.

2.2 부호 연산자

부호 연산자’-’는 피연산자의 부호를 반대로 변경한 결과를 반환.
부호 연산자는 boolean형과 char형을 제외한 기본형에만 사용 가능.

class OperatorEx4 {
	public static void main(String[] args) {
		int i = -10;
		i = +i;
		System.out.println(i);

		i=-10;
		i = -i;
		System.out.println(i);
	}
}

3. 산술 연산자


3.1 사칙 연산자 +, -, *, /

피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없음. → ArithmeticException 발생.

연산자 통해서 연속된 char 출력하기

class OperatorEx14 { 
      public static void main(String[] args) { 
            char c = 'a'; 
            for(int i=0; i<26; i++) {          // 블럭{} 안의 문장을 26번을 반복한다. 
                        System.out.print(c++); //'a'부터 26개의 문자를 출력한다. 
            } 
            
            System.out.println(); // 줄바꿈을 한다.

            c = 'A'; 
            for(int i=0; i<26; i++) {          // 블럭{} 안의 문장을 26번을 반복한다. 
                        System.out.print(c++); //'A'부터 26개의 문자를 출력한다. 
            } 

            System.out.println(); 

            c='0'; 
            for(int i=0; i<10; i++) {          // 블럭{} 안의 문장을 10번을 반복한다. 
                        System.out.print(c++); //'0'부터 10개의 문자를 출력한다. 
            } 
            System.out.println(); 
      } 
}

3.2 나머지 연산자 %

왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환.
피연산자로 정수만 허용됨.

class OperatorEx20 { 
      public static void main(String[] args) { 
            System.out.println(-10 % 8); // -2
            System.out.println(10 % -8);  // 2
            System.out.println(-10 % -8); // -2
      } 
}

나머지 연산자는 나누는 수로 음수도 허용하지만 부호는 무시한다.

4. 비교 연산자


4.1 대소비교 연산자 <, >, ≤, ≥

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

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

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

문자열의 비교

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"); // T
		System.out.printf(" str1==\"abc\" ? %b%n",    str1=="abc"); // T
		System.out.printf(" str2==\"abc\" ? %b%n",    str2=="abc"); // F 객체가 다르기 때문
		System.out.printf("str1.equals(\"abc\") ? %b%n", str1.equals("abc")); // T
		System.out.printf("str2.equals(\"abc\") ? %b%n", str2.equals("abc")); // T
		System.out.printf("str2.equals(\"ABC\") ? %b%n", str2.equals("ABC")); // F
		System.out.printf("str2.equalsIgnoreCase(\"ABC\") ? %b%n", str2.equalsIgnoreCase("ABC")); // T
	}
}

문자열을 비교할 때 equals()
대소문자를 구별하지 않고 비교하고 싶으면 equalsIgnoreCase()

5. 논리 연산자


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

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

xyx || yx && y
truetruetruetrue
truefalsetruefalse
falsetruetruefalse
falsefalsefalsefalse
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);
		// true

		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);
		// true
		// false		

		ch='1';
		System.out.printf("ch='%c', '0' <= ch && ch <= '9' =%b\n", ch, '0' <= ch && ch <='9');
		// true
		
		ch='a';
		System.out.printf("ch='%c', 'a' <= ch && ch <= 'z' =%b\n", ch, 'a' <= ch && ch <='z');
		// true

		ch='A';
		System.out.printf("ch='%c', 'A' <= ch && ch <= 'Z' =%b\n", ch, 'A' <= ch && ch <='Z');
		// true

		ch='q';
		System.out.printf("ch='%c', ch=='q' || ch=='Q' =%b\n", ch, ch=='q' || ch=='Q');
		// true
	}
}

효율적인 연산

xyx || y
truetruetrue
truefalsetrue
falsetruefalse
falsefalsefalse

x가 true이면 x || y 는 항상 true이다

xyx && y
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

x가 false이면 x && y 는 항상 false이다.

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

xy
truefalse
falsetrue

5.2 비트 연산자 &, |, ^, ~, <<, >>

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

xyx | yx & yx ^ y
11110
10101
01101
00000

| 는 주로 특정 비트의 값을 변경할 때 사용.
&는 주로 특정 비트의 값을 뽑아낼 때 사용.
^는 간단한 암호화에 사용.

class OperatorEx28 {
	public static void main(String[] args) { 
		int x = 0xAB;
		int y = 0xF;

		System.out.printf("x = %#X \t\t%s%n", x, toBinaryString(x));
		System.out.printf("y = %#X \t\t%s%n", x, toBinaryString(y));
		System.out.printf("%#X | %#X = %#X \t%s%n", x, y, x | y, toBinaryString(x | y));
		System.out.printf("%#X & %#X = %#X \t%s%n", x, y, x & y, toBinaryString(x & y));
		System.out.printf("%#X ^ %#X = %#X \t%s%n", x, y, x ^ y, toBinaryString(x ^ y));
		System.out.printf("%#X ^ %#X ^ %#X = %#X %s%n", x, y, y, x ^ y ^ y, toBinaryString(x ^ y ^ y));
	} // main의 끝

	// 10진 정수를 2진수로 변환하는 메서드
	static String toBinaryString(int x) {
		String zero = "00000000000000000000000000000000";
		String tmp = zero + Integer.toBinaryString(x);

		return tmp.substring(tmp.length()-32);
	}
}
/* x = 0XAB  00000000000000000000000010101011
y = 0XAB  00000000000000000000000000001111
0XAB | 0XF = 0XAF  00000000000000000000000010101111
0XAB & 0XF = 0XB  00000000000000000000000000001011
0XAB ^ 0XF = 0XA4  00000000000000000000000010100100
0XAB ^ 0XF ^ 0XF = 0XAB 00000000000000000000000010101011 */

비트 전환 연산자 ~
피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾼다.
논리부정 연산자 ! 와 비슷.

x~x
10
01

피연산자의 1의 보수를 얻을 수 있어 비트전환연산자를 1의 보수 연산자라고 부르기도 함.

class OperatorEx29 {
	public static void main(String[] args) {
		byte p =  10;
		byte n = -10;

		System.out.printf(" p  =%d \t%s%n",  p,   toBinaryString(p));
		System.out.printf("~p  =%d \t%s%n", ~p,   toBinaryString(~p));
		System.out.printf("~p+1=%d \t%s%n", ~p+1, toBinaryString(~p+1));
		System.out.printf("~~p =%d \t%s%n", ~~p,  toBinaryString(~~p));
		System.out.println();
		System.out.printf(" n  =%d%n",  n);	
		System.out.printf("~(n-1)=%d%n", ~(n-1));
	} // main의 끝

	// 10진 정수를 2진수로 변환하는 메서드
	static String toBinaryString(int x) {
		String zero = "00000000000000000000000000000000";
		String tmp = zero + Integer.toBinaryString(x);

		return tmp.substring(tmp.length()-32);
	}
}
/* p  =10  00000000000000000000000000001010
~p  =-11  11111111111111111111111111110101
~p+1=-10  11111111111111111111111111110110
~~p =10  00000000000000000000000000001010

 n  =-10
~(n-1)=10 */

쉬프트 연산자 << >>
피연산자의 각 자리를 오른쪽(>>) 또는 왼쪽(<<)으로 이동.
자리이동으로 저장범위를 벗어난 값들은 버려지고 빈자리는 0으로 채워짐.

class OperatorEx30 {
	public static void main(String[] args) {
		int dec = 8;

		System.out.printf("%d >> %d = %4d \t%s%n", dec, 0, dec >> 0, toBinaryString(dec >> 0));
		System.out.printf("%d >> %d = %4d \t%s%n", dec, 1, dec >> 1, toBinaryString(dec >> 1));
		System.out.printf("%d >> %d = %4d \t%s%n", dec, 2, dec >> 2, toBinaryString(dec >> 2));

		System.out.printf("%d << %d = %4d \t%s%n", dec, 0, dec << 0, toBinaryString(dec << 0));
		System.out.printf("%d << %d = %4d \t%s%n", dec, 1, dec << 1, toBinaryString(dec << 1));
		System.out.printf("%d << %d = %4d \t%s%n", dec, 2, dec << 2, toBinaryString(dec << 2));
		System.out.println();

		dec = -8;
		System.out.printf("%d >> %d = %4d \t%s%n", dec, 0, dec >> 0, toBinaryString(dec >> 0));
		System.out.printf("%d >> %d = %4d \t%s%n", dec, 1, dec >> 1, toBinaryString(dec >> 1));
		System.out.printf("%d >> %d = %4d \t%s%n", dec, 2, dec >> 2, toBinaryString(dec >> 2));

		System.out.printf("%d << %d = %4d \t%s%n", dec, 0, dec << 0, toBinaryString(dec << 0));
		System.out.printf("%d << %d = %4d \t%s%n", dec, 1, dec << 1, toBinaryString(dec << 1));
		System.out.printf("%d << %d = %4d \t%s%n", dec, 2, dec << 2, toBinaryString(dec << 2));
		System.out.println();

		dec = 8;
		System.out.printf("%d >> %2d = %4d \t%s%n", dec, 0,  dec >> 0,  toBinaryString(dec << 2));
		System.out.printf("%d >> %2d = %4d \t%s%n", dec, 32, dec >> 32, toBinaryString(dec << 2));
	} // main의 끝

	// 10진 정수를 2진수로 변환하는 메서드
	static String toBinaryString(int x) {
		String zero = "00000000000000000000000000000000";
		String tmp = zero + Integer.toBinaryString(x);

		return tmp.substring(tmp.length()-32);
	}
}

/*
8 >> 0 =    8  00000000000000000000000000001000
8 >> 1 =    4  00000000000000000000000000000100
8 >> 2 =    2  00000000000000000000000000000010
8 << 0 =    8  00000000000000000000000000001000
8 << 1 =   16  00000000000000000000000000010000
8 << 2 =   32  00000000000000000000000000100000

-8 >> 0 =   -8  11111111111111111111111111111000
-8 >> 1 =   -4  11111111111111111111111111111100
-8 >> 2 =   -2  11111111111111111111111111111110
-8 << 0 =   -8  11111111111111111111111111111000
-8 << 1 =  -16  11111111111111111111111111110000
-8 << 2 =  -32  11111111111111111111111111100000

8 >>  0 =    8  00000000000000000000000000100000
8 >> 32 =    8  00000000000000000000000000100000
*/

6. 그 외의 연산자


6.1 조건 연산자 ?:

조건식 ?1 :2;
// 조건식이 참이면 식1 수행, 거짓이면 식2 수행
// 1
result = (x > y) ? x : y;

// 2
if (x > y) {
	result = x;
} else {
	result = y;
} 

// 1과 2는 같음.
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);
	}
}

6.2 대입 연산자 =, op=

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

lvalue와 rvalue
lvalue = left value = 왼쪽 피연산자. 변수처럼 값을 변경할 수 있는 것이어야 함. 리터럴, 상수 불가능.
rvalue = right value = 오른쪽 피연산자. 변수, 식, 상수 모두 가능.

복합 대입 연산자
복합 대입 연산자: 다른 연산자(op)와 결합하여 op= 과 같은 방식으로 사용.
결합된 두 연산자는 반드시 공백없이 붙여써야 함.
ex) x += 3; y -= 2;

0개의 댓글