본문 바로가기
Language/JAVA

JAVA :: 자바 문법 정리(1)

by stern07s 2023. 4. 20.
728x90
반응형

JAVA :: 자바 문법 정리(1)

변수

덧셈 연산자(+)는 피연산자가 모두 숫자일 때는 두 수를 더하지만, 피연산자 중 어느 한쪽이 String 이면 나머지 한 쪽을 먼저 String 으로 변환한 다음 두 String 을 결합한다.


참조변수의 출력이나 덧셈연산자를 이용한 참조변수와 문자열의 결합에는 toString()이 자동적으로 호출되어 참조변수를 문자열로 대치한 후 처리한다.

 

연산자

✔️ x << 2 + 1 : 쉬프트연산자(<<)는 덧셈연산자보다 우선순위가 낮다. 그래서 해당 식은 ‘x << (2 + 1)’ 과 같다.
✔️ data & 0xFF == 0 : 논리연산자(&)는 비교연산자(==)보다 우선순위가 낮으므로 비교연산 후에 논리연산이 수행된다. 
그래서 해당 식은 ‘data & (0xFF == 0)’ 과 같다.
✔️ x < -1 || x > 3 && x < 5 : 논리연산자 중에서 AND 를 의미하는 ‘&&’가 OR 을 의미하는 ‘||’보다 우선순위가 높다. 
그래서 해당 식은 ‘x < -1 || (x > 3 && x < 5)’ 과 같다.


산술 변환 : 연산 전에 피연산자 타입의 일치를 위해 자동 형변환되는 것. 이 변환은 이항 연산에서 뿐만 아니라 단항
연산에서도 일어난다. ‘산술 변환’의 규칙은 다음과 같다.


1. 두 피연산자의 타입을 같게 일치시킨다. (보다 큰 타입으로 일치)
✔️ long + int -> long + long -> long
✔️ float + int -> float + float -> float


2. 피연산자의 타입이 int 보다 작은 타입이면 int 로 변환된다.
✔️ byte + short -> int + int -> int
✔️ char + short -> int + int -> int
첫 번째 규칙은 자동 형변환처럼 피연산자의 값손실을 최소화하기 위한 것이고, 두 번째 규칙은 정수형의 기본 타입인 int 가 가장 효율적으로 처리할 수 있는 타입이기 때문에, 그리고 int 보다 작은 타입, 예를 들면 char 나 short 의 표현범위가 좁아서 연산중에 오버플로우(overflow)가 발생할 가능성이 높기 때문에 만들어진 것이다.

long a = 1000000 * 1000000;
long b = 1000000 * 1000000L;
System.out.println("a="+a);
System.out.println("b="+b);
// 결과
a = -727379968
b = 1000000000000

위의 예제에서 ‘1000000 1000000’의 결과가 1000000000000(2\10 의 12 승)임에도 불구하고, -727379968 라는
결과가 출력되었다. 그 이유는 int 타입과 int 타입의 연산 결과는 int 타입인데, 연산결과가 int 타입의 최대값인 1000000000(2*10 의 9 승)을 넘으므로 오버플로우(overflow)가 발생했기 때문이다. 이미 오버플로우가 발생한 값을 아무리 long 타입의 변수에 저장해도 소용이 없다.

char c1 = 'a'; // c1 에는 문자 'a'의 코드값은 97 이 저장된다.
char c2 = c1; // c1 에 저장되어 있는 값이 c2 에 저장된다.
char c3 = ' '; // c3 를 공백으로 초기화 한다.
int i = c1 +1; // 'a' + 1 -> 97 + 1 -> 98
c3 = (char)(c1 + 1);
c2++;
c2++;

위의 예제에서 c2++; 대신에 c2=c2+1;을 사용하면 에러가 발생할 것이다. c2+1 의 연산결과는 int 형이며, 그 결과를 다시 c2 에 담으려면 형변환 연산자를 사용하여 char 형으로 형변환해야 하기 때문이다.

char c1 = 'a';
char c2 = c1 + 1; // 컴파일 에러 발생 O
char c2 = 'a' + 1; // 컴파일 에러 발생 X

‘a’ + 1 은 리터럴 간의 연산이기 때문에 에러가 발생하지 않는다. 상수 또는 리터럴 간의 연산은 실행과정동안 변하는 값이 아니기 때문에, 컴파일 시에 컴파일러가 계산해서 그 결과로 대체함으로써 코드를 보다 효율적으로 만든다. 컴파일러가 미리 덧셈연산을 수행하기 때문에 실행 시에는 덧셈 연산이 수행되지 않는다. 수식에 변수가 들어가 있는 경우에는 컴파일러가 미리 계산을 할 수 없기 때문에 형변환을 해줘야한다. (char c2 = (char) (c1 + 1)) 그렇지 않으면 컴파일 에러가 발생한다.

float f = 0.1f; // f 에 0.10000000149011612 로 저장된다.
double d = 0.1; // d 에 0.10000000000000001 로 저장된다.

float 타입의 값을 double 타입으로 형변환하면, 부호와 지수는 달라지지 않고 그저 기수의 빈자리를 0 으로 채울 뿐이므로 0.1f 를 double 타입으로 형변환해도 그 값은 전혀 달라지지 않는다. 즉, float 타입의 값을 정밀도가 더 높은 double 타입으로 형변환했다고 해서 오차가 적어지는 것이 아니라는 말이다.

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

str2 와 “abc”의 내용이 같은데도 ‘==’로 비교하면, false 를 결과로 얻는다. 내용은 같지만 서로 다른 객체이기 때문이다. 
그러나 equals()는 객체가 달라도 내용이 같으면 true 를 반환한다. 그래서 문자열을 비교할 때는 항상 equals()를 사용해야 한다.

 

✔️ 효율적인 연산
  👉 OR 연산 ‘||’의 경우, 두 피연산자 중 어느 한 쪽만 ‘참’이어도 전체 연산결과가 ‘참’이므로 좌측 피연산자가
‘true(참)’이면, 우측 피연산자의 값은 평가하지 않는다.
  👉 AND 연산 ‘&&’의 경우, 어느 한쪽만 ‘거짓(0)’이어도 전체 연산결과가 ‘거짓(0)’이므로 좌측 피연산자가
‘거짓(0)’이면, 우측 피연산자의 값은 평가하지 않는다.


비트 XOR 연산자 ‘^’는 두 피연산자의 비트가 다를 때만 1 이된다. 그리고 같은 값으로 두고 XOR 연산을 수행하면 원래의
값으로 돌아온다는 특징이 있어서 간단한 암호화에 사용된다.


비트 전환 연산자는 피연산자의 타입이 int 보다 작으면 int 로 자동 형변환(산술 변환) 후에 연산하기 때문에 연산결과는
32 자리의 2 진수이다.


쉬프트 연산자의 좌측 피연산자는 산술변환이 적용되어 int 보다 작은 타입은 int 타입으로 자동 변환되고 연산결과 역시 int 타입이 된다. 그러나 쉬프트 연산자는 다른 이항연산자들과 달리 피연산자의 타입을 일치시킬 필요가 없기 때문에 우측
피연산자에는 산술변환이 적용되지 않는다.


변수 앞에 키워드 ‘final’을 붙이면 상수가 된다. 상수는 반드시 선언과 동시에 값을 저장해야하며, 한 번 저장된 값은 바꿀 수 없다.

반응형

'Language > JAVA' 카테고리의 다른 글

JAVA :: 자바 문법 정리(3)  (0) 2023.04.22
JAVA :: 자바 문법 정리(2)  (0) 2023.04.21
JAVA :: 자바 용어 정리(5)  (0) 2023.04.19
JAVA :: 자바 용어 정리(4)  (0) 2023.04.18
JAVA :: 자바 용어 정리(3)  (0) 2023.04.17

댓글