본문 바로가기

기술 서적/자바의 정석

[자바의 정석] ch3. 연산자

1.1 연산자

연산자: 연산을 수행하는 기호

피연산자: 연산자의 작업대상(변수, 상수, 리터럴, 수식)

=> 연산자는 피연산자 연산의 결과를 항상 반환한다.

 

1.2 연산자의 종류

 

>>헷갈리는 연산자 우선규칙

설명
x << 2+1 (2+1) => <<
data & 0xFF==0 (0xFF==0 )=>  &
x<-1 || x>3 && x<5 (x>3) / (x<5) => && => || 
=> and가 or보다 우선순위가 높음

 

>>연산자 우선순위

1. 산술>비교>논리>대입, 대입은 제일 마지막에 수행된다.
2. 단항(1) / 이항(2) >삼항(3). 단항 연산자의 우선순위가 이항 연산자보다 높다.
3. 단항/대입을 제외한 모든 연산의 진행방향은 왼쪽-> 오른쪽이다.

 

>>산술변환

1) 두 피연산자의 타입을 같게 일치시킨다.

2) 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.

 

=> 실수로 답을 얻기 위해서는 한 피연산자를 float or double로 변화해야 함

5/2 => 2

(float)5 /2 => 2.5

 

>>증감연산자 해석 편하게 하는 법

 

>>사칙연산시 주의할 사안

 

1) byte/char는 연산하면 int로 자동형변환된다.

public class operatorex6 {
    public static void main(String []args) {
        byte a = 10;
        byte b = 20;
        byte c= (byte)(a+b); //명시적 형변환이 필요
        System.out.println(c);
    }
}

 => byte+byte는 int로 변환되므로

 

2) 큰 값을 작은 자료형에 넣으면 값 손실이 발생한다.

public class operatorex6 {
    public static void main(String []args) {
        byte a = 10;
        byte b = 30;
        byte c= (byte)(a*b); //형변환 과정에서 값 손실 발생
        System.out.println(c);
    }
}

=> 결과 : 44 

=> byte는 127까지 저장하므로 

 

3) 자동형변환은 대입할 때 일어난다.

=> 결과 : -1454759936

=> 이미 int와 int 연산의 결과는 int이므로

=> 계산된 결과를 long으로 확장함

=> 즉, 저장공간을 넘어가는 연산결과를 위해선 미리 형변환을 해주어야 한다.

 

 

>> 문자를 숫자로 바꾸는 방법

문자-> 숫자 : "3" -"0" == 51 - 48 = 3

문자<- 숫자 : "3"+"0" == 3  + 48=51

=>안의 유니코드를 연산

 

>>주의사항 : 리터럴 연산은 형변환을 해주지 않아도 괜찮다.

char c2='a'+1 =>연산되어도 char

=>컴파일 과정에서 int로 변환되지 않는 리터럴 값이기에

 

>>나머지 연산자 %

: 음수로 나누는 수를 허용

: 앞의 부호 연산은 계산결과에 - 붙이기

: 뒤의 부호 연산자는 무시

public class operatorex20 {
    public static void main(String []args)
    {
        System.out.println(-10%8);
        System.out.println(10%-8);
        System.out.println(-10%-8);
    }
}

=>실행결과

-2

2

-2

 

=> 앞의 연산자는 부호 반영되나 뒤의 연산자는 안됨

 

>> 등가비교 연산자

public class operatorex22 {

    public static void main(String []args)
    {
        float f=0.1f;
        double d=0.1;
        double d2= (double)f;

        System.out.printf("10.0==10.0f %b%n", 10.0==10.0f);
        System.out.printf("0.1==0.1f %b%n", 0.1==0.1f);
        System.out.printf("f=%19.17f%n", f);
        System.out.printf("d=%19.17f%n", d);
        System.out.printf("d2=%19.17f%n", d2);
        System.out.printf("d==f %b%n", d==f);
        System.out.printf("d2==f %b%n", d2==f);
        System.out.printf("d==d2 %b%n", d==d2);
        System.out.printf("(float)d==f %b%n", (float)d==f);

    }
}

 

=> 실행결과

 

10.0==10.0f true
0.1==0.1f false
f=0.10000000149011612
d=0.10000000000000000
d2=0.10000000149011612
d==f false
d2==f true
d==d2 false
(float)d==f true

 

 

=> 정밀도 차이에 따른 등가비교 결과를 주의

=>float을 double로 확장한다고 해서 정밀도가 높다지지 않음(애초에 선언할 때가 중요)

 

 

>>문자열 비교 : equals

==       => 문자열 객체가 같은가?
equals => 문자열 내용이 같은가?

=> 내용을 비교하기 위해선 equals라는 메서드 사용

=> 같으면 true / 아니면 false 반환

=> .equalsIgnoreCase() : 대소문자 무시비교

public class operatorex23 {

    public static void main(String []args)
    {
        String str1="abc";
        String str2= new String("abc");

        System.out.printf("\"abc\"==\"abc\" ? %b%n","abc"=="abc");
        System.out.printf("\"str1\"==\"abc\" ? %b%n",str1=="abc");
        System.out.printf("\"str2\"==\"abc\" ? %b%n",str2=="abc");
        System.out.printf("str1.equals(\"abc\") ? %b%n",str1.equals("abc"));
        System.out.printf("str2.equals(\"abc\") ? %b%n",str2.equals("abc"));
        System.out.printf("str1.equals(\"ABC\") ? %b%n",str1.equals("ABC"));
        System.out.printf("str1.equalsIgnoreCase(\"ABC\") ? %b%n",str1.equalsIgnoreCase("ABC"));


    }
}

실행결과

"abc"=="abc" ? true
"str1"=="abc" ? true
"str2"=="abc" ? false
str1.equals("abc") ? true
str2.equals("abc") ? true
str1.equals("ABC") ? false
str1.equalsIgnoreCase("ABC") ? true

 

 

>>논리 연산자 &&, || , !

- python과 달리 10<x<20과 같은 표현은 안됨

- &&의 우선순위 > ||의 우선순위

 

효율적인 연산을 함

(a &&b) => a가 false면 b의 연산을 안함

(a || b) => a가 true면 b 연산을 안함

 

>예제

public class operatorex26 {

    public static void main(String []args)
    {
        int a=5;
        int b=0;

        System.out.printf("a=%d, b=%d%n", a,b);
        System.out.printf("a!=0 || ++b!=0 = %b%n", a!=0|| ++b!=0); //뒤의 연산이 실행되지 않음
        System.out.printf("a=%d, b=%d%n", a,b);
        System.out.printf("a==0 && ++b!=0 =%b%n", a==0 &&++b!=0); //뒤의 연산이 실행되지 않음
        System.out.printf("a=%d, b=%d%n", a,b);

    }
}

 =>뒤에 연산이 실행되지 않음

>실행결과

a=5, b=0
a!=0 || ++b!=0 = true
a=5, b=0
a==0 && ++b!=0 =false
a=5, b=0

 

>>비트 연산자

 

>>쉬프트 연산자 << >>

- 곱셈/나눗셈보다 더 빠른 속도를 보장

- x<<n or x>>n에서 n의 값이 자료형의 bit 수보다 크면, 자료형의 bit수로 나눈 나머지만큼만 이동

ex) int (32bit)

8>>34 ===> 8>>2 (34%32)

 

 

>> 삼항 연산자

(조건식) ? 식1 : 식2

=> 식1과 식2도 형변환이 발생