연산자의 개념
연산(Operations) : 프로그램에서 데이터를 처리하여 결과를 산출하는 것.
연산자(Operator) : 연산에 사용되는 표시나 기호
피연산자(Operand) : 연산에 사용되는 데이터
연산식(Expressions) : 연산 계산식
연산자의 종류
피연산자의 갯수에 따라 단항, 이항, 삼항 연산자로 구분됨.
연산식은 무조건 1개의 값만 반환함.
연산자의 종류에 따라 산출되는 값의 데이터타입이 다름.
산술연산자는 숫자타입(byte, short, int, long, float, double), 비교연산자와 논리연산자는 boolean 타입이 반환됨.
단항 : a++; !조건식
이항 : x + y;
삼항 : (score>90) : "A" : "B";
연산자 종류 | 연산자 | 피연산자수 | 산출값 | 설명 |
산술 | +, -, *, / , % | 이항 | 숫자 | 사칙연산, 나머지 |
부호 | +, - | 단항 | 숫자 | 음수, 양수 부호 |
문자열 | + | 이항 | 문자열 | 문자열 붙이기 |
대입 | =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>= | 이항 | 우변의 값을 좌변의 변수에 대입 | |
증감 | ++, -- | 단항 | 숫자 | 1씩 /감소 |
비교 | ==, !=, >, <. >=, <=, instance Of | 이항 | boolean | 값 비교 |
논리 | !, &, |, &&, || | 단항, 이항 | boolean | 논리값 NOT, AND, OR 연산 |
조건 | (조건식) ? A : B | 삼항 | 다양 | 조건식이 true이면 A, false면 B |
비트 | ~, &, |, ^ | 단항, 이항 | 숫자, boolean | 비트 NOT, AND, OR, XOR 연산 |
쉬프트 | >>, <<, >>> | 이항 | 숫자 | 비트를 밀어서 이동 |
산술 연산자
더하기(+), 빼기(-), 곱하기(*), 나누기(/) 와 나머지를 구하는 연산자(%)
산술 연산자를 피연산자들의 타입이 동일하지 않을 경우 규칙을 사용해 피연산자들의 타입을 일치시킨 후 연산을 수행한다.
연산자 타입 변환 규칙
① byte, short, int 의 정수형 타입 연산에서, 피연산자들이 모두 int 보다 작을 경우 int로 변환되어 계산된다.
* 정수형의 계산이 int로 나오는 이유는 JVM이 기본적으로 32비트, int 단위로 계산을 수행하기 때문이다.
byte a = 1;
byte b = 2;
Object c = a+b;
Object d = a/b;
System.out.println( c.getClass().getName()+", "+c );
System.out.println( d.getClass().getName()+", "+d );
java.lang.Integer, 3
java.lang.Integer, 0
결과값을 double로 받더라도, 피연산자 값이 int거나, int보다 범위가 작은 정수형이면 결과값이 int로 반환된다.
int a = 1;
int b = 3;
double c = 3;
double d = a/b;
double e = a/c;
System.out.println(d);
System.out.println(e);
0.0
0.3333333333333333
② int 와 long 연산에서는 long 으로 변환되어 계산된다.
long a = 100000;
int b = 1;
Object c = a+b;
Object d = a/b;
System.out.println( c.getClass().getName()+", "+c );
System.out.println( d.getClass().getName()+", "+d );
java.lang.Long, 100001
java.lang.Long, 100000
③ 정수형과 실수형 연산에서는 실수형 타입으로 변환되어 계산된다.
float a = 1;
int b = 2;
Object c = a+b;
Object d = a/b;
System.out.println( c.getClass().getName()+", "+c );
System.out.println( d.getClass().getName()+", "+d );
java.lang.Float, 3.0
java.lang.Float, 0.5
④ 피연산자 중 실수타입(double, float)이 있는 경우, 크기가 가장 큰 실수타입으로 변환되어 계산된다.
float a = 1;
double b = 2;
Object c = a+b;
System.out.println( c.getClass().getName()+", "+c );
java.lang.Double, 3.0
오버플로우
연산 후의 결과값이 return 데이터 타입으로 표현할 수 있는 범위의 값이 아니면, 오버플로우가 발생해 올바른 결과값을 얻을 수 없다.
int a = 111111;
int b = 222222;
System.out.println(a*b);
long A = 111111;
long B = 222222;
System.out.println(A*B);
-1078495134
24691308642
NaN과 Infinity 연산
/ 또는 % 연산에서 우측연산자가 0.0(실수)인 경우에 발생한다.
0(정수)인 경우에는 ArithmeticException이 발생한다.
NaN : Not a Number, 숫자가 아닌 값
Infinity : 무한대
System.out.println( Integer.valueOf(5%0) );
System.out.println( Integer.valueOf(5/0) );
Exception in thread "main" java.lang.ArithmeticException: / by zero
System.out.println( 5 % 0.0);
System.out.println( 5 / 0.0);
NaN
Infinity
* https://www.baeldung.com/java-not-a-number
비트 연산자
비트연산자는 데이터를 비트(bit) 단위, 0과 1로 연산하기 때문에 0 과 1로 표현이 가능한 정수타입만 비트 연산을 할 수 있다.
비트 연산자는 피연산자를 int 타입으로 변환한 후 연산을 수행한다. 결과값이 int로 출력된다.
(피연산자가 int보다 큰 정수형인 long이면 long타입으로 결과가 반환된다.)
비트 논리 연산자
구분 | 피연산자1 | 연산자 | 피연산자2 | 결과 | 설명 |
AND (논리곱) |
1 | & | 0 | 0 | 두 비트 모두 1일때만 1을 반환 |
1 | 1 | 1 | |||
0 | 0 | 0 | |||
0 | 1 | 0 | |||
OR (논리합) |
1 | | | 0 | 1 | 두 비트 중 하나가 1이면 1을 반환 |
1 | 1 | 1 | |||
0 | 0 | 0 | |||
0 | 1 | 1 | |||
XOR (배타적 논리합) |
1 | ^ | 0 | 1 | 두 비트중 하나는 1이고, 하나는 0일 경우 1을 반환 |
1 | 1 | 0 | |||
0 | 0 | 0 | |||
0 | 1 | 1 | |||
NOT(논리부정) | ~ | 0 | 1 | 보수(32비트, 합치면 -1) | |
1 | 0 |
* 보수 : 보수 (수학), 위키백과
int ten = 10;
int eight = 8;
String A = Integer.toBinaryString(ten);
String B = Integer.toBinaryString(eight);
System.out.println(A+"\n"+B);
System.out.println("10 AND 8 = "+(ten&eight)+"("+Integer.toBinaryString(ten&eight)+")");
System.out.println("10 OR 8 = "+(ten|eight)+"("+Integer.toBinaryString(ten|eight)+")");
System.out.println("10 XOR 8 = "+(ten^eight)+"("+Integer.toBinaryString(ten^eight)+")");
System.out.println("NOT 10 = "+(~ten)+"("+Integer.toBinaryString(~ten)+")");
1010
1000
10 AND 8 = 8(1000)
10 OR 8 = 10(1010)
10 XOR 8 = 2(10)
NOT 10 = -11(11111111111111111111111111110101)
Long 타입이면 long으로 연산자가 반환된다.
long tenLong = 10;
System.out.println("NOT 10 = "+(~tenLong)+"("+Long.toBinaryString(~tenLong)+")");
NOT 10 = -11(1111111111111111111111111111111111111111111111111111111111110101)
비트 이동 연산자
정수 데이터의 비트를 좌측 또는 우측으로 밀어서 이동시키는 연산자이다. (32비트 기준)
피연산자1 | 연산자 | 피연산자2 | 설명 |
A | << | B | 정수 A의 각 비트를 B만큼 왼쪽으로 이동(빈자리는 0으로 채워짐) |
A | >> | B | 정수 A의 각 비트를 B만큼 오른쪽으로 이동(빈자리는 A의 최상위비트(부호비트)와 같은 값으로 채워짐) |
A | >>> | B | 정수 A의 각 비트를 B만큼 오른쪽으로 이동(빈자리는 0으로 채워짐) |
int fifteen = 15;
System.out.println(Integer.toBinaryString(fifteen));
System.out.println("15 << 2 = "+(fifteen<<2)+"("+Integer.toBinaryString(fifteen<<2)+")");
System.out.println("15 >> 2 = "+(fifteen>>2)+"("+Integer.toBinaryString(fifteen>>2)+")");
System.out.println("-15 >> 2 = "+(-fifteen>>2)+"("+Integer.toBinaryString(-fifteen>>2)+")");
System.out.println("-15 >>> 2 = "+(-fifteen>>>2)+"("+Integer.toBinaryString(-fifteen>>>2)+")");
1111
15 << 2 = 60(111100)
15 >> 2 = 3(11)
-15 >> 2 = -4(11111111111111111111111111111100)
-15 >>> 2 = 1073741820(111111111111111111111111111100)
관계 연산자
값의 크고 작음이나 같은지를 비교해서 boolean(true/false)를 반환한다.
대소(크고작음) 연산자는 boolean 타입을 제외한 모든 기본 타입에 사용할 수 있다.
동등(같음) 연산자는 모든 타입에 사용될 수 있다.
구분 | 피연산자1 | 연산자 | 피연산자2 | 설명 |
동등 | A | == | B | A,B가 같은지를 검사 |
A | != | B | A,B가 다른지를 검사 | |
대소 | A | > | B | A가 B보다 큰지를 검사 |
A | >= | B | A가 B보다 크거나 같은지를 검사 | |
A | < | B | A가 B보다 작은지를 검사 | |
A | <= | B | A가 B보다 작거나 같은지를 검사 |
boolean result1 = 15 > 10;
boolean result2 = 15 < 10;
boolean result3 = 15 == 10;
boolean result4 = 15 != 10;
System.out.println("15 > 10 = "+result1);
System.out.println("15 < 10 = "+result2);
System.out.println("15 == 10 = "+result3);
System.out.println("15 != 10 = "+result4);
15 > 10 = true
15 < 10 = false
15 == 10 = false
15 != 10 = true
피연산자의 타입이 char이면 아스키코드값으로 변환하여 비교 연산을 수행한다.
두 피연산자의 타입이 일치하지 않으면 int로 변환하여 비교 연산을 수행한다.
boolean result1 = 'A' > 10;
boolean result2 = 0.1 == 0.1f;
boolean result3 = (float) 0.1 == 0.1f;
boolean result4 = 'A' > 'B';
System.out.println("'A' > 10 = "+result1);
System.out.println("0.1 == 1.0f = "+result2);
System.out.println("(float) 0.1 == 0.1f = "+result3);
System.out.println("A > B = "+result4);
'A' > 10 = true
0.1 == 1.0f = false
(float) 0.1 == 0.1f = true
0.1 == (int) 0.1f = false
A > B = false
*부동소수점 타입인 0.1f는 0.1의 근사값으로 표현되여 0.1과 다른 값이 된다. 정확하게 비교하려면 double인 0.1을 float형으로 변환 후 비교연산을 수행해야 한다.
*A는 아스키코드로 65
//유니코드
System.out.println(Character.getNumericValue('A'));
System.out.println(Character.getNumericValue('B'));
//아스키코드
System.out.println((int) 'A' );
System.out.println((int) 'B' );
10
11
65
66
문자열(String)은 값을 객체로 비교하기 때문에 ==이 아닌 equals를 이용해 비교해야 한다.
String a = "AAA";
String b = "AAA";
String c = new String("AAA");
System.out.println("a==b : "+(a==b));
System.out.println("a.equals(b) : "+a.equals(b));
System.out.println("a==c : "+(a==c));
System.out.println("a.equals(c) : "+a.equals(c));
a==b : true
a.equals(b) : true
a==c : false
a.equals(c) : true
논리 연산자
논리 연산자는 논리곱(&&), 논리합(||), 배타적 논리합(^), 논리 부정(!) 연산을 수행한다.
피연산자는 boolean 타입만 사용할 수 있다.
& : 첫번째 피연산자의 값이 flase이면 뒤의 연산을 수행하지 않는다.
&& : 첫번째 피연산자의 값이 true이더라도 두번째 피연산자의 값을 확인한다.
구분 | 피연산자1 | 연산자 | 피연산자2 | 결과 | 설명 |
AND (논리곱) |
true | && & |
true | true | 피연산자가 모두 true면 true를 반환 |
true | false | false | |||
false | true | false | |||
false | false | false | |||
OR (논리합) |
true | || | |
true | true | 피연산자 중 하나면 true면 true를 반환 |
true | false | true | |||
false | true | true | |||
false | false | false | |||
XOR (배타적 논리합) |
true | ^ | true | false | 피연산자 중 하나가 true, 하나가 false이면 true를 반환 |
true | false | true | |||
false | true | true | |||
false | false | false | |||
NOT (논리부정) |
! | true | false | 피연산자의 논리값을 바꿈 | |
false | true |
boolean result1 = 1 < 2 & 3 > 4;
boolean result2 = 1 < 2 | 3 > 4;
boolean result3 = 1 < 2 ^ 3 > 4;
System.out.println("1 < 2 & 3 > 4 = "+result1);
System.out.println("1 < 2 | 3 > 4 = "+result2);
System.out.println("1 < 2 ^ 3 > 4 = "+result3);
1 < 2 & 3 > 4 = false
1 < 2 | 3 > 4 = true
1 < 2 ^ 3 > 4 = true
instanceof
객체가 어떤 클래스의 인스턴스인지 확인하는 연산자이다.
객체가 어떤 클래스의 인스턴스라면 true, 아니면 false를 반환한다.
boolean isInstanceOf = 객체1 instanceOf 클래스
Integer a = 1234;
boolean isInstanceOf1 = a instanceof Integer;
System.out.println(isInstanceOf1);
Double b = 1234.0;
boolean isInstanceOf2 = b instanceof Double;
System.out.println(isInstanceOf2);
double c = 1234.0;
boolean isInstanceOf3 = c instanceof double;
System.out.println(isInstanceOf3);
true
true
Incompatible conditional operand types double and double
* double은 클래스가 아닌 원시 타입이기 때문에 instanceof로 연산이 불가능하다.
* generic이나 부모 클래스 사용시 객체의 클래스를 판단하는데 사용됨.
public <T> boolean checkClass1(T input) {
if(input instanceof Integer) {
}
if(input instanceof String) {
}
return false;
}
public boolean checkClass2( ParentClass input) {
if(input instanceof ChildClass1) {
}
if(input instanceof ChildClass2) {
}
return false;
}
대입연산자
오른쪽 피연산자의 값을 왼쪽 피연산자에 저장한다.
오른쪽 피연산자의 값을 저장하는 단순대입연산자와, 정해진 연산을 수행 후 결과를 저장하는 복합 대입 연산자로 구분된다.
구분 | 연산자 | 설명 | ||
단순 | A | = | B | 값을 저장 |
복합 | A | += | B | A = A+B |
A | -= | B | A = A-B | |
A | *= | B | A = A*B | |
A | /= | B | A = A/B | |
A | %= | B | A = A%B | |
A | &= | B | A = A&B (논리곱 비트연산) | |
A | |= | B | A = A|B (논리합 비트연산) | |
A | ^= | B | A = A^B (배타적 논리합 비트연산) | |
A | <<= | B | A = A<<B (A에서 B만큼 좌측으로 비트 이동) | |
A | >>= | B | A = A>>B (A에서 B만큼 우측으로 비트 이동) | |
A | >>>= | B | A = A>>>B (A에서 B만큼 우측으로 비트 이동) |
int a = 3;
a += 3;
System.out.println(a);
a /= 3;
System.out.println(a);
a &= 3;
System.out.println(a);
6
2
2
화살표(->) 연산자
람다식에서 사용되는 문법으로 왼쪽의 피연산자를 이용해 오른쪽의 연산을 수행한다는 의미이다.
런타임시 람다식으로 구현된 익명 구현 객체를 생성한다.
일반적으로 익명구현객체는 아래와 같이 생성한다.
public interface Optest{
public int add(int a, int b);
}
public static void main(String[] args) {
Optest op = new Optest() {
@Override
public int add(int a, int b) {
return a+b;
}
} ;
System.out.println(op.add(1, 2));
}
3
람다식을 이용하면 훨씬 간결하게 구현이 가능하다.
public interface Optest{
public int add(int a, int b);
}
public static void main(String[] args) {
Optest op = (a,b) -> {return a+b;};
System.out.println(op.add(1, 2));
}
3
3항 연산자
조건식 ? 값 또는 연산식 : 값 또는 연산식
int score = 70;
String result = score > 70 ? "PASS" : "FAIL";
System.out.println(result);
FAIL
연산자 우선 순위
① 단항, 이항, 삼항 연산자 순으로 우선순위가 높다.
② 산술, 비교, 논리, 대입 연산자 순으로 우선순위가 높다.
③ 단항, 대입 연산자를 제외한 모든 연산자의 연산방향은 -> 이다.
④ 복잡한 연산식에서는 괄호를 사용해 우선순위를 정해준다.
연산자 | 연산방향 | 우선순위 |
증감(++, --), 부호(-, +), 비트(~), 논리(!) | ◀---------------- | 높음 ▲ ▼ 낮음 |
산술(*,/,%) | ----------------▶ | |
산술(+,-) | ----------------▶ | |
쉬프트(<<, >>, >>>) | ----------------▶ | |
비교(<, >, <=, >=, instanceof) | ----------------▶ | |
비교(==, !=) | ----------------▶ | |
논리(&) | ----------------▶ | |
논리(^) | ----------------▶ | |
논리(|) | ----------------▶ | |
논리(&&) | ----------------▶ | |
논리(||) | ----------------▶ | |
3항(?:) | ----------------▶ | |
대입 | ◀---------------- |
(optional) Java 13. switch 연산자
https://blogs.oracle.com/javamagazine/post/new-switch-expressions-in-java-12
출처
신용권, 이것이 자바다, 한빛미디어
'JAVA > JAVA' 카테고리의 다른 글
Collection 컬렉션 (0) | 2021.10.25 |
---|---|
제어문(조건문 if, 반복문 for/while) (0) | 2021.10.07 |
JVM 자바 가상머신 (0) | 2021.10.02 |
Objects 클래스 (0) | 2021.09.28 |
Object Class (0) | 2021.09.28 |