Search
Duplicate
😀

03. 연산자

태그
연산자
instanceof

연산자

산술 연산자

산술 연산자는 사칙연산을 다루는 연산자이다. 산순 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 외쪽에서 오른쪽 방향이다.
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
복사