연산자는 '연산을 수행하는 기호'를 말하며 +, -, * 등이 연산자에 해당됩니다.
연산자가 연산을 수행하려면 연산자의 대상이 있어야하는데, 이 대상을 '피연산자'라고 합니다.
피연산자로 상수, 변수, 식을 사용할 수 도 있습니다.
연산자(operator) = 연산을 수행하는 기호 ( +, -, * 등 )
피연산자(operand) = 연산자의 작업 대상(변수, 상수, 리터럴, 수식)
연산자의 종류
연산자의 종류는 다음과 같으며 하나씩 알아보도록 하겠습니다.
종류 | 연산자 | 설명 |
산술 연산자 | + - * / % << >> | 사칙 연산( +, -, *, / )과 나머지 연산 ( % ) |
비교 연산자 | > < >= <= == != | 크고 작음과 같거나 크고 작음, 같은 다름을 비교 |
논리 연산자 | && || ! & | ^ ~ | 그리고 (AND) 와 또는 (OR)으로 조건 연결 |
대입 연산자 | = | 우변의 값을 좌변에 저장 |
삼항 연산자 | (type) ? true : false | 타입이 true인지 false인지 판별 |
연산자의 우선운위와 연산방향
- 단항, 이항, 삼항 연산자 순으로 우선순위를 가집니다.
- 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 가집니다.
- 단항, 부호, 대입 연산자를 제외한 모든 연산의 방향은 왼쪽에서 오른쪽입니다.
- 괄호 ()를 사용하면 가장 우선순위로 연산합니다.
단항 연산자
증감연산자 ++, --
증감연산자는 피연산자에 저장된 값을 1 증가 또는 감사 시킵니다.
증가 연산자 (++) = 피연산자의 값을 1 증가시킨다.
감소 연산자 (--) = 피연산자의 값을 1 감소하킨다.
일반적으로 단항 연산자는 피연산자의 왼쪽에 위치하지만, 증감 연산자는 피연산자의 왼쪽 오른쪽 둘다 위치가능하며,
위치에 따라 전위형, 후위형으로 나뉩니다.
타입 | 설명 | 사용예시 |
전위형 | 값이 참조되기 전에 증가시킨다 | j = ++i; |
후위형 | 값이 참조된 후에 증가시킨다 | j = i++; |
결과적으로는 증가되는 것은 같지만 차이점을 알아보자면 다음 코드를 보면 됩니다.
public class Operator3 {
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);
}
}
위 코드를 보면, i++ (후위형) 은 값이 증가 되기 전에 i에 저정된 값 5를 println()에게 넘겨주고 나서 i 값이 증가해 5가 출력되고,
++j (전위형) 은 j에 저장된 값을 증가시킨 후에 println()에게 값을 넘겨주므로 6이 출력됩니다.
결과적으로는 i, j 모두 1씩 증가되어 6이 됩니다.
부호 연산자 + , -
부호 연산자는 피연산자 왼쪽에 위치하며 '-' 음수인지 '+' 양수인지 판별합니다.
부호 연산자는 boolean과 char를 제외한 기본형에만 사용할 수 있습니다.
public class Operator4 {
public static void main(String[] args) {
int i = -10;
i = +i;
System.out.println(i);
i = -10;
i = -i;
System.out.println(i);
}
}
산술 연산자
사칙 연산자 +, -, *, /
사칙 연산자는 덧셈 ( + ), 뺄셈 ( - ), 곱셈 ( * ), 나눗셈 ( / )으로 프로그래밍에서 가장 많이 사용되는 연산자입니다.
public class OperatorEx5 {
public static void main(String[] args) {
int a = 10;
int b = 4;
System.out.printf("%d + %d = %d%n", a, b, a+b);
System.out.printf("%d - %d = %d%n", a, b, a-b);
System.out.printf("%d * %d = %d%n", a, b, a*b);
System.out.printf("%d / %d = %d%n", a, b, a/b); // int 형이므로 소숫점 버려짐
System.out.printf("%d / %f = %f%n", a, (float)b, a / (float)b);
}
}
원래 10 / 4 는 결과가 2.5여야하는데 a와 b가 int 형이므로 소숫점을 버려 2라는 결과가 나옵니다.
소숫점 결과까지 얻고 싶을 때는 int 보다 표현범위가 변수 둘 또는 하나를 큰 float 형으로 형변환하여 연산하면 2.5를 얻을 수 있습니다.
또 다른 예시를 봅시다.
public class OperatorEx7 {
public static void main(String[] args) {
byte a = 10;
byte b = 30;
byte c = (byte) (a*b);
System.out.print(c);
}
}
원래 10 * 30은 300이라는 값이 나와야합니다.
하지만 byte의 표현가능한 범위는 -128 ~ 127 로 300은 표현범위를 넘어서 값 손실이 일어나 44 라는 값이 결과로 나왔습니다.
이처럼 값 손실을 방지하기 위해서는 충분히 큰 자료형을 사용해야합니다.
또한 숫자뿐만 아니라 문자도 연산이 가능합니다.
public class OperatorEx11 {
public static void main(String[] args) {
char a = 'a';
char e = 'e';
char zero = '0';
char three = '3';
System.out.printf("'%c' - '%c' = %d%n", e, a, e - a);
System.out.printf("'%c' - '%c' = %d%n", three, zero, three - zero);
System.out.printf("'%c'= %d%n", a, (int)a);
System.out.printf("'%c'= %d%n", e, (int)e);
System.out.printf("'%c'= %d%n", zero, (int)zero);
System.out.printf("'%c'= %d%n", three, (int)three);
}
}
해당 문자들은 위와 같은 유니코드 코드를 가져 위와 같은 연산이 가능합니다.
문자 | 코드 | 문자 | 코드 | 문자 | 코드 |
0 | 48 | A | 65 | a | 97 |
1 | 49 | B | 66 | b | 98 |
2 | 50 | C | 67 | c | 99 |
3 | 51 | D | 68 | d | 100 |
4 | 52 | E | 69 | e | 101 |
5 | 53 | ... | ... | .... | ... |
6 | 54 | W | 87 | w | 119 |
7 | 55 | X | 88 | x | 120 |
8 | 56 | Y | 89 | y | 121 |
9 | 57 | Z | 90 | z | 122 |
유니코드 코드를 이용해 다음과 같이 대소문자로 변경할 수 도 있습니다.
public class OperatorEx15 {
public static void main(String[] args) {
char lowerCase = 'a';
// 대문자 A는 소문자 a보다 코드 값이 32가 작다.
// 반대로 대문자를 소문자로 변환하려면 대문자의 코드 값에 32를 더해주면된다.
char upperCase = (char) (lowerCase - 32);
System.out.println(upperCase);
}
}
나머지 연산자 %
나머지 연산자는 왼쪽의 피연산자를 오른족 피연산자로 나누고 난 나머지 값을 결과로 반환합니다.
나머지 연산자는 주로 짝수(n%2==0) , 홀수(n%3==0) , 배수, 약수를 구하는데 주로 사용됩니다.
public class OperatorEx20 {
public static void main(String[] args) {
System.out.println(10%9);
System.out.println(-10%9);
System.out.println(10%-9); // 피연산자의 부호는 무시한다.
System.out.println(-10%-9); // 피연산자의 부호는 무시한다.
}
}
비교 연산자
대소비교 연산자 < , > , <= , >=
두 피연산자의 값의 크기를 비교합니다. 참이면 true를, 거짓이면 false를 반홚바니다.
기본형 중에서는 boolean형을 제외하고 다 사용할 수 있지만, 참조형에서는 사용할 수 없습니다.
비교연산자 | 연산결과 |
> | 좌변 값이 크면 true, 아니면 false |
< | 좌변 값이 작으면, true 아니면 false |
>= | 좌변 값이 크거나 같으면 true, 아니면 false |
<= | 좌변 값이 작거나 같으면 true, 아니면 false |
등가비교 연산자 == , !=
두 피연산자의 값이 같은지 또는 다른지를 비교합니다.
등가비교 연산자는 기본형은 물론 참조형, 즉 모든 자료형에 사용할 수 있습니다.
비교연산자 | 연산결과 |
== | 두 값이 같으면 true, 아니면 false |
!= | 두 값이 다르면 true, 아니면 false |
문자열의 비교
두 문자열을 비교할 때는 비교 연산자 == 대신, equals() 라는 메서드를 사용해야 합니다.
equals()는 비교하는 두 문자열이 같으면 true를 다르면 false를 반환합니다.
public class OperatorEx23 {
// 문자열은 비교 할 대는 == 연산자 말고 equals() 메서드를 사용해야한다.
// equals() 는 서로 객체가 달라도 내용이 같으면 true를 반환한다.
public static void main(String[] args) {
/* String은 클래스이므로 아래 처럼 new를 사용해 객체를 생성해야하지만,
특별히 String만 예외로 new를 사용하지 않고 str1처럼 객체를 생성할 수 있다. */
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"));
// equalsIgnoreCase() 는 대소문자를 구별하지 않고 비교한다.
System.out.printf("str2.equalsIgnoreCase(\"ABC\") ? %b%n", str2.equalsIgnoreCase("ABC"));
}
}
위 결과를 보면 비교연산자 ( == ) 를 사용했을 시 str2와 "abc"의 내용이 같은데도 false를 반환한다.
내용은 같지만 다른 객체이기 때문이다.
하지만 equals()는 객체가 달라도 내용이 같으면 true를 반환한다.
그렇기 때문에 문자열을 비교할땐 꼭 equals()를 사용해야한다.
논리 연산자
논리 연산자 &&, ||
&& (AND 그리고) = 피연산자 양쪽이 모두 true 여야 true를 결과로 얻는다.
|| (OR 또는) = 피연산자 중 어는 한쪽 만 true이면 true를 결과로 얻는다.
유니코드를 이용한 숫자 문자 확인 코드
import java.util.*;
public class OperatorEx25 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char ch = ' ';
System.out.println("문자를 하나 입력하세요. : ");
String input = scanner.nextLine();
ch = input.charAt(0);
if('0' <= ch && ch <= '9') {
System.out.println("입력하신 문자는 숫자 입니다");
}
if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
System.out.println("입력하신 문자는 영문자입니다.");
}
}
}
효율적인 연산
OR연산자 "||" 의 경우 한 쪽만 참이면 true를 반환하기 때문에, 좌측 피연산자가 true이면 우측 피연산자의 값을 평가하지 않습니다.
AND 연사자 "&&" 의 경우 둘 중 하나라도 거짓이면 false를 반환하기 때문에, 좌측 연산자가 false이면, 우측 피연산자의 값을 평가하지 않습니다.
그래서 이 특징을 사용해 피연산자의 위치에 따라 연산속도를 효율적으로 할 수 있습니다.
OR 연산자 "||" 의 경우에는 연산결과가 "true"일 확률이 높은 것을 왼쪽에,
AND 연산자 "&&" 의 경우에는 연산결과가 "false" 일 확률이 높은 것을 왼쪽에 놓아야 더 빠른 연산 결과를 얻을 수 있습니다.
논리 부정 연산자 !
이 연산자는 피연산자가 true 이면 false를 , false 이면 true로 결과를 반환합니다.
즉 true와 false 결과 값을 반대로 바꿉니다.
x | !x |
true | false |
false | true |
어떠한 값에 논리 부정 연산자 ! 를 반복 사용하면 참과 거짓이 차례대로 반복됩니다.
이러한 성질을 이용하여 TV 전원버튼 같은 토글 버튼을 논리적으로 구현할 수 있습니다.
비트 연산자 & | ^
비트 연산자는 피연산자를 비트단위로 논리 연산합니다.
| (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 |
비트 전환 연산자 ~ ( '1의 보수' 연산자 )
피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꿉니다.
x | ~x |
1 | 0 |
0 | 1 |
비트 전환 연산자 ~ 에 의해 비트 전환 되고 나면, 부호있는 타입의 피연산자는 부호가 반대로 변경됩니다.
즉, 피연산자의 '1의 보수'를 얻을 수 있습니다.
2진수 | 10진수 |
00001010 | 10 |
11110101 | -11 |
11110101 + 00000001 = 11110110 (2의 보수) | -11 + 1 = -10 ( 2의 보수 ) |
1의 보수에 + 1 을 하면 2의 보수를 얻을 수 있습니다.
쉬프트 연산자 << >>
피연산자의 각 자리(2진수로 표현했을 때)를 오른쪽 ( >> ) , 또는 왼쪽 ( << ) 으로 이동(shift) 합니다.
예를 들어 8 << 2 는 왼쪽 피연산자인 10진수 8의 2진수를 왼쪽으로 2자리 이동합니다.
이 때, 자리이동으로 저장범위를 벗어난 값들은 버려지고 빈자리는 0으로 채워집니다.
1. 10진수 8을 2진수로 변환하면
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
2. 8 << 2 는 왼쪽 피연산자인 10진수 8의 2진수를 왼쪽으로 2자리 이동하고 자리이동으로 저장범위를 벗어난 값들은 버려집니다.
0 | 0 | 1 | 0 | 0 | 0 |
3. 빈자리는 0으로 채워집니다.
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
4. 8 << 2 의 결과는 2진수로 00100000이 됩니다 ( 10진수로 32 )
<< 연산자의 경우 피연산자의 부호에 상관없이 각 자리를 왼쪽으로 이동시키며 빈칸을 0으로 채우면되지만,
>> 연산자의 경우 오른쪽으로 이동시키기 떄문에 부호있는 정수는 부호를 유지하기 위해 왼쪽 피연산자가 음수인 경우 빈자리를 1로 채웁니다. ( 양수일 땐 0 )
-8 >> 2
1 1 1 1 1 0 0 0
1 1 1 1 1 0 -8 >> 2 는 10진수로 -2가 된다.
1 1 1 1 1 1 1 0
위 표를 보면 다음과 같다는 결과를 알 수 있다.
x << n은 : x * 2^n의 결과와 같다.
x >> n은 : x / 2^n의 결과와 같다.
참고 자료
https://hongong.hanbit.co.kr/%EC%9E%90%EB%B0%94-%EA%B8%B0%EC%B4%88-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%97%B0%EC%82%B0%EC%9D%98-%EB%B0%A9%ED%96%A5%EA%B3%BC-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84/
'◼ JAVA' 카테고리의 다른 글
[Java/자바] 클래스와 객체 (1) | 2022.10.18 |
---|---|
(Java/자바) System.arraycopy()를 이용해 배열 복사 (1) | 2022.10.14 |
[Java/자바] StringBuilder 클래스란 ? (0) | 2022.10.13 |
(Java/자바) 숫자를 문자열로 변환 - toString(), valueOf() (0) | 2022.10.12 |
(Java/자바) 문자열을 정수로 변환 - parseInt(), valueOf() (0) | 2022.10.12 |