Java ‐ 자바 특징과 객체 지향 원칙 - dnwls16071/Backend_Summary GitHub Wiki
📚 자바 개요
자바의 특징
- 객체지향 프로그래밍 언어 - 클래스와 객체를 기반으로 설계되며, 추상화, 캡슐화, 상속, 다형성을 지원
- 플랫폼 독립성 - 자바 코드는 JVM 위에서 실행되므로 OS에 관계없이 동작
- 자동 메모리 관리 - 개발자 메모리를 해제하지 않아도 JVM이 자동으로 불필요한 객체를 분리
- 멀티쓰레딩 지원 - 여러 작업을 동시에 실행할 수 있는 멀티 쓰레딩 기능을 제공
📚 SOLID 원칙⭐
SRP
// ❌ SRP 위반 예시
public class Computer {
public void startComputer() {
System.out.println("부팅 중...");
checkHardware();
loadOS();
connectNetwork();
System.out.println("컴퓨터 준비 완료");
}
private void checkHardware() {
System.out.println("하드웨어 점검");
}
private void loadOS() {
System.out.println("운영체제 로딩");
}
private void connectNetwork() {
System.out.println("네트워크 연결");
}
}
// ✅ SRP 준수한 리팩토링
class Hardware {
void check() {
System.out.println("하드웨어 점검");
}
}
class OS {
void load() {
System.out.println("운영체제 로딩");
}
}
class Network {
void connect() {
System.out.println("네트워크 연결");
}
}
public class Computer {
private final Hardware hardware = new Hardware();
private final OS os = new OS();
private final Network network = new Network();
public void startComputer() {
hardware.check();
os.load();
network.connect();
}
}
OCP
// ❌ OCP 위반 예시
public class NotificationService {
public void send(String type, String message) {
if (type.equals("email")) {
System.out.println("이메일 전송: " + message);
} else if (type.equals("sms")) {
System.out.println("문자 전송: " + message);
}
}
}
// ✅ OCP 준수 리팩토링
interface Notifier {
void send(String message);
}
class EmailNotifier implements Notifier {
public void send(String message) {
System.out.println("이메일 전송: " + message);
}
}
class SmsNotifier implements Notifier {
public void send(String message) {
System.out.println("문자 전송: " + message);
}
}
public class NotificationService {
public void notify(Notifier notifier, String message) {
notifier.send(message);
}
}
ISP
// ❌ ISP 위반 예시
interface Machine {
void print();
void scan();
void fax();
}
class BasicPrinter implements Machine {
public void print() {
System.out.println("문서 출력");
}
public void scan() {
throw new UnsupportedOperationException("스캔 지원 안함");
}
public void fax() {
throw new UnsupportedOperationException("팩스 지원 안함");
}
}
// ✅ ISP 준수 리팩토링
interface Printable {
void print();
}
interface Scannable {
void scan();
}
interface Faxable {
void fax();
}
class BasicPrinter implements Printable {
public void print() {
System.out.println("문서 출력");
}
}
class MultiFunctionPrinter implements Printable, Scannable, Faxable {
public void print() {
System.out.println("문서 출력");
}
public void scan() {
System.out.println("문서 스캔");
}
public void fax() {
System.out.println("문서 팩스 전송");
}
}
DIP
// ❌ DIP 위반 예시
class MySQLDatabase {
public void connect() {
System.out.println("MySQL에 연결");
}
}
class DataService {
private final MySQLDatabase database;
public DataService() {
this.database = new MySQLDatabase();
}
public void use() {
database.connect();
}
}
// ✅ DIP 준수 리팩토링
interface Database {
void connect();
}
class MySQLDatabase implements Database {
public void connect() {
System.out.println("MySQL에 연결");
}
}
class DataService {
private final Database database;
public DataService(Database database) {
this.database = database;
}
public void use() {
database.connect();
}
}
LSP
// ❌ LSP 위반 예시
class Bird {
public void fly() {
System.out.println("날아갑니다");
}
}
class Ostrich extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("타조는 날 수 없습니다");
}
}
public class Zoo {
public void makeBirdFly(Bird bird) {
bird.fly();
}
}
Zoo zoo = new Zoo();
zoo.makeBirdFly(new Ostrich()); // 예외 발생 → LSP 위반
// ✅ LSP 준수 리팩토링
interface Flyable {
void fly();
}
class FlyingBird implements Flyable {
public void fly() {
System.out.println("날아갑니다");
}
}
// 이제 날 수 있는 새만 fly()를 갖고, 타조는 분리됨
class Ostrich {
public void run() {
System.out.println("달립니다");
}
}
public class Zoo {
public void makeFly(Flyable bird) {
bird.fly();
}
}
📚 JVM 자바 가상머신 구조⭐⭐
- JVM(Java Virtual Machine)은 자바 프로그램을 실행하기 위한 가상 머신
- 자바 코드를 바이트 코드로 변환하여 실행하는 역할을 담당
- 운영체제와 독립적으로 동작하며 어떤 OS에서도 실행 가능
JVM의 구성 요소
- 클래스 로더(Class Loader)
- 런타임 데이터 영역(Runtime Data Area)
- 실행 엔진(Execution Engine)
- 가비지 컬렉터(Garbage Collector)
1. 클래스 로더(Class Loader)
- 바이트 코드를 메모리에 로드하는 역할
- 클래스 로딩 과정 : 로딩(Loading) - 링크(Linking) - 초기화(Initialization)
- 로딩 : 바이트 코드를 메모리에 적재하는 단계
- 링크 : 로드된 클래스의 코드와 데이터를 사용할 수 있도록 준비
- 초기화 : static 변수에 초기값을 할당하고 static 블록을 실행
2. 런타임 데이터 영역(Runtime Data Area)
- JVM이 실행 중 사용하는 메모리 영역
- Heap : 객체와 인스턴스 변수 저장
- Stack : 메서드 호출 시 생성되는 메서드 정보와 지역변수 저장
- Method Area : 클래스 정보, static 변수 저장
- PC Register : 현재 실행 중인 명령어 주소 저장
- Native Method Stack : 네이티브 코드 실행 시 사용
3. 실행 엔진(Execution Engine)
- JVM이 바이트 코드를 실제 실행하는 역할
- 인터프리터(Interpreter)
- 바이트 코드를 한줄씩 읽고 실행
- 컴파일 과정이 없어 빠르게 시작 가능
- 같은 코드가 반복 실행될 때마다 다시 해석
- JIT 컴파일러
- 반복 실행되는 바이트 코드를 기계어로 변환해 캐싱
- 인터프리터보다 빠르게 실행
- 한 번 변환된 코드는 다시 변환되지 않고 바로 실행 가능
- 처음 실행 시 컴파일 시간이 추가됨
- 인터프리터(Interpreter)
4. 가비지 컬렉터(Garbage Collector)
- 가비지 컬렉터(Garbage Collector)
- 사용하지 않는 객체를 자동으로 메모리에서 정리
- 메모리 누수를 방지하고 효율적인 메모리 관리를 수행
📚 GC 동작 원리⭐⭐
가비지 컬렉션(Garbage Collection, GC)
- JVM이 필요하지 않은 객체를 자동으로 제거해 메모리를 관리하는 기능
- 프로그래머가 직접 메모리 해제를 하지 않아도 되도록 함
- 힙 영역(객체와 인스턴스 변수가 저장되는 곳)에 존재하는 객체 중 더 이상 참조되지 않은 객체를 정리 대상으로 판단한다.
- 힙 영역에 있는 객체들은 언제까지 필요한지 예측하기 어렵다.
- 반면, 스택에 있는 변수들은 메서드가 끝나면 자동으로 사라짐(수명 명확)
- GC 대상 판단 기준
- GC는 루트 객체에서 시작해 참조 가능한 객체를 따라가며 도달할 수 없는 객체만을 가비지로 간주하고 제거함
- 루트 객체의 예시
- 쓰레드 스택에 있는 지역 변수(메서드 내부 변수, 매개변수)
- Method Area에 있는 static 변수
- Native Method Stack에서 참조 중인 객체
- GC 동작 구분
- Stop-the-World
- GC가 실행될 때 JVM이 애플리케이션 실행을 멈추는 현상
- 모든 실행 중인 쓰레드가 중단되며 GC가 완료될 때까지 기다려야 한다.
- Mark and Sweep
- GC의 기본 동작 방식으로 객체를 식별하고 제거하는 과정
- Stop-the-World
- GC의 기본 동작 과정
- 객체 생성
- new 키워드로 객체를 생성하면 Heap 영역에 저장된다.
- 생성된 객체는 Young Generation의 Eden 영역에 위치
- 객체 생존 여부 확인
- GC가 실행되면 사용 중 객체와 사용되지 않는 객체를 구분한다.
- 참조가 없는 객체는 GC 대상으로 표시된다.
- 사용되지 않는 객체 제거
- 참조되지 않는 객체를 Heap에서 제거해 메모리 회수
- 제거 후 남은 객체를 압축해 메모리 단편화를 방지
- 객체 생성
📚 가비지 컬렉터(Garbage Collector)⭐⭐
힙 메모리 내 객체 생존 흐름
- Eden 영역에서 객체를 생성
- 자바 애플리케이션에서 new 키워드로 객체를 생성하면 대부분 Eden 영역에 생성된다.
- Eden은 Young Generation에 속한다.
- Minor GC 발생
- Eden 영역이 꽉 차면 Minor GC가 발생
- GC는 살아있는 객체만을 Survivor 영역으로 복사
- 살아남은 객체들은 Survivor 영역으로 이동하고 죽은 객체는 제거됨
- Survivor ↔ Survivor
- 이후 다시 Eden 영역에 객체가 쌓이고 또 Minor GC가 발생하면 Survivor 영역에 있던 객체들은 다른 Survivor 영역으로 복사됨
- 복사될 때마다 age값(생존 횟수)이 증가한다.
- Old Generation으로 Promotion
- age값이 특정 임계값 이상이 되면 더 이상 Young Generation에 두지 않고 Old Generation으로 승격된다.
- Old 영역은 Major GC의 대상이 된다.
❗Minor GC란?
- Young Generation에서 발생하는 GC
- 빠르게 실행되며 Stop-the-World 시간이 짧다.
❗Major GC란?
- Old Generation에서 발생하는 GC
- 힙 영역 전체를 검사하기 때문에 실행 시간이 길고 Stop-the-World 시간이 길어 성능에 영향을 준다.
- GC 튜닝을 통해 Major GC 발생을 최소화하는 것이 중요하다.
📚 GC 알고리즘
- GC는 상황에 따라 다른 알고리즘을 사용한다.
- 주요 GC 알고리즘 정리
| GC 종류 | 특징 | STW 시간 | 사용 예시 |
|---|---|---|---|
| Serial GC | 단일 쓰레드, 간단 | 길다 | 작은 애플리케이션 |
| Parallel GC | 멀티 쓰레드, Throughput 높다 | 중간 | 서버, 배치 등 |
| CMS | 사용자 지연 최소화 | 낮다 | GUI 앱 |
| G1 GC | 병렬 + 병합, Region 단위 관리 | 중간~낮다 | 대부분의 앱 |
| ZGC / Shenandoah | 초저지연 GC | 매우 짧다 | 대규모 시스템 |