🌑 연산자(Operator)와 피연산자
연산자(operator)와 피연산자(operand)?
- 연산자(operator): 연산 기호 (ex: `+`, `-`)
- 피연산자(operand): 연산 대상 (ex: `3`, `4`, `a`, `b`)
연산자 종류
- 산술 연산자: `+`,` -` , `*`, `/`, `%`, `<<`, `>>`, ...
- 증감(증가 및 감소) 연산자: `++`, `--`
- 비교 연산자: `==`, `!=`, `>`, `<`, `>=`, `<=`
- 논리 연산자: `&&(AND)`, `||(OR)`, `!(NOT)`, ...
- 대입 연산자: `=`, `+=`, `-=`, `*=`, `/=`, `%=`
- 삼항 연산자: `? :`
- 형변환 연산자: '(변환하고자 하는 타입)'
- · instanceof연산자
연산자의 우선순위 (상식적인 개념)
- 괄호 ()
- 단항 연산자 (예: `++` , `--` , `!` , `~` , `new` , `(type)` )
- 산술연산자 (`*` , `/` , `%` 우선,그다음에 `+` , `-` )
- Shift 연산자 ( `<<` , `>>` , `>>>` )
- 비교 연산자 ( `<` , `<=` , `>` , `>=` , `instanceof` )
- 등식 연산자 (`==` , `!=` )
- 비트 연산자 (`&` ,`^` ,`|` )
- 논리 연산자 ( `&&` , `||` )
- 삼항연산자 (`? :` )
- 대입 연산자 (`=` , `+=` , `-=` , `*=` , `/=` , `%=` 등등)
💡 연산자 우선순위가 너무 많은데 어떻게 하지 ?
1. 상식선에서 우선순위를 사용하자.
2. 애매하면 괄호()를 사용하자.
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.
➙ 개발에서 가장 중요한 건 단순함과 명확함 ! 애매하거나 복잡할 필요가 없기 때문에, 애매하면 괄호를 사용하자 !
연산자의 결합규칙
- 단항 연산자 & 대입연산자 ( ← )
(ex: `i++`, `a=1`) - 나머지 연산자 ( → )
💡 산술 변환 ?
연산 수행 직전에 발생하는 피연산자의 자동 형변환을 말한다.
* 산술 변환의 규칙 *
1. 두 피연산자의 타입을 같게 일치시킨다 (보다 큰 타입으로 일치).
2. 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.
🌒 산술 연산자
주로 숫자를 계산하는 데 사용되는 "산술 연산자"
- `+`: 더하기
- `-`: 빼기
- `*`: 곱하기
- `/`: 나누기
(ex: `5/2`의 결과값은 소수점이 제거된 `2`, 0으로 나누면 'ArithmeticException'이라는 예외 발생) - `%`: 나머지
➙ 짝수, 홀수 또는 배수 검사 등에 주로 사용하며, 나누는 수(오른쪽 피연산자)로 0은 사용 불가능하다.
( 나누는 수에 음수를 넣어도 그냥 절대값으로 나눈 나머지를 반환한다 ! )
- int타입과 int타입의 계산을 할 때, long으로 형변환(casting)을 해주지 않으면 올바른 값이 출력되지 않는다 !
class OperatorCasting {
public static void main(String[] args) {
int a = 1_000_000;
int b = 1_000_000;
long c = (long)a * b;
}
}
- 연산의 순서에 따라 다른 결과가 나오는 예제
class OperatorCasting {
public static void main(String[] args) {
int a = 1000000;
int resultWrong = a * a / a; // Overflow : 먼저 곱하는 과정에서 int의 범위를 넘어선다.
int resultRight = a / a * a;
}
}
문자열 더하기
- Java는 특별하게 문자열에도 `+` 연산자를 사용 가능하다.
➙ 두 문자열 연결, 문자열과 숫자 연결(숫자를 문자열로 변경한 다음에 서로 더한다)
//문자열과 숫자 더하기2
int num = 20;
String str = "a + b = ";
String result4 = str + num;
System.out.println(result4); // a + b = 20
🌓 증감 연산자
증감 연산자
- 증가 및 감소 연산자를 줄여서 증감 연산자(`++`, `--`)라 한다!
➙ 변수의 값을 1만큼 증가시키거나 감소시킨다 !
( 프로그래밍에선 값을 1씩 증가시키거나 감소시킬 때가 아무 많기 때문에 ! )
전위(prefix) 증감 연산자 & 후위(postfix) 증감 연산자
- 전위 증감 연산자: 증감 연산자가 변수 앞에 오는 경우
➙ 증감 연산이 먼저 수행된 후 나머지 연산 수행 ! - 후위 증감 연산자: 증감 연산자가 변수 뒤에 오는 경우
➙ 다른 연산이 먼저 수행된 후 증감 연산 수행 !
// 전위 증감 연산자 사용 예
int a = 1;
int b = 0;
b = ++a; // a의 값을 먼저 증가시키고, 그 결과를 b에 대입
System.out.println("a = " + a + ", b = " + b); // 결과: a = 2, b = 2
// 후위 증감 연산자 사용 예
a = 1; // a 값을 다시 1로 지정
b = 0; // b 값을 다시 0으로 지정
b = a++; // a의 현재 값을 b에 먼저 대입하고, 그 후 a 값을 증가시킴
System.out.println("a = " + a + ", b = " + b); // 결과: a = 2, b = 1
🌔 비교 연산자
비교 연산자
- `==` : 동등성 (equal to)
- `!=` : 불일치 (not equal to)
- `>` : 크다 (greater than)
- `<` : 작다 (less than)
- `>=` : 크거나 같다 (greater than or equal to)
- `<=` : 작거나 같다 (less than or equal to)
대소비교 연산자(`<`, `>`, `<=`, `>=`)
- 기본형(boolean형 제외) 모두 사용 가능하다 !
( 참조형은 사용 불가능. )
등가 비교 연산자(`==`, `!=`)
- 모든 자료형에 사용 가능
➙ 하지만 '기본형'과 '참조형'과의 비교는 불가능하다 ! ( 서로 형변환이 안되기 때문에 ! )
문자열 비교는 어떻게 ?
- 문자열이 같은지 비교할 때는 `==`이 아니라 `.equals()` 메서드를 사용해야 한다 !
- '=='로 비교한 경우 ➙ 내용은 같아도 서로 다른 객체면 false 반환
- 'equals()'로 비교한 경우 ➙ 객체가 달라도 내용이 같으면 true 반환
String str1 = "문자열1";
String str2 = "문자열2";
boolean result1 = "hello".equals("hello"); //리터럴 비교
boolean result2 = str1.equals("문자열1"); //문자열 변수, 리터럴 비교
boolean result3 = str1.equals(str2); //문자열 변수 비교
System.out.println("result1 = " + result1); //result1 = true
System.out.println("result2 = " + result2); //result2 = true
System.out.println("result3 = " + result3); //result3 = false
🌕 논리 연산자
논리 연산자
- `&&` (AND) : 두 피연산자가 모두 참이면 참을 반환, 둘중 하나라도 거짓이면 거짓을 반환.
- `||` (OR) : 두 피연산자 중 하나라도 참이면 참을 반환, 둘다 거짓이면 거짓을 반환.
- `!` (NOT) : 피연산자의 논리적 부정을 반환. 즉, 참이면 거짓을, 거짓이면 참을 반환.
int a = 15;
//a는 10보다 크고 20보다 작다
boolean result = a > 10 && a < 20; //(10 < a) && (a < 20)
System.out.println("result = " + result); // result = true
피연산자의 위치에 따라 달라지는 연산 속도
- `&&`를 사용한 경우
➙ 좌측 피연산자의 값이 거짓(false)이면 우측 피연산자의 값은 체크하지 않고 넘어간다 ! - `||`를 사용한 경우
➙ 좌측 피연산자의 값이 참(true)이면 우측 피연산자의 값은 체크하지 않고 넘어간다 ! - 아래 코드를 보면 좌측 피연산자(`a!=0`, `a==0`)의 값에 따라 우측 피연산자(`++b!=0)는 체크하지 않는 것을 확인할 수 있다 !
int a = 5;
int b = 0;
System.out.printf("a=%d, b=%d%n", a, b); // a=5, b=0
System.out.printf("a!=0 || ++b!= = %b%n", a!=0 || ++b!=0); // a!=0 || ++b!=0 = true
System.out.printf("a=%d, b=%d%n", a, b); // a=5, b=0
System.out.printf("a!=0 || ++b!= = %b%n", a==0 || ++b!=0); // a==0 && ++b!=0 = false
System.out.printf("a=%d, b=%d%n", a, b); // a=5, b=0
비트 연산자
- `&`(AND), `|`(OR), `^`(XOR)
- `~`(1's complent)
- `<<` : 각 자리를 왼쪽으로 이동
- `>>` : 각 자리를 오른쪽으로 이동
➙ `-8>>2`처럼 왼쪽 피연산자가 음수인 경우 빈자리를 1로 채운다
- 사실 '비트 연산자'는 실제로 개발할 땐 거의 사용할 일이 없기 떄문에, 그냥 필요할 때 찾아보자 !
🌖 삼항 연산자
삼항 연산자 ?
- 삼항 연산자는 Java에서 유일하게 항이 3개인 연산자를 말한다 !
( 이외에 대부분의 연산자(ex: 증감연산자 `++`,`--`)는 모두 "단항 연산자"라고 보면 된다 ! )
(조건) ? 참_표현식 : 거짓_표현식
삼항 연산자를 왜 쓸까 ?
- 삼항 연산자를 사용하지 않은 코드
int age = 18;
String status;
if (age >= 18) {
status = "성인";
} else {
status = "미성년자";
}
System.out.println("age = " + age + " status = " + status);
- 삼항 연산자를 사용한 코드
➙ 보다 간결한 코드를 작성하기 위해서 사용 !
int age = 18;
String status = (age >= 18) ? "성인" : "미성년자";
System.out.println("age = " + age + " status = " + status);
🌗 그외 연산자
부호 연산자
- 부호 연산자 `-`는 피연산자의 부호를 반대로 변경한 결과를 반환한다 !
➙ boolean형과 char형을 제외한 기본형에만 사용할 수 있다.
( 부호 연산자 `+`는 하는 일이 없으니 몰라도 된다. )
`instanceof` 연산자
- 객체 타입을 확인한다.
class A { }
class B extends A { } // A 클래스를 상속
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true : A를 상속 받았기 때문
System.out.println(a instanceof B); // false
System.out.println(b instanceof B); // true
}
`new` 연산자
- 객체를 생성할 때 사용하고 'Heap'이라는 메모리 영역 안에 새로운 메모리 공간을 할당해주는 것이다 !
className object = new className();
`.` 연산자
- 객체 멤버에 접근할 때 사용 !
System.out.println(anyObject.callMember);
`()` 연산자
- '메소드'를 호출할 때 사용 !
callMethod();