ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바의 정석] Chapter03. 연산자
    스터디플래너/공부하기 2022. 1. 2. 22:56

    1. 연산자(operator)
      1. 연산자와 피연산자
        1. 연산자가 연산을 수행하려면 반드시 연산의 대상이 있어야 하는데, 이것을 '피연산자(operand)'라고 한다. 피연산자로 상수, 변수 또는 식 등을 사용할 수 있다. 연산자는 피연산자로 연산을 수행하고 나면 항상 결과값을 반환한다.
      2. 식과 대입연산자
        1. 연산자와 피연산자를 조합하여 계산하고자하는 바를 표현한 것을 식이라고 한다. 그리고 식을 계산하여 결과를 얻는 것을 식을 평가한다고 한다.
      3. 연산자의 종류
        1. 연산자는 기능에 따라 산술 연산자(+ - * / % << >>), 비교 연산자(> < >= <= == !=), 논리 연산자(&& || ! & | ^ ~)), 대입 연산자(=), 그 외 기타 연산자( (type) ?: instanceof)로 나눌 수 있다.
      4. 연산자의 우선순위와 결합규칙
        1. 산술 > 비교 > 논리 > 대입의 순으로 대입은 제일 마지막에 수행한다.
        2. 단항(1) > 이항(2) > 삼항(3)으로 단항 연산자의 우선순위가 이항 연산자보다 높다.
        3. 단항 연산자와 대입 연산자를 제외한 모든 연산자의 진행방향은 왼쪽에서 오른쪽이다.
      5. 산술 변환(usual arithmetic conversion)
        1. 산술 변환이란 연산 수행 직전에 발생하는 피연산자의 자동 형변환이다. 산술 변환은 두 피연산자의 타입을 보다 큰 타입으로 같게 일치시킨다. 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.
    2. 단항 연산자
      1. 증감 연산자(++, --)
        1. 하나의 식에서 증감연산자의 사용을 최소화하고, 식에 두 번 이상 포함된 변수에 증감연산자를 사용하는 것을 피해야 한다.
      2. 부호 연산자(+, -)
    3. 산술 연산자
      1. 사칙 연산자 + - * /
        1. 나누기 연산자의 두 피연산자가 모두 정수형인 경우 연산결과도 정수형으로 10 / 4의 결과값은 2.5가 아니고 2이다.
        2. 피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다. 만일 0으로 나누면, 컴파일은 정상적으로 되지만 실행 시 오류(ArithmeticException)가 발생한다. 부동 소수점값인 0.0f, 0.0d로 나누는 것은 간으하지만 그 결과는 Infinity(무한대)이다.
        3. 두 피연산자가 byte 자료형인 경우 두 피연산자의 자료형을 int로 변환한 다음 연산을 수행한다. 피연산자의 자료형에 따라 오버플로우가 발생할 수 있으니 연산자 수행 순서에 주의해야한다.
        4. 상수 또는 리터럴 간의 연산은 실행과정동안 변하는 값이 아니기 때문에, 컴파일 시에 컴파일러가 계산해서 그 결과로 대체함으로써 코드를 보다 효율적으로 만든다. 그러나 수식에 변수가 들어가 있는 경우에는 컴파일러가 미리 계산할 수 없기 때문에 컴파일 에러가 발생하므로 이를 막기위해 형변환을 해주어야 한다. 
      2. 나머지 연산자
        1. 나눗셈에서처럼 나누는 수로 0을 사용할 수 없다.
    4. 비교 연산자
      1. 대소비교 연산자(< > <= >=)
        1. 기본형 중에서는 boolean형을 제외한 나머지 자료형에 모두 사용할 수 있지만 참조형에는 사용할 수 없다.
      2. 등가비교 연산자(== !=)
        1. 기본형과 참조형 모든 자료형에 사용할 수 있다. 기본형의 경우 변수에 저장된 값이 같은지 알 수 있고, 참조형의 경우 객체의 주소값을 저장하기 때문에 두 개의 피연산자가 같은 객체를 가리키고 있는지를 알 수 있다.
        2. float과 double을 비교할 때 실수형은 근사값으로 저장하므로 float과 double의 부호와 지수가 달라 오차가 발생할 수 있다. 따라서 두 자료형을 비교할 때는 double을 float으로 변환한 뒤 비교해야한다.
        3. 문자열 비교시 비교 연산자 '=='가 아니라 'java.lang'패키지의 equals()메소드를 이용해야한다. 대소문자를 구별하고 싶지 않다면, equal()대신 equalsIgnoreCase()를 사용하면 된다.
    5. 논리 연산자
      1. 논리 연산자(&&  ||)
        1. 효율적인 연산(short circuit evaluation, SCE)
          1. OR연산의 경우 어느 한 쪽이 참이어도 전체 결과가 참이므로 왼쪽의 피연산자가 참이면 오른쪽 피연산자 값은 평가하지 않는다. AND연산도 마찬가지로 어느 한 쪽이 거짓이면 전체 결과가 거짓이므로 왼쪽 피연산자가 거짓이면 오른쪽 피연산자 값은 평가하지 않는다. 이처럼 같은 조건식이라도 피연산자의 위치에 따라 연산속도가 달라질 수 있으므로 OR연산은 참일 확률이 높은 피연산자를 왼쪽에,  AND연산은 거짓일 확룰이 높은 피연산자를 왼쪽에 두변 연산속도를 높일 수 있다.
      2. 비트 연산자(& | ^ ~ << >>)
        1. '<<'연산자의 겅우, 피연산자의 부호에 상관없이 각 자리를 왼쪽으로 아동시키며 반탄을 0으로 채우면 되지만, '>>'연산자는 오른쪽으로 이동시키기 때문에 부호있는 정수는 부호를 유지하기 위해 왼쪽 피연산자가 음수인 경우 빈자리를 1로 채운다, 물론 양수알 때는 0으로 채운다. 
          x << n 은 x * 2^n의 결과와 같다. x >> n 은 x / 2^n의 결과와 같다.
    6. 그 외의 연산자
      1. 조건 연산자 ? :
        1. 조건연산자가 여러 번 중첩되면 코드가 간략해지긴 하지만, 가독성이 떨어지므로 꼭 필요한 경우에 한번 정도만 중첩하는 것이 좋다.
      2. 대입연산자 = (operator)=
        1. 대입 연산자는 연산자들 중에서 가장 낮은 우선순위를 갖고 있기 때문에 식에서 제일 나중에 수행된다.
        2. 대입 연산자의 왼쪽 피연산자를 'lvalue(left value)'이라 하고, 오른쪽 피연산자를 'rvalue(right value)'라고 한다. rvalue는 변수뿐만 아니라 식이나 상수 등이 모두 가능한 반면, lvalue는 반드시 변수처럼 값을 변경할 수 있는 것이여야 한다. 그래서 리터럴이나 상수같이 값을 저장할 수 없는 것들은 lvalue가 될 수 없다.
        3. 복합 대입 연산자에서 대입연산자의 우변이 둘 이상의 항으로 이루어져 있는 경우 주의해야한다. 'i *= 10 + j'는 'i = i * (10+j)'이지 'i = i * 10 + j'가 아니다.
    7. instanceof 연산자
      1. 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용한다. 연산의 결과로 boolean값을 반환하여 주로 조건문에 사용된다. instanceof의 왼쪽에는 참조변수를 오른쪽에는 타입(클래스명)이 피연산자로 위치한다.  (객체) instanceof (클래스)의 형식으로, 객체가 클래스로 형변환할 수 있는지 확인함으로써 상속관계를 확인한다. 
    8. -> 연산자
      1. 인터페이스와 인터페이스를 구현하는 클래스가 있을 때, 인터페이스를 구현한 클래스를 정의하고 이 클래스의 객체를 생성해야 객체의 메소드를 호출할 수 있다.
      2. //인터페이스 선언
        interface A {
        	public void callSomeone(String name);
        }
        
        //클래스 선언
        class Myname implements A{
        	public void callSomeone(String name){
            	System.out.println("Hello!" + name);
            }
        }
        
        //인터페이스를 구현한 클래스를 객체로 선언
        Myname name = new Myname();
        //클래스의 메소드 호출
        name.callSomeone("SOOLSOOL");
        일일이 클래스를 선언하는 것, 특히나 익명 클래스처럼 단 한번 객체를 선언하기 위해 클래스를 선언하는 것은 번거로운 일이다. 이런 복잡한 코드를 람다식을 이용하면 간단하게 구현할 수 있다.
      3. //(인터페이스 이름) 변수 이름 = (함수의 매개변수) -> {함수의 바디}
        A name = (String name) -> { System.out.println("HELLO!" + name); };
        name.callSomeone("SOOLSOOL");
    9. switch 연산자
      1. switch문이 변경된 것이 아니고 switch연산자가 추가되었다. 기존에 case, break, return 등 복잡하게 사용했던 것에서 java12에서는 -> 화살표 연산자를 사용할 수 있게 되었고 java. 13d에서는 yield라는 예약어를 사용하여 간단하게 표현할 수 있다.
      2. int num = 2;
        int returnNum = 0;
        switch(num){
        		case 1: returnNum = 1;
           	 	break;
           	 	case 2: returnNum = 2;
           		break;
        	}
        
        //java12
        returnNum = switch(num){
        		case 1 -> 1;
        	    case 2 -> 2;
            	default -> throw new IllegalStateException("Unexpected value")
        	}
        
        //java13
        returnNum = switch(num){
                    case 1 : yield 1;
                    case 2 : yield 2;
                    default : throw new IllegalStateException("unexpected value");
                };
Designed by Tistory.