연산자와 피연산자 구별하기
9 * x + 3
"모든 연산자는 연산결과를 반환한다."
즉, 연산결과를 반환하지 않으면 연산자가 아니다.
ex) ()괄호는 연산자가 아님.
산술 연산자
산술 연산자의 종류에는 +, -, *, /, %, <<, >> 가 있다.
사칙 연산과 나머지 연산(%) 기호들이다.
비교 연산자
비교 연산자의 종류에는 <, >, >=, <=, ==, !=가 있다.
크고 작음과 같고 다름을 비교한다.
논리 연산자
논리 연산자의 종류에는 &&, ||, !, &, |, ^, ~가 있다.
'그리고(AND)'와 '또는(OR)'으로 조건을 연결한다.
대입 연산자
대입 연산자 기호는 = 이다.
우변의 값을 좌변에 저장한다.
기타 연산자
기타 연산자에는 (type) ?:instanceof 가 있다.
형변환 연산자, 삼향 연산자, instanceof 연산자 이다.
- 산술 > 비교 > 논리 > 대입 : 대입은 제일 마지막에 수행된다.
- 단항(1) > 이항(2) > 삼항(3) : 단항 연산자의 우선순위가 제일 높다.
- 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행 방향은 왼쪽에서 오른쪽이다.
증가 연산자(++) : 피연산자의 값을 1 증가시킨다.
감소 연산자(--) : 피연산자의 값을 1 감소시킨다.
타입 | 설명 | 사용예 |
---|---|---|
전위형 | 값이 참조되기 전에 증가/감소 시킨다. | k == +j; k = --j; |
후위형 | 값이 참조된 후에 증가/감소 시킨다. | k == j++; k == j--; |
' - ' 는 피연산자의 부호를 바대로 변경한다.
' + ' 는 아무런 일도 하지 않는다. (실제로 사용하지 않음)
형변환이란?
: 변수 또는 상수의 타입을 다른 타빙으로 변환 하는 것을 의미한다.
(type)피연산자
변환 | 수식 |
---|---|
int -> char | (char)65 |
char -> int | (int)'A' |
float -> int | (int)1.6f |
int -> float | (float)10 |
- 예제코드
class Operator3_1 {
public static void main(String[] args) {
int i = 65, num = 10;
char ch = 'A';
float f = 1.6f;
System.out.println("(char)i = " + (char)i);
System.out.println("(int)ch = " + (int)ch);
System.out.println("(int)f = " + (int)f);
System.out.println("(float)num = " + (float)num);
}
}
float f = 1234; => int 타입의 값을 float 타입의 변수에 저장한다.
- 상대적으로 int 타입이 float 타입 보다 크기가 작기 때문에 가능합니다.
float f = (float)1234; => 사실 변수와 리터럴의 타입을 일치 시켜줘야 합니다.- 우리가 보는 코드에는 형변환이 생략되어 있었습니다.
즉, 컴파일러에 의해 자동으로 형변환된 것입니다.
int i = 3.14f;
- 이렇게 큰 타입을 작은 타입에 저장할 때 Error가 발생합니다.
- 3.14f 가 int 타입으로 변환될 때 소수점이 사라지면서 원래 값이 달라집니다.
- 즉, 값 손실이 발생하는데 이런 경우, 컴파일러가 자동으로 형변환을 안 해줍니다.
int i =(int)3.14f; =>이렇게 직접 수동으로 형 변환을 시켜주어야 합니다.
"기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환된다."
- 형변환을 하는 이유는 주로 서로 다른 두 타입을 일치시키기 위해서인데, 형변환을 생략하려면 컴파일러가 알아서 자동으로 형변환을 해야합니다.
- 따라서 표현범위가 좁은 타입에서 넓은 타입으로 형변환하는 경우에는 값 손실이 없음으로 두 타입 중에서 표현 범위가 더 넓은 쪽으로 형변환됩니다.
- 예제코드
class Operator3_2 {
public static void main(String[] args) {
// 큰 타입을 작은 타입에 저장!
// int i = 3.14f; // Error 발생
int i = (int)3.14f; // 형변환 필요!
System.out.println("i = " + i);
// 예외 경우 확인
// 100 은 int 타입 따라서 아래 코드는 현재 큰 타입(int)을 작은 타입(byte)에 넣고 있음!
// 컴퓨터는 byte의 범위가 -128 ~ 127 인 것을 알고 있다.
// 따라서 100을 byte b 에 집어 넣어도 값 손실이 발생하지 않는 다는 것을 알기 때문에
// 자동으로 형변환을 해준다.
// byte b = (byte)100; -> 컴파일러가 자동 형변환
byte b = 100; // OK
System.out.println("b = " + b);
// 위의 경우는 100 은 리터럴 즉, 상수이기 때문에 컴파일러가 값을 명확하게 알지만
// 아래 num 은 변수, 따라서 확신할 수 없기 때문에 Error 발생
int num = 100;
// byte b2 = num; // Error 발생
byte b2 = (byte) num; // byte 타입으로 형변환
System.out.println("b2 = " + b2);
// byte b3 = 1000; // Error 발생, 범위를 넘어감
byte b3 = (byte) 1000;
// OK, 그러나 값 손실 발생, b3 에는 -24 가 저장됨
// 즉, 상수여도 값 손실이 일어나면 자동 형변환 불가능!
System.out.println("b3 = " + b3);
}
}
사칙 연산자
덧셈(+) 뺄셈(-) 곱셈(*) 나눗셈(/)
- 예제코드
class Operator4_1 {
public static void main(String[] args) {
int a = 10, b = 4;
// 덧셈
System.out.print("a + b = ");
System.out.println(a + b);
// 뺄셈
System.out.print("a - b = ");
System.out.println(a - b);
// 곱셈
System.out.print("a b = ");
System.out.println(a b);
// 나눗셈
// 소수점 이하는 버려진다.
System.out.print("a / b = ");
System.out.println(a / b);
// 10 / 4.0f -> 10.0f / 4.0f -> 2.5
System.out.print("a / (float)b = ");
System.out.println(a / (float)b);
}
}
연산 전에 피연산자의 타입을 일치시키는 것을 의미한다.
1. 두 피연산자의 타입을 같게 일치시킨다.
(보다 큰 타입으로 일치)
- long + int -> long + long => long
- float + int -> float + float => float
- double + float -> double + double => double
- 피연산자의 타입이 int 보다 작은 타입이면 int로 변환된다.
- byte + short -> int + int => int
- char + short -> int + int => int
- 이는 int 보다 작은 타입이 계산을 통해 쉽게 범위가 넘어갈 수 있기 때문에 오버플로우가 발생해,
정확한 계산값을 가져오지 못할 수 있어서 미리 큰 범위인 int 타입으로 변환시킨 후 계산하는 것이다.
class Operator4_2 {
public static void main(String[] args) {
char ch = '2';
// 문자 '2' 는 숫자로 50, '0' 은 48
// 따라서 int 타입으로 자동으로 변하기 때문에 50 - 48 = 2
System.out.print("ch - '0' = ");
System.out.println(ch - '0');
int a = 1_000_000; // 1백만
int b = 2_000_000; // 2백만
// a b = 2_000_000_000_000 -> 10^12
// long 에 저장하려는 것은 맞지만 a b 의 결과 타입이 int
// 따라서 이미 계산을 할 때 오버플로우 발생! -> 따라서 계산을 할 때 형변환 필요!
// long l = a b; // -1454759936
long l = (long)a b;
// long int -> long long => 1_000_000L 2_000_000 -> 1_000_000L 2_000_000L
System.out.println("l = " + l);
}
}
Math는 수학과 관련된 메서드를 가지고 있는 클래스이다.
메서드는 '특정한 기능을 수행하기 위해 코드로 작성된 단위!' 라고 생각하면 된다.
round() : 실수를 소수점 첫째자리 에서 반올림 한 정수를 반환
cell() : 올림값을 double 형으로 반환
floor() : 내림값을 double 형으로 변환
abs() : int, double 기본형 모두 사용 가능하며 절대값을 얻는다.
예제코드 1
class Operator5_1 {
public static void main(String[] args) {
long result = Math.round(3.645678);
System.out.println("result = " + result);
// 소수점 4째 자리에서 반올림한 값을 구하라!
double pi = 3.141592;
// pi 1000 = 3141.592
// Math.round(3141.592) = 3142
// 3142 / 1000.0 = 3.142
double shortPi = Math.round(pi 1000) / 1000.0;
System.out.println(shortPi); // 3.142
// 3.141 구하기!
double pi2 = 3.141592;
// pi2 1000 = 3141.592
// (int)3141.592
System.out.println("(int)(pi2 1000) = " + (int) (pi2 1000));
System.out.println("(int)(pi2 1000) / 1000.0 = " + (int) (pi2 * 1000) / 1000.0);
}
}
예제코드 2
class Operator5_2 {
public static void main(String[] args) {
double num = 3.14;
System.out.println("반올림 : " + Math.round(num)); // 반올림 : 3
System.out.println("올림 : " + Math.ceil(num)); // 올림 : 4.0
System.out.println("내림 : " + Math.floor(num)); // 내림 : 3.0
System.out.println("절대값 : " + Math.abs(num*-1)); // 절대값 : 3.14
}
}
class Operator5_3 {
public static void main(String[] args) {
int x = 10;
int y = 8;
System.out.print("x를 y로 나눈 몫 = ");
System.out.println(x / y);
System.out.print("x를 y로 나눈 나머지 = ");
System.out.println(x % y);
// 부호 무시 확인
int n = 3;
int z = -3;
System.out.println("x % n = " + x % n);
System.out.println("x % z = " + x % z);
}
}
비교 연산자 | 설명 |
---|---|
== | 왼쪽의 피연산자와 오른쪽의 피연산자가 같으면 참을 반환함 |
!= | 왼쪽의 피연산자와 오른쪽의 피연산자가 같지 않으면 참을 반환함 |
> | 왼쪽의 피연산자가 오른쪽의 피연산자보다 크면 참을 반환함 |
>= | 왼쪽의 피연산자가 오른쪽의 피연산자보다 크거나 같으면 참을 반환함. |
< | 왼쪽의 피연산자가 오른쪽의 피연산자보다 작으면 참을 반환함. |
<= | 왼쪽의 피연산자가 오른쪽의 피연산자보다 작거나 같으면 참을 반환함. |
두 피연산자를 비교해서 ture(참) 또는 false(거짓)를 반환한다.
예제코드
class Operator6_1 {
public static void main(String[] args) {
int n1 = 10, n2 = 6;
char c1 = 'A', c2 = 'B';
System.out.print("n1 >= n2 = " ); // true
System.out.println(n1 >= n2);
System.out.print("n1 <= n2 = " ); // false
System.out.println(n1 <= n2);
System.out.print("n1 == n2 = " ); // false
System.out.println(n1 == n2);
System.out.print("n1 != n2 = " ); // true
System.out.println(n1 != n2);
// 산술변환 규칙에 의해서 char 타입이 int 타입으로 변환되어 연산됨
System.out.print("c1 < c2 = "); // true
System.out.println(c1 < c2); // 65 < 66
System.out.print("c1 > c2 = "); // false
System.out.println(c1 > c2); // 65 > 66
}
}
문자열 비교에는 == 대신 equals()를 사용해야 한다.
- equals : 비교하고자 하는 두 피연산자의 값 자체를 비교한다
- == : 비교하고자 하는 두 피연산자의 주소값을 비교한다
지금은 '문자열 비교에는 == 대신 equals()를 사용해야 한다!'만 기억하면 된다.
예제코드
class Operator6_2 {
public static void main(String[] args) {
String s1 = "사랑";
String s2 = "사랑";
System.out.print("s1 == s2 = "); // true
System.out.println(s1 == s2);
System.out.println("s1.equals(s2) = " + s1.equals(s2)); // true
// 하지만!
String s3 = new String("사랑");
System.out.print("s1 == s3 = "); // false
System.out.println(s1 == s3);
System.out.println("s1.equals(s3) = " + s1.equals(s3)); // true
}
}
논리 연산자 | 설명 |
---|---|
&& | 논리식이 모두 참이면 참을 반환함. (논리 AND 연산) |
∥ | 논리식 중에서 하나라도 참이면 참을 반환함. (논리 OR 연산) |
! | 논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환함. (논리 NOT 연산) |
A | B | A&&B | A∥B | !A |
---|---|---|---|---|
true | true | true | true | false |
true | flase | false | true | flase |
flase | true | flase | treu | true |
false | false | false | false | true |
class Operator7_1 {
public static void main(String[] args) {
boolean result1, result2, result3, result4, reusult5, result6;
char ch1 = 'a', ch2 = 'B'; // 'a' : 97 , 'A' : 65, 'B' : 66, 'C' : 67
result1 = ch1 > 'A' && ch2 < 'C';
result2 = ch1 == 'A' && ch2 < 'C';
result3 = ch1 > 'A' || ch2 < 'C';
result4 = ch1 < 'A' || ch2 > 'C';
System.out.println("&& 연산자에 의한 결과 result1 = " + result1); // true
System.out.println("&& 연산자에 의한 결과 result2 = " + result2); // false
System.out.println("|| 연산자에 의한 결과 result3 = " + result3); // true
System.out.println("|| 연산자에 의한 결과 result4 = " + result4); // false
System.out.println("! 연산자에 의한 결과 result4 = " + !result4); // true
System.out.println();
int num = 10;
// num 은 2의 배수 그리고 3의 배수이다.
reusult5 = num % 2 == 0 && num % 3 == 0;
System.out.println("num 은 2의 배수 그리고 3의 배수 = " + reusult5); // false
// num 은 2의 배수 또는 3의 배수이다.
result6 = num % 2 == 0 || num % 3 == 0;
System.out.println("num 은 2의 배수 또는 3의 배수 = " + result6); // true
}
}
비트연산자 | 설명 |
---|---|
& | 대응되는 비트가 모두 1이면 1을 반환함 (비트 AND 연산) |
| | 대응되는 비트 중에서 하나라도 1이면 1을 반환함 (비트 OR 연산) |
^ | 대응되는 비트가 서로 다르면 1을 반환함 (비트 XOR 연산) |
~ | 비트를 1이면 0으로, 0이면 1로 반전 시킴 (비트 NOT 연산, 1의 보수) |
<< | 명시된 수 만큼 비트들을 전부 왼쪽으로 이동시킴 (left shift 연산) |
>> | 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴 (right shift 연산) |
>>> | 지정한 수만큼 비트를 전부 오른쪽으로 이동시키며, 새로운 비트는 전부 0이 됨 |
비트 연산자는 값을 비트 단위로 연산한다.
따라서 0과 1로 표현이 가능한 정수형이나 형변환이 가능한 자료형만 연산이 가능함
예제코드
class Operator7_2 {
public static void main(String[] args) {
int num1 = 8, num2 = -8;
System.out.println("8의 2진수 = " + Integer.toBinaryString(num1)); // 0 생략 가능!
System.out.println("-8의 2진수 = " + Integer.toBinaryString(num2));
System.out.println("-9의 2진수 = " + Integer.toBinaryString(-9)); // 32bit, int = 4byte
// 00000000000000000000000000001000 , 8
// 11111111111111111111111111111000 , -8
System.out.println("& 연산자에 의한 결과 = " + (num1 & num2)); // 00000000000000000000000000001000, 8
System.out.println("| 연산자에 의한 결과 = " + (num1 | num2)); // 11111111111111111111111111111000, -8
System.out.println("^ 연산자에 의한 결과 = " + (num1 ^ num2)); // 11111111111111111111111111110000, -16
System.out.println("~ 연산자에 의한 결과 = " + ~num1); // 11111111111111111111111111110111, -9
System.out.println("<< 연산자에 의한 결과 = " + (num1 << 2)); // 32
System.out.println(">> 연산자에 의한 결과 = " + (num2 >> 2)); // -2
System.out.println(">>> 연산자에 의한 결과 = " + (num2 >>> 2)); // 1073741822
}
}
조건 연산자
삼항 연산자 : 조건식 ? 반환값 1 : 반환값2
- 조건식의 결과에 따라 연산결과를 달리할 수 있다.
예제코드
class Operator8_1 {
public static void main(String[] args) {
int num1 = 5, num2 = 7;
int result;
result = num1 - num2 > 0 ? num1 : num2;
System.out.println("두 정수 중 더 큰 수는 " + result + "입니다."); // 7
}
}
대입 연산자
대입 연산자 | 설명 |
---|---|
= | 왼쪽의 피연산자에 오른쪽의 피연산자를 대입함 |
+= | 왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
-= | 왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
*= | 왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
/= | 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
%= | 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
&= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
!= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
^= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
<<= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
>>= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
>>>= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트한 후, 그 결과값을 왼쪽의 피연산자에 대입함 |
class Operator8_2 {
public static void main(String[] args) {
int num1 = 7, num2 = 7, num3 = 7;
num1 = num1 - 3;
num2 -= 3;
num3 =- 3;
System.out.println("- 연산자에 의한 결과 : "+ num1); // 4
System.out.println("-= 연산자에 의한 결과 : "+ num2); // 4
// = 위치를 주의하셔야 합니다.
// num3 =- 3; 는 num3 = -3 입니다.
System.out.println("=- 연산자에 의한 결과 : "+ num3); // -3
}
}