Exam0100.java
$ java ... Exam0110↵
// # 변수의 종류
package com.eomcs.oop.ex03;
public class Exam0100 {
// static 필드 = 클래스 필드(변수)
// - 클래스를 로딩할 때 Method Area 영역에 생성된다.
// - 클래스는 단 한 번만 로딩된다.
// - 따라서 스태틱 변수도 한 번만 생성된다.
// - JVM을 종료할 때 메모리에서 한꺼번에 제거된다.
static int a;
// non-static 필드 = 인스턴스 필드
// - new 연산자를 실행할 때 Heap 영역에 생성된다.
// - new 연산자를 실행할 때마다 생성된다.
// - Garbage Collector에 의해 인스턴스가 해제될 때 제거된다.
int b;
public static void main(String[] args /* 파라미터 = 로컬 변수 */) {
// 로컬 변수
// - 메서드가 호출될 때 JVM Stack 영역에 생성된다.
// - 메서드 호출이 끝나면 제거된다.
int c;
c = 100;
// <=== 현재 실행 시점
// - Method Area: a 변수 존재
// - JVM Stack: args, c, obj 변수 존재
// - Heap: 아직 생성된 객체 없음
Exam0100 obj; // obj는 main()을 호출할 때 시작 시점에 JVM Stack에 생성된 상태이다.
obj = new Exam0100();
// <=== 현재 실행 시점
// - Method Area: a 변수 존재
// - JVM Stack: args, c, obj 변수 존재
// - Heap: b 변수 존재
System.out.println(c);
}
}
ㄴ 이 코드의 실행과정을 그림으로 나타내면 위 그림과 같음
Exam0110.java
$ java ... Exam0110↵
// # 인스턴스 변수
package com.eomcs.oop.ex03;
public class Exam0110 {
// 지금 당장 A 클래스 앞에 붙은 static은 고민하지 말라!
// 이 예제의 목표는 인스턴스 변수이다.
static class A {
// 인스턴스 변수 = 논스태틱 변수
// => new 명령을 통해 생성된다.
// => new 명령을 실행하기 전까지는 인스턴스 변수는 존재하지 않는다.
// => Heap 영역에 생성된다.
// => static이 붙지 않는다.
int v1; // 4바이트 int 값을 저장할 메모리를 만들라는 명령!
boolean v2; // true/false 논리값을 저장할 메모리를 만들라는 명령!
// 이 명령은 new 명령을 실행할 때 비로서 실행된다.
}
public static void main(String[] args) {
// A 클래스에 대해 new 명령을 사용하기 전에는 v1, v2 메모리는 존재하지 않는다.
// 단지 설계도일 뿐이다.
A obj1 = new A(); // A 클래스에서 변수 선언 명령을 실행한다. 주의! 메서드 정의는 실행하지 않는다!
A obj2 = new A();
A obj3 = new A();
// 이렇게 생성된 메모리를 "인스턴스", "객체"라고 부른다.
// 이 인스턴스의 주소를 저장하는 obj1, obj2, obj3를 "레퍼런스"라 부른다.
// 인스턴스가 생성될 때 만들어지는 v1, v2를 변수를 "인스턴스 변수"라 부른다.
// 인스턴스 변수는 레퍼런스를 통해 사용할 수 있다.
obj1.v1 = 100;
obj2.v1 = 200;
obj3.v1 = 300;
System.out.printf("%d, %d, %d\n", obj1.v1, obj2.v1, obj3.v1);
}
}
// 인스턴스 변수는 new 명령을 실행할 때 마다 생성되기 때문에
// 각각 구분되는 개별 데이터를 저장할 때 사용한다.
ㄴ 이 코드의 실행과정을 그림으로 나타내면 아래 그림과 같음
Exam0120.java
$ java ... Exam0120↵
// # 인스턴스 변수 응용 - 성적 데이터 저장할 메모리 만들기
package com.eomcs.oop.ex03;
public class Exam0120 {
// 1) 성적 데이터를 설계할 클래스이기 때문에 그에 맞는 클래스명을 사용하라!
static class Score {
// 2) 여러 명의 구별되는 성적 데이터를 저장해야 하기 때문에
// 인스턴스 변수로 메모리를 설계하라!
String name;
int kor;
int eng;
int math;
int sum;
float average;
}
public static void main(String[] args) {
// 저장하고 싶은 데이터 개수 만큼 인스턴스를 생성하라!
Score s1 = new Score(); // 1명 분의 성적 데이터를 저장할 메모리
Score s2 = new Score();
Score s3 = new Score();
// 각 인스턴스에 한 명의 성적 데이터를 저장하라!
s1.name = "홍길동";
s1.kor = 100;
s1.eng = 90;
s1.math = 80;
s1.sum = s1.kor + s1.eng + s1.math;
s1.average = s1.sum / 3f;
s2.name = "임꺽정";
s2.kor = 100;
s2.eng = 100;
s2.math = 100;
s2.sum = s2.kor + s2.eng + s2.math;
s2.average = s2.sum / 3f;
s3.name = "유관순";
s3.kor = 100;
s3.eng = 90;
s3.math = 60;
s3.sum = s3.kor + s3.eng + s3.math;
s3.average = s3.sum / 3f;
}
}
ㄴ 이 코드의 실행과정을 그림으로 나타내면 아래 그림과 같음
Exam0130.java
$ java ... Exam0130↵
// # 클래스 변수
package com.eomcs.oop.ex03;
public class Exam0130 {
// 지금 당장 A 클래스 앞에 붙은 static은 고민하지 말라!
// 이 예제의 목표는 스태틱 변수이다.
static class A {
// 클래스 변수 = 스태틱 변수
// - static 이 붙은 변수이기 때문에 "스태틱 변수"라고도 부른다.
// - 클래스를 로딩하는 순간 자동 생성된다.
// - 클래스와 함께 "Method Area" 영역에 존재한다.
// - 클래스 이름으로 접근
// 클래스 이름으로 접근한다고 해서 "클래스에 소속된 변수", "클래스 변수"라 부른다.
// - 문법
// static 데이터타입 변수명;
//
static int v1;
static boolean v2;
}
public static void main(String[] args) {
// 클래스 변수 사용법
// 클래스명.스태틱변수명 = 값;
// 클래스를 사용하는 순간 클래스가 로딩되고, 스태틱 변수는 자동 생성된다.
A.v1 = 100;
A.v2 = true;
System.out.printf("%d, %b\n", A.v1, A.v2);
}
}
// JVM을 실행하는 동안 한 번 클래스가 로딩되면 같은 클래스에 대해 중복 로딩되지 않는다.
// 클래스 변수는 클래스가 로딩될 때 자동 생성되기 때문에
// 클래스에 대해 딱 한 번 생성된다.
//
// ## 클래스 로딩
// - 외부 저장장치(예: HDD, USB 메모리, DVD-ROM 등)에 있는 .class 파일을
// JVM이 관리하는 메모리로 로딩하는 것.
// - 클래스의 코드를 사용하는 시점에 메모리(Method Area 영역)에 로딩된다.
// ## 클래스의 코드를 사용하는 시점?
// - 스태틱 멤버(필드와 메서드)를 사용할 때
// 예) A.v1 = 200; <--- 스태틱 변수 v1 사용
// 예) System.out.println(A.v1); <--- 스태틱 변수 out 사용
// 예) Integer.parseInt(..); <--- 스태틱 메서드 parseInt() 사용
// - new 명령을 사용하여 인스턴스를 생성할 때
// 예) new A();
// - 한 번 클래스가 로딩되면 JVM을 종료할 때까지 유지한다.
// - 물론 강제로 클래스를 unloading 할 수 있다.
// 그리고 다시 로딩할 수 있다.
// ## 주의! 클래스를 로딩할 거라고 착각하는 경우
// - 다음과 같이 레퍼런스 변수를 선언할 때는 클래스를 로딩하지 않는다.
// 로딩하지 않는다! 로딩하지 않는다! 로딩하지 않는다!
// 예) A obj;
// 예) String str;
// ## 클래스 로딩 과정
// $ java com.eomcs.oop.ex03.Exam0130
// 1) 클래스 파일 'Exam0130.class'을 찾는다.
// - JDK에서 제공하는 기본 라이브러리에서 찾는다.
// - JVM을 실행할 때 -classpath(또는 -cp) 지정한 CLASSPATH 디렉토리에서 찾는다.
// - CLASSPATH에 없으면 JVM을 실행하는 현재 폴더에서 찾는다.
// - 그래도 없으면 오류를 띄운다.
// 2) 바이트코드 검증(Verify)
// - 클래스의 바이트코드 유효성을 검사한다.
// 3) Exam0130.class를 "Method Area 영역"에 로딩한다.
// - 즉 클래스를 외부 저장소(HDD)에서 내부 저장소(RAM)로 로딩한다.
// - bytecode를 분석하여 코드(생성자, 메서드)와 상수를 따로 분리하여 보관한다.
// 4) 스태틱 필드 및 메서드 테이블 준비(Prepare)
// - Method Area 에 스태틱 필드 생성한다.
// - 클래스 내부에서 사용하는 이름(변수명, 메서드명, 클래스명 등) 목록을 준비한다.
// 5) 참조하는 외부 클래스나 인터페이스 검사(Resolve)
// - 로딩된 클래스가 참조하는 외부 클래스나 인터페이스의 유효성을 검사한다.
// 6) 클래스 초기화시키기
// - 스태틱 블록(static initializers)을 실행한다.
// 7) main() 메서드를 호출한다.
// - 클래스를 실행하는 것이라면 main() 메서드를 찾아 실행한다.
// ## Exam0130의 main() 메서드 호출
// 1) main() 메서드에 선언된 로컬 변수를 "JVM 스택 영역"에 생성한다.
// - args 변수를 스택 영역에 생성한다.
// 2) main()의 코드를 실행한다.
// - A.v1 = 100;
// => A.class 를 "Method Area"에 로딩한다.
// => A의 클래스(스태틱) 필드를 "Method Area"에 생성한다.
// => `A.v1 = 100` 문장을 실행한다.
// - A.v2 = true;
// => A 클래스가 이미 로딩되었기 때문에 다시 로딩하지 않는다.
// => `A.v2 = true` 문장을 실행한다.
// - System.out.printf() 를 실행한다.
//
// ## JVM이 관리하는 메모리 영역
// 1) Heap
// - new 명령으로 생성한 인스턴스 변수가 놓인다.
// - 즉 인스턴스 필드가 이 영역에 생성된다.
// - 메서드는 생성하지 않는다!
// - 가비지 컬렉터는 이 메모리의 가비지들을 관리한다.
// 2) JVM Stack
// - 각 스레드가 개인적으로 관리하는 메모리 영역이다.
// - 스레드에서 메서드를 호출할 때 메서드의 로컬 변수를 이 영역에 만든다.
// - 메서드가 호출될 때 그 메서드가 사용하는 로컬 변수를 프레임에 담아 만든다.
// - 메서드 호출이 끝나면 그 메서드가 소유한 프레임이 삭제된다.
// 3) Method Area
// - JVM이 실행하는 바이트코드(.class 파일)를 두는 메모리 영역이다.
// - 바이트코드를 그대로 메모리에 두는 것이 아니라, 멤버의 종류에 따라 적절하게 분류한다.
// - 즉 클래스 코드가 이 영역에 놓이는 것이다.
// - JVM은 코드를 실행할 때 이 영역에 놓은 명령어를 실행하는 것이다.
// - 개발자가 작성한 클래스, 메서드 등 이런 코드들이 이 영역에 놓이는 것이다.
// - 스태틱 필드를 이 영역에 생성한다.
// - 주의!
// Heap에는 개발자가 작성한 명령어가 없다.
//
ㄴ 이 코드의 실행과정을 그림으로 나타내면 아래 그림과 같음
Exam0140.java
$ java ... Exam0140↵
// # 클래스 변수와 인스턴스 변수 생성 시점과 메모리 영역
package com.eomcs.oop.ex03;
public class Exam0140 {
static class A {
static int v1;
int v2;
}
public static void main(String[] args) {
// 클래스 변수는 클래스가 로딩되는 순간 바로 사용할 수 있다.
// 클래스가 로딩되는 경우:
// - 클래스 변수나 클래스 메서드를 사용할 때
// - 인스턴스를 생성할 때
// - 단 중복 로딩되지 않는다.
//
A.v1 = 100;
// v2 는 인스턴스 변수이기 때문에 사용하기 전에 new 명령으로 먼저 생성해야 한다.
// A.v2 = 200; // 컴파일 오류!
A p = new A();
// 이제 v2 변수는 Heap에 생성되었다.
// A클래스의 인스턴스를 만들 때
// static 이 안붙은 변수(non-static 변수 = 인스턴스 변수)가 그 대상이다.
//
// v2 인스턴스 변수는 인스턴스 주소를 통해 사용해야 한다.
// 클래스이름으로 사용할 수 없다.
// A.v2 = 200; // 컴파일 오류!
p.v2 = 200; // OK!
// 인스턴스 변수는 인스턴스를 만들 때 마다 생성된다.
A p2 = new A(); // 새 v2 변수가 생성된다.
p2.v2 = 300;
System.out.printf("A.v1=%d, p.v2=%d, p2.v2=%d\n", A.v1, p.v2, p2.v2);
}
}
ㄴ 이 코드의 실행과정을 그림으로 나타내면 아래 그림과 같음
설명
1. Exam0140.class를 메모리에 로딩한 다음 Exam0140.class 에 static 필드가 존재하는지 확인(해당 스태틱 필드 생성)
2. Exam0140.class에 main() 메서드가 존재하는지 확인 후, 존재한다면 main() 메서드 호출
3. main() 메서드 실행 전 main() 메서드가 사용할 로컬 변수를 JVM Stack 영역에 준비 (args, p, p2)
4. A.class의 스태틱 필드인 v1에 100을 넣어야 하는데, A.class가 아직 로딩 안 됐으므로 Method Area 영역에서 A.class 를 로딩하여 A.class에 스태틱 필드가 있는지 확인 후, 존재한다면 생성하고(v1 => 초기 값은 0) 스태틱 필드 v1 에 100을 저장
6. A.class의 설계도에 따라 Heap 영역에 논스태틱 변수(=인스턴스 변수) v2를 생성하고, 생성된 인스턴스 주소 1200(임의로 지정)을 p 레퍼런스에 저장
7. p 레퍼런스가 가리키는 인스턴스의 인스턴스 변수 v2(v2라는 필드)에 200을 저장
8. A.class의 설계도에 따라 Heap 영역에 새로운 논스태틱 변수(=인스턴스 변수) v2를 생성하고, 생성된 인스턴스 주소 1300(임의로 지정)을 p2 레퍼런스에 저장
9. p2 레퍼런스가 가리키는 인스턴스의 인스턴스 변수 v2(v2라는 필드)에 300을 저장
'네이버클라우드 > JAVA 웹 프로그래밍' 카테고리의 다른 글
JAVA 15일차 (2023-06-13) 자바 기초 DAY13_인스턴스 메서드와 스태틱 메서드 (0) | 2023.06.13 |
---|---|
JAVA 15일차 (2023-06-13) 자바 기초 DAY13_게시판 관리 기능 추가 (0) | 2023.06.13 |
JAVA 14일차 (2023-06-12) 자바 기초 DAY12_개인 프로젝트 - 마트 물품 관리 시스템 (0) | 2023.06.12 |
JAVA 14일차 (2023-06-12) 자바 기초 DAY12_Eclipse git 사용법 (0) | 2023.06.12 |
JAVA 14일차 (2023-06-12) 자바 기초 DAY12_getter/setter 적용 (0) | 2023.06.12 |