연산자(Operator)
아래 순서는 연산자 단일경우이다. 연산자가 같이 있으면 경우에 따라 달라진다.
1. 종류
1) 산술연산자
- 이항연산자 : *, /, %, +, -
- 단항(증감)연산자 : ++, --
단항(증감)연산자를 써보자.
<예제 1>
class Op1{
public static void main(String[] args){
int a = 10;
a++; //후위연산자 a = a+1;
++a; //전위연산자
System.out.println("a=" + a);
}
}
※ 결과값
a=12
아래 두개의 예제를 비교하여 살펴보자.
<예제2>
class Op1 {
public static void main(String[] args) {
// TODO 연산자1
int a = 10, b;
b = ++a;
//b=a++;
System.out.println("a="+a);
System.out.println("b="+b);
}
}
※ 결과값
a=11
b=11
<예제 3>
class Op1{
public static void main(String[] args){
int a = 10, b;
//b = ++a;
b = a++;
System.out.println("a=" + a);
System.out.println("b=" + b);
}
}
※ 결과값
a=11
b=10
어떻게 이런 다른 결과가 나오는 것일까?
왜냐하면 연산자우선순위 때문에 a값이 증감되기 전에 b로 넘어가버렸기 때문이다.
이렇게 증감연산자을 계산식과 연동할 경우 오류를 찾기 어렵기 때문에
증감연산자는 될 수 있으면 계산식과 연동하지 말고 단독으로 쓰는 것이 좋다.
2) 비교연산자
>, <, >=, <=, ==(같다), !=(같지 않다)
3) 논리연산자 (단락회로 기능)
&&(and), ||(or), !(not)
t = true
f = fause
a |
b |
a && b |
a || b |
!a |
a^b |
t |
t |
t |
t |
f |
f |
t |
f |
f |
t |
f |
t |
f |
t |
f |
t |
t |
t |
f |
f |
f |
f |
t |
f |
여기서 ! 는 스위치처럼 한 번씩 왔다갔다 반복을 하기 때문에 Toggle이라고 한다. (ex_바둑게임)
4) 대입(치환)연산자
대입연산자
= (오른쪽에 있는 값은 왼쪽에 집어넣어라)
복합대입연산자
+=, -=, *=, /=, ....
(+= 는 '변수 = 변수 + 값'을 생략한 것이다.)
(다른 연산자와 조합해서 사용한다. 이는 누적 연산자라고 한다.)
class Op2{
public static void main(String[] args){
int a = 10;
a = 5;
a = 2;
a = 3;
System.out.println("a=" + a)
}
}
※ 결과값
3
변수는 아무리 다른 값을 집어넣어도 하나밖에 저장이 안되기 때문에 마지막에 집어 넣은 값이 출력값이 된다.
이렇듯 대입연산자는 값이 누적되지 않고 계속 덮어 씌어진다.
class Op2{
public static void main(String[] args){
/*
int a = 10;
a = 5;
a = 2;
a = 3;
System.out.println("a=" + a)
*/
int a = 10;
a += 5; // a = a+5;
a += 2; // a = a+2;
a += 3; // a = a+3;
System.out.println("a=" +a);
}
}
※ 결과값
20
이 때 a의 값은 20이 된다. 누적되어서 계산 되었기 때문이다.
대입연산자와 달리 복합대입연산자는 다른 연산자를 포함하고 있지만
생략하여 나타낸 연산자기 때문에 값이 누적되어 계산된다.
이렇듯 연산자에게 가장 중요한 것은 '우선순위'이다.
연산우선순서를 모두 외울 수 있지만 쉽지 않다.
연산자는 괄호()를 묶어 연산하는 습관을 기른다.
정확하고 안전한 것이 가장 중요하다.
5) 비트연산자
& (and연산자), | (or연산자), ^ (exclusive-or, xor, 베타적인or, 데이터를 암호화 하거나 복구한다.), >>, >>> << ~, ...
프로그램의 성능을 올리기 위해 사용하는 연산자이다.
최근 하드웨어의 사향의 상향 평준화 되었기 때문에
하드웨어를 다루지 않는이상 잘 쓰지는 않는다.
class Op3 {
public static void main(){
int a = 10, b = 5;
System.out.println("a&&b" + a&&b);
}
}
// 논리 연산식은 참과 거짓으로만 판단할 수 있기 때문에 오류가 된다.
※ 결과값
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The operator && is undefined for the argument type(s) String, int
at operator.Op3.main(Op3.java:8)
class Op3 {
public static void main(String[] args){
int a = 10, b = 5;
//System.out.println("a&&b" + a&&b);
System.out.println("a>5&&b<3" + (a>5&&b<3));
}
}
※ 결과값
a>5&&b<3false
변수의 값이 참인지 거짓인지를 물었기 때문에 값이 위와 같이 나온다.
비트연산자 & 는 논리연산자 &&와는 다르게
숫자를 대변해도 값이 나온다. 비트연산자는 이진수를 계산하기 때문이다.
class Op3 {
public static void main(String[] args){
int a = 10, b = 7;
//System.out.println("a&&b" + a&&b);
System.out.println("a>5&&b<3" + (a>5&&b<3));
System.out.println("a>5&b<3" + (a>5&b<3));
System.out.println("a&b" + (a&b));
}
}
※ 결과값
a>5&&b<3false
a>5&b<3false
a&b2
논리연산자는 단락회로기능을 가지고 있다. '단락회로기능'이란
이미 앞에서 계산된 것은 계산하지 않는 것을 말한다.
아래의 예제들을 비교하면서 생각해보자.
class Op3 {
public static void main(String[] args){
int a = 10, b = 7;
//System.out.println("a&&b" + a&&b);
System.out.println("a>5&&b<3" + (a>5&&b<3));
System.out.println("a>5&b<3" + (a>5&b<3));
System.out.println("a&b" + (a&b));
System.out.println(a>12 && ++b>5);
System.out.println(a + ", " + b);
}
}
※ 결과값
a>5&&b<3false
a>5&b<3false
a&b2
false
10, 7
class Op3 {
public static void main(String[] args){
int a = 10, b = 7;
//System.out.println("a&&b" + a&&b);
System.out.println("a>5&&b<3" + (a>5&&b<3));
System.out.println("a>5&b<3" + (a>5&b<3));
System.out.println("a&b" + (a&b));
System.out.println(a<12 && ++b>5);
System.out.println(a + ", " + b);
}
}
※ 결과값
a>5&&b<3false
a>5&b<3false
a&b2
true
10, 8
이 값의 변화는 논리연산자(&&, ||)가 가진 단락회로기능 때문이다.
^(exclusive-or, xor, 베타적인or, 데이터를 암호화 하거나 복구한다.
^는 서로의 값이 다르면 참 서로의 값이 같으면 거짓이다.
키값만 있다면 데이터를 암호화 할 수도, 복구 할 수도 있다.
<암호화>
11010110
^ 11000011 (key)
-------------------------
00010101
<복구>
00010101 (key)
^ 11000011
----------------
11010110
class Op4{
public static void main(String[] args){
int data = 34876;
int key = 2986;
int enc = data^key;
System.out.println("암호화된 값 : " + enc);
int dec = enc ^ key;
System.out.println("복호화된 값 : " + dec);
}
}
※ 결과값
암호화된 값 : 33686
복호화된 값 : 34876
비트연산자는 2진수로 연산함을 잊지말자!
6) 캐스팅 연산자 (강제형변환 연산자)
- 묵시적(암시적) : 작은 그릇을 큰 그릇에 넣었기 때문에 자동으로 캐스팅 된다.
- 명시적 : (data type) 변수
이 변수의 형식을 괄호 안에 있는 형식으로 강제로 바꾸겠다는 말이다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 오류가 난다.
int i1 = d1 + d2;
}
}
이를 캐스팅연산자를 사용하여 강제 형변환 해주면,
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
}
}
※ 결과값
i1 = 5
위와 같은 결과가 나오는 이유는 강제형변환을 했기 때문에. 0.8을 손해보아서 이다.
입력되는 숫자를 예측하기 어려운 경우에 많이 쓰인다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1;
System.out.println("d1 =" +d1);
}
}
※ 결과값
i1 = 5
d1 =5.0
이 경우 i1 값은 명시적 캐스팅을 헀고, d1의 경우
작은그릇을 큰그릇에 넣을 수 있기 때문에 암시적 캐스팅이 되었다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
b1 = b1 + 5;
System.out.println("b1 =" + b1);
}
}
※ 결과값
오류가 난다
이렇게 하면 오류가 난다.
문법적으로는 문제가 없으나 이는 하드웨어적인 이해가 필요하다.
작은 연산결과를 임시로 저장하는 곳을 레시스터라고 하는데
그 때 임시로 저장되는 형식이 기본형인 int이다.
int로 임시저장된 값을 bite로 다시 바꾸려고 하기 때문에 오류가 난다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//임시연산저장소에서 int로 저장된 값을 형변환 해준다.
b1 = (byte)(b1 + 5);
System.out.println("b1 =" + b1);
}
}
※ 결과값
i1 = 5
d1 =5.0
b1 = 5
b1 =105
b1 =110
강제형변환을 하지 않는 방법은 복합치환연산자를 쓰는 것이다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
}
}
※ 결과값
i1 = 5
d1 =5.0
b1 = 5
b1 =105
b1 =110
이렇듯 복합치환연산자는 자동캐스팅기능이 포함이 되어있어 연산이 가능하다.
하드웨어 문제로 연산이 안되는 또다른 문제가 있다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
float f1 = 3.14;
System.out.println("f1 =" + f1);
}
}
※ 결과값
오류
컴퓨터는 2진수이기 때문에 정수처리를 한다. 실수처리를 잘 못한다.
컴퓨터가 실수를 처리할 때는 정수부와 실수부를 따로 저장한다.
정수부와 실수부를 따로 저장할 때 타입은 실수의 기본형인 double이다.
이런 경우 역시 캐스팅으로 해결한다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
float f1 = (float)3.14;
System.out.println("f1 =" + f1);
}
}
※ 결과값
i1 = 5
d1 =5.0
b1 = 5
b1 =105
b1 =110
f1 =3.14
다른 방식으로 깔끔하게 표현을 바꾸어 보자.
강제형변환은 정수형 일 때만 한다. 그런데 실수형의 경우기 때문에 강제형변환 표현이 조금 지저분하다. 다른 방법으로 이를 표현하면 아래와 같이 된다.
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
//소문자나 대문자 f를 형변환 해야하는 값 옆에 써준다.
float f1 = 3.14f;
System.out.println("f1 =" + f1);
}
}
문자의 경우는 어떻게 캐스팅이 될까?
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
//float f1 = (float)3.14;
float f1 = 3.14f;
System.out.println("f1 =" + f1);
f1 = f1 + 2.5f;
System.out.println("f1 = " + f1);
//아스키코드기 때문에 숫자로 자동 형변환 해준다.
int i2 = 'a';
System.out.println("i2 = " + i2);
//아스키코드기 때문에 문자로 자동 형변환 해준다.
char c1 = 98;
System.out.println("c1 = " + c1);
}
}
※ 결과값
i1 = 5
d1 =5.0
b1 = 5
b1 =105
b1 =110
f1 =3.14
f1 = 5.6400003
i2 = 97
c1 = b
매우 큰 값의 경우는 어떨까?
class Op5{
public static void main(String[] args){
double d1 = 3.5, d2 = 2.3;
//값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.
int i1 = (int)d1 + (int)d2;
System.out.println("i1 = " + i1);
d1 = (double)i1; //d1 = (double) i1;
System.out.println("d1 =" +d1);
byte b1 = (byte)i1;
System.out.println("b1 = " + b1);
b1 = 100 + 5;
System.out.println("b1 =" + b1);
//b1 = (byte)(b1 + 5);
b1 += 5; // b1 = b1 + 5;
System.out.println("b1 =" + b1);
//float f1 = (float)3.14;
float f1 = 3.14f;
System.out.println("f1 =" + f1);
f1 = f1 + 2.5f;
System.out.println("f1 = " + f1);
//아스키코드기 때문에 숫자로 자동 형변환 해준다.
int i2 = 'a';
System.out.println("i2 = " + i2);
//아스키코드기 때문에 문자로 자동 형변환 해준다.
char c1 = 98;
System.out.println("c1 = " + c1);
//i2 = 10000000000;
//정수형으로 안되는 값이기 때문에 L이라는 꼬리표로 형변환시켜준다.
long var = 10000000000L;
}
}
★ 연습문제 ★
https://gist.github.com/muyongseja/472f3c3a8f32a412d4cec00412e935ef
1. 리터를 갤런으로 바꿔보자.
두 개의 double변수를 이용해서 각각 갤런과 리터값을 저장하고
갤런값을 해당하는 리터값으로 바꿔보자.(1갤런은 3.7584리터이다.)
2. 달의 중력은 지구 중력의 17%정도이다.
달에서의 당신의 체중을 계산하는 프로그램을 작성하시오.
66퍼센트 감소하면?
답) 526.32
3. 번개가 얼마나 먼 곳에서 발생했나?
(번개 소리를 들은 사람이 번개가 치는 곳에서부터 몇 피트 정도 떨어져 있는가를 계산하라.
소리는 공기 중은 약 1,100피트/초의 속도로 진행한다.
- 번개를 본 시각과 천둥소리를 들은 시각 사이의 시간을 알면 거리를 계산할 수 있다.
여기서는 7.2초로 가정하자.)
'개발 > Java' 카테고리의 다른 글
[java] 제어문(Control Statement) : 조건문과 반복문 (0) | 2017.10.18 |
---|---|
[java] Dos에서 Java 컴파일 하기 (0) | 2017.10.18 |
[java] 변수(Variable)와 데이터타입(Data Type) (0) | 2017.10.17 |
[java] 주석과 역슬래쉬(\) (0) | 2017.10.17 |
[java] Java 처음 설치 & 환경변수 설정 & JAVA API 보기 (0) | 2017.10.17 |