티스토리 뷰

연산자(Operators)

연산자를 이번 편에서 배우지만 이전 강좌에서 연산자를 써본 적이 있습니다.

연산자는 대입, 산술, 논리, 비트 연산자 등이 있습니다. 이와 함께 어떤 연산자가 먼저 계산되는지에 관한 우선순위에 대해 알아봅시다.

 

연산자 소개 순서는 제가 임의로 작성하였습니다. 우선순위는 아래에서 최종적으로 다루겠습니다.

시작하기 앞서 Operators.kt 파일을 만들고 여기서 진행해봅시다.

 

Operators.kt 만들기

산술 연산자 (+, -, *, /, %)

산술 연산자는 덧셈, 뺄셈, 나눗셈, 곱셈 그리고 나머지 연산(MOD)을 수행하는 연산자입니다.

간단한 예시를 보고 넘어가겠습니다.

fun main() {
    val a = 1+2
    val b = 1-2
    val c = 1*2
    val d = 1/2
    val e = 1%2

    print("1+2 = $a\n")
    print("1-2 = $b\n")
    print("1*2 = $c\n")
    print("1/2 = $d\n")
    print("1%2 = $e\n")
}
// 실행결과
// 1+2 = 3
// 1-2 = -1
// 1*2 = 2
// 1/2 = 0
// 1%2 = 1
나머지 연산은 예시와 같이 수행합니다.
일반적으로 4를 2로 나누었을 때 (4/2) 몫은 2이고 나머지는 0입니다. 이때 4 % 2는 0을 반환합니다.
3을 2로 나웠을 때 몫은 1, 나머지는 1이며 이때 3 % 2는 나머지인 1을 반환합니다.

위 연산자들은 메소드로도 사용할 수 있습니다. (메소드의 개념은 나중에 알아보고 이런 게 있다는 것만 알아둡시다.)

fun main() {
    val a = 1+2
    val b = 1-2
    val c = 1*2
    val d = 1/2
    val e = 1%2

    print("1+2 = $a\n")
    print("1-2 = $b\n")
    print("1*2 = $c\n")
    print("1/2 = $d\n")
    print("1%2 = $e\n")

    print("1 plus 2 = ${1.plus(2)}\n")
    print("1 minus 2 = ${1.minus(2)}\n")
    print("1 times 2 = ${1.times(2)}\n")
    print("1 div 2 = ${1.div(2)}\n")
    print("1 rem 2 = ${1.rem(2)}\n")
}
// 실행결과
// 1+2 = 3
// 1-2 = -1
// 1*2 = 2
// 1/2 = 0
// 1%2 = 1
// 1 plus 2 = 3
// 1 minus 2 = -1
// 1 times 2 = 2
// 1 div 2 = 0
// 1 rem 2 = 1

메소드를 사용해서 출력해도 같은 결과를 확인할 수 있습니다.

 

대입 연산자 (=)

대입 연산자(=)는 특정 변수에 값을 넣을 때(대입) 사용하는 연산자입니다.

간단하게 예시만 보고 넘어가겠습니다.

fun main() {
    var f: Int
    f = 5
    print("$f\n")
}
// 실행결과
// 5
처음부터 변수에 값을 넣지 않을 때는 자료형을 생략할 수 없습니다.

대입 연산자 =는 변수 a에 정수 5를 대입하는 역할을 수행합니다.

복합 대입 연산자 (+=, -=, *=, /=, %=), 증감 연산자(++, --)

복합 대입 연산자

복합 대입 연산자는 산술 연산자와 대입 연산자를 합친 연산자입니다.

 

A += BA = A + B와 같으며 A *= B A = A * B와 같고 나머지 역시 똑같습니다.

아래 코드를 작성하여 확인해봅시다.

fun main() {    
    var g = 5
    g += 10 // 실행되면 15
    g -= 5 // 실행되면 10
    g *= 2 // 실행되면 20
    g /= 2 // 실행되면 10
    g %= 2 // 실행되면 0

    print("변수 g의 결과는? $g\n")
}
// 실행결과
// 변수 g의 결과는? 0

증감 연산자

증감 연산자는 변수의 값을 증가하거나 (1씩 더하거나) 감소시키는 (1씩 빼는) 연산자입니다.

변수 A가 있을 때 A++는 A의 값을 먼저 반환하고 증가시키며 ++A는 먼저 값을 증가시키고 A의 값을 출력합니다. -- 연산자도 똑같습니다.

var A = 10
print("A++: ${A++}\n") // A의 값을 먼저 반환하므로 10입니다.
print("++A: ${++A}\n") // 위의 연산에 의하여 11이 되고 먼저 증가 시킨 후에 출력하므로 12입니다.
print("A--: ${A--}\n") // A의 값을 먼저 반환하고 감소되므로 출력은 12이지만 실제 값은 11입니다.
print("--A: ${--A}\n") // 먼저 감소 시키므로 10이 출력됩니다.
// 실행결과
// A++: 10
// ++A: 12
// A--: 12
// --A: 10
A++ 형태를 후위 증감 연산자, ++A를 전위 증감 연산자라고 합니다.

비교 연산자 (>, >=, <, <=, ==, !=, ===, !==)

비교 연산자는 두 변수의 대소 관계나 값, 객체를 비교할 때 쓰입니다.

비교 연산자를 포함하여 앞으로 나올 논리 연산자를 결과가 이진값(Boolean)으로 나옵니다. 즉, true 또는 false입니다.

 

연산자 설명
A > B A가 B보다 크다.
A >= B A가 B보다 크거나 같다.
A < B A가 B보다 작다.
A <= B A가 B보다 작거나 같다.
A == B A와 B의 값이 같은가?
A != B A와 B의 값이 다른가?
A === B A 객체와 B 객체가 같은가?
A !== B A 객체와 B 객체가 다른가?

=== 그리고 !==에 대하여는 나중에 자세하게 알아보겠습니다.

print("1 > 1 : ${1>1}\n")
print("1 >= 1 : ${1>=1}\n")
print("1 == 1 : ${1==1}\n")
print("1 != 1 : ${1!=1}\n")
// 실행결과
// 1 > 1 : false
// 1 >= 1 : true
// 1 == 1 : true
// 1 != 1 : false
해당 코드 작성 시 인텔리제이에서는 1>1 1>=1 등 비교 연산자 부분에 밑줄이 그어집니다.
1>1은 결국 false이고 1>=1은 결국 true이기 때문에 Alt + Space 키를 눌러 결과 값(true, false)으로 바꿀 수 있습니다.

비트 연산자

비트 연산자는 정수형에서만 사용할 수 있습니다.

비트 단위에서 비교하는 연산자입니다. (해당 연산자는 Kotlin에서 많이 쓰이질 않습니다. 개념만 알아둡시다!)

 

연산자 설명 예시 예시 결과
A and B A 그리고 B 모두다 1일 때 참 1 and 0 0
A or B A 또는 B에 1이 있으면 참 1 or 0 1
A xor B A 또는 B에 1이 홀수개이면 참 1 xor 0 1
A.inv() A의 비트를 반전 0.inv() -1
A shl B  왼쪽 시프트 연산 2 shl 2 8
A shr B 오른쪽 시프트 연산 2 shr 2 0
A ushr B 부호비트 포함 오른쪽 시프트 연산 2 ushr 2 0
시프트 연산?
시프트 연산은 비트를 왼쪽이나 오른쪽으로 옮기는 연산을 말합니다.
왼쪽 시프트 연산은 비트를 B 만큼 왼쪽으로 옮기며 오른쪽 시프트 연산은 비트를 B 만큼 오른쪽으로 옮깁니다.
일반적으로 오른쪽으로 옮겼을 때 새로 생기는 공간을 양수이면 0, 음수이면 1로 채웁니다.
단, 부호 비트 포함 오른쪽 시프트 연산(unsigned shift right)을 사용하면 옮겼을 때 생기는 공간을 무조건 0으로 채웁니다.
왼쪽 시프트 연산은 A에 2의 B승을 곱하며, 오른쪽 시프트 연산은 A에 2의 B승을 나눕니다.
일반적으로 비트 연산자는 표 순서대로 &, |, ^, ~, <<, >>, >>>로 사용합니다.
Kotlin에서는 연산자가 컴파일러에서 최종적으로 메소드 형태로 바뀌며 위 특수기호를 사용하는 비트 연산자는 Kotlin에서 사용할 수 없습니다. 또한 A and B 말고 A.and(B)형태로 사용 가능합니다. (전자가 권장하는 방법입니다.)

위 표를 Kotlin으로 작성해보면,

print("1 & 0 : ${1.and(0)}\n")
print("1 | 0 : ${1.or(0)}\n")
print("1 ^ 0 : ${1.xor(0)}\n")
print("~1 : ${0.inv()}\n")
print("2 << 2 : ${2.shl(2)}\n")
print("2 >> 2 : ${2.shr(2)}\n")
print("2 >>> 2 : ${2.ushr(2)}\n")
// 실행결과
// 1 & 0 : 0
// 1 | 0 : 1
// 1 ^ 0 : 1
// ~1 : -1
// 2 << 2 : 8
// 2 >> 2 : 0
// 2 >>> 2 : 0

논리 연산자 (&&, ||, !)

마지막으로 논리 연산자입니다.

비트 연산자가 비트의 논리에 대해 다뤘다면 논리 연산자는 논리식에 대한 참, 거짓을 다룹니다.

print("true && false : ${true && false}\n")
print("true || false : ${true || false}\n")
print("true && !false : ${true && !false}\n")
// 실행결과
// true && false : false
// true || false : true
// true && !false : true

각각 AND, OR, NOT 연산자이며 NOT 연산자는 true는 false로 false는 true로 바꿉니다.

따라서 마지막 실행 결과는 false의 부정이므로 true && true의 연산 결과가 나오게 됩니다.

우선순위

연산자마다 먼저 실행되는 순서가 있습니다. 연산자 여러 개가 쓰인 경우 이 순서를 따라 연산됩니다.

 

이를 표로 정리해봤습니다.

(메소드로 사용되는 것들은 우선순위가 적용되지 않으므로 제외되어 있습니다.)

우선순위 연산자
1 ++(후위), --(후위), ., ?., ?
2 -, +, ++(전위), --(전위), !, 그 외(label)
3 :, as, as? (자료형을 바꿀 때 쓰는 연산자입니다.)
4 *, /, %
5 +, -
6 .. (범위를 나타내는 연산자입니다.)
7 simpleIdentifier (자세히보기)
8 ?:
9 in, !in, is, !is (각각 범위와 타입 체크를 위해 쓰입니다.)
10 <, <=, >, >=
11 ==, !==
12 &&
13 ||
14 =, +=, -=, *=, /=, %=

 

마무리

Kotlin은 Java 하고 다르게 모든 연산자는 최종적으로 .plus() .and()와 같은 메소드 형태로 변환됩니다.

아래에 이러한 메소드 종류가 담긴 사이트 링크를 올려드리겠습니다.

 

감사합니다 :D

 

 

Operator overloading: https://kotlinlang.org/docs/reference/operator-overloading.html

 

수정 19-05-29) 비트연산자 설명 추가, A.and(B) 에서 A and B 형태로 변경

 

댓글
댓글쓰기 폼