1. JVM - 자바 메모리 구조
▶ 자바 메모리 구조는 크게 메서드 영역, 스택 영역, 힙 영역으로 나눌 수 있다.
- 메서드 영역 : 클래스 정보를 보관한다. 이 클래스 정보가 붕어빵 틀이다.
- 클래스 정보 : 클래스의 실행 코드(바이트 코드), 필드, 메서드와 생성자 코드 등 모든 실행 코드 존재
- static 영역 : static 변수들을 보관
- 런타임 상수 풀 : 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관한다. 예를 들어 프로그램에 “안녕” 이라는 문자가 있으면 이런 문자를 공통으로 묶어서 관리한다.
- 스택 영역 : 실제 프로그램이 실행되는 영역. 메서드를 실행할 때 하나씩 쌓인다. (후입 선출)
- 스택 프레임 : 스택 영역에 쌓이는 네모 박스가 하나의 스택 프레임이다. 메서드를 호출할 때마다 하나의 스택 프레임이 쌓이고, 메서드가 종료되면 해당 스택 프레임이 제거된다.
- 각 스택 프레임은 지역 변수, 중간 연산 결과, 메서드 호출 정보 등을 포함한다.
- 힙 영역 : 객체(인스턴스)가 생성되는 영역이다. new 명령어를 사용하면 이 영역을 사용한다. 쉽게 이야기해서 붕어빵 틀로부터 생성된 붕어빵이 존재하는 공간이다. 참고로 배열도 이 영역에 생성된다.
- 가비지 컬렉션이 이루어지는 주요 영역이며, 더 이상 참조되지 않는 객체는 가비지 컬렉션 (GC)에 의해 제거된다.
2. static 변수 (클래스 변수)
-
- 객체가 생성되면 생성자에서 정적 변수 count의 값을 하나 증가시킨다.
package static1; public class Data3 { public String name; public static int count; //static 이 붙은 멤버 변수는 메서드 영역에서 관리한다. count는 static이 붙은 정적 변수이다. 정적 변수는 인스턴스 영역이 아님 public Data3(String name) { this.name = name; count++; } } // static 변수는 쉽게 이야기 해서 클래스인 붕어빵틀이 특별히 관리하는 변수이다. 붕어빵 틀은 1개이므로 클래스 변수도 하나만 존재한다. 반면에 인스턴스인 붕어빵은 인스턴스의 수만큼 변수가 존재한다.
→ Data3.count와 같이 마치 클래스에 직접 접근하는 것처럼 느껴진다.package static1; public class DataCountMain3 { public static void main(String[] args) { Data3 data1 = new Data3("A"); System.out.println("A count=" + Data3.count); Data3 data2 = new Data3("B"); System.out.println("B count=" + Data3.count); Data3 data3 = new Data3("C"); System.out.println("C count=" + Data3.count); //추가 //인스턴스를 통한 접근 (권장 안함) -> count가 인스턴스 변수에 접근하는 것처럼 오해 Data3 data4 = new Data3("D"); System.out.println(data4.count); //클래스를 통해 바로 접근 가능 System.out.println(Data3.count); } }
- → static이 붙은 멤버 변수 count는 인스턴스 영역이 아니라 메서드 영역에서 생성되어 관리된다.
- → 생성자에는 count++ 코드가 있다. count는 정적 변수이기 때문에 메서드 영역에서 관리하고, 이 경우 메서드 영역에 있는 count의 값이 하나 증가된다. (공용으로 사용)
- 3. 멤버 변수(필드)의 종류
- 멤버 변수의 종류
- 인스턴스 변수 : static이 붙지 않은 멤버 변수 - name
- 클래스 변수 : static이 붙은 변수 - count
- 클래스 변수, 정적 변수, static 변수 등으로 부른다.
- static이 붙은 멤버 변수는 인스턴스와 무관하게 클ㅋ래스에 바로 접근해서 사용할 수 있고, 클래스 자체에 소속되어 있다.
- 클래스 변수는 자바 프로그램을 시작할 때 딱 1개가 만들어진다. 인스턴스와는 다르게 보통 여러 곳에서 공유하는 목적으로 사용된다.
- 변수와 생명 주기
- 지역 변수(매개변수 포함) : 지역 변수는 스택 영역에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거되는데 이 때 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다. 따라서 지역 변수는 생존 주기가 짧다.
- 인스턴스 변수 : 인스턴스에 있는 멤버 변수를 인스턴스 변수라 한다. 인스턴스 변수는 힙 영역을 사용한다. 힙 영역은 가비지 컬렉션이 발생하기 전까지는 생존하기 때문에 보통 지역 변수보다 생존 주기가 길다.
- 클래스 변수 : 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이다. 클래습 변수는 해당 클래스가 JVM에 로딩되는 순간 생성된다. 그리고 JVM이 종료될 때까지 생명주기가 이어져 가장 긴 생명주기를 가진다.
- 멤버 변수의 종류
public class Data3 {
public String name;
public static int count;
}
→ Data3(”A”) 인스턴스를 생성하면 생성자가 호출된다.
→ static이 붙은 멤버 변수는 메서드 영역에서 관리한다.
4. static 메서드
package static2;
public class DecoUtil2 {
public static String deco(String str) {
return "*" + str + "*";
}
}
// 메서드 앞에 static이 붙어있음 -> 정적 메서드 생성, 인스턴스 생성 없이 클래스 명을 통해 바로 호출 가능
package static2;
public class DecoMain2 {
public static void main(String[] args) {
String s = "hello java";
String deco = DecoUtil2.deco(s);
System.out.println("before: " + s);
System.out.println("after: " + deco);
}
}
- 클래스 메서드 : 메서드 앞에 static을 붙인 것으로 정적 메서드라고도 한다. 정적 메서드를 이용하면 불필요한 객체 생성 없이 편리하게 메서드를 사용할 수 있다.
- 인스턴스 메서드 : static이 붙지 않은 메서드는 인스턴스를 생성해야 호출할 수 있다.
하지만 정적 메서드를 항상 사용할 수 있는 것은 아니다.
- static 메서드는 static만 사용할 수 있다.
- 클래스 내부의 기능을 사용할 때, static이 붙은 메서드는 static 메서드와 static 변수만 사용 가능
- 클래스 내부의 기능을 사용할 때, static 메서드는 인스턴스 변수나 인스턴스 메서드를 사용할 수 없다.
- 반대로 모든 곳에서 static을 호출할 수 있다.
- 정적 메서드는 공용기능이다. 따라서 접근 제어자만 허락한다면 클래스를 통해 모든 곳에서 static을 호출할 수 있다.
[예시]
package static2;
public class DecoData {
private int instanceValue;
private static int staticValue;
public static void staticCall() {
//instanceValue++; //인스턴스 변수 접근, compile error
//instanceMethod(); //인스턴스 메서드 접근, compile error
staticValue++; //정적 변수 접근
staticMethod(); //정적 메서드 접근
}
public void instanceCall() {
instanceValue++; //인스턴스 변수 접근
instanceMethod(); //인스턴스 메서드 접근
staticValue++; //정적 변수 접근
staticMethod(); //정적 메서드 접근
}
private void instanceMethod() {
System.out.println("instanceValue=" + instanceValue);
}
private static void staticMethod() {
System.out.println("staticValue=" + staticValue);
}
}
package static2;
//import static static2.DecoData.staticCall;
//import static static2.DecoData.*;
public class DecoDataMain {
public static void main(String[] args) {
System.out.println("1. 정적 호출");
DecoData.staticCall();
System.out.println("2. 인스턴스 호출1");
DecoData data1 = new DecoData();
data1.instanceCall();
System.out.println("3. 인스턴스 호출2");
DecoData data2 = new DecoData();
data2.instanceCall();
//추가
//인스턴스를 통한 접근
DecoData data3 = new DecoData();
data3.staticCall();
//클래스를 통한 접근
DecoData.staticCall();
}
}
★새배개★
1. 클래스 다이어그램 : Unified Modeling Language(UML) 중 하나로, 클래스 내부 구성요소 및 클래스 간의 관계를 도식화하여 시스템의 특정 모듈이나 일부 및 전체를 구조화 한다.
2. 포맷 지정자 : 자바에서 형식화된 출력을 제공하는 printf 메서드를 통해 사용할 수 있다( System.out.printf() ) . 다양한 데이터를 특정 형식으로 정렬하거나 변환하여 출력하는 데 유용하다.
// 형식 : System.out.printf("포맷 문자열", 값1, 값2, ...);
public class PrintfExample {
public static void main(String[] args) {
int number = 42;
double pi = 3.14159;
String text = "Java";
// 정수 출력
System.out.printf("정수: %d%n", number); // "정수: 42"
// 실수 출력
System.out.printf("실수: %.2f%n", pi); // "실수: 3.14"
// 문자열 출력
System.out.printf("문자열: %s%n", text); // "문자열: Java"
}
}
포맷 지정자 | 설명 |
%d | 10진수 정수 |
%f | 소수점이 있는 실수 |
%s | 문자열 |
%c | 문자 |
%b | 불리언(boolean)값 |
%n | 줄바꿈 |
%x | 16진수 정수 |
'내일배움캠프 > TIL' 카테고리의 다른 글
[Spring_4기 본캠프] Spring 입문 - build terminal 오류 트러블 슈팅 | Day 30 (3) | 2024.11.28 |
---|---|
[Spring_4기 본캠프] 상속 & 다형성과 캐스팅 | Day 29 (0) | 2024.11.27 |
[Spring_4기 본캠프] 키오스크 과제&트러블 슈팅 | Day 27 (0) | 2024.11.25 |
[Spring_4기 본캠프] 기본형과 참조형, final | Day 26 (0) | 2024.11.22 |
[Spring_4기 본캠프] 3주차 - 새로운 과제 키오스크 | Day 25 (2) | 2024.11.21 |