[자바의정석]Chapter 03. 연산자

seungwon·2023년 1월 4일
0

자바의 정석

목록 보기
3/14

1. 연산자(operator)

1.1 연산자 & 피연산자

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

1.2 식과 대입연산자

식(expression) : 연산자와 피연산자를 조합하여 계산하고자하는 바를 표현한 것
"식을 평가(evaluation)" : 식을 계산하여 결과를 얻는 것
문장 : 작성한 식을 프로그램에 포함시키기 위해 식의 끝에 ';'를 붙여서 만듬

1.3 연산자의 종류

피연산자의 개수에 의한 분류

  • 단항 연산자(피연산자 1개)
  • 이항 연산자(2개) : 대부분의 연산자
  • 삼항 연산자(3개) : "? :"

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

우선순위 : 식에 사용된 연산자 간의 연산 순서

*괄호는 연산자가 아닌 우선순위를 임의로 지정할 때 사용하는 기호

결합순위 : 하나의 식에 같은 우선순위의 연산자들이 여러 개 있는 경우의 연산 순서
1. 산술〉비교〉논리〉대입. 대입은 제일 마지막에 수행된다.
2. 단 항 (1) 〉이항(2) > 삼항(3). 단항 연산자의 우선순위가 이항 연산자보다 높다.
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.

1.5 산술 변환(일반 산술 변환)

자동형변환 (연산 전에 두 피연산자의 타입을 일치시키는 것)

  1. 두 피연산자의 타입을 같게 일치시킨다. (보다 큰 타입으로 일치)
    -> 피연산자의 값손실을 최소화
  2. 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.
    *모든 연산에서 ‘산술 변환’이 일어나지만, 쉬프트연산자(《 ,》 ),증감연산자(++,—)는 예외

2. 단항 연산자

2.1 증감 연산자 ++ --

대입 연산자와 증감연산자만 피연산자의 값을 변경
(<-> 대부분의 연산자 : 피연산자의 값을 읽어서 연산에 사용할 뿐 값을 변경시키지 않음)

전위형 vs. 후위형

2.2 부호 연산자 + -

덧셈, 뺄셈 연산자와 다른 연산자(피연산자 개수가 다름)

  • boolean/char을 제외한 기본형에만 사용 가능

+) 논리부정 연산자(!), 비트전환 연산자(~)


3. 산술 연산자

3.1 사칙 연산자 + - * /

피연산자가 정수형인 경우 : 나누는 수로 0을 사용할 수 없음 -> ArithmeticException 오류
피연산자가 실수인 경우 : ±Infinity\pm Infinity, ±0.0\pm0.0

👽 예제

  • 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.
class operatorEx7 {
	public static void main(String[] args) {
      byte a = 10;
      byte b = 30;
      byte c = a * b; // 🚨 에러 -> (byte)(a * b)로 변경해야 함
      System.out.println(c);
	} 
}

변수 a,b가 byte형으로 int보다 작으므로 int로 변환된다
byte c=abc = a * b 에서 크기가 작은 자료형의 변수 c에 크기가 큰 자료형(int)을 대입하려고하니 컴파일 에러가 발생한다. byte로 형변환시 1030=30010 * 30 = 300 이 아닌 값 손실이 발생한 44가 결과로 나온다.

값을 저장하기에 충분한 자료형을 사용해야 함

  • 연산 결과 = 피연산자의 자료형 -> 오버플로우 발생 주의
class operatorEx8 {
	public static void main(String args[]) {
		int a = 1_000_000; // 1,000,000 1백만 
        int b = 1_000_000; // 2,000,000 2백만
		long c = a <* b; // 🚨 a * b != 2,000,000,000,000  ->  (long)a * b;로 수정해야 함
	}
}

int 타입인 a 와 b의 연산 결과인 a * b 도 int 타입이라 long 타입에 대입을 하더라도 이미 오버플로우가 발생하여(-1454759936) 값의 손실이 일어난 상태이다

  • 오버플로우 주의(연산 순서에 따라 다른 결과 발생)
class OperatorExlO {
	public static void main(String args(1) {
		int a = 1000000;
		
        int resultl = a * a / a; // 1000000 * 1000000 / 1000000 🚨오버플로우 발생 
        int result2 = a / a * a; // 1000000 / 1000000 * 1000000
		System.out.printf("%d * %d / %d = %d%n", a, a, a , resultl);
        System.out.printf("%d / %d * %d = %d%n", a, a , a, result2);
	}
}

💻
10000001000000/1000000=7271000000 * 1000000 / 1000000 = -727
1000000/10000001000000=10000001000000 / 1000000 * 1000000 = 1000000

  • char + int : 형변환필요
  class OperatorExl2 {
      public static void main(String[] args) {
          char c1 = 'a'; // c1에는 문자 'a'의 코드값인 97이 저장됨
          char c2 = c1; 
          char c3 =' ';
          int i = c1 + 1;
          c3 = (char)(c1 + 1);  
          //덧셈연산 c1+1의 결과가 int이므로 이 결과를 char형 변수 c3에 담기 위해서는 char형으로의 형변환필요

          c2++; // c2=c2+1;을 사용하면 에러 발생 (∵ c2+1은 int형 -> char형으로 형변환 필요)
          c2++;
          System.out.println("i=" + i); 
          System.out.println("c2=" + c2); 
          System.out.println("c3=" + c3);
      }
  }
  • char(리터럴) + 상수 : 형변환 필요x
    class OperatorEx13 {
        public static void main (String[] args)
            char c1 = 'a';
        //	char c2 = c1+1; // 🚨 컴파일 에러
            char c2 = 'a'+1; // 🚨 컴파일 에러없음
            System.out.println(c2);
        }
    }
    상수/리터럴간의 연산 : 컴파일시에 컴파일러가 계산해서 그 결과로 대체(실행과정동안 변하는 것x)
  • 변수가 포함된 수식 계산(ex. char c2 = c1 + 1)
    컴파일러가 미리 계산할 수 없어 형변환을 해주어야 함(그렇지 않으면 컴파일 에러 발생)
    char c2 = c1 + 1 -> char c2 = (char)(c1+1);
  • 소수점 아래 n자리 까지 뽑아내기(버림)
    class 0peratorExl6 {
    		  public static void main(String[] args) {
    			  float pi = 3.141592f;
            float shortPi = (int) (pi * 1000) / lOOOf; //
            System.out.println(shortPi);
    		}
    }

    💻 3.141

  • 소수점 아래 n자리 까지 뽑아내기(반올림)

     class operatorExl7 {
         public static void main(String args[]) {
             double pi = 3.141592;
             double shortPi = (int)(pi * 1000 + 0.5)/1000.0;
             System.out.println(shortPi); 
         }
     }

    💻 3.142

  • 반올림(메소드 활용) : Math.round()
    class operatorExl8 {
        public static void main(String args[]) {
            double pi = 3.141592;
            double shortPi = Math.round(pi * 1000) / 1000.0;
            System.out.println(shortPi);
        } 
    }

3.2 나머지 연산자 %

왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자이다.
*나눗셈에서 처럼 나누는 수(오른쪽 피연산자)로 0을 사용할 수 없음

나누는 수가 음수인 경우 : 피연산자의 부호를 모두 무시하고 나머지 연산 -> 나눠지는 수의 부호 붙이기

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 대소비교 연산자 < > <= >=

boolean형을 제외한 기본형에 사용(참조형에 사용x)

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

모든 자료형(기본형+참조형)에 사용 가능

👽 실수간의 비교시 오차 발생

ex)

class OperatorEx22 {
	public static void main(String args[]) {
		System.out.printf("10.0==10.0f %b%n",10.0 == 10.0f);
        System.out.printf("0.1==0.1f %b%n" , 0.1 == 0.1f); 
	}
}

💻
10.0==10.0f true
0.1==0.1f false

float f = 0.1f; // f에 0.10000000149011612로 저장
double d = 0.1; // d에 0.10000000000000001로 저장

-> float값을 double로 형변환하여도 결과는 동일
(∵ 부호와 지수는 달라지지 않고 가수의 빈자리를 0으로 채우기만 할뿐임)

👽 문자열의 비교

  • equals() : 대소문자 구별
  • equalsIgnoreCase() : 대소문자 무시
  • == : 서로 같은 문자열 객체인지를 비교

5. 논리 연산자

5.1 논리 연산자 && || !

AND(&&), OR(||)

효율적인 연산
OR연산(||)은 좌측 피연산자가 참이면 우측 피연산자의 값은 평가x,
AND연산(&&)은 좌측 피연산자가 거짓이면 우측 피연산자의 값은 평가x
-> 같은 조건식이라도 피연산자의 위치에 따라 연산속도가 달라질 수 있음
-> OR연산(||) : 연산결과가 ‘참’일 확률이 높은 피연산자를 연산자의 왼쪽에 놓아야 더 빠른 연산결과를 얻을 수 있음

논리 부정 연산자(!)

조건식/토글 버튼 구현등에 쓰임

이중으로도 사용가능(!!b)

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

피연산자는 정수(문자 포함)만 허용

☑️ ### | : OR연산자, 주로 특정 비트의 값을 변경할 때 사용

☑️ & : AND연산자 , 특정 비트의 값을 뽑아낼 때 사용

☑️ ^ : XOR연산자(두 피연산자의 비트가 다를 때만 1), 같은 값으로 두고 XOR연산을 수행하면 원래의 값으로 돌아오는 특징 -> 암호화에 사용

☑️ ~ : 비트 전환 연산자(1의 보수 연산자), 부호가 반대로 변경됨, 중복 적용(~~p) 가능 - 단 결과는 int형

☑️ <<, >> : 쉬프트 연산자
x << n = x2nx * 2^n
x >> n = x/2nx / 2^n

  • 나눗셈/곱셈 연산자보다 실행 속도가 빠름
  • << : 부호와 상관없이 빈칸을 0으로 채움
  • >> : 빈칸을 부호 비트로 채움(음수 1, 양수 0)
  • 쉬프트 연산자의 좌측 피연산자에는 산술 변환이 적용되어 int보다 작은 타입->int, 연산결과도 + int
  • 우측 피연산자에는 산술변환 적용x (∵ 다른 이항연산자들과 달리 피연산자의 타입을 일치시킬 필요x)

☑️ 예제
16진수를 끝에서부터 한자리씩 뽑아내는 예제

설명

class OperatorEx31 {
	public static void main(String[] args) {
	int dec = 1234; 
   int hex = OxABCD; 
   int mask = OxF;
	
   System.out.printf("hex=%X%n", hex) ; 
   System.out.printf("%X%n", hex & mask) ;
	
   hex = hex » 4;
   System,out.printf("%X%n", hex & mask) ;

	hex = hex» 4; 
	System,out.printf("%X%n", hex & mask) ;
   
   hex = hex» 4; 
	System,out.printf("%X%n", hex & mask) ;
} 

💻
hex=ABCD
D
C
B
A


6. 그 외의 연산자

6.1 조건 연산자 ?:

6.2 대입 연산자 = op=

op= : +=, -=, *=, |= ,....

0개의 댓글