연산자

반응형
반응형

 산술 연산자

산술이란것은 뭘까? 

 

 

이라고 한다. 즉, +,-,*,/,%이 존재한다. 이들의 가장 큰 특징은 두 개의 변수 사이에 존재한다는 것이 특징인데 우리가 아는 사칙연산과 굉장히 유사 아니 똑같다.

사용 방법은 간단하다. 

c = a + b;

이런식으로 작성된다. 주의해야 될 점은 선언과 동시에 사칙연산을 하면 안된다. 
하지만 계산 된 결과 값을 선언값으로 사용할때는 선언과 동시에 해도 상관없다.

c = int a + int b; (X)

 

int c = a + b; (O)

예제에서는 +만 사용했지만 다른 연산들도 마찬가지다. 그런데 산술연산자는 변수도 아니고 객체도 아니다. 이것을 사용하러면 변수 2개가 존재해야하는데... 실제로는 어떻게 작성이 되어질까?

바이너리 코드로 만들어서 확인해보자.

 

 

line 4에 2가 추가 된것말고는 잘 모르겠다. 
위 식의 코드는 

int a = 2 + 3;

으로 하였다.

3가지 정도 생각해 봤다.

1. 서로 다른 자료형이지만 비슷한 역할을 하는 자료형을 가진 변수 두개를 연산한다면? 
자료형은 어떻게 리턴 될까? (int vs long)

2. 서로 다른 자료형이고, 다른 역할을 하는 자료형을 가진 변수 두개를 연산한다면? 
(double vs int)

3. 같은 자료형일때, 연산하는 순간 범위를 넘어선다면 어떻게 될까?

인텔리제이가 켜지기 전에 예상해보자.

1번 같은 경우는 더 큰 자료형이 이길 것 같구, 2번은 실수로 변할 것 같구, 3번은 자료형이 바뀔 것 같다. 
실제로도 그러는지 확인해 보자.

int a = 2;
long b = 3;
long c = a + b;

int a = 2;
double b = 3.0;
double c = a + b;

1번과 2번은 예상한대로 흘러갔지만, 3번은 아니였다. 오버플로우가 발생하여 범위를 넘어서게 되었다.
여기서 알 수 있는 사실은 정해진 자료형은 자바 프로그래밍이 알아서 변경되지 않는다는 것을 알 수 있다.

다른 연산들은 아래처럼 사용된다.

c = a + b;
c = a - b;
c = a * b;
c = a / b;
c = a % b;

나머지는 기존 사칙연산에 포함되는 연산이지만 %는 포함되지 않는다.
%는 나머지를 구할때 사용된다.
몫을 구할때는 /를 사용하면 된다.(다만, 자료형을 실수형으로 둘시 몫만 나오지 않는다)

신경 써야 되는 부분이 있다면?
바로 0이다. 애초에 0으로는 나눌 수 없기 때문이다.(굳이 따진다면 무한대가 나온다.)

비트 연산자

공부하기에 앞서 비트 연산자가 무엇인지 생각해보자.
아무래도 비트라고 작성되어 있으니까 비트를 가지고 사용하는게 아닐까 추측한다. 

더보기

컴퓨터 시스템은 크게 hardware  software 두 부분으로 구성된다.

컴퓨터가 다루는 모든 정보는 컴퓨터 하드웨어의 메모리에 이진수(binary digit; BIT) 형태로 저장된다. 하나의 bit는 ON/OFF, TRUE/FALSE 또는 1/0과 같은 2가지 상태만 표현할 수 있다. Bit 8개를 한 묶음으로 처리하면 2의 8승, 총 256가지의 상태를 표현할 수 있다. 이러한 bit 8개의 묶음을 BYTE라 한다. Byte가 다시 묶여서 word, double word와 같은 보다 큰 정보 저장 체계를 구성한다.

1/0과 같은 두가지 상태에 관한 연산 처리(AND, OR, XOR, NOT)를 부울대수(Boolean algebra)라 한다.

nlp.kookmin.ac.kr/sskang/JOC/Chapters/cprog/basic.htm

참고로 int는 8비트를 가지고 있다. 또한 비트는 이진수로 되어있기 때문에 아래 숫자는 2진수다. 이것을 십진수로 바꾼다면 16 + 8 + 4 + 2 + 1 => 31 이된다. 

 

10진수로 31

 

비트 연산자의 종류는 &,|,^,~,<<,>>,>>> 가 존재한다.

산술연산과 달리 이 연산자는 생소할수 있다고 생각한다.

1. & : and와 같다. 이 연산을 하기 위해서는 비트한개가 더 필요하다. 

 

10진수로 31
10진수로 27

 

이 두 개를 더 하자. 산술 연산과 다른점은 더한다고 값이 증가되는 형태는 아니다.

이것을 벤다이어 그램으로 그려보면

 

 

이렇게 나온다.

즉, 두 개 모두 같아야 된다는 뜻이다. 그렇다면 무엇이 같아야 할까? 아니 어떻게 같아야 할까? 두개 식 모두 1이면 된다. 

표를 살펴 보자.

111
100
010
000

그러면 이제 계산해보자.

그러면 

 

10진수로 27

 

이렇게 나오지 않을까 추측해본다. 

 

 

이제 빠르게!

| : or 이라고 부른다. 둘중 하나라도 1이 존재한다면 1을 리턴한다.

 

10진수로 31
10진수로 27
10진수로 31

 

111
101
011
000

 

^ : xor연산으로 부르며, 상호배타적인 관계라고 불린다. 두개가 서로 다를때 1를 리턴한다.

 

10진수로 31
10진수로 27
4

 

110
101
011
000

~ : not연산이랑 같으며, 1을 0으로 0을 1로 바꾸는 연산이다.

 

10진수로 31
0

 

근데 과연 0이 나올까? 사실 0 0 0 1 1 1 1 1이라는 사실을 알아야 한다.

정답은 

 

?????

 

근데 뭔가 이상하다.  정답은 -32인데... 이진수에는 음수가 없을 텐데... 음수를 어떻게 표현할 것일까?
사실 맨 앞은 부호 값이다. 예를 들면, 1이면 음수 0이면 양수 이런 식이다.

이것을 이해하기 위해서는 1의 보수, 2의 보수를 이해 해야한다.

1의 보수와 2의 보수를 이해하자!

● 정수 표현 컴퓨터는 N개의 비트를 이용해 2^N개의 정수만 표현할 수 있습니다. 이러한 방식을 이용해서 수를 표현해야 하기 때문에 쉽지 않습니다. 또한 정수는 음의 정수와 양의 정수로 나누

ndb796.tistory.com

자 그러면 다시 해보자.
인텔리제이로 실행한 결과

11111111 11111111 11111111 11100000

라고 나온다.
이는 int가 4byte로 구성이 되있고 1byte는 8bit로 구성되었기 때문이다.
뒷자리만 계산하면 128+64+32 = 224가 나온다. 그리고 앞자리는 부호 비트라 불린다. 여기에 1이 존재하면 -을 뜻하고 0이면 +을 뜻하게 된다.

[알고리즘] java 비트연산 정리하기

기초개념인 java 비트연산을 정리해보도록 하겠습니다. 비트연산은 2개의 이진수에 대해서 연산하는 것을 말합니다. 컴퓨터는 이진수로 대화를 하고 있기 때문에 이 비트연산을 알아두는 것이

vmpo.tistory.com

 

<< : 비트를 왼쪽으로 n칸 움직이는것을 뜻하며 *2^n와 같은 결과를 리턴한다.

 

10진수로 31
62

 

>> : 비트를 오른쪽으로 n칸 움직이는것을 뜻하며 /2^n와 같은 결과를 리턴한다.

 

10진수로 31
15

 

>>> : 음수를 고려하지 않고, 양수만 고려한다는 뜻이다.

11111111111111111111111111100001 : -31

여기에서 >>를 사용하면 -15가 나온다. 하지만 >>>를 사용하게 되면 이야기가 달라진다.

01111111 11111111 11111111 11110000 : 2147483632

>>도 함께 호출해보자.

11111111 11111111 11111111 11110000 : -16

맨 앞을 유심히 살펴보면 다르다는것을 확인 할 수 있다.

 

관계 연산자

관계 연산자는 다른 말로 '비교' 연산자라고 부른다.
<,><= ,>=, ==, != 가 존재한다. 그리고 이들은 boolean 즉, true/false를 리턴한다.

사용 방법은 다음과 같다.

변수1 = 3, 변수2 = 4

변수1 < 변수2;

즉, 위 코드는 변수2가 더 크다는 뜻이 된다.

그런데 위 식은 다음처럼 작성해도 같은 결과가 출력된다.

변수2 > 변수1;

위치만 바꿨을 뿐인데, 같은 결과가 나온다. 그렇다면 어떤식으로 작성이 되는게 좋을까? 
정확한 출처는 기억이 나지는 않지만, 모든 조건문은 긍정적으로 끝나는게 좋다는 말을 들은 적이 있던것 같다. 이것 자체로는 조건문은 아니지만, 조건문에 포함되기 때문에 긍정적인 결과가 나오게 하는것이 좋다고 생각한다. 

그렇다면 >, >= 는 될 수 있으면 지양하고, < , <= 는 될 수 있으면 지향하는게 좋다고 생각한다.
왜냐하면 '크다'라는 표현이 '작다'라고 표현하는 것보다 긍정적이라고 생각하기 때문이다. 

!= 같은 경우도 마찬가지만, ==로 바꾸게 되면 쓸데없이 길어질 수도 있기 때문에 !=를 사용하는것이 좋다.(짧은게 좋으니까) >,>=같은 경우도 <, <=로 바꿀려고 할때, 길어진다면 그냥 >,>= 로 사용하는것이 좋은 판단이 아닐까?

논리 연산자

논리? 

 

 

즉, 참과 거짓을 뜻한다. 비트연산자에서 설명했던 용어?와 유사하다. 다른점이라면, 비트에 사용이 되냐, 아니면 논리값에 사용이 되냐의 차이다.

논리 연산에는 &&, || , !가 존재한다. 간단하게 설명하고 넘어가자. 
&& => and, || => or, ! => not
놀랍게도 이 3가지 연산으로 모든것을 표현이 가능하다. 
그렇다면, 논리 연산자는 어떻게 사용하는게 좋을까?

바로 shortcut연산을 해야된다. shortcut이란 &&와 ||을 보고 두 번째 값을 볼지 결정하는 행위다.

A = true이고 B = false 일때 ||을 사용한다고 가정하자.

그렇다면 어떻게 구해야할까? A || B 라고 하는게 좋을까? 아니면 B || A 라고 하는게 좋을까? 
||의 특징상 맨 앞이 true라면, 뒤는 볼 필요가 없다. 왜냐하면 false인지 true인지 여부는 중요하지 않다. 어차피

가장 처음이 true인 순간인것 부터 이 식은 true이기 때문이다.

&&도 존재할까? 한번 해보자.

A && B 가 좋을까? B && A가 좋을까? &&는 두개다 true여야 된다 그렇기 때문에 앞에 false를 두는 것이 더 유리하다. 왜나하면 앞이 false인 순간인 것 부터 뒤는 볼 필요없이 false이기 때문이다.

위에서 말했듯이 부정으로 끝내는 것 보다 긍정으로 끝내는게 좋다고 생각한다. 따라서 false으로 리턴이 된다면 한번은 고민해봐야될 듯 싶다.

예를 들어, !(B && A) 로 한다면 긍정이 된다. 하지만 굳이 사용해야 좋을까? 한번  쯤은 생각해봐야 할것 같다.

instanceof

이 연산자는 형 변환이 가능한지 여부를 확인할 때 사용한다. 주로 부모 타입인지 자식 타입인지 확인할 때 사용된다.

자바(Java) instanceof 사용방법

instanceof는 객체타입을 확인하는데 사용한다. 속성은 연산자이고 형변환이 가능한 지 해당 여부를 true 또는 false로 가르쳐준다. 객체 타입이라 하니 어려운 개념 같은데, 주로 부모 객체인지 자식

improver.tistory.com

사용 방법은 자식 인스턴스(객체) instance of 부모(클래스) 로 작성이 되며 A가 부모로 세팅하고 B를 자식으로 세팅한다.
이것은 부모의 인스턴스는 자식이냐 라고 해석된다.

class A {}
class B extends A {}

가 존재한다고 가정하자.

그러면 B의 부모는 A가 된다. 그러면 B instanceof A라고 작성하면 될까?
위에서 말했듯이 자식은 인스턴스로 만들어?줘야한다. 즉, heap메모리를 사용된다는 뜻이다.

B b = new B();

 이제 인스턴스를 만들었다.
이제 instancsof를 사용할 수 있게 되었다. b instanceof A , 근데 어째서 앞은 인스턴스로 사용되는데 뒤는 인스턴스로 작성되지 않을까? b instanceof b로 작성하면 안되는 걸까? 결과적으로는 안되지만... 여기서 알 수 있는 사실은 자식은 여러개 생성이 되지만, 부모는 딱 하나만 존재한다는 사실을 알 수 있다. 물론, 부모의 부모의 부모의 부모의 부모의 부모는 존재 할 수 있다. 

참고로 모든 객체의 어머니는 Object이다. 그렇기 때문에 b instanceof Object라고 해도 맞을 것 같다.

assignment(=) operator

할당 연산자로 불리며 산술 연산자, 비트 연산자등에서 사용된다. 이들의 특징은 boolean으로 리턴이 안 된다는 점이다. 산술을 많이 해도 true가 나오지는 않는다. 비트도 마찬가지다. 이러한 상황에서 모두 사용이 가능하다.

사용 방법을 살펴 보자.

a += 2;

이런식으로 산술 혹은 비트 연산자 뒤에 = 을 추가한다. 그렇다면 위 식은 어떻게 동작이 되는걸까?
보통 = 이먼저 나오는데, 이거는 +가 먼저 나온다. 뭔가 이상하다.

이것을 풀어서 다시 작성해보자.

a = a + 2;

위 식과 같은 결과가 나온다.

즉, 자기자신과 2를 더해서 자기자신에 초기화 시키는 식이 된다. 여기서 주목해야하는 부분은 자기자신이라는 부분이다. 중복 되었다. 결국, 중복이라는 단어를 제거?하기 위해 이 방법을 사용한다. 

비트연산자도 같은 방식으로 사용된다.

C 언어 코딩 도장: 23.4 비트 연산 후 할당하기

이번에는 비트 연산자와 할당 연산자를 함께 사용해보겠습니다. a &= b a |= b a ^= b a <<= b a >>= b bitwise_asign.c #include int main() { unsigned char num1 = 4; // 4: 0000 0100 unsigned char num2 = 4; // 4: 0000 0100 unsigned char n

dojang.io

(+추가) 증감 연산자가 여기에 포함이 되는지는 잘 모르겠지만, 설명하겠다.
증감연산자에는 ++ 와 --가 있다. 또 이들은 위치에 따라 전위와 후위로 나눠진다.

a++를 풀어쓰면 a += 1 와 같고,  a = a + 1와 같다.

그렇다면 왜 전위와 후위로 나눠 질까?

int a = 5;
a++;
a ? 6 // 없는 문법입니다.
int a = 5;
++a;
a ? 6 // 없는 문법입니다.

이렇게 보면 전위와 후위를 사용하는것이 의미가 없는 것 같다. 하지만 언제 할당이 되는지에 따라 값이 달라진다. 위 예제에서는 단순히 더하기 때문에 이러한 결과가 발생된다.

쉽게 설명하면 +를 먼저하냐 하니면 연산을 먼저 하냐의 차이다.

다시 코드를 작성해 보자.

int a = 5;
b = (a++) + 3;

a ? 6 
b ? 8 // 없는 문법입니다.
int a = 5;
b = (++a) + 3;

a ? 6 
b ? 9 // 없는 문법입니다.

연산을 먼저 한다의 뜻은 증감을 하지 않고 산술이나 비트 같은 연산을 먼저 한다는 의미다. 
답은 이렇게 달라 졌다. 그렇다면 전위를 사용하는게 좋을까? 후위를 사용하게 좋을까?

정확한 답은 잘 모르겠지만, 나 같은 경우에는 후위를 더 많이 사용한다. 왜냐하면 후위가 더 가독성이 더 좋다고 생각하기 때문이다. (알고리즘 대회에서는 전위를 많이 사용하는 것 같다. 알고리즘 문제 해결 전략같은 책을 보면 전위를 사용했기 때문... ) 

스터디에서 공부하다 들은 이야기인데 증감 연산자는 될 수 있으면 사용하지 말고 풀어서 사용하는 것이 가독성 측면에서 더 좋다고 하는데 나는 잘 모르겠다. 

화살표(->) 연산자

화살표 연산자는 익명 메소드의 매개변수와 리턴변수를 통해 만들어 진다. 더 정확히 말하자면 익명 메소드가 아니라 람다를 통해 만들어진다. 그럼에도 익명 메소드라고 말한 이유는 람다가 익명 메소드로 만들어졌기 때문이다. 자세한 내용은 람다를 공부하면서 작성할 예정이기 때문에 지금은 람다는 이쁜 익명 메소드라고 생각해도 좋다.

가장 대표적인 익명 메소드로는 Runnable이 있다. runnable에서 하는 역할은 스레드와 관련이 있다. 이는 스레드를 학습하면서 작성될예정이다. 지금은 runnable은 스레드와 관련이 되있다고 생각하면 된다.

Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.print("Run method");
        }
};

이렇게 생긴 메소드가 있다고 가정하자. 지금까지 new XXX();이런식으로 끝맺음이 되있었다. 하지만 ; 가 아닌 {}로 표현되고 있다. 이는 무언가를 추가해야한다는 뜻이된다. 왜냐하면 runnable이라는 클래스는 추상 클래스이기 때문이다. 즉 이 말은 어딘가에 구체화를 시켜야 된다는 의미다. 이 또한 클래스에서 설명될것 같다. 지금은 추상 클래스는 어딘가에서 구체화를 시켜줘야된다는 정도만 기억하자.

아무튼 익명 메소드는 이런식으로 호출이 된다. 내 기억이 맞다면 이 방식은 자바8부터 도입된 방식으로 알고 있다.  그 전까지는 위 처럼 익명 메소드로 만들던가 아니면 클래스를 새로 만드는 수 밖에 없었을 것 이다.

어떻게 하면 여기에서 더 줄일 수 있을까? 

제일 먼저 해야되는 건 어디서 중복이 될지 생각해야한다. 당연히 @Override에 존재하는 모든 메소드가 중복이 될것이다. 그다음에는 의미가 있는 것을 찾아야된다. 의미가 없는건 public같은 범위고, 두 번째는 메소드명이다. 이들은 의미가 없다. 왜냐하면 이들이 변경되어도 이 메소드의 역할이 틀려지지 않기 때문이다. 그렇다고 이들이 중요하지 않는다는 이야기는 아니다. 

그렇다면 의미가 있는 건 무엇일까 바로 매개변수와 리턴 값이다. 이들만 알아도 대충 메소드를 만들 수 있기 때문이다.

위 코드를 보면 메개변수는 없고, 리턴 값은 void로 측정되어있다.

그러면 어떻게 바뀔까?

Runnable r = () -> System.out.print("Run method");

 이런식으로 바뀐다. 즉, 화살표 연산자는 익명메소드를 보다 깔끔하게 작성되기 위해 만들어진 방식인거라는 걸 알 수 있다. 

3항 연산자

3항 연산자는

(조건식)? true : false

이렇게 작성된다. 이 연산자의 가장 큰 특징은 조건식에 의해 동작한다.
위 식을 풀어서 해석하면, 조건식이 맞으면 true이 리턴되고, 틀리면 false가 리턴되는 방식이다. 
이렇게 보면 무조건 boolean형으로 리턴된다고 착각할 수 있지만,

리턴되는 것이 무엇이냐에 따라 답이 달라질 수 있다. 즉, 3항연산자만 작성한다면, compile에러가 발생하게 되는것이 긍그 이유다. (왜냐하면 어떤 자료형으로 리턴 되는지 모르기 때문이다.)

만약에, 어떠한 조건식이 만족한다면 true일때는 정수를 리턴하고 false일때는 문자열을 리턴을 해야한다고 가정하자. 
한 문장으로 작성하는 것은 불가능해 보인다.
왜냐하면 자바는 정적 타입 언어이기 때문이다.  var을 이용하면 해결 할 수 있다.

var test = (n == 10) ? 10 : "십이 아닙니다.";

var은 자료형이 어떤것인지 동적으로 할당되는 것을 말한다. 자세히 알고 싶은 분들은
이 글의 가장 맨 마지막을 참고하면 자세히 알 수 있다. 

자바 데이터 타입, 변수 그리고 배열 

프리미티브 타입 종류와 값의 범위 그리고 기본 값 프리미티브 타입은 기본값 타입으로 불립니다. 종류는 크게 정수타입, 실수타입, 불리언타입으로 나눠져있습니다. 정수형에는 byte,short,int,long

b-programmer.tistory.com

3항 연산자는 다음처럼 사용이 가능하다.

(조건식1) ? (조건식2 ? (조건식3 ? true : false) : false) : false;

(여기에서는 자료형은 생략했다.) 그런데 이렇게 작성되는게 의미가 있을까? 어디까지 3항연산자를 사용해야할까?
추가적으로 ()는 사용하지 않아도 상관없지만, ()를 작성하는게 가독성이 훨씬 좋다.

간단하게 사용이 되기 때문이 좋지만, 그렇다고 무분별하게 사용은 하지 맙시다. 과유불급

연산자 우선 순위

지금까지 8가지의 연산자를 학습하였다. 그런데 이들은 언제 동작할까? 이들은 동시에 발생할까? 만약, 동시에 동작하지 않는다면 우선순위가 있을까? 

 

자바의 정석

 

(optional) Java 13. switch 연산자

자바13부터 추가된 연산자로 
일반적인 switch문에서는 break로 리턴을 시켜줬지만, 

자바13부터는 yield키워드를 이용해서 리턴하게 변경되었다.

Java 13 - Switch Expressions - Mkyong.com

- Java 13 - Switch Expressions

mkyong.com

 

yield와 break의 차이에 대한 글입니다.

What does the new keyword "yield" mean in Java 13?

Java 13 introduced the yield keyword for switch expressions. How can I use it and what's the difference to a default return or break value?

stackoverflow.com

 

반응형

'프로그래밍 언어 > 자바' 카테고리의 다른 글

반복문과 조건문  (0) 2020.11.29
백기선님 스터디에서 배운거 2가지 (간략히 정리)  (0) 2020.11.29
자바 데이터 타입, 변수 그리고 배열   (5) 2020.11.18
JVM이란?  (0) 2020.11.13
서블릿과 JSP  (0) 2020.09.24

댓글

Designed by JB FACTORY