관리 메뉴

JIE0025

[WhiteShip][3주차] 연산자 본문

개발/Java, Kotlin

[WhiteShip][3주차] 연산자

Kangjieun11 2022. 11. 3. 01:58
728x90

 

 

WhiteShip Java Live Study 의 커리큘럼을 따라 개인적으로 공부한 내용입니다.

 

 

 

 


Codestates BE 42 : Study, Commercise 01 Java

 

Thanks to

" Codestates_SEB_BE_42 : Commercise "

강지은, 김례화, 전진우, 주대경

 

 22.11.02

 

 


 

 

3주차 : 연산자

 

 

목차

  • 산술 연산자
  • 비트 연산자
  • 관계 연산자
  • 논리 연산자
  • instanceof
  • assignment(=) operator
  • 화살표(->) 연산자
  • 3항 연산자
  • 연산자 우선 순위
  • (optional) Java 13. switch 연산자

 

 


 

 

✅ 산술 연산자

+, -, *, / (사칙연산) + %, ++, --

 

  • 산술 연산자의 동작은 우리가 알고 있는 일반적인 수학 연산과 거의 동일
  • 연산은 왼쪽에서부터 오른쪽으로 진행 함

 

 


 

✅ 비트 연산자

피연산자를 비트 단위로 논리연산한다. (이진수로 표현하고 논리연산)

 

비트 연산자  설명
& 대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산)
| 대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산)
^ 대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산)
~ 비트를 1이면 0으로, 0이면 1로 반전시킴. (비트 NOT 연산, 1의 보수)
<< 명시된 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산)
>> 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산)
>>> 지정한 수만큼 비트를 전부 오른쪽으로 이동시키며, 새로운 비트는 전부 0이 됨.

 

TCP SCHOOL.com 에서 가져온 이미지

 

시프트 연산자

 

비트 이동 연산자는 정수 데이터의 비트를 왼쪽 또는 오른쪽으로 이동시키는 연산을 함

 

기호  설명  예시
<< 왼쪽 항을 왼쪽으로 오른쪽 항만큼 시프트 a << 2
>> 왼쪽 항을 오른쪽으로 오른쪽 항만큼 시프트 a >> 2
>>> >>와 동일 (단, unsigned 부호없음) a >>> 2

 

 

왼쪽으로 Shift  한번   ==     *2 

오른쪽으로 Shift 한번  ==   /2  

 

 

그림 1, 2

그림 1)

num = 2인데 왼쪽으로 shift 2 되어 곱하기 4와 같아  8로 변했다. 

00010  ⏩   01000 

 

그림 2)

num = 40인데 오른쪽으로 shift 2되어,  나누기 4와 같아  10으로 변했다. 

0101000  ⏩  0001010

 

 

 

 

 

 

⏺  >>   vs   >>>

>> 와 >>>는 양수를 계산할 때는 차이가 없지만, 음수를 계산할 때 차이가 남.

>> 는 시프트 연산을 하고 빈 공간을 1로 채움.

>>>는 시프트 연산을 수행하고 빈 공간을 0으로 채움 (때문에 - 부호가 사라져서 + 부호가 됨)

 

 


 

관계 연산자 (=비교 연산자)

두 값을 비교하는 데 사용.

비교 반환값 : true, false ( boolean 값 )

 

 


 

논리 연산자

주어진 논리식을 판단하여, 'true', 'false'를 결정하는 연산자

 

AND ( && ) , OR (  ||  ) 

  • 두 개의 피연산자를 가지는 이항 연산자
  • 연산 방향 : 왼쪽에서 오른쪽

 

NOT ( ! )

  • 연산자는 피연산자가 단 하나 뿐인 단항 연산자
  • 연산 방향 : 오른쪽에서 왼쪽

 

  • && : 논리식이 모두 true이면 true 를 반환 (AND 연산)
  • || : 논리식 중에 하나라도 true이면 true 를 반환(OR 연산)
  • ! : 논리식의 결과가 참이면 거짓을, 거짓이면 참을 변환함 (NOT 연산)

 


 

✅ 복합 대입 연산자 Assignment(=) Operator

 

기호  설명  풀이
+= 좌변의 변수 + 연산하고 좌변에 할당 a = a + 1
-= 좌변의 변수 - 연산하고 좌변에 할당 a = a - 1
*= 좌변의 변수 * 연산하고 좌변에 할당 a = a * 1
/= 좌변의 변수 / 연산하고 좌변에 할당 a = a / 1
%= 좌변의 변수 % 연산하고 좌변에 할당 a = a % 1
&= 좌변의 변수 & 연산하고 좌변에 할당 a = a & 1
^= 좌변의 변수 ^ 연산하고 좌변에 할당 a = a ^ 1
ㅣ = 좌변의 변수 ㅣ 연산하고 좌변에 할당 a = a ㅣ 1
<<= 좌변의 변수 << 연산하고 좌변에 할당 a = a << 1
>>= 좌변의 변수 >> 연산하고 좌변에 할당 a = a >> 1
>>>= 좌변의 변수 >>> 연산하고 좌변에 할당 a = a >>> 1

 

복합 대입 연산자 예제

&= 예제

 

^= 예제

 

<<= 예제

 

 


 

 

✅ instanceof

변수가 참조하고 있는 객체의 실제타입을 확인하기 위해 사용하는 연산자

  • 형변환이 가능한지 여부를 알기 위해 사용
  • boolean (true/false) 타입을 이용해 결과값 반환

 

참조변수  instanceof  타입/class명 

//결과 : boolean

 

 

⏺언제 사용할까? 

(설명용으로 급하게 만든 예시입니다..)

 

자동차 <- 현대자동차 <-  A , B, C (대문자영어 : 차 종류) — a, b, c (소문자영어 : 차 종류별 인스턴스)

 

현대자동차 기업이 운영하지만, 어떤차든 이용할 수 있는 서비스를 만들었음

근데 현대 자동차에만 어떤 동작을 시키려고 함

이럴때 인스턴스a가 현대자동차(객체)인지 확인한다.

if( a instanceof 현대자동차) {   
   // 어떤 동작
}

 

⏺ 상위클래스와 하위클래스의 관계

변수의 타입 클래스가 다른 클래스를 상속받는 클래스인 경우, 상위클래스를 대상으로 instanceof 연산 수행하면, true반환

[하위클래스instance]    instanceof    [상위클래스]

 

 

예제코드

* redBeanBreadMachine을 만들고 싶었는데 급하게 코드 작성하느라 redBeanFishBread가 되어버림..

(팥빵기계로 자연스럽게 읽으시길...)

public class Main {
    public static void main(String[] args) {
        BreadMachine myMachine = new BreadMachine();
        System.out.println(myMachine instanceof BreadMachine);
        System.out.println(myMachine instanceof redBeanFishBread);

        BreadMachine yourMachine = new redBeanFishBread();
        System.out.println(yourMachine instanceof BreadMachine);
        System.out.println(yourMachine instanceof redBeanFishBread);

    }
    public static class BreadMachine{
        public BreadMachine(){
            //만능 빵을 만들어내는 기계 (생성자)
        }
    }

    public static class redBeanFishBread extends BreadMachine {
        public redBeanFishBread(){
            //팥빵만 생성 가능한 기계 (생성자)
        }
    }
}
  • 코드를 보면, 자식클래스가 부모를 선택하는것을 볼 수 있음 // (팥빵기계) extends (빵기계)

 

 

⏺ 인터페이스와 클래스(구현부)의 관계

인터페이스를 구현하는 클래스의 경우 인터페이스를 대상으로 instanceof 연산 수행하면, true반환

 

[구현 클래스] instanceof [인터페이스]

 

 

public class Main {
    public static void main(String[] args) {
				
				//연산 수행 [class instance] instanceof [interface]
        System.out.println(myMachine instanceof Machine);
        System.out.println(yourMachine instanceof Machine);
				
				// yourMachine instanceof 연산자로 Machine 으로 바꿀 수 있음을 알았다
				// yourMachine에 myMachine을 할당해보고 출력해보자.
        myMachine.run();
        myMachine.stop();
        System.out.println();
        yourMachine.run();
        yourMachine.stop();
        yourMachine = myMachine;
        yourMachine.run();
        yourMachine.stop();

    }

    public interface Machine{
        // 인터페이스는 -- 필요한 기능과 변수를 강제함.

        // 기계의 경우 공통적으로 <동작한다. 멈춘다> 등의 기능이 있을 수 있음  
				// run() ,stop()  ...

        // 기계의 경우 공통적으로 <전원상태, 제작년도> 등의 변수가 있을 수 있음  
				// boolean onState, string date  ...

        public boolean onState =false;
        public void run();
        public void stop();

    }
    public static class BreadMachine implements Machine{
        public BreadMachine(){
            //만능 빵을 만들어내는 기계 (생성자)
        }

        @Override
        public void run(){
            System.out.println("빵기계가 동작합니다.");
        }
        @Override
        public void stop(){
            System.out.println("빵기계를 멈춥니다.");
        }
    }
    public static class redBeanFishBread extends BreadMachine {
        public redBeanFishBread(){
            //팥빵만 생성 가능한 기계 (생성자)
        }
        @Override
        public void run(){
            System.out.println("팥빵기계가 동작합니다.");
        }
        @Override
        public void stop(){
            System.out.println("팥빵기계를 멈춥니다.");
        }
    }

}

yourMachine instanceof Machine 이 true가 나왔기 때문에 대체한 후 동작시켜보는 코드

 

 


 

✅  ( → )화살표 연산자

  • 람다 표현식을 구성하는 데 사용

 

 람다를 알기위해 추가로 필요한 내용들...😂😂


⏺ 익명함수

  • 람다식은 함수의 이름 없이 사용되기때문에 익명함수라고 불리기도 한다.
  • (사실은 익명객체이다.)

 

⏺  람다식에 대한 간략한 이해

  • 하위 내용은 화살표 연산자에 대한 조사로 인해 람다가 무엇인지, 어떻게 이루어지는지 가볍게이해하기 위한 정리글
  • 람다의 정확한 개념과 활용을 위한 지식은 추후에 다룰 예정
    • 람다식의 타입과 형변환
    • 람다식의 외부 변수 참조
    • java.util.function 패키지
    • 메서드 참조 등

 

⏺  람다식 소개

람다란

 

자바의 큰 두가지 변화

1)  JDK 1.5부터의 Generics ( 제네릭 )
2)  JDK 1.8부터의 Lambda expression ( 람다식 )

 

  • 람다식의 도입으로 인해 자바는 객체지향 언어임과 동시에 함수형 언어의 기능을 갖출 수 있었다.
    • 람다는 특정 클래스에 속하지 않고도 사용 가능
    • 그래서 클래스 내에 속하는 함수라는 의미를 내포하는 메서드라는 용어 대신 함수라는 용어를 채택
  • 람다는 메서드를 하나의 식으로 표현한 것
// 일반 메서드 
int max (int a, int b) {
	return a > b ? a : b; 
}

// max() 와 같은 역할을 하는 람다 표현식
(a, b) -> a > b ? a: b

// -------------------------------------------

// 일반메서드 
void printVar(String name, int i) {
	System.out.println(name + " = " + i);
}
// printVar() 와 같은 역할을 하는 람다식
(name, i) -> System.out.println(name + "=" + i)

 

 

장점

  • 간결면서도 이해하기 쉽다.
  • 함수를 정의하기 위해 클래스를 새로 만들 필요없이 필요시 바로 람다식을 통한 메서드 역할 수행이 가능하다.
  • 람다식을 사용하여 메서드를 변수처럼 다루는것이 가능하다.
    • 람다식은 다른 메서드의 매개변수로 전달되어지는것이 가능하다.
    • 람다식은 메서드의 결과로 반환되는것이 가능하다.

단점

  • 지나치게 남발하면 코드가 이해하기 어렵고 지저분해짐.
  • 람다를 사용하여 만든 무명함수는 재사용이 불가능함.

 

 

⏺  람다에서의 타입추론

  • 자바 컴파일러가 타입을 추론하는 것을 타입추론이라고 한다.
    (컴파일러는 타입을 추론하기 위해 메서드 호출과 이에 상응하는 선언부를 살펴 봄)

  • 람다식에 선언된 매개변수의 타입은 추론이 가능한 경우 생략이 가능
  • 반환타입이 없는 이유 역시 추론이 가능하기 때문

** 추후 람다파트( Whiteship Java Live Study 15주차 )에서 자세히 기술

 

⏺  Anonymous class 익명클래스

  • 이름이 없는 클래스 (조상의 클래스이름 또는 인터페이스 이름을 통해 정의)
  • 클래스의 선언 + 객체생성 (동시에)
    • 따라서 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있음 (일회용)
  • 사용예
class Example {
	// 익명클래스 정의 형태 
	Object annyClass01 = new Object() { void methodEx() {}}; 
	static	Object annyClass01 = new Object() { void methodEx() {}};

	void methodNormal(){
		Object annyClass02 = new Object() { void methodEx() {}};
	}
}
// 익명클래스 사용 X 
public class NoAnny {
    public static void main(String[] args) {
        Button buttonStart = new Button("Start");
        buttonStart.addActionListener(new **EventHandler**());
    }
}

class **EventHandler** implements **ActionListener** {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("ActionEvent Occurred !!! ");
    }
}
//---------------------------------------------------------------

// 익명클래스 사용시 
public class YesAnny {
    public static void main(String[] args) {
        Button buttonStart = new Button("Start");
        buttonStart.addActionListener(new **ActionListener**() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("ActionEvent Occurred !!! ");
            }
        });
    }
}

//---------------------------------------------------------------
//---------------------------------------------------------------

interface **MyFunction** {
    public abstract int max(int a, int b);
}

// ...생략 main() 
MyFunction f = new **MyFunction**() {
            @Override
            public int max(int a, int b) {
                return a > b ? a : b;
            }
        };

int maxNum = f.max(3, 50);
// ...생략

 

 

⏺  함수형 인터페이스

 

이해

* 람다식은 어떤 클래스에 포함되어있을까
* 자바에서 모든 메서드는 클래스 내에 포함되어야한다.

 

  • 사실 람다식은 익명 클래스의 객체와 동등하다.
  • 익명클래스에서의 메서드 호출과 마찬가지로  람다식이 익명클래스의 객체와 동등하다면  --  같은 방법으로 호출 가능

 

  • MyFunction 인터페이스를 구현한 익명 객체를 람다식으로 대체 가능한 이유
    • 람다식도 실제로는 익명 객체이기때문
    • MyFunction 인터페이스를 구현한 익명 객체의 메서드 max() 와
    • 람다식의 매개변수의 타입과 갯수 , 반환값이 일치하기 때문
  • 위와 같은 사실들을 통해 하나의 메서드가 선언된 인터페이스를 정의해서 람다식을 다루면 기존의 자바의 규칙들을 어기지 않으면서 자연스럽게 구현 가능

 

람다식을 다루기 위한 인터페이스 : Functional Interface (함수형 인터페이스)

→ 따라서 인터페이스를 통해 람다식을 다루기로 결정

 

 

함수형 인터페이스

@FunctionalInterface
interface MyFunction{
    public abstract int max(int a, int b);
}

// 함수형 인터페이스를 참조변수로 사용 : MyFunction f 
MyFunction f = () -> System.out.println("myMethod is occurred !!!");

 

함수형 인터페이스는 오직 하나의 추상 메서드만 정의되어있어야 한다.

  • 람다식과 인터페이스의 메서드가 1:1 로 연결되어야 하기 때문
  • static 메서드와 defualt 메서드의 개수는 제약이 없다.
  •  @FunctionalInterface  을 붙이면 컴파일러가 함수형 인터페이스 정의를 검사해준다.

 

⏺  람다식의 사용예시

  • 람다식은 매개변수로 사용 가능
@FunctionalInterface
interface MyFunction{
    public abstract int max(int a, int b);
}

// --------------------------생략 
// 다음과 같이 함수형 인터페이스가 어떤 메서드의 매개변수 형으로 선언되어있을때 
void aMethod(MyFunction f) {
        f.myMethod();
}

// --------------------------생략 

MyFunction f = () -> System.out.println("myMethod is occurred !!!");

// 람다식을 참조하는 참조변수가 매개변수로 지정될 수 있다.
aMethod(f);

// 또는 다음과 같은 방식 역시 가능하다.
aMethod(() -> System.out.println("myMethod is occurred !!!"));

 

  • 람다식은 반환될 수 있다.
@FunctionalInterface
interface MyFunction{
    public abstract int max(int a, int b);
}
// --------------------------생략 

// 다음과 같이 함수형 인터페이스가 어떤 메서드의 매개변수 형으로 선언되어있을때 
MyFunction myMethod() {
	MyFunction f = () -> {};
	
	// 람다식을 가리키는 참조변수를 return 
	return f;
	// 또는 다음과 같은 방식 역시 가능
	return () -> {}; // myMethod 함수의 리턴타입이 지정되어있으므로 가능
}

 

 

 

화살표 연산자가 왜이리 깊어졌을까 ㅠㅠ 

 

 

 


 

 

✅ 삼항 연산자

유일하게 세 개의 항으로 만들어진 연산자

 

구조

 

👉🏻 조건식 ? 반환값1 : 반환값2 => 조건식이 true일 경우 반환값1의 값을 반환, false일 경우 반환값2의 값을 반환.

ex)

int a = 10 , int b= 20 //일 때, a > b ? a : b ; //조건식이 ``false`` 이므로 b 반환

cf) 삼항 연산자의 중첩

(조건A)?(조건B)?(반환값A):(반환값B):(반환값C)

  • 우선, (조건A) 가 true인지 false 인지 판단.
  • false이면 (반환값C) 반환.
  • (조건A)가 true일 경우, (조건B)가 true 인지false 인지 판단하여 반환. true 일 경우 : 반환값 A false 일 경우 : 반환값 B

 

 

 


 

✅  연산자 우선 순위

 

 

  • 단항, 이항, 삼항 연산자 순으로 우선순위를 갖는다.
  • 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 갖는다.
  • 단항과 대입 연산자를 제외한 모든 연산 방향은 왼쪽에서 오른쪽이다.
  • 복잡한 연산식에는 ()괄호를 사용해서 우선순위를 정해준다.

 

 


 

(optional) Java 13. switch 연산자

 

 switch 연산자

⏺ 기존 switch

  • 값을 return하고 싶으면 result 변수를 만들어 주어야 함
  • multiple case는 지원하지 않음 case 1: case 2: 이런식으로 붙힘.
  • 다수의 case와 break가 존재하고, break를 빼먹을 경우 다음 분기로 넘어가게 됨
int test(int num) {
        int result = 0;
        switch(num){
            case 1:
            case 2:
                result = 1;
                break;
            case 3:
            case 4:
                result = 2;
                break;
            default:
                result = 3;
                break;
        }
        return result;
    }

 

⏺ Java 13. switch연산자

  • 문장이 아닌, 식으로 가능해서 return값으로 사용 가능하다. (switch문 뒤에 세미콜론; 쓰기)
  • 값을 return할 때 yield 키워드 사용 (자바 13)
  • multiple case를 지원한다.
  • -> 사용 가능 (자바 12)
int test(int num) {
        return switch (num) {
            case 1, 2:
                yield 1;
            case 3, 4:
                yield 2;
            default:
                yield 3;
        };
}

 

⏺ Java 12. switch 연산자

  • :  대신  -> 를 사용
  • multicase : 여러 조건을  ,   로 구분해 한번에 처리 가능
  • break문 생략 가능
  • ->  를  사용했다면, 실행문이 2개이상이거나, 반환값이 존재할 경우  { }   를 사용해야 함.
  • :  를 사용했다면, 실행문이 여러개여도  { }   사용하지 않아도 됨.
public class Main {
    public static void main(String[] args) {

        System.out.println(condition_check("soso"));
        System.out.println(condition_check("sad"));
        System.out.println(condition_check("happy"));

        System.out.println(condition_check2("soso"));
        System.out.println(condition_check2("sad"));
        System.out.println(condition_check2("happy"));
    }
		
		// -> 사용  
    public static String condition_check(String emotion){
        return switch (emotion){
            case "happy", "fun" -> "best";
            case "sad", "angry" -> "not good";
            default -> "--";
        };
    }

		//yield 사용
    public static String condition_check2(String emotion){
        return switch (emotion){
            case "happy", "fun": yield "best";
            case "sad", "angry": yield "not good";
            default: yield "--";
        };
    }
}

 

 

 


 

 

references