티스토리 뷰
선언위치에 따른 변수의 종류
- 선언위치(영역)
- 선언위치에 따른 변수의 종류
- 변수의 생성시기
선언위치(영역)
- 클래스 영역 - 선언문만 가능(변수 선언, 메서드 정의), 순서 상관x
- 클래스 영역 이외의 영역 : ① 메서드 영역, ② 생성자, ③ 초기화 블럭 내부
그 동안은 '변수 타입'에 대해서만 다뤘는데, 이제부터 '변수의 종류'에 대해 공부할 예정이다. '변수의 종류'는 선언위치에 따라 나눈다. 따라서 선언 위치에 대해 공부해야 한다.
선언위치에 따른 변수의 종류
- 인스턴스변수(iv) - 클래스 영역
- 클래스변수(static변수, cv) - 클래스 영역
- 지역변수(lv) - 클래스 영역 이외의 영역

변수의 생성시기
- lv - 변수 선언문이 수행되었을 때
메서드 종료 시 자동 제거(범위, scope) - iv - 인스턴스가 생성되었을 때 ⭐
객체 생성 후 사용 가능 - cv - 클래스가 메모리에 올라갈 때
아무때나 사용 가능

(프로그래밍 관점)객체 = iv 집합
‘객체’란 변수 여러 개를 묶어놓은 것이다. 이렇게 생각하면 앞으로 ‘객체지향’을 쉽게 공부할 수 있다. 엄밀히 얘기하면 이 명제가 틀리다 할 수 있지만, 그런거 생각하지 말라는 것이다. ‘객체지향’이란 프로그램에 ‘객체지향’ 개념을 끌어온 것이다. ‘객체지향’ 자체를 완벽히 이해하는 것보다, 철저하게 프로그래밍, 코딩 관점에서 ‘객체지향’ 개념을 이해하는 것이 훨씬 쉽다. 프로그래밍 관점에서 ‘객체’란 iv, 즉 변수를 여러 개 묶어놓은 것이다. 그 이상 그 이하도 아니다.
‘객체’란 변수 여러 개를 묶어놓은 것이라 암기하면 그만이다. 이해할 필요도 없다.
‘클래스가 메모리에 올라갈 때’란 ‘클래스가 필요할 때’ 메모리가 올라가겠죠. ‘클래스’란 ‘설계도’를 뜻한다. ‘설계도’가 언제 필요할까. ‘객체’를 생성할 때 필요하다. 객체를 만들기 전에 설계도가 메모리에 먼저 올라가야 한다. 그래야 그 설계도를 보고 객체를 만들 수 있기 때문이다.
CPU는 모든 작업을 RAM하고만 한다.
CPU가 있을 때, 여러분이 가지고 있는 파일들은 SSD나 하드디스크인 ‘디스크’에 저장되어 있다. 예를 들어, Time 클래스가 ‘Time.class’와 같이 파일 형태로 디스크에 저장되어 있다. 그런데 CPU는 이와 같은 파일을 직접 갖고 오지 못 한다. 왜냐하면, CPU와 ‘저장 장치’와의 속도 차이 때문이다. 저장장치보다 CPU가 훨씬 빠르기 때문에 읽어오지 못한다. 그래서 중간에 둔 게 RAM이다. RAM은 메모리이다. 따라서, 파일을 읽으려면, 파일을 메모리에 올려야 한다. 디스크에서 파일을 메모리에 올리는 것을 ‘로딩’이라 한다. 메모리에 Time.class가 로딩된 다음에서야 CPU가 읽고 쓸 수 있다. CPU는 모든 작업을 RAM하고만 한다. 우리가 작업한 내용을 RAM에서 디스크에 저장해야 한다. 이를 ‘세이브’라 한다. 우리가 작업한 내용을 디스크에 저장하지 않고 컴퓨터를 끄면 다 날라간다. 그래서 우리가 모든 작업을 하려면 파일이 메모리에 올라와야 한다. 이것을 ‘클래스가 메모리에 올라간다’고 표현한다. 예를 들어, Time.class 파일이 메모리에 올라가면서 클래스변수 cv가 자동으로 만들어진다. 객체 생성을 할 필요가 없다.
cv는 아무때나 사용할 수 있다고 기억하면 된다. 반면 iv는 ‘객체 생성’을 해야 사용할 수 있다.

클래스변수와 인스턴스변수
- 클래스변수
- 인스턴스변수
1. 클래스변수
- 공통 속성
- 아무때나 사용 가능
- 사용 방법 : '클래스이름.클래스변수'
- 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다
2. 인스턴스변수
- 개별 속성
- 객체 생성 후 사용 가능
- 사용 방법 : '참조변수.인스턴스변수'
- 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지
cv - 공통 속성 iv - 개별 속성


[객체 사용 방법] cv - '클래스이름.클래스변수' iv - '참조변수.인스턴스변수'

플래시로 보는 cv와 iv

- iv는 객체마다 여러 개 만들어지고, cv는 다른 공간에 한 개만 만들어진다.
예제6-3
'참조변수.클래스변수' 형태로 static변수를 사용하면 안 되는 이유
c1.width = 50;
c1.height = 80;
코드를 해석하면, c1의 width와 height의 값을 변경하는 것이다.
하지만, width와 height 모두 클래스변수이기 때문에, 참조변수로 c1을 사용했다 하더라도, Card인스턴스 c2의 width와 height도 같이 변경된다.
c1의 width와 height를 각각 50, 80으로 변경합니다.
c1은 Heart, 7이며, 크기는 (50, 80)
c2는 Spade, 4이며, 크기는 (50, 80)
따라서 코드에 '클래스이름.클래스변수', 즉 'Card.width'와 'Card.height' 형태로 사용해야 한다.
플래시MemberVar.exe
메모리 구조를 그려보세요.(MemberVar.exe) - 코드만 보고 그림을 따라그릴 수 있도록 연습을 하셔야 해요.
메서드
- 작업단위로 {문장들}을 묶어서 이름 붙인 것
- 값(입력)을 받아서 처리하고, 결과를 반환(출력)
작업단위로 {문장들}을 묶어서 이름 붙인 것


반환타입 메서드이름 (타입 변수명, 타입 변수명, ...) {
// 메서드 호출 시 수행될 코드
}
값(입력)을 받아서 처리하고, 결과를 반환(출력)

- | 참고 | 메서드는 클래스 안에 있어야 하는 제약이 있고, 함수는 클래스에 독립적이다. 메서드와 함수가 같다 생각하면 된다.
메서드의 장점
- 높은 재사용성(reusability)
- 중복된 코드의 제거
- 프로그램의 구조화
메서드의 작성
- 반복적으로 수행되는 여러 문장을 메서드로 작성
- 하나의 메서드는 한 가지 기능만 수행하도록 작성
메서드의 구성
- 메서드 = 선언부 + 구현부
메서드 = 선언부 + 구현부
- 선언부 : 반환타입 메서드이름(타입 변수명, 타입 변수명, ...) ← 매개변수 목록
- 구현부 : { /* 메서드 호출 시 수행될 코드 */ }
메서드의 선언부
- 입력(매개변수) : 0 ~ n개
- 출력(반환값) : 0 ~ 1개
- 출력값이 없는 경우, 반환타입 대신 void 작성

메서드의 구현부
- 지역변수(lv) : 메서드 내에 선언된 변수
- 지역변수의 유효범위(scope)는 메서드 시작({)부터 끝(})까지
- 매개변수도 지역변수다.

메서드의 호출
- 메서드의 호출 방법
- 메서드의 실행 흐름
메서드의 호출 방법
- 메서드 호출
- 메서드 호출 후, 결과를 변수에 저장(반환값O)
메서드이름(값1, 값2, …); // 메서드 호출 방법 1
타입 변수명 = 메서드이름(값1, 값2, …) // 메서드 호출 방법 2
print99danAll(); // void print99danAll()을 호출
int result = add(3, 5); // int add(int x, int y)를 호출하고, 결과를 result에 저장
- 괄호안에는 메서드 작업 시 필요한 값들을 적어주면 된다.
- 이러한 값들을 '인수(argument, 원본)'라 한다.
메서드의 실행 흐름
① main메서드에서 add메서드를 호출한다. 호출 시 지정한 인수 1L과 2L이 add메서드의 매개변수 a, b에 각각 복사(대입)된다.
② add메서드의 괄호{} 안에 있는 문장들이 순서대로 수행된다.
③ add메서드의 모든 문장이 실행되거나 return문을 만나면, 호출한 메서드(main메서드)로 되돌아와서 이후의 문장들을 실행한다.


- 인수(argument, 원본) : 메서드를 호출할 때 괄호()안에 지정해준 값들
- 매개변수(parameter, 복사본) : 메서드를 호출한 쪽에서 넘겨준 값을 메서드에 전달하는 중간 매개체 역할을 하는 변수
예제6-4
return문
- 실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.
- 반환타입이 void가 아닌 경우, 반드시 return문 필요
실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.
- 반환타입이 void일 경우에만 return;생략 가능(컴파일러가 자동 추가)
void printGugudan(int dan) {
if(!(2 <= dan && dan <= 9))
return; // dan의 값이 2~9가 아닌 경우, 호출한 곳으로 그냥 되돌아간다.
for(int i = 1; i <= 9; i++) {
System.out.printf("%d * %d = %d%n", dan, i, dan * i);
}
// return; // 반환 타입이 void이므로 생략가능. 컴파일러가 자동추가
}
반환타입이 void가 아닌 경우, 반드시 return문 필요
- 조건식이 참일 경우와, 거짓일 때 모두 빠짐없이 return문을 작성해야 한다.(에러)
int multiply(int x, int y) {
int result = x * y;
return result; // 반환 타입이 void가 아니므로 생략불가
}
int max(int a, int b) {
if(a > b)
return a; // 조건식이 참일 때만 실행된다.
// 에러. 조건식이 거짓일 경우 return문이 없음
}
반환값
- 반환타입이 void가 아닌 경우 return문 옆에 반환값을 생략할 수 없다.
- 반환값의 타입은 반환타입과, 반환값의 타입이 일치해야 한다.
JVM의 메모리 구조
- ① 메서드 영역(method area)
- ② 호출 스택(call stack)
- ③ 힙(heap)
JVM의 메모리 구조

메서드 영역(Method Area)
- 클래스와 클래스변수(cv)가 저장되는 공간
- 프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장
호출 스택(call stack)
- 스택 : 밑이 막힌 상자, 위에 차곡차곡 쌓인다.
- 호출스택 : 메서드 수행에 필요한 메모리가 제공되는 공간
밑이 막힌 상자, 위에 차곡차곡 쌓인다.

메서드 수행에 필요한 메모리가 제공되는 공간
- 특징 1. 메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제
- 특징 2. 아래 있는 메서드가 위의 메서드를 호출한 것
- 특징 3. 맨 위의 메서드 하나만 실행 중, 나머지는 대기중

예제6-5
힙(heap)
- 인스턴스(iv)가 생성되는 공간
기본형 매개변수
- 변수의 값을 읽기만 할 수 있다. (read only)
예제6-6
- 코드
- 플래시PrimitiveParam.exe
플래시PrimitiveParam.exe

메모리 구조를 그려보세요.(PrimitiveParam.exe) - 코드만 보고 그림을 따라그릴 수 있도록 연습을 하셔야 해요.
참조형 매개변수
- 변수의 값을 읽고 변경할 수 있다. (read & write)
예제6-7
- 코드
- 플래시ReferenceParam.exe

메모리 구조를 그려보세요.(ReferenceParam.exe) - 코드만 보고 그림을 따라그릴 수 있도록 연습을 하셔야 해요.
참조형 반환타입
예제6-8
- 코드
- 플래시PrimitiveParam.exe

메모리 구조를 그려보세요.(ReferenceReturn.exe) - 코드만 보고 그림을 따라그릴 수 있도록 연습을 하셔야 해요.
static메서드와 인스턴스메서드
- 인스턴스 메서드
- static메서드(클래스메서드)
1. 인스턴스 메서드
- 인스턴스 생성 후, 호출 가능한 메서드
- 호출 방법 : ‘참조변수.메서드이름()’
- 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
- 메서드 내에서 iv, im 사용 가능
2. static메서드(클래스메서드)
- 객체 생성 없이 호출 가능한 메서드
- 호출 방법 : ‘클래스이름.메서드이름()’ ex. Math.random(), Math.round()
- 인스턴스 멤버(iv, im)와 관련 없는 작업을 하는 메서드
- 메서드 내에서 iv, im 사용 불가

| 외우세요 | iv를 사용하지 않을 때 static 붙인다. ⭐️
예제6-9
static을 언제 붙여야 할까?
- 속성(멤버변수) 중 공통 속성에 static을 붙인다.
- 인스턴스 멤버(iv, im)를 사용하지 않는 메서드에 static을 붙인다.
속성(멤버 변수) 중 공통 속성에 static을 붙인다.

인스턴스 멤버(iv, im)를 사용하지 않는 메서드에 static을 붙인다.
class MyMath2 {
long a, b;
long add() { return a + b; } // a, b는 인스턴스변수(iv)
static long add(long a, long b) { return a + b; } // a, b는 지역변수(lv)
}
| 외우세요 | iv를 사용하지 않을 때 static 붙인다. ⭐️
메서드 간의 호출과 참조
- static메서드는 인스턴스 변수(iv)를 사용할 수 없다.
- static메서드는 인스턴스 메서드(im)를 호출할 수 없다.
static메서드는 인스턴스 멤버(iv, im)를 사용할 수 없다.
class TestClass {
int iv; // 인스턴스변수
static int cv; // 클래스변수
void instanceMethod() { // 인스턴스메서드
System.out.println(iv); // 인스턴스변수를 사용할 수 있다.
System.out.println(cv); // 클래스변수를 사용할 수 있다.
}
static void staticMethod() { // static메서드
System.out.println(iv); // 에러!!! 인스턴스변수를 사용할 수 없다.
System.out.println(cv); // 클래스변수는 사용할 수 있다.
}
} // end of class
static메서드는 인스턴스 메서드(im)를 호출할 수 없다.
class TestClass {
void instanceMethod() {} // 인스턴스메서드
static void staticMethod() {} // static메서드
void instanceMethod2() { // 인스턴스메서드
instanceMethod(); // 다른 인스턴스메서드를 호출한다.
staticMethod(); // static메서드를 호출한다.
}
static void staticMethod2() { // static메서드
instanceMethod(); // 에러!!! 인스턴스메서드를 호출할 수 없다.
staticMethod(); // static메서드는 호출할 수 있다.
}
} // end of class
인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수도 있기 때문이다. 🙆
자주 물어보는 질문 ❓
- Q1. static메서드는 static메서드 호출 가능?
- Q2. static메서드는 인스턴스변수 사용 가능?
- Q3. static메서드는 인스턴스메서드 호출 가능
- Q4. 왜? static메서드는 인스턴스멤버를 쓸 수 없나요?
Q1. static메서드는 static메서드 호출 가능?
A. 네
Q2. static메서드는 인스턴스변수 사용 가능?
A. 아니요
Q3. static메서드는 인스턴스메서드 호출 가능?
A. 아니요
Q4. 왜? static메서드는 인스턴스멤버를 쓸 수 없나요?
A. static메서드 호출 시 객체(iv묶음)가 없을 수도 있어서
🍪
📄 - 객체지향개념 암기노트 바로가기
'Java의 정석_기초편' 카테고리의 다른 글
| 생성자(constructor) (0) | 2022.10.12 |
|---|---|
| 오버로딩(overloading)과 오버라이딩(overriding) (0) | 2022.10.12 |
| 클래스와 객체 (0) | 2022.10.10 |
| 객체지향 언어 (0) | 2022.10.10 |
| 추상 클래스(abstract class) (0) | 2022.10.09 |


