Java 정리 (2)

Hazel·2025년 2월 5일

JVM (Java Virtual Machine)

  • 자바 프로그램이 실행되는 환경 제공
  • 메모리를 체계적으로 관리하기 위해 여러 영역으로 나뉘어져 있음
    • 메서드
    • 스택
    • PC 레지스터
    • 네이티브 메서드 스택
  • GC(Garbage Collection) : JVM은 가비지 컬렉터를 통해 자동으로 메모리를 관리, 사용되지 않는 객체를 메모리에서 해제

메서드 영역

  • 클래스의 정보를 저장하는 영역
  • 정적 변수, 상수, 메서드 등이 저장된 (+클래스 정보) → 정적 : 즉각적으로 값을 가져올 수 있음 (person.name)
  • 일부 JVM에 따라 GC가 관리해주는 경우도 있음
  • 모든 스레드가 공유 (= 멀티 태스킹이 가능)
  • static 쓰면 바로 메서드 영역에 올라감
  • 클래스 로더에 의해 클래스가 로드될 때 저장되는 공간 → 회사 메뉴얼(설계도), 지침
  • 인스턴스 안의 필드는 고유함, 메서드는 공통으로 활용됨
    • 메서드를 인스턴스마다, 객체마다 따로 관리할 필요가 없음

힙 영역

  • 객체 인스턴스를 저장하는 공간
    • new Person();
  • 인스턴스 변수, 배열 등이 해당 영역에 저장
  • GC가 관리하는 영역(사용되지 않는 객체를 자동으로 삭제)
  • 객체화시키면 힙에 올라감.
  • 어플리케이션이 사용할 수 있는 가장 큰 메모리
  • 가장 많이 사용되는 영역
  • 모든 스레드가 공유 (private가 아닌 이상) → 프로젝트 자료 같은 것들

스택 영역

  • 지역 변수, 메서드 호출 시 사용되는 값, 연산 결과 등 저장
  • 메서드 호출 시 스택 프레임이 생성되며, 끝나면 스택 프레임 제거
  • 접시를 쌓듯 쌓이는 형태
  • 스택 영역 가장 아래는 main 메서드, 그 위에는 지역 변수나 사용자가 생성한 메서드들이 쌓인다…?
  • 스메드마다 생성 → 작업 중인 문서 or 책상 (곧 치워질 예정)

PC 레지스터

  • 현재 실행 중인 메모리의 주소를 저장하는 영역
  • 프로그램 실행 흐름을 제어하는 데 사용
  • 스레드마다 생성 → 지금 하고 있는 작업 위치

네이티브 메서드 스택

  • 네이티브 언어(C,C++)로 작성된 메서드 호출 시 사용하는 메모리 영역

객체 생성과 메모리 할당

Person p1 = new Person();
p1.name = "김하리";   // 스택
p1.age = 24;
p1.hobby = "Jazz";

Person p2 = new Person();
p2.name = "이준호";
p2.age = 33;
p2.hobby = "Dance";

static 키워드

  • 클래스 수준에서 공유되는 멤버(필드, 메서드, 중첩 클래스)를 정의하는 데 사용
  • static 키워드를 작성하면 객체와 무관하게 클래스 자체에 속함
  • 특정 객체에 속하지 않고 모든 객체가 동일한 static 멤버 참조
  • 클래스의 이름을 통해 직접 호출 가능(권장)
  • JVM 메서드 영역에 저장
public class PersonTest {

	public static void main(String[] args) {
		Person p = new Person();
		p.name = "Yan";
		
		System.out.println(p.name);
		System.out.println(p.pCount++);
		
		
		Person p2 = new Person();
		System.out.println(++p2.pCount); 
		//pCount에 warning이 있음 -> static 필드에 접근하려면 인스턴스 변수명이 아니라 
		// 클래스명으로 접근하는게 좋다
		// p2.pCount -> Person.pCount로 수정
		System.out.println(Person.pCount);
	}

}
public class Person {
	
	// 클래스 변수 : 모든 클래스가 공유하는 값
	static int pCount=1;
	
	//  인스턴스 변수(생성되는 인스턴스마다 고유한 값을 가지고 있음)
	String name;
	int age;
	String hobby;
}

static 메서드

  • 정적 메서드는 클래스 이름을 통해 직접 호출할 수 있는 메서드
  • 객체와 무관하게 동작, 전역적인 작업에 적합(보통 알고리즘 문제 풀 때 사용)
    - ClassName.methodName[];

static 블록

  • 정적 블록은 클래스 로드시 한 번만 실행되는 블록
  • 정적 필드 초기화에 사용
// Person.java

public class Person {
	
	// 클래스 변수 : 모든 클래스가 공유하는 값
	static int pCount=1; // 단순하게 값 할당 중
	
	//  인스턴스 변수(생성되는 인스턴스마다 고유한 값을 가지고 있음)
	String name;
	int age;
	String hobby;
	
	// 초기화 블록
	static {
		// 클래스 변수를 초기화하기도 하지만
		// 안에서 특정한 작업 또한 가능하다
		pCount = 1000;
	}
	
	// 정적 메서드 : 미리 메모리에 올라가 있음 
	// static
	public static void eat() {
		pCount =100; // 가능 
//      this.name = "Yan";
		// 왜 에러남?
		// 위에 있는건 인스턴스 변수 
		// 현재 메모리에 name이 없어서 에러남
		// static 영역에서는 non-static 영역 직접 접근 X
	}
	
	// 메서드 : 인스턴스를 "new 인스턴스" 해야만 사용 가능 
	// non-static
	public void study() {
		pCount = 1000; // non-static 영역에서 static 영역에 대한 접근 가능
		name = "Yan";
	}
}
// PersonTest.java
public class PersonTest {

	public static void main(String[] args) {
		Person p = new Person();
		p.name = "Kim";
		
		System.out.println(p.name);
		System.out.println(p.pCount++);
		
		
		Person p2 = new Person();
		System.out.println(++p2.pCount); 
		// pCount에 warning이 있음 -> static 필드에 접근하려면 인스턴스 변수명이 아니라 
		// 클래스 변수는 클래스명으로 접근하는게 좋다
		// p2.pCount -> Person.pCount로 수정
		System.out.println(Person.pCount);
		
		p.eat();
		p.study();
		
		
		Person.eat();
	}
}

패키지

  • 클래스와 인터페이스를 묶는 디렉토리 구조
  • 클래스 이름 충돌 방지 (패키지명까지 해서 네임 스페이스 제공)
  • 클래스 파일 첫 번째 줄에 package 키워드를 사용하여 선언
  • .(dot)을 이용하여 패키지 구분
  • 일반적으로 소속이나 회사의 도메인 역순으로 작성

임포트

  • 다른 패키지 안에 있는 클래스 사용하기 위해서 import 과정 필요
    • 단일 import → import [풀 패키지명]
    • 전체 import → import [풀 패키지명].*
  • 자바는 클래스가 실제로 사용되는 시점에서 메모리에 로드 → import 많다고 느려지지 않음

캡슐화

  • 필드와 메서드를 하나의 단위로 묶고, 외부로부터 데이터를 숨기며 안전하게 보호하는 것
  • 정보 은닉 → 내부 데이터를 외부에서 직접 접근하지 못하게 하고 특정 메서드를 통해서만 접근하도록 제한

접근 제한자

  • 클래스, 메서드, 변수 등에 대한 접근 범위를 지정
  • 캡슐화와 정보은닉으 가능하게 함
  • 다른 제한자들과는 달리 접근 제한자는 하나만 작성이 가능

접근 제한자 종류

  • public : 모든 위치에서 접근 가능
  • protected : 같은 패키지 또는 패키지가 달라도 상속 관계에서 접근 가능
  • default(package-private) : 같은 패키지 안에서만 접근 가능 → 안 쓰면 default값
  • private : 같은 클래스 내부에서만 접근 가능

클래스와 접근 제한자

  • 최상위 클래스 (외부 클래스) : public default
  • 중첩 클래스 (내부 클래스) : 4가지 종류 모두 가능

접근자 (Getter)/ 설정자(Setter)

  • 캡슐화를 구현하는데 사용되는 메서드
  • Getter : private 필드 값을 외부에서 읽을 수 있게 함
  • Setter : private 필드 값을 외부에서 수정할 수 있게 함 → 직접 접근이 아닌 안전하게 읽고 쓰는 방식 제공
  • 접두사 get/set 이용하여 메서드 작성

객체 배열 관리

  • 여러 객체를 하나의 배열로 묶어 관리하는 방식
  • 객체 배열의 요소는 객체 참조 값을 저장
  • 기본값은 null로 초기화
  • 객체를 추가, 조회, 수정, 삭제할 수 있음 (CRUD)
  • 싱글턴 패턴을 사용하여 관리할 수 있음

싱글턴 패턴

  • 객체를 하나만 생성하도록 보장하는 디자인 패턴
  • 객체의 유일성 보장 → 하나의 인스턴스만 생성 (전역적으로 동일한 객체 공유)
  • 생성자를 private으로 만들어 클래스 내부에서만 생성 가능
  • 정적 메서드를 통해 전역적으로 접근 가능
public class Manager{

	// 나 자신을 private로 객체화
	private static Manager manager = new Manager(); 
	// Heap에만 있으면 언제든지 접근이 안 됨 -> 객체화 시킨 인스턴스를 static에 올려줌
	
	// 기본 생성자 : 접근제한자 바꾸려고 언급
	private Manager(){}
	
	// 외부에서 접근하려면 public으로 getter 생성
	// 나 자신을 반환하는거라 나의 타입이 그냥 나 자신이 됨
	public static Manager getManager(){
		return manager;       // 나의 인스턴스 반환
	}
}
profile
이것저것 학습 기록장

0개의 댓글