모든 연산자는 연산결과를 반환한다.
연산자는 총 5가지 종류가 있다.
instanceof는 객체지향에서 쓰는 연산자이다.
두괄식 정리하면, 연산자의 우선순위와 결합법칙은 3가지만 기억하면 된다.
하나의 식에 연산자가 둘 이상 있을 때, 어떤 연산을 먼저 수행할지에 대한 규칙이다.
(연산자의 우선순위와 결합규칙)
결합규칙: 우선순위가 같은 연산자가 있을 때, 어떤 것을 먼저 할건지에 대한 얘기이다.
3+4-5 라는 식이 있을 때, 덧셈 연산자(+)와 뺄셈 연산자(-)는 우선순위가 같다.
그럼 어떻게 하지? 마찬가지로 우린 자연스럽게 알고있다.
위의 정리표를 보면 대입 연산자, 단항 연산자를 제외하면, 기본적으로 모두 왼쪽에서 오른쪽 (→) 방향이다.
형변환: 변수 또는 상수의 타입을 다른 타입으로 변환하는 것
바꾸는 방법은 쉽다: (타입) 피연산자
double d = 85.4;
int score = (int)d;
System.out.println(score); // 85
변수와 리터럴의 타입은 일치해야 하지만, 앞에서 배웠듯 Java는 유도리 있게 자동 형변환을 해준다.
float f = 1234; // 리터럴은 int이지만 float에 저장됨
그러나 더 큰 표현범위의 리터럴을 낮은 표현범위의 변수에 넣으려고 하면 에러가 발생한다.
int i = 3.14f; // 에러
int i = (int)3.14f; // ok
마찬가지로, byte → int 는 형변환 연산자를 생략 가능하다 (자동 형변환)
형변환을 생략하면 컴파일러가 자동으로 형변환을 한다.
어떤 타입으로? → 기존의 값을 최대한 보존할 수 있는 타입으로 (큰 쪽으로)
왼쪽 타입의 리터럴을 오른쪽 타입의 변수에 담을 때는 모두 자동 형변환.
반대 방향은 값손실이 있을 수 있으므로 자동 형변환 되지 않고, 유저가 수동 형변환 해야한다.
뭔지 알겠지?: +, -, *, /
유의할 점:
(int) 10/ (int) 4 = 2.5가 아니라 (int) 2 가 나온다. 이러한 경우, 2.5를 얻으려면 피연산자 중 하나를 float로 바꿔줘야 한다.
그럼 나머지 하나도 float으로 취급되면서 (float) 10/ (float) 4= float 값인 2.5가 나온다.
왜지? → 산술변환 규칙 때문에!
피연산자를 나누고 남은 나머지를 반환한다.
int a = 11;
int b = 3;
System.out.println(a%b); // 2
% 연산자는 몇가지 특징을 지닌다.
// %의 양쪽 피연산자는 정수가 아니어도 된다.
double a = 11.0;
double b = 3.1;
System.out.println(a%b); // 1.6999999999999997
// 나누는 피연산자(오른쪽) 부호는 무시된다.
int a = 11;
int b = -3;
System.out.println(a%b); // 2
int c = -11;
int d = 3;
System.out.println(c%d); // -2
산술 변환: 연산 전에 피연산자들의 타입을 일치시키는 Java의 기능
산순 변환에는 두 가지 중요한 규칙이 있다. (암기)
하나씩 살펴보자.
1. 두 피연산자의 타입을 같게 일치시킨다. (값손실을 최소화하기 위해, 둘 중에 큰 타입으로 일치)
2. 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다. (byte, char, short)
잘 이해해보자.
이를 이해하지 않으면 초보자때 실수를 종종 하게 된다.
int a = 1_000_000;
int b = 2_000_000;
long c = a * b;
System.out.println(c); // -1454759936 (오버플로우)
‘결과값이 int 범위를 넘어가지만 long 타입 변수에 담았으니 됐겠지?’ 라고 생각했겠지만 오버플로우 된 다음에 long c 에 담기는 거라 상관없다.
이럴 때 a나 b 중에 하나를 (long)으로 바꿔주었다면, 자동으로 나머지도 산술 변환 처리되면서 long 타입의 결과값이 나왔을 것이다.
int a = 1_000_000;
int b = 2_000_000;
long c = (long)a * b;
System.out.println(c); // 2,000,000,000,000
A. (int) 2
둘 다 char 타입으로, 유니코드로 변환하면 50, 48이다.
char은 int보다 작은 타입이다. 따라서 자동으로 int로 바뀐다.
때문에 (int) 50 - (int) 48 = (int) 2가 된다.
반올림은 round()라는 메소드를 통해 가능하다.
이 메소드는 Math라는 클래스에 소속되어 있다.
Math.round() 를 그냥 쓰면 소수점을 반올림한 정수를 반환한다.
long a = Math.round(4.5); // a에 5가 저장된다.
살짝 구식으로 해야한다.
만약 소수점 셋째자리까지를 원한다면,
double a = 4.52152;
double result = Math.round(a*1000); // 4521.52 기준으로 반올림
System.out.println(result/1000); // 4.522
프린트할 때 int인 1000으로 나눠주었으나 result가 double임. 따라서 산술변환에 의해 double 값이 나온다.
double a = 4.52152;
System.out.println(Math.round(a*1000)/1000);
// 4 -> (int)4522/(int)1000 이기 때문
System.out.println((double)Math.round(a*1000)/1000);
// 4.522 -> (double)4522.0/(int)1000 이기 때문
따로 변수에 넣어줄 게 아니고 바로 print해야 하는 상황이라면, 이처럼 형변환 연산자를 활용해줘도 된다.
랜덤한 수를 생성한다. 게임, 섞기 등을 구현할 때 자주 쓴다.
이 때 쓰이는 메서드는 Math 클래스의 random() 메서드이다.
원하는 정수를 얻는 법:
예를 들어 1~3 중에 random한 정수를 얻고싶다면?
0.0 * 3 <= Math.random() * 3 < 1.0 * 3
= 0.0 <= Math.random() * 3 < 3.0
(int) 0.0 <= (int) Math.random() * 3 < (int) 1.0 * 3
= 0 <= (int) Math.random() * 3 < 3
0 + 1 <= (int) Math.random() * 3 + 1 < 3 + 1
= 1 <= (int) Math.random() * 3 + 1 < 4
a ~ b 사이 정수를 얻는 방법을 일반화하면 다음과 같다.
int num = 0;
num = (int)Math.random()*(b-a+1) + a;
예시1) 1~100 사이 정수 출력하기
Scanner scanner = new Scanner(System.in);
System.out.println("난수 생성 횟수를 입력하세요.");
int times = scanner.nextInt();
int num = 0;
// 난수 범위: 1~100, 정수
for (int i=0; i < times ; i++) {
num = (int)(Math.random()*100) + 1;
System.out.println(num);
}
break는 하나의 반복문만 벗어날 수 있다.
그러나 중첩 반복문을 벗어나야 하는 상황도 있다.
최상단 for문 앞에 Loop1 이라는 이름을 줬다.
예제) 4반의 4번을 불러선 안 돼..
Loop: for (int i=1; i<=10; i++) {
System.out.printf("%d반 - ",i);
for (int j=1; j<=10; j++) {
if (i == 4 && j ==4) {
System.out.printf(" ");
break Loop;
}
System.out.printf("%d ",j);
}
System.out.println();
}
[자바의 정석 스터디] Ch.2 변수 (0) | 2024.03.08 |
---|---|
[자바의 정석] (Ch.6 객체지향개념) 클래스 변수, 인스턴스 변수 (0) | 2023.09.28 |
[자바의 정석] (Ch6. 객체지향개념) 선언 위치에 따른 변수의 종류 (0) | 2023.09.26 |
[자바의 정석] (Ch6. 객체지향개념) 클래스의 정의 (0) | 2023.09.26 |
[자바의 정석] (Ch6. 객체지향개념) 클래스와 객체 (0) | 2023.09.26 |