연산자
산술 연산자
산술 연산자는 사칙연산을 다루는 연산자이다.
산순 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 외쪽에서 오른쪽 방향이다.
int num1 = 8, num2 = 4;
System.out.println("+ 연산자에 의한 결과 : "+ (num1 + num2));
System.out.println("- 연산자에 의한 결과 : "+ (num1 - num2));
System.out.println("* 연산자에 의한 결과 : "+ (num1 * num2));
System.out.println("/ 연산자에 의한 결과 : "+ (num1 / num2));
System.out.println("% 연산자에 의한 결과 : "+ (num1 % num2));
/////////////////////////////
+ 연산자에 의한 결과 : 12
- 연산자에 의한 결과 : 4
* 연산자에 의한 결과 : 32
/ 연산자에 의한 결과 : 2
% 연산자에 의한 결과 : 0
Java
복사
비트 연산자(bitwise operator)
비트 연산자는 bit 단위로 논리연산을 할 때 사용하는 연산자이다.
또한, 비트 단위로 전체 비트를 왼쪽이나 오른쪽으로 이동시킬 때도 사용한다.
AND(&) 연산자의 동작
•
비트 AND 연산자는 대응되는 두 비트가 모두 1일때만 1일 반환하고, 다른 경우는 0을 반환
OR(|) 연산자의 동작
•
비트 OR 연산자는 대응되는 두 비트 중 하나라도 1이면 1을 반환하며, 두 비트가 모두 0일때만 0을 반환한다.
XOR(^) 연산자의 동작
•
비트 XOR 연산자는 대응되는 두 비트가 다르면 1을 반환하고, 서로 같으면 0을 반환한다.
비트 NOT(~) 연산자의 동작
•
비트 NOT 연산자는 해당 비트가 1이면 0을 반환하고, 0이면 1을 반환한다.
int num01 = 15; int num02 = 8;
printf(" ~ 연산자에 의한 결괏값은 %d입니다.\n", ~num01); // 1의 보수
printf("<< 연산자에 의한 결괏값은 %d입니다.\n", num02 << 1); // 곱하기 2
printf(">> 연산자에 의한 결괏값은 %d입니다.\n", num02 >> 1); // 나누기 2
///////////////////////////////////////////////////////////////////////
// 실행 결과
~ 연산자에 의한 결괏값은 -16입니다.
<< 연산자에 의한 결괏값은 16입니다.
>> 연산자에 의한 결괏값은 4입니다.
Java
복사
관계 연산자
비교 연산자라고도 하며, 좌항과 우항을 비교하여 boolean 값으로 반환하는 연산자를 말한다.
int num1 = 8, num2 = 4;
System.out.println("> 연산자의 의한 결과 : "+ (num1 > num2));
System.out.println("< 연산자에 의한 결과 : "+ (num1 < num2));
System.out.println("!= 연산자에 의한 결과 : "+ (num1 != num2));
///////////////////////////////////////////////////////////////
> 연산자의 의한 결과 : true
< 연산자의 의한 결과 : false
!= 연산자의 의한 결과 : true
Java
복사
논리 연산자
주어직 논리식을 판단하여, 참과 거짓을 결정하는 피연산자를 말한다.
char ch1 = 'b', ch2 = 'B';
boolean result1, result2;
result1 = (ch1 > 'a') && (ch1 < 'z') ;
result2 = (ch2 < 'A') || (ch2 < 'Z') ;
System.out.println("&& 연산자에 의한 결과 : "+ result1);
System.out.println("|| 연산자에 의한 결과 : "+ result2);
System.out.println("! 연산자에 의한 결과 : "+ !result2);
///////////////////////////////////////////////
&& 연산자에 의한 결과 : true
|| 연산자에 의한 결과 : true
! 연산자에 의한 결과 : false
Java
복사
단락회로평가(short circuit evaluation)
•
단락회로 평가는 논리 연산자를 사용할 때 고려해야 할 사항으로 두 항 중 앞의 항에서 결과값이 정해지는 경우, 뒤의 값이 참인지 거짓인지 평가하지 않는 것을 단락회로 평가라고 한다.
•
아래의 예시에서 num1의 값이 이미 10보다 크거나 같기 때문의 if 문의 조건을 충족하게 되고, 따라서 뒤쪽의 num2 값의 비교를 수행하지 않게 된다.
int num1 = 10, num2 = 20;
if(num1++ >= 10 || num2++ >= 20) System.out.println("true");
System.out.println("num1 : " + num1);
System.out.println("num2 : " + num2);
/////////////////////////////////////
num1 : 11
num2 : 20
Java
복사
instanceof
객체가 특정 클래스 / 인터페이스 유형인지 여부를 확인하는 명령어
객체 instanceof 클래스 형태로 사용하며, 좌항이 우항의 특정 클래스/인터페이스인 경우 참을 반환, 아닌 경우에는 false를 반환한다.
class A {}
class B extends A {}
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true
System.out.println(a instanceof B); // false
System.out.println(b instanceof B); // true
}
Java
복사
할당 연산자(대입 연산자)
변수에 값을 대입할 때 사용하는 이항 연산자이며, 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다. 또한, 자바에서는 대입 연산자와 다른 연산자를 결합하여 만든 다양한 복합 대입 연산자를 제공한다.
int num1 = 7, num2 = 7, num3 = 7;
num1 = num1 - 3;
num2 -= 3;
num3 =- 3;
System.out.println("- 연산자에 의한 결과 : "+ num1);
System.out.println("-= 연산자에 의한 결과 : "+ num2);
System.out.println("=- 연산자에 의한 결과 : "+ num3);
//////////////////////////////////////////////////
- 연산자에 의한 결과 : 4
-= 연산자에 의한 결과 : 4
=- 연산자에 의한 결과 : -3
Java
복사
Java의 Reference Type과 연산자
•
Java의 Primitive Type과 Reference Type 은 연산자에 의한 결과가 다른 값을 가진다.
•
대표적인 예로 아래의 두가지가 있다.
◦
== 연산자
◦
= 연산자
== 연산자와 객체의 동등비교
값 비교와 참조값 비교에 대한 이해
•
자바의 Reference Type 변수는 변수의 실제 value가 아닌 Referece 값을 가지고 있다.
Reference Type 변수로 == 연산자를 통해 값을 비교하는 경우에는 참조변수 내부의 실제 value가 아닌 객체의 Reference 값의 비교를 하게 된다. (Reference value + hashcode 비교)
•
Reference Type 참조변수의 내부 값을 이용한 비교를 하고 싶은 경우에는
.equals() 메서드를 통해 값의 비교를 수행할 수 있다.
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2) // false
System.out.println(s1.equals(s2)) // true
Java
복사
= 연산자와 깊은 복사, 얕은 복사
주소 할당과 값 할당의 차이에 대한 이해
•
Shallow copy(얕은 복사)는 '주소값'을 복사한다. (참조하고 있는 실제값은 같다)
Deep copy(깊은 복사)는 '실제값'을 새로운 메모리 공간에 복사한다.
•
배열의 값을 복사하기 위해 = 연산자를 사용하는 경우 얕은 복사로 인한 문제가 발생할 수 있다.
◦
이러한 문제를 방지하기 위해 아래의 메서드를 사용할 수 있다.
▪
.clone()
▪
Arrays.copyOf(원본배열, 내가 원하는 length까지)
▪
System.copyOfRange(원본배열, 원하는 시작점, 원하는 끝점)
▪
System.arrayCopy()
◦
주로 2차원 배열의 복사에서 많이 발생하며,
2차원 배열의 모든 행에 대해 .clone 메소드를 통해 깊은 복사를 수행하던가,
2중 반복문을 통해 배열의 모든 값을 복사하는 방법으로 해결할 수 있다.
int arr1[] = new int[5]{1,2,3,4,5};
int arr2[] = new int[5]{6,7,8,9,10};
for(int data : arr2){
System.out.println(data + " "); // 6 7 8 9 10
}
arr2 = arr1; // 얕은 복사 수행
arr1[0] = 11;
arr1[1] = 12;
// arr1의 값을 수정했지만, 얕은 복사로 인해 참조값이 대입되었기 때문에
// arr1 값의 변경이 arr2의 값에 영향을 줌
for(int data : arr2){
System.out.println(data + " "); // 11 12 8 9 10
}
Java
복사
화살표(→) 연산자
화살표 연산자는 Java 8 버전부터 추가된 것으로, 람다 표현식과 함께 사용된다.
람다 표현식
•
익명 메서드만 전달하여, 인터페이스를 구현한 익명 클래스의 인스턴스를 생성하는 방법
•
메서드만 전달하지만, 결과적으로 익명 구현 객체를 만들게 된다.
•
람다식이 구현할 인터페이스는 단 1개의 추상 메서드만 가지고 있어야 한다.
•
람다식이 구현할 인터페이스는 @FunctionalInterface 어노테이션이 선언되어있어야 한다.
•
익명 메소드를 전달하면, 단 1개의 추상 메소드를 구현한 익명 인스턴스를 생성해낸다.
람다식을 이용한 예시
•
인스턴스 생성 코드를 생략하고, 메서드만 전달할 수 있다.
new Thread(() -> {
for (int i=0; i<10; i++) {
System.out.println("run!");
}
}).start();
Java
복사
람다식의 주요 활용처
•
Runnable 인터페이스의 run() 구현
•
Comparable 인터페이스의 compareTo() 구현
3항 연산자
자바에서 유일하게 피연산자를 세 개 가지는 조건 연산자로,
물음표(?) 앞의 조건식에 따라 결과값이 참이면 반환값 1을 반환하고, 아닌 경우 반환값 2를 반환한다.
int num1 = 5, num2 = 7;
int result;
result = (num1 - num2 > 0) ? num1 : num2;
System.out.println("두 정수 중 더 큰 수는 " + result + "입니다.");
///////////////////////////////////////
두 정수 중 더 큰 수는 7입니다.
Java
복사
연산자 우선순위
•
모든 연산자에는 우선순위가 존재하며, 우선순위에 따라 실행 순서가 달라지게 된다.
•
모든 것을 정확하게 외울 필요는 없고 간단하게 아래의 정도만 숙지하여도 문제없다
1.
괄호 연산자의 우선순위가 가장 높다.
2.
* , / , % 연산자의 우선순위가 +, - 연산자보다 높다
3.
++, — 의 우선순위가 * , / , % 보다 높다
4.
산술연산이 관계연산을 만드므로, 관계 연산자>,<,==,!=가 산술연산보다 우선순위가 낮다.
•
모든 연산자의 우선순위는 아래 링크에서 확인
Switch 연산자
Java 12부터 switch 연산자가 추가되었다.
기존의 switch 문이 변경된 것이 아니라. switch 연산자가 추가된 것
switch statement
•
다수의 case, break가 존재하게 된다.
•
break; 를 빼먹을 경우 다음 분기로 넘어가게 된다.
•
return 값이 존재할 수 없다.
switch operator
•
break를 사용하지 않아도 된다.
•
yield 값이 존재한다.
•
return값이 존재할 수 있다.
•
case → A 의 형식으로 표현 가능하다
•
switch의 반환값이 따로 필요하지 않거나 case가 switch 들어오는 모든 인자를 커버하는 경우 default 항목을 넣어주지 않아도 되나 그렇지 않은 경우는 default -> code를 작성해야 한다.
[ Java12 ]
1. ->(화살표) 표현이 가능하고 data만 존재할 경우 return이 가능하다.
2. -> 구문을 사용할 경우 break;를 적지 않아도 다음 case 구문으로 넘어가지 않는다.
3. -> 표현 오른쪽은 꼭 단일 수행일 필요는 없다. 블록 {} 안에서의 작업도 가능하다.
[ Java13 ]
1. yield 예약어가 추가됨. yield x 하게 되면 x가 리턴됨.
2. yield는 예약어이지만 변수명으로 사용가능하다. int yield = 3;
public class Main {
public static void main(String[] args) {
//Java 12 이전
int num = 1;
int returnNum = 0;
switch(num){
case 1:
returnNum = 1;
System.out.println("1들어옴");
break;
case 2:
returnNum = 2;
System.out.println("2들어옴");
break;
case 3:
returnNum = 3;
System.out.println("3들어옴");
break;
}
System.out.println("returnNum : [ " + returnNum + " ]");
//Java 12
returnNum = switch(num){
case 1 -> 1;
case 2 -> 2;
default -> throw new IllegalStateException("Unexpected value: " + num);
};
System.out.println("returnNum : [ " + returnNum + " ]");
//Java13
returnNum = switch(num){
case 1 : yield 3;
default : throw new IllegalStateException("unexpected value : " + num);
};
System.out.println("returnNum : [ " + returnNum + " ]");
}
}
1들어옴
returnNum : [ 1 ]
returnNum : [ 1 ]
returnNum : [ 3 ]
Java
복사