스코프 1 - 지역 변수와 스코프
변수는 선언한 위치에 따라 지역변수, 맴버 변수(클래스, 인스턴스 변수)와 같이 분류 됨
package scope;
public class Scope1 {
public static void main(String[] args) {
int m = 10; //m 생존 시작 if (true) {
int x = 20; //x 생존 시작
System.out.println("if m = " + m); //블록 내부에서 블록 외부는 접근 가능 System.out.println("if x = " + x);
} //x 생존 종료
//System.out.println("main x = " + x); //오류, 변수 x에 접근 불가
System.out.println("main m = " + m); } //m 생존 종료
}
int m
int m
은 main 내부에서 선언되었으므로 main 블록 종료시점까지 생존한다.
int x
int x
는 if 블록 내부에 선언되었으므로 if 블록 종료시점까지 생존한다
즉,
Scope란 변수의 접근 가능한 범위를 말한다.
스코프 2 - 존재 이유
다음 코드를 보자
package scope;
public class Scope3_1 {
public static void main(String[] args) {
int m = 10;
int temp = 0;
if (m > 0) {
temp = m * 2;
System.out.println("temp = " + temp);
}
System.out.println("m = " + m);
}
}
이 코드에서 temp는 if 조건 내부에서만 사용하는 코드이지만 main 블록에서 선언되어있다. 이러한 코드는 다음과 같은 문제가 발생한다.
- 비효율적 메모리 사용
- 코드 복잡성 증가
package scope;
public class Scope3_2 {
public static void main(String[] args) {
int m = 10;
if (m > 0) {
int temp = m * 2;
System.out.println("temp = " + temp);
}
System.out.println("m = " + m);
}
}
다음과 같이 수정하면 유지보수하기 용이하다.
정리
- 변수는 꼭 필요한 범위로 한정해서 사용하라. 메모리를 효율적으로 사용하고 더 유지보수하기 좋은 코드를 만들 수 있다.
- 좋은 프로그램은 무한한 자유가 있는 프로그램이 아닌 적절한 제약이 있는 프로그램이다.
형변환 - 자동 형변환
형변환
- 작은 범위에서 큰범위로는 값을 넣을 수 있다.
int
->long
->double
- 큰 범위에서 작은 범위는 다음과 같은 문제가 발생할 수 있다.
- 소수점 버림
- 오버플로우
작은 범위에서 큰 범위로 대입은 허용한다.
package casting;
public class Casting1 {
public static void main(String[] args) {
int intValue = 10;
long longValue;
double doubleValue;
longValue = intValue; // int -> long
System.out.println("longValue = " + longValue);
//longValue = 10
doubleValue = intValue; // int -> double
System.out.println("doubleValue1 = " + doubleValue);
//doubleValue1 = 10.0
doubleValue = 20L; // long -> double
System.out.println("doubleValue2 = " + doubleValue);
//doubleValue2 =20.0
}
}
//결과
longValue = 10
doubleValue1 = 10.0
doubleValue2 = 20.0
- 자바는 기본적으로 같은 타입에 값을 대입할 수 있다.
- int < long 이다. 따라서 long -> int는 대입 가능하다.
자동 형변환
하지만 결국 데이터 타입을 맞춰야 하기 때문에 개념적으로는 다음과 같이 동작한다.
//intValue = 10
doubleValue = intValue
doubleValue = (double) intValue //형 맞추기
doubleValue = (double) 10 //변수 값 읽기
doubleValue = 10.0 //형변환
이렇게 형을 변경하는 것을 형변환이라고 한다.
작은 범위 숫자 타입에서 큰 범위 숫자 타입으로의 대입은 개발자가이렇게 직접 형변환 하지 않아도 된다. 이런 과정이 자동으로 일어나기 때문에 자동 형변환
, 또는 묵시적 형변환
이라 한다.
형변환 - 명시적 형변환
큰 범위에서 작은 범위 대입은 명시적 형변환이 필요하다.
package casting;
public class Casting2 {
public static void main(String[] args) {
double doubleValue = 1.5;
int intValue = 0;
//intValue = doubleValue;
//컴파일 오류 발생 intValue = (int) doubleValue;
//형변환 System.out.println(intValue);
//출력:1
}
}
이런 컴파일에러는 개발자가 타입을 통해 안전하게 개발 가능하게 한다.
하지만 만약 개발자가 위험을 감수하고도 값을 대입하고 싶다면 데이터 타입을 강제로 변경할 수 있다.
이땐 ()
를 사용해 명시적으로 입력하면 된다.
intValue = (int) doubleValue; //형변환
이것을 타입을 바꾼다해서 형 변환(명시적 형변환
)이라고 한다. 영어로는 캐스팅이라 한다.
명시적 형변환 과정
//doubleValue = 1.5
intValue = (int) doubleValue;
intValue = (int) 1.5; //doubleValue에 있는 값을 읽는다.
intValue = 1; //(int)로 형변환 한다. intValue에 int형인 숫자 1을 대입한다.
형 변환을 한다고 해서 doubleValue
자체의 타입이나 내부 값이 변경되는 것은 아니다.
참고
변수의 값은 대입 연산자(=)를 통해서 직접 대입할 때만 변경된다.
형변환과 오버플로우
형변환을 할때 만약 작은 숫자가 표현할 수 있는 범위를 넘어서면 어떻게 될까?
package casting;
public class Casting3 {
public static void main(String[] args) {
long maxIntValue = 2147483647; //int 최고값
long maxIntOver = 2147483648L;
//int 최고값 + 1(초과) int intValue = 0;
intValue = (int) maxIntValue; //형변환
System.out.println("maxIntValue casting=" + intValue);
//출력:2147483647
intValue = (int) maxIntOver; //형변환
System.out.println("maxIntOver casting=" + intValue);
//출력:-2147483648 }
}
}
// 결과
maxIntValue casting=2147483647
maxIntOver casting=-2147483648
정상범위
maxIntValue
를 보면 int
타입의 가장 높은 숫자를 입력했다. 이 경우 int
범위 밖에 포함되기 때문에 long
-> int
로 형변환을 해도 아무런 문제가 없다.
초과 범위
다음으로 maxIntOver
를 보면 int
타입의 가장 높은 숫자 + 1을 입력했다. 이 숫자는 리터럴은 int
범위를 벗어나기 때문에 형변환시 문제가 발생한다.
계산과 형변환
형변환은 대입 뿐 아니라, 계산시에도 발생한다.
package casting;
public class Casting4 {
public static void main(String[] args) {
int div1 = 3 / 2;
System.out.println("div1 = " + div1); //1
double div2 = 3 / 2;
System.out.println("div2 = " + div2); //1.0
double div3 = 3.0 / 2;
System.out.println("div3 = " + div3); //1.5
double div4 = (double) 3 / 2;
System.out.println("div4 = " + div4); //1.5
int a = 3;
int b = 2;
double result = (double) a / b;
System.out.println("result = " + result); //1.5
}
}
// 출력
div1 = 1
div2 = 1.0
div3 = 1.5
div4 = 1.5
result = 1.5
자바의 계산은 다음 2가지를 기억하자.
- 같은 타입끼리의 계산은 같은 타입의 결과를 반환한다.
- 서로 다른 타입의 계산은 큰 범위의 타입으로 자동 형변환이 일어난다.
정리
- 작은 범위에서 큰범위로는 대입할 수 있다.
- 이를
묵시적 형변환
또는자동 형변환
이라 한다.
- 이를
- 큰 범위에서 작은 범위의 대입은 다음과 같은 문제가 발생할 수 있다. 이때는
명시적 형변환
을 사용해 방지할 수 있다.- 소수점 버림
- 오버플로우
- 연산과 형변환
- 같은 타입의 연산은 같은 타입을 반환한다.
- 다른 타입의 연산은 큰 범위의 타입으로
자동 형변환
이 일어난다.