상세 컨텐츠

본문 제목

2. 자료형 보다 기본! Java의 연산자

How To Java/Java Tutorial

by 카페코더 2020. 2. 19. 18:27

본문

반응형

취업 준비를 하며 복습한다는 마음으로, 이것을 보는 누군가에게 도움이 되었으면 하는 마음으로
Java-Tutoral을 작성해 봅니다. 입문서와 순서가 잘못되었을 수 있고, 제가 아는 정보가 틀렸을 수 있습니다.
이 글에 대한 잘못된 정보나, 오탈자 등 수정해야 할 항목 혹은 추가해야 할 항목은 댓글로 알려주시면 감사하겠습니다.

이 자료가 올라가는 저장소 :
https://github.com/hwk0911/Java-tutorial

 

hwk0911/Java-tutorial

Java tutorial. Contribute to hwk0911/Java-tutorial development by creating an account on GitHub.

github.com

Java의 연산자에 대해 알아본다.

정말 단순하다. 정말 쉽다. 하지만 모르면 아무것도 못한다. 그만큼 중요하다.
1. Java의 자료형을 시작하며 "기초를 쌓지 않은 프로그래머는 소금과 모래로 된 기둥 위에 지어진 성과 같다." 고 했다.
이걸 모른 채 시작한다면, 기둥 자체가 없다.

1. Java의 연산자는 크게 4가지로 분류한다.

  1. 최우선 연산자
  2. 단항 연산자
    1. 증감 연산자
  3. 이항 연산자
    1. 산술 연산자
    2. 비교 연산자
    3. 비트 연산자
    4. 논리 연산자
    5. 대입 연산자
  4. 삼항 연산자

1.1 연산의 우선순위

우리는 초등학교 4학년쯤 사칙연산에 대해 배웠고, 곱셈과 나눗셈을 우선 계산하되, 괄호를 먼저
처리한다 배웠다. 컴퓨터 연산도 결국 수학과 일맥상통한다 생각한다. 컴퓨터도 연산의 우선순위가 있다.

최우선 연산자 > 단항 연산자 > 산술 연산자 > 비교 연산자 > 비트 연산자 > 논리 연산자 >
삼항 연산자 > 대입 연산자 순으로 처리한다.

1.2 최우선 연산자

최우선 연산자. 이름만 들었을 때는 와.. 뭐지 진짜 어려울 것 같은데..라고 생각할 수 있다.
이상하게 수학이든 컴퓨터든 공학 쪽은 이름이 상당히 거창한 친구들이 많더라.

최우선 연산자란 말 그대로 우선적으로 처리되는 연산자를 말한다.
대표적으로 우리 모두 초등학생 시절 사용해본 괄호 친구들이 여기에 해당된다.

연산자의 우선순위가 지정되어있지 않다면, 2 + 2 * 2 = 6 or 8로 의견이 나뉠 것이다.

두뇌 풀 가동!

 

최우선 연산자 . 멤버 참조 연산자
[] 첨자 연산자
() 우선순위 연산자 (추정)
  1. 멤버 참조 연산자 : 클래스 내의 멤버를 참조하는 연산자다. (  ex : String.length()  )
  2. 첨자 연산자 : 주로 배열의 특정 인덱스를 참조할 때 사용한다.
  3. 우선순위 연산자 (추정) : 도저히 구글링해도 이름을 못찾겠더라. 연산의 우선순위를 지정하는 연산자다.

1.3 단항 연산자

피연산자가 하나인 연산자이다.
피연산자, 연산자 이 둘이 헷갈릴 수 있어서 또 그림을 하나 준비해 왔다.

계산식 용어 정리

대입 연산자가 다른 연산자들에 비해 크게 표현이 되었는데, 단순히 내용이 길어서 커진 것이다.
더 중요하거나 하지 않다.

위 그림을 보면 피연산자가 두개인데, 이것을 이항 연산이라 한다. 다항 연산자 파트지만, 용어 정리를 위해 사용했다.

단항 연산자는 증감 연산자, 부정 연산자, 1의 보수 연산자 가 있다.

단항 연산자 ++ 증가 연산자
-- 감소 연산자
! 부정 연산자
~ 1의 보수 연산자
  1. 증감 연산자 : ++, -- 두 연산자를 합쳐 증감 연산자라 부른다. 이것은 세부 파트로 자세히 다루겠다.
  2. 부정 연산자 : true, false 를 반전시키는 연산자다.
  3. 1의 보수 연산자 : 피연산자의 1의 보수를 반환하는 연산자다.

1.3.1 증감 연산자

증감 연산자는 주관적으로 중요한 부분이라 생각되어 세부 파트로 나눴다.
이것은 최적화 문제에도 직결된다!

증감 연산자는 크게 두가지로 나뉜다. 증가 감소가 아닌 전위, 후위로 나뉜다.

1.3.1.1 전위 증감 연산자

전위 증감 연산자는 실행문에서 값이 먼저 증가 또는 감소하여 반환된다.

public class operator {
    public static void main(String[] args) {
        int a = 1;
        int b = ++a;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
/*
결과 :
a = 2
b = 2

Process finished with exit code 0
 */

코드를 순차적으로 살펴보면 다음과 같다.

  1. int 형 변수 a를 1로 초기화 하여 선언한다.
  2. a를 1만큼 증가시킨다. (a = a + 1)
  3. int 형 변수 b를 a의 값으로 초기화 하여 선언한다.
  4. a, b 출력

"++a"을 실행문으로 표현하면 다음과 같다.

public class operator {
    static int a = 1;
    static int b;

    public static int increaseData(){
        a = a + 1;
        return a;
    }

    public static void main(String[] args) {
        b = increaseData();

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
/*
결과 :
a = 2
b = 2

Process finished with exit code 0
 */

전위 증감 연산자의 경우 변수 자체의 값을 1증가 또는 감소하여 반환한다.

1.3.1.2 후위 증감 연산자

후위 증감 연산자는 실행문에서 값이 나중에 증가 또는 감소해서 반한된다.

public class operator {
    public static void main(String[] args) {
        int a = 1;
        int b = a++;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
/*
결과 :
a = 2
b = 1

Process finished with exit code 0
 */

코드를 순차적으로 살펴보면 다음과 같다.

  1. int 형 변수 a를 1로 초기화 하여 선언한다.
  2. int 형 상수 temp를 a의 값으로 초기화 하여 선언한다.
  3. a를 1만큼 증가시킨다. (a = a + 1)
  4. temp를 반환한 값으로 int 형 변수 b를 초기화 하여 선언한다.
  5. a, b 출력

위와 마찬가지로 a가 증가하지만, int 형 상수 temp 에 먼저 a의 값이 저장된 후 증가해 b는 1로 초기화가 된 것이다.

"a++"을 실행문으로 표현하면 다음과 같다.

public class operator {
    static int a = 1;
    static int b;

    public static int increaseData(){
        final int temp = a;
        a = a + 1;
        return temp;
    }

    public static void main(String[] args) {
        b = increaseData();

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
/*
결과 :
a = 1

Process finished with exit code 0
 */​

후위 증감 연산자는 다른 상수에 현재 변수 값을 저장하고, 변수 값을 1 증가 or 감소하여
상수에 저장 된 값을 반환한다.

1.3.1.3 증감 연산자 마무리

대부분의 컴파일러 에서는 전위, 후위 에 대한 자체 최적화를 진행한다.
그래서 코드 실행에 차이가 없을 수 있다. 하지만, 연산자 오버로딩으로 증감 연산자를 만들어 사용하는 경우
후위 증감 연산자는 클래스를 복사하여 사용되므로, 성능이 전위 증감 연산자에 비해 떨어지게 된다.

의문이 생길 수 있다. 고작 한줄의 코드에 무슨 큰 차이가 있겠느냐 하겠지만, 우리가 대부분 증감 연산자를 사용하는
경우를 한번 생각해보자. 주로 반복문에 사용되었다 (물론 사람마다 차이가 있을 수 있음).

반복문의 경우 0 ~ n 회 반복하는데, 만약 1억번 반복한다면 의미없는 1억번의 연산이 낭비된다.
따라서 가능하면 전위 연산자를 사용하여 성능상 이득을 챙기자.

1.4 이항 연산자

단항 연산자가 하나의 피연산자를 사용하는 연산자라면, 이항 연산자는 말 두개의 피연산자를 사용한다.

산술 연산자, 비교 연산자, 비트 연산자, 논리 연산자, 대입 연산자 가 여기에 해당된다.

산술 연산자 * 곱셈 연산자
/ 나눗셈 연산자
% 나머지 연산자
+ 덧셈 연산자
- 뺄셈 연산자
시프트 연산자 << X X칸 만큼 비트 좌측으로 이동
>> X X칸 만큼 비트 우측으로 이동
비교 연산자 > X X 초과 true 반환
X 이하 false 반환
< X X 미만 true 반환
X 이상 false 반환
>= X X 이상 true 반환
X 미만 false 반환
<= X X 이하 true 반환
X 초과 false 반환
== X X와 같을 때 true 반환
X와 다를 때 false 반환
!= X X와 다를 때 true 반환
X와 같을 때 false 반환
비트 연산자 & AND 연산자
| OR 연산자
~ (단항 연산자) 1의 보수 연산자
논리 연산자 X && Y X와 Y모두 참일경우 true 반환
그 외 false 반환
X || Y X나 Y중 하나라도 참일경우 true 반환
그 외 false 반환
! (단항 연산자) true, false 반전 연산자
대입 연산자 = X X 를 대입하는 연산자
*= X X를 곱한 값을 대입하는 연산자
/= X X로 나눈 몫을 대입하는 연산자
%= X X로 나눈 나머지를 대입하는 연산자
+= X X를 더한 값을 대입하는 연산자
-= X X를 뺀 값을 대입하는 연산자

연산자의 대부분이 이항 연산자에 해당되어 분류를 각 파트로 나누어 표를 그렸다.
~, ! 연산자의 경우 단항 연산자에 해당하지만, 분류에 포함되어 같이 적었다.

  1. 산술 연산자
    1. *, /, %, +, - (basic operator) : 단순한 사칙연산에 나머지를 구하는 연산이 추가되어 있다.
    2. 시프트 연산자 (shift operator) : 비트를 지정된 수 만큼 좌측, 우측으로 이동한다.
  2. 비교 연산자
    1. >, <, >=, <=, ==, != (inequality operator) : 부등호 연산자.

      추가로, >=, <= 의 순서를 잘 못외우는 경우가 있다. 사실 내 얘기다. =< ???? =< ??
      저런식으로 순서가 헷갈렸다. 그래서 외우는 방법을 생각한 결과 다음이 가장 편했다.

      >= : 작거나 같다. < (작거나) = (같다)
      <= : 크거나 같다. > (크거나) = (같다)
  3. 비트 연산자
    1. & (AND operator) : AND 연산자이다. 피연산자들의 비트를 비교하여 AND 연산을 진행한다.

      int a = 6, b = 10 으로 선언하였을때, a & b = 2가 된다.

a 0 1 1 0 6
b 1 0 1 0 10
result 0 0 1 0 2

        2. | (OR operator) : OR 연산자이다. 피연산자들의 비트를 비교하여 OR 연산을 진행한다.
           
           int a = 6, b = 10 으로 선언하였을때, a | b = 14가 된다.

a 0 1 1 0 6
b 1 0 1 0 10
result 1 1 1 0 14

        3. ~ (ones' complement operator) : 1의 보수 연산자이다. 피연산자의 비트를 1의 보수로 변환한다.

           int a = 6 으로 선언하였을때, ~a = -7 이 된다.

a 0 1 1 0 6
result 1 0 0 1 -7

           표에서 보면 result = 9가 아니냐 할 수 있지만, 비트를 모두 표현하면 다음과 같다.
           a       = 0000 0000 0000 0000 0000 0000 0000 0110
           result = 1111 1111 1111 1111 1111 1111 1111 1001

           따라서 result = -7이 된다.

  4. 논리 연산자
        1. && (and operator) : 비트 연산의 AND와 혼동하면 안된다. 그리고의 의미와 같다.
        2. || (or operator) : 비트 연산의 OR와 혼동하면 안된다. 또는의 의미와 같다.
        3. ! (not operator) : true, false 를 반전시킨다.

  5. 대입 연산자
        1. = (assignment operator) : 우측의 피연산자를 좌측의 피연산자에 대입한다.
        2. *=, /=, %=, +=, -= : 우측의 피연산자를 좌측의 피연산자에 추가 연산하여 대입한다.

1.5 삼항 연산자

처음 삼항연산자가 뭔지 모르고 선배님의 코드를 한번 본 적 있었는데, 물음표가 들어가고 처음보는 코드가 있어서
구글에 한참 물음표 연산자 라고 검색했던 기억이 있다.

역시 구글

그런데 나같은 사람이 꽤 많았던 것 같다. ㅋㅋㅋ

삼항 연산자. 즉 피 연산자가 세개인 연산자다.
정확히 말하면, 조건식, 피연산자1, 피연산자2 로 이뤄져 있다.

잘 쓰면 몇줄의 코드를 단 한줄로 바꿀 수 있지만, 남용하면 코드가 상당히 더러워진다. 가독성이 떨어진다.
처음 삼항 연산자를 배우고, 쓰지 않아도 될 상황에 써서 한동안 코드가 꽤 더러웠다.

삼항 연산자의 기본 구조

삼항 연산자

겉은 복잡한데 속은 간단하다. (겉복속간)
시작은 조건문에서 부터 시작한다.
조건문 (ex : a == b)이 true 일 경우 피연산자1을 반환, false 일 경우 피연산자2를 반환한다.

코드로 한번 살펴보자.

public class operator {
    public static void main(String[] args) {
        int a = 5;
        int b = 7;
        int c;

        c = (a == b) ? 1 : 0;

        System.out.println("c = " + c);
    }
}
/*
결과 :
c = 0

Process finished with exit code 0
 */

a 를 5로 초기화 하여 선언하였고, b를 7로 초기화 하여 선언하였다. 마지막으로 c를 초기화 없이 선언하였다.

위 기본구조 다이어그램에 대입하면

  1. 조건식 : (a == b)
  2. 피연산자1 : (1)
  3. 피연산자2 : (0)

조건식 (a == b) 가 거짓이므로, 1이 아닌 0이 반환되어 c가 초기화 되었다.

피연산자1, 2 는 주로 값이 오지만, 필요에 따라 연산식을 넣을 수 있다.
결국 프로그래밍은 누가 얼마나 더 응용을 잘 하나의 차이인 것 같다.

 

 

이렇게 Java Tutorials의 2장이 끝이 났다!
3장은 조건문, 반복문에 대해 다뤄보겠다.

반응형

관련글 더보기

GitHub 댓글

댓글 영역