[Java] 스코프, 형변환, 배열, 메서드
스코프
1. 지역변수와 스코프
- 지역변수 : 특정 지역(코드 블록
{}
)에서만 사용할 수 있는 변수- 자신이 선언된 코드 블록을 벗어나면 제거되기 때문에 접근할 수 없다.
- 스코프(Scope) : 변수의 접근 가능한 범위
2. 스코프 존재 이유
- 비효율적인 메모리 사용을 줄이기 위해
- 코드 복잡성을 감소시키기 위해
- 변수를 생각해야 하는 범위를 줄이면 유지보수하기 좋은 코드가 된다.
형변환
1. 자동 형변환
- 작은 범위에서 큰 범위로 값을 대입하면 직접 형변환을 하지 않아도 형이 변경된다.
- 예)
int
→long
→double
- (double)로 적어주면 int 형이 double 형으로 변한다.
int intValue = 10; double doubleValue; doubleValue = intValue; // 10.0
자동 형변환 과정
doubleValue = intValue doubleValue = (double) intValue //형 맞추기 doubleValue = (double) 10 //변수 값 읽기 doubleValue = 10.0 //형변환
- 예)
2. 명시적 형변환
- 큰 범위에서 작은 범위 대입 시 필요하다.
- 예)
double
→int
- 명시적 형변환을 해주지 않으면 컴파일 오류가 발생한다.
- doubleValue 안에 들어 있는 값은 1.5로 유지된다.
double doubleValue = 1.5; int intValue = 0; //intValue = doubleValue; //컴파일 오류 발생 intValue = (int) doubleValue; // 명시적 형변환 System.out.println(intValue); // 1
- 예)
- 형변환과 오버플로우
- maxIntOver은 int로 표현할 수 있는 범위를 넘는다.
- int형은 2147483648L를 표현할 수 있는 방법이 없다.
- 오버플로우로 인해 결국, int 의 가장 작은 숫자인 -214783648을 출력한다.
- 오버플로우 : 기존 범위를 초과해서 표현하면 전혀 다른 숫자가 표현되는 현상
- 오버플로우의 발생을 막기 위해 intValue의 타입을
int
→long
으로 변경해서 사이즈를 늘려야 한다.
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
- maxIntOver은 int로 표현할 수 있는 범위를 넘는다.
3. 연산과 형변환
1) 같은 타입끼리의 계산은 같은 타입의 결과를 낸다.<br>
2) 서로 다른 타입의 계산은 큰 범위로 자동 형변환이 일어난다.
- 예시
double + int는 double + double로 자동 형변환이 일어난다.
double div3 = 3.0 / 2; System.out.println("div3 = " + div3); //1.5
형변환 과정
double div3 = 3.0 / 2; //double / int double div3 = 3.0 / (double) 2; //double / int이므로, double / double로 형변환이 발생한다. double div3 = 3.0 / 2.0; //double / double -> double이 된다. double div3 = 1.5;
배열
1. 배열의 선언과 생성
- 배열 변수 선언
int[] 이면 정수를, double[]이면 실수를 담을 수 있다.
int[] students;
- 배열 생성
int형 변수 5개를 다룰 수 있는 배열을 생성한다.
students = new int[5]; //배열 생성
- 배열 초기화
- 배열 생성 시, 내부값을 자동으로 초기화한다.
- 숫자는 0, boolean은 false, String은 null로 초기화된다.
배열 참조값 보관
- 배열 생성시, 배열에 접근할 수 있는 참조값(주소)를 반환한다.
- int[] students 변수는 생성된 배열의 참조값을 가지고 있게 된다.
2. 배열 사용
- 배열에 값 대입
- 배열의 위치를 나타내는 인덱스를
[]
에 넣어준다. 배열의 인덱스는 0부터 시작한다.
students[0] = 90; students[1] = 80;
- 배열의 위치를 나타내는 인덱스를
- 값 대입의 순서
- 변수에 있는 참조값(x001)을 통해 실제 배열에 접근 → 인덱스를 사용해서 해당 위치의 요소에 접근 → 값 대입
3. 기본형 vs 참조형
- 기본형(Primitive Type) : 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
- int, long, double, boolean
- 기본형은 선언과 동시에 크기가 정해지기 때문에 크기를 동적으로 바꿀 수 없다.
- 더 빠르고 메모리를 효율적으로 처리한다.
- 참조형(Reference Type) : 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입
- int[] students
- 크기를 동적으로 할당할 수 있다. (동적 메모리 할당)
- 더 복잡한 데이터 구조를 만들고 관리한다.
4. 1차원 배열 리팩토링
- 1차원 배열의 편리한 초기화 : 배열 선언 시 new int[] 생략 가능
자바가 내부에서 배열 요소의 크기를 보고
new int[5]
를 사용해서 배열을 생성한다.int[] students = {90, 80, 70, 60, 50};
5. 2차원 배열
- 2차원 배열은 행과 열로 구성된다.
[]
가 하나 추가되는 것을 제외하고는 1차원 배열과 사용법이 동일하다.행은 row, 열은 column
int[][] arr = new int[2][3]; arr[0][0] = 1; //0행, 0열 arr[0][1] = 2; //0행, 1열 arr[0][2] = 3; //0행, 2열 arr[1][0] = 4; //1행, 0열 arr[1][1] = 5; //1행, 1열 arr[1][2] = 6; //1행, 2열
6. 2차원 배열 리팩토링
2차원 배열의 편리한 초기화
int[][] arr = {{1, 2, 3},{4, 5, 6}};
arr.length
: 행의 길이- 2차원 배열에서는
{}, {}
2개의 배열 요소를 가진다.
- 2차원 배열에서는
arr[row].length
: 열의 길이arr[0].length
를 실행하면 3개의 요소를 가진다.
메서드
1. 메서드 사용
- 메서드(Method) : 함수
메서드 선언
public static int add(int a, int b)
- public : 다른 클래스에서 호출할 수 있는 메서드
- static : 객체를 생성하지 않고 호출할 수 잇는 정적 메서드
- int : 반환 타입 정의
- add : 메서드의 이름 부여, 해당 이름으로 메서드를 호출 할 수 있다.
- 메서드 선언에 사용되는 변수를 파라미터(parameter, 매개변수)라고 한다.
- 메서드 본문
- 메서드가 수행해야 하는 코드 블록
{ System.out.println(a + "+" + b + " 연산 수행"); int sum = a + b; return sum; }
- return 문을 사용하여 메서드의 실행 결과를 반환한다.
- 반환값이 없다면 반환 타입을 void로 설정해야 한다.
- 메서드 호출
- 메서드 이름에 입력 값을 전달한다.
int sum1 = add(5, 10); int sum2 = add(15, 20);
2. 용어 정리
- 인수(Argument) : 메서드에 넘기는 값
call("hello", 20)
에서 “hello”와 20
- 매개변수(Parameter) : 메서드를 정의할 때 선언한 변수
int call(String str, int age)
에서 String str와 int age- 메서드 호출시 인수를 넘기면, 해당 인수가 매개변수에 대입된다.
3. 메서드 호출과 값 전달
- 자바는 항상 변수의 값을 복사해서 대입한다.
예시1
public class MethodValue1 { public static void main(String[] args) { int num1 = 5; System.out.println("1. changeNumber 호출 전, num1: " + num1); changeNumber(num1); System.out.println("4. changeNumber 호출 후, num1: " + num1); } public static void changeNumber(int num2) { System.out.println("2. changeNumber 변경 전, num2: " + num2); num2 = num2 * 2; System.out.println("3. changeNumber 변경 후, num2: " + num2); } }
- 실행 결과
- num1의 값을 복사해서 num2에 전달한다.
- num2 값은 10으로 변경되지만, num2의 변경은 num1에 영향을 주지 않는다.
1. changeNumber 호출 전, num1: 5 2. changeNumber 변경 전, num2: 5 3. changeNumber 변경 후, num2: 10 **4. changeNumber 호출 후, num1: 5**
- 실행 결과
- 예시2
- 메서드의 호출 결과를 반환받아서 사용하면 값이 변경된다.
public class MethodValue3 { public static void main(String[] args) { int num1 = 5; System.out.println("changeNumber 호출 전, num1: " + num1); // 출력: 5 **num1** = changeNumber(num1); System.out.println("changeNumber 호출 후, num1: " + num1); // 출력: 10 } public static int changeNumber(int num2) { num2 = num2 * 2;return num2; } }
실행 결과
changeNumber 호출 전, num1: 5 **changeNumber 호출 후, num1: 10**
4. 메서드 오버로딩(Overloading)
- 이름이 같고, 매개변수가 다른 메서드를 여러 개 정의하는 것
반환타입이 다른 건 인정하지 않는다.
public static void main(String[] args) { myMethod(1, 1.2); // myMethod(int a, double b) 호출 myMethod(1.2, 2); // myMethod(double a, int b) 호출 } public static void myMethod(int a, double b) { System.out.println("int a, double b"); } public static void myMethod(double a, int b) { System.out.println("double a, int b"); }
- 본인의 타입에 최대한 맞는 메서드를 찾아서 실행하고, 그래도 없으면 형 변환이 가능한 타입의 메서드를 찾아서 실행한다.
김영한의 자바 입문을 참고하였습니다