[JAVA] 연산자(operator)

PiggPotato·2023년 8월 5일
2

자바

목록 보기
7/7
post-thumbnail

🤔연산자?

연산자는 연산을 수행하는 기호를 말한다.

  • 연산자가 연산을 수행하려면 연산의 대상이 있어야하며 그것을 '피연산자'라고 한다.

  • 연산자(operator) : 연산을 수행하는 기호
  • 피연산자(operand) : 연산의 작업 대상
  • 연산자는 피연산자로 연산을 수행하고 나면 항상 결과 값을 반환한다.
    // 대입연산자(=)도 우변의 값을 좌편에 저장하고 저장된 값을 반환한다.
    int A = 0;
    int B = 0
    A = b = 1;

🤔연산자의 종류

종류결합규칙연산자우선순위
단항 연산자<---++ -- + - ~ ! (type)높음
산술 연산자--->* / %
+ -
<< >>
비교 연산자--->< > <= >= instanceof
논리 연산자--->&
^
|
&&
||
삼항 연산자--->? :
대입 연산자<---= += -= *= /= %= <<= >>= &= ^= |=높음
  • 연산자의 기능이 비슷한 것들끼리 묶어놓은 연산자는 산술, 비교, 논리, 대입 4가지가 있고

  • 피연산자의 개수에 의한 분류한 것으로는 단항 연산자와 삼항 연산자가 있는데 이는 대부분의 연산자는 이항 연산자 이기 때문이다.

  • 단항 연산자의 -(부호 연산자)와 산술 연산자의 -(뺄셈 연산자)는 기호가 같은 경우가 있을 때는 피연산자의 개수로 구분한다.

💡 연산자의 우선순위와 결합규칙

  • 식에 사용된 연산자가 둘 이상인 경우, 우선순위에 의해 연산 순서가 결정된다.


위와 같이 대부분의 실제 프로그래밍에서 사용되는 식은 수학에서의 우선순위와 같아 판단이 가능하다.

  • 괄호()는 연산자가 아니며 연산자의 우선순위를 임의로 지정할 때 사용하는 기호다.

🤔 같은 우선순위의 연산자들이 여러개 있는 경우에는 어떤 순서로 연산을 수행할까?

우선순위가 같을 경우에 연산자의 결합규칙을 따른다.

  • 결합 규칙은 연산자마다 다르지만, 단항 연산자와 대입 연사자만이 오른쪽에서 왼쪽(<-)으로 연산을 수행하고 나머지 연산자는 반대 방향인 왼쪽에서 오른쪽(->)으로 연산을 수행한다.

🤔 단항 연산자

종류결합규칙연산자우선순위
단항 연산자<---++ -- + - ~ ! (type)높음

💻 증감 연산자(++, --)

증감연산자는 피연산자에 저장된 값을 1 증가/감소 시킨다.

  • 대부분의 연산자는 피연사의 값을 읽어 연산에 사용하지만. 오직 대입 연산자와 증감 연산자 만이 피연산자의 값을 변경한다.
  • 산술 변환에 의한 자동 형변환이 발새라지 않으며, 결과의 타입은 피연산자의 타입의 타입과 같다.
  • 피연산자의 양쪽에 모두 위치할 수 있다.
타입설명예시
전위형(prefix)피연산자의 왼쪽에 위치, 값이 참조되기 전에 증가시킨다.++i
후위형(postfix)피연산자의 오른쪽에 위치, 값이 참조된 후에 증가시킨다.i++
  • 전위형 후휘형 모두 피연산자의 값을 1 증가/감소 시키지만, 수식이나 메서드 호출에 포함된 경우 결과가 다르다.
    int i = 5, j = 0;
    j = i++; //실행시 j = 5, i = 6
    i = 5;
    j = i++; // 실행시 j = 6, i = 6
  • 전위형은 변수의 값을 먼저 증간 시킨 후 변수의 값을 읽어온다.
  • 후위형은 변수의 값을 먼저 읽어온 후 변수의 값을 증가시킨다.
  • 하나의 식에서 연산자의 사용을 최소화 하고, 식에 두 번 이상이상 포함된 변수에 증감 연산자를 사용하는 것은 피해야 한다.

💻 부호 연산자(+, -)

부호 연산자 '-'는 피연산자의 부호를 반대로 변경한 결과를 반환한다.

  • 피연산자가 음수면 양수로, 양수면 음수로 변경한 결과를 반환한다.
  • 부호 연산자 '+'는 역할이 없으며 거의 사용하지 않는다.
  • boolean형과 char형을 제외한 기본형에만 사용이 가능하다.
int i = -1; // i = -1
i = +i; i = -1

🤔산술 연산자

종류결합규칙연산자우선순위
산술 연산자--->* / %높음
+ -
<< >>낮음

💻 사칙 연산자(+, -, *, /)

  • 수학에서 사용될때 처럼 *, /, % 연산자가 +, - 연산자 보다 우선순위가 높다.
  • 피연산자가 정수일 경우, 나누는 수로 0을 사용할 수 없다(에러 발생)
int a = 0;
a = 10 / 0;	//에러 발생
  • 산술변환이 발생한다.
byte a = 10;
byte b = 5;
byte c = a + b; // 에러 발생
  • byte형은 int형보다 작은 표현범위를 가졌기 때문에 피연산자들의 자료형을 int형으로 변경한 다음 연산이 수행된다. 수행 결과가 int형(4byte)이기 때문에 byte(1byte)형 변수에 형변환 없이 저장하려 하면 오류가 발생한다.
  • 아래와 같은 방법을 통해 해결이 가능하지만 작은 자료형인 byte로의 형변환은 데이터의 손실로 인한 값의 오차가 발생할 수 있다.
    byte c = (byte)(a + b);

💡 범위보다 큰 값의 연산

int a = 1_000_000;
int b = 1_000_000;
long c = a * b;
  • 결과를 저장하는 변수의 자료형이 long이지만, 연산 수행시 연산의 결과가 int 타입 이기 때문에 int의 최대값을 넘어 오버플로우가 발생한다.

    c = (long)a * b //또는 a * (long)b로 작성하여 형변환을 해줘야 한다.
  • 마찬가지로 연산의 결과가 int형으로 오버플로우가 발생하는 경우

    long a = 1_000_000 * 1_000_000 
  • 아래와 같이 작성하여 long 타입 리터럴임을 명시하여 long타입으로 산술 변환이 발생하게 작성해야한다.

    long a = 1_000_000 * 1_000_000L // 또는 1_000_000L * 1_000_000L

💡 문자의 사칙연산

문자는 해당 문자의 유니코드(정수)로 저장된다. 따라서 정수간의 연산과 동일하다.

문자형으로 이루어진 정수('1')를 정수형으로 변환하는데 사용한다.

  • '0' ~ '9'는 유니코드상 연속적으로 배치 되어있다. ('0' = 48, '1' = 49)
  • 연속적으로 배치되어 있기 때문에 '0'을 빼는 연산을 통해 실제 정수값을 구할 수 있다.
'1' - '0' = 1

'A' ~ 'Z'와 'a' ~ 'z'도 연속적으로 배치되어 있기 때문에 정수를 더해 원하는 문자를 찾을 수 있다.

char c = 'a';
char c1 = 'c1;
char c2 = ' ';
c2 = (char)(c1 +1);
c1 ++;
  • int형으로 변환한 후 덧셈 연산을 수행, 결과가 int형이기 때문에 char형 변수에 저장하기 위해서 형변환이 필요하다.
  • 증감연산자(++)는 피연산자 c1에 저장된 값을 1 증가시킨다.

에러가 발생하는 경우

char c = 'a';
char c1 = 'c + 1;	// 에러 발생
char c2 = 'a' + 1;	// 에러 발생 X
  • c1 = c + 1의 경우 수식에 변사가 들어가 있어 컴파일러가 미리 계산을 할 수 없어 형변환이 필요해 에러가 발생한다.

  • c2의 경우 에러가 발생하지 않는데 'a' + 1은 리터럴 간의 연산이기 때문이다.

    char c2 = 'a' + 1 // 컴파일 전
    char c2 = 'b' // 컴파일 후
  • 상수 또는 리터럴 간의 연산은 실행 과정 동안 변하는 값이 아니기 때문에 컴파일러가 컴파일 시 컴파일러가 계산하여 최적화된 코드를 미리 계산하여 그 결과로 대체하기 때문이다.

💡 나눗셈 연산자 성질 이용하기

int형 간의 나눗셈의 성질을 이용하여 실수의 소수점 버리기

  • pi : 3.141592f
  1. float형 pi * 1000은 float형 3141.592f가 된다.
  2. int형으로 형변환되어 소수점을 버린다. 3141이 된다.
  3. int와 float의 연산으로 float형 3.141f가 된다.
  • 예시는 소수점 셋째 자리까지만을 남기는 예시로 10^3(남기고 싶은 자리수)의 정수를 곱한뒤 정수형으로 형변환 함으로 나머지 소수점을 버린다.
  • 그 후 실수와의 연산을 통해 다시 실수형으로 형변환 한다.
  • 1번 단계를 (pi * 1000 + 0.5)로 변경 한다면 남기고 싶은 자리수(3번째)의 다음 자리의 수(3번째)를 반올림 할 수 있다.

💡 Math.round를 사용하여 반올림 하기

  • pi : 3.141592
  • Math.round 메서드는 매개변수로 받은 값을 소수점 첫째 자리에서 반올림하고 결과를 정수로 반환한다.
  1. pi * 1000은 double형 3141.592가 된다.
  2. round 메서드가 첫째 자리에서 반올림한 정수 3142를 반환한다.
  3. int와 double의 연산으로 double형 3.141가 된다.

💻 나머지 연산자

왼쪽 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자이다.

  • 피연산자로 정수만을 허용하며 0을 피연산자로 사용할수 없다.
    int a = 10, b = 8;
    int c = a % n;	// 나머지 값 2를 반환한다.

💡 피연산자로 음수를 허용한다.

  • 부호는 무시되어 결과는 음수의 절대값으로 나눈 나머지 값과 같다.
  • 나머지 연산을 한 결과에 왼쪽 피연산자의 부호를 붙히면 된다.
    -10 % 8;	// -2
    10 % -8 	// 2
    -10 % -8	// -2

🤔 비교 연산자

두 피연산자를 비교하는데 사용되는 연산자이다. 결과는 오직 true와 false중 하나만을 반환한다.

  • 이항 연산자이기 때문에 자동 형변환후 비교된다.

💻 대소비교 연산자(>, <, >=, <=)

두 피연산자의 값의 크기를 비교하는 연산자이다.

  • boolean형과 참조형을 제외한 나머지 자료형에 사용이 가능하다.
종류연산자연산결과
비교 연산자>좌변의 값이 크면 true, 아니라면 false
<좌변의 값이 작으면 true, 아니라면 false
>=좌변의 값이 크거나 같다면 true, 아니라면 false
<=좌변의 값이 작거나 같다면 ture, 아니라면 false

💻 등가비교 연산자(==, !=)

두 피연산자의 값이 같은지 다른지 비교하는 연산자이다.

종류연산자연산결과
비교 연산자==두 값이 같다면 true, 아니라면 false
!=두 값이 다르다면 true, 아니라면 false
  • 대소비교 연산자(>, <, >=, <=)와 달리 기본형과 참조형 포함 모든 자료형에 사용이 가능하지만 기본형과 참조형 사이의 비교는 불가능하다.(형변환 불가)
    10.0
  • 기본형 : 저장된 값을 비교
  • 참조형 : 저장된 객체의 주소값이 같은지 비교

float과 double 타입의 비교

  • double 타입의 값을 float 타입으로 형변화 한 다음 비교해야한다.

  • 실수형은 근사값으로 저장되기 때문에 정확도를 넘어가는 값을 오차가 발생할 수 있다.

    double d = 0.1;
    float f = 0.1f;
  • d == f :변수 f를 double 타입으로 형변환하여 비교한다. 형변환을 해도 근사값으로 처리한 부분의 값은 변하지 않기 때문에 비교 연산시 false를 반환한다.

  • (float)d = f : 변수 d를 float 타입으로 형변환하여 비교한다.

💡 문자열의 비교

비교 연산자가 아닌 equals() 메서드를 사용하여 비교한다.

  • equals()메서드는 두 비교하는 문자열이 같으면 true, 다르면 false를 결과로 반환한다.

문자열(String)은 클래스로, 객체를 생성할 때 new를 사용해야 하지만 특변히 간단히 표현하여 사용하는 방법이 있다.

String str = new String("abc") // 일반적인 객체를 생성
String str = "abc" //  간단히 표현
boolean b = str.equals("abc") // 내용이 같으므로 true가 반환된다.

비교 연산자(==)로 비교

String str = "abc";
String str1 = new String("abc");
str == "abc"	// true
str1 == "abcc"	// false
// 둘의 차이는 나중에 자세히 다룬다.
str.equals("abc")	// true
str1.equals("abc")	// true
  • 내용이 같더라도 비교연산자(==)로 비교하면 false를 결과로 반환한다.
  • 비교연산자는 두 문자열이 완전히 같은것인지 비교하기 때문에 str1 == "abc"의 경우는 내용은 같지만 서로 다른 객체이므로 false를 반환한다.
  • equals()는 객체가 달라도 내용이 같다면 true를 반환한다.
  • equalsIgnoreCase() : 내용을 대소문 구분 없이 비교한다.

🤔 논리연산자

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

논리 연산자는 '1보다 크고 10보다 작다'와 같이 둘 이상의 조건을 그리고(AND)와 또는(OR)으로 연결하여 하나의 식으로 표현할 수 있게 해준다.

종류연산자연산결과
논리 연산자||(OR)어느 한쪽만 true여도 true를 반환
&&(AND)양쪽 모두 true여야만 true를 반환
!(NOT)피연산자가 true면 false로, false면 true를 반환
  • x는 1보다 크고 10보다 작다

    1 < x && x <10
  • x는 2의 배수 또는 3의 배수지만 6의 배수는 아니다.

    (x % 2 == 0 || x % 3 == 0) && x % 6 != 0
  • 문자 x는 대문자 또는 소문자이다.

    ('a' <= x && x <='z') || ('A' <= x && x <='z')
  • 문자 x는 대문자 또는 소문자가 아니다.

    !(('a' <= x && x <='z') || ('A' <= x && x <='z'))

💻 효율적인 연산(short circuit evaluation)

  • ||(OR)는 좌측 피연산자가 true이면 우측 피연산자를 평가하지 않는다.
    - 어느 한쪽만 true여도 전체 연산결과가 true 이므로 true일 확률이 높은 피연산자를 왼쪽에 놓아 더 빠른 연산 결과를 얻을 수 있다.
x(피연산자)y(피연산자)||(연산자)
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse
  • &&(AND)는 좌측 피연산자가 false이면 우측 피연산자를 평가하지 않는다.
    - 어느 한쪽만 false여도 전체 연산의 결과가 false이므로 좌측 연산자가 false 이면 우측 연산자의 값은 평가하지 않는다.
x(피연산자)y(피연산자)&& (연산자)
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse
  • 논리 연산자의 특징인 효율적인 연산은 같은 조건식이라도 피연산자의 위치에 따라서 연산속도가 달라질 수 있다는 것이다.

💻 비트 연산자(&, |, ^, ~, <<, >>)

비트 연산자는 피연산자를 비트단위로 논리 연산하는 연산자를 말한다.

종류연산자연산결과
비트 연산자(OR)피연산자 중 한 쪽의 값이 1이면 1을 결과를 얻는다. 그 외에는 0을 얻는다.
&(AND)피연산자 양 쪽이 모두 1이면 1을 결과를 얻는다. 그 외에는 0을 얻는다.
^(XOR)피연산자의 값이 서로 다를 때만 1을 결과를 얻는다. 같을 때는 0을 얻는다.
  • 피연산자로 실수를 혀용하지 않고 정수만을 허용한다..
x(피연산자)y(피연산자)x|y(연산자)x&y (연산자)x^y(연산자)
11111
10101
01101
00000

'|'(OR)는 주로 특정 비트의 값을 변경할 때 사용한다.

  • 피연산자중 한쪽의 비트만 1이여도 값이 1로 변경되기 때문에, 변경할 값을 제외한 나머지 비트를 0으로 연산한다면 값을 유지한 채로 변경할 비트의 값을 변경할 수 있다.

'&'(AND)는 주로 특정 비트의 값을 뽑아낼 때 사용한다.

  • 피연산자중 한쪽의 비트만 0이여도 값이 0으로 변경되기 때문에 뽑아낼 값을 제외한 비트의 값을 0으로 연산하여 제거한뒤, 뽑아낼 비트의 값은 1로 연산하여 기존 값을 유지 시켜 남은 값을 뽑아낼 수 있다.

'^'(XOR)은 주로 간단한 암호화에 사용된다.

  • 피연산자의 비트가 다를 때만 1이되기 때문에, 같은 값을 두고 XOR 연산을 수행하면 원래의 값으로 돌아오는 특징이 있다.

💡 비트 전환 연산자(~)

비트 전환 연산자는 피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾸는 연산자이다.

  • 비트 전환 연산자에 의해 비트 전환이 되면 부호가 있는 피연산자는 부호가 반대로 변경된다.

  • 피연산자의 1의 보수를 얻을 수 있어 1의 보수 연산자라고도 한다.
  • 산술 변환후 연산되기 때문에 byte와 byte의 연산 결과는 int형이다.
  • 정수의 음수를 구하려면 '~정수 + 1', 다시 음수로 양수를 구하려면 '~(음수 - 1)'를 계산하여 구할 수 있다.

💡 쉬프트 연산자(<<, >>)

쉬프트 연산자는 2진수로 표현한 피연산자를 이동(shift)시키는 연사자이다.

  • <<와 >>는 이동할 방향을 뜻하며 <<는 왼쪽, >>는 오른쪽으로 이동한다는 의미이다.
  • 산술변환이 좌측에 있는 피연산자에 적용된다.

쉬프트 연산자 (<<)는 부호를 신경쓰지 않고 왼쪽으로 이동 시키며 빈칸을 0으로 채운다.

쉬프트 연산자 (>>)는 부호를 유지시킨다.

  • 피연산자가 음수인 경우, 오른쪽으로 이동시키고 빈자리를 1로 채운다.

  • 피연산자가 양수인 경우, 오른쪽으로 이동시키고 빈자리를 0으로 채운다.

쉬프트 연산자의 연산 결과

  • x << n : x * 2^n와 같다.
  • x >> n : x / 2^n와 같다.
  • n이 x의 자료형의 크기 이상 경우, n을 x의 자료형의 크기로 나눈 나머지 만큼 이동한다.
    - x << n : x * 2^(n % x의 자료형의 크기)와 같다.
    - x >> n : x / 2^(n % x의 자료형의 크기)와 같다

🤔 삼항 연산자

💻 조건 연산자( ? : )

조건 연산자는 첫번째 피연산자 (조건문)을 평가하여 평가 결과에 따라 다른 결과를 반환한다.

  • 삼항 연산자로 삼항 연산자는 조건 연산자 하나뿐이다.
  • 결과가 true이면 식1이 반환되고, 결과가 false인 경우에는 식2가 결과로 반환된다.
  • if를 사용하여 작성된 조건문 대신 조건 연산자를 사용하여 보다 간단히 작성할 수 있다.

🤔 대입 연산자(=, op=)

저장공간(변수)에 값이나 수식의 연산 결과를 저장하는 연산자이다.

  • 오른쪽 피연산자의 값을 왼쪽 피연산자에 저장하고 저장된 값을 연산결과로 반환한다.
  • 연산자들중 가장 낮은 우선순위를 가진다.
  • 진행 방향은 오른쪽에서 왼쪽이다.

lvalue와 rvalue

  • lvalue(왼쪽 피연산자, left value) : 값을 변경할 수 있어야 한다. 값을 저장할 수 없는 리터럴이나 상수는 될 수 없다.
  • rvalue(오른쪽 피연산자, right value) : 변수, 상수, 식 등이 모두 될 수 있다.

💡 복합 대입 연산자(op)

  • 대입 연산자 '='와 다른 연산자(op)와 결합하여 시용된다.

profile
초보 개발자 입니다.

0개의 댓글