우리는 다양한 변수의 종류에 대해서 알아보았다
..변수를 클릭하면 자세한 내용을 알 수 있다
이번엔 객체 지향에서 변수의 종류에 대해서 알아보자
선언 위치에 따른 변수의 종류
class Variables {
int iv;
static int cv;
void method() {
int lv = 0;
}
}
영역에 따른 변수는 종류가 정해져있고 이는 후에 객체 지향을 할때 굉장히 중요하게 작용한다.
영역은 크게 두개로 나뉜다.클래스 영역(iv)과 메소드 영역(lv)
- 클래스 영역 ( 클래스 영역은 변수 or 메소드선언만이 가능하다 )
- iv = 인스턴스 변수
- cv = 클래스 변수(static 변수, 공유 변수) - static이 붙어야만 한다.
- 메소드 영역 ( 메소드는 안에 내용이 적혀있지 않다면 선언한것이고, 적혀있다면 정의한것이다 )
- lv = 지역 변수 - 이 변수는 메소드 종료시에 자동으로 제거된다
변수의 종류 | 선언위치 | 생성시기 |
클래스 변수 ( CV ) | 클래스 영역 | 클래스가 메모리에 올라갈때 |
인스턴스 변수 ( IV ) | 인스턴스가 생성되었을때 | |
지역 변수 ( LV ) | 메소드 영역 (메서드 생성자, 초기화 블럭 내부) |
변수 선언문이 수행되었을때 |
클래스 변수와 인스턴스 변수
class Card {
String kind;
int number;
static int width = 100;
static int height = 250;
}
이렇게 되어있다 가정한다면
Card c = new Card();
c.kind = "HEART"; // IV사용법
c.number = 5; // IV사용법
Card.width = 200; // CV사용법
Card.height = 300; // CV사용법
CV를 잘 봐야 한다 c.width, c.height 이렇게 사용해도 되지만 권장되지 않는 스타일이다
매개변수
스택을 쌓아보며 이해한다면 스택까지 같이 이해 할수 있다.
- 기본형 매개변수 - 변수의 값을 읽기만 할 수 있다.
1번. 매개변수를 기본형으로만 지정해서 Data값을 건들일 수가 없다.
class Data { int x; }
class Ex1 {
public static void main ( String[] args) {
Data d = new Data(); //객체를 생성
d.x = 10; //x의 값을 10으로 저장
System.out.println("main() : x = " + d.x);
change(d.x); //여기서 스택에 change가 쌓인다.
System.out.println("After change(d.x)");
System.out.println("main() : x = " + d.x); //d.x의 값은 바뀌지 않았다.
}
static void change(int x) { //x(기본형 매개변수)에 d.x의 값인 10이 저장된다.
x = 1000; //불러낸 change메소드에 의해 x가 1000으로 저장된다.
System.out.println("change() : x = " + x);
} // change메소드가 끝나며 다시 돌아간다.
※ 여기서 d.x와 x의 값은 다르다.
- 참조형 매개변수 - 변수의 값을 읽고 변경을 할 수 있다.
2번. 매개변수 자체를 참조형으로 집어넣으니 메소드가 직접 참조값을 바꿀수 있다.
class Data2 { int x; }
class Ex2 {
public static void main ( String[] args) {
Data2 d = new Data2(); // 객체를 생성한다.
d.x = 10; // d.x에 10을 저장하고
System.out.println("main() : x = " + d.x); // 출력한다. 스택이 쌓였다가 실행되고 빠진다.
change(d); // d.x의 값이 아닌 d자체를 보낸다.
System.out.println("After change(d)");
System.out.println("main() : x = " + d.x); // d.x의 값이 change에 의해 바뀌었기 때문에 1000이 출력된다.
}
static void change(Data2 d) { // 기본형과 다르게 d값(참조형 매개변수)자체가 바뀐다
d.x = 1000; // d.x가 1000으로 바뀐다.
System.out.println("change() : x = " + d.x);
} // change메소드가 끝나며 다시 돌아간다.
※ 참조형을 직접 매개변수로 지정하면서 change메소드가 d의 값을 직접 건들이는것이 중요하다.
- 참조형 매개변수 - 변수의 값을 읽고 변경을 할 수 있다.
3번. 지금까지의 반환타입은 그저 void였다. 이번엔 반환타입 또한 참조타입이 된다면 어떨까
class Data3 { int x; }
class Ex2 {
public static void main ( String[] args) {
Data3 d = new Data3(); // 객체를 생성한다.
d.x = 10; // d.x의 값은 10으로 저장된다.
Data3 d2 = copy(d); // d2라는 객체를 생성한다. copy의 return값이 d2에 저장된다.
System.out.println("d.x = " + d.x); // 처음에 만든 d는 저장해둔 10을 반환하고
System.out.println("d2.x = " + d2.x); // copy값을 받은 d2또한 10을 반환한다.
}
static Data3 copy(Data3 d) { // d를 참조형 매개변수로 하여 d가 바라보는값과 같아진다
Data3 tmp = new Data3(); // tmp를 생성한다 그러면 tmp라는건 새로운 곳을 바라본다
tmp.x = d.x; // d가 바라보는 값(10)이 tmp가 바라보는 값에 저장되는것이다.
return tmp; // tmp값을 반환한다.
}
여기서 중요한것은 tmp는 Data3값이다. 즉, copy를 받는 값또한 Data3을 참조하고 있어야한다는것이다.
※ 여기선 주소의 개념이 중요하다. copy는 새로운 주소를 만들었고 거기에 정보를 저장했다. 그리고 스택에서 사라지면서 남긴 데이터를 main의 d2가 사용한다는것이 중요하다.
변수의 초기화
지역 변수(lv)는 반드시 사용하기 전에 초기화를 해주어야 한다
class InitTest {
int x;
int y = x;
void method1() {
int i;
int j = i; // 에러
}
}
에러의 이유는 i라는 지역변수를 초기화 하지 않았다.
하지만 iv(인스턴스 변수)와 cv(클래스 변수)는 자동으로 0으로 초기화가 되기 때문에 괜찮다.
이것이 자동 초기화 이다.
● 멤버 변수의 초기화
1. 명시적 초기화 ( = ) : 대입 연산자를 이용한 간단 초기화이다.
class Car {
int door = 4; // 기본형(primitive type)변수의 초기화
Engine e = new Engine(); // 참조형(reference type)변수의 초기화
}
2. 초기화 블럭 : 안에 여러문장을 넣어서 해야할일이 살짝 복잡할땐 복잡한 초기화할때 사용한다
- 인스턴스(iv) 초기화 블럭 : {}
- 클래스(cv) 초기화 블럭 : static {}
3. 생성자 : iv 초기화에 사용하고 복잡한 초기화에도 사용한다.
Car(String color, String gearType, int door) { // 매개변수있는 생성자
this.color = color;
this.gearType = gearType;
this.door = door;
}
● 초기화 시점
- 클래스 변수 초기화 시점 : 클래스가 처음 로딩될때 단 한번
- 인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때 마다.
class InitTest {
static int cv = 1; // static 명시적 초기화
int iv = 1; // 인스턴스 명시적 초기화
static { cv = 2; } // 클래스 초기화 블럭
{ iv = 2; } // 인스턴스 초기화 블럭 ( {} )
InitTest() { // 인스턴스 초기화 ( 생성자 )
iv = 3;
}
}
InitTest it = new InitTest(); 라고 선언 해주었을때 | ||||||
클래스 초기화 | 인스턴스 초기화 | |||||
기본값 | 명시적 초기화 | 클래스 초기화블럭 | 기본값 | 명시적 초기화 | 인스턴스 초기화 블럭 | 생성자 |
cv = 0 자동 초기화 |
cv = 1 간단 초기화 |
cv = 2 복잡초기화 static {} |
cv = 2 iv = 0 자동초기화 |
cv = 2 iv = 1 간단초기화 |
cv = 2 iv = 2 복잡초기화 |
cv = 2 iv = 3 복잡초기화 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
- cv를 먼저 처리한 후에 iv를 정의한다
- 순서는 자동 - 간단 - 복잡(static{}, 생성자)
정리
CV,IV 초기화 방법에는 3가지가 있다.
- 자동초기화 = 0으로 초기화되는것
- 간단초기화 = 대입연산자를 사용( = )
- 복잡초기화
- CV초기화 = { }, static { }
- IV초기화 = 생성자
CV 복잡 초기화 하는 방법
class StaticBlockTest {
static int[] arr = new int[10]; 간단 초기화(명시적 초기화)
static { 복잡 초기화 (클래스 초기화 블럭)
for(int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * 10) + 1;
}
}
}
이것이 CV복잡초기화 static {} 을 사용한 방법이다.
'Java > 객체 지향' 카테고리의 다른 글
호출 스택(call stack) (0) | 2023.05.08 |
---|---|
메소드(ft . return 문) (0) | 2023.05.08 |
클래스와 객체(feat. 객체 지향 언어의 역사) (0) | 2023.05.04 |
다향성 (참조변수의 형변환, instanceof 연산자) (0) | 2023.03.07 |
클래스들의 관계. 상속과 포함 (0) | 2023.03.07 |