WEB BE/JAVA

Java 에 대하여

조금씩 차근차근 2025. 3. 7. 21:57

자바의 기본 특징

자바는 객체지향 프로그래밍(OOP)에 기반하여 설계되었으며, "Write Once, Run Anywhere"라는 플랫폼 독립성을 갖는다. 이는 한 번 작성된 코드가 어떠한 운영체제에서도 동일하게 실행될 수 있음을 의미한다.


JDK 구조

자바 개발 환경은 JDK(Java Development Kit), JRE(Java Runtime Environment), 그리고 JVM(Java Virtual Machine)으로 구성되며, 각 계층은 다음과 같이 역할을 분담한다.

1. JDK

JDK는 자바 개발에 필요한 모든 도구를 포함하는 패키지이다.

JDK의 주요 구성 요소는 다음과 같다.

  • JRE: 자바 애플리케이션을 실행하기 위한 환경을 제공한다.
  • 개발 도구: 자바 컴파일러(javac), 패키징 도구(jar), 문서화 도구(javadoc), 디버거 등으로 구성되어 있으며, 소스 코드(.java)를 바이트코드(.class)로 변환하는 등의 역할을 수행한다.

2. JRE

JRE는 자바 애플리케이션을 실행할 수 있도록 다음의 요소들을 포함한다.

  • JVM: 자바 바이트코드를 실행하는 가상 머신.
  • 코어 라이브러리: 자바 표준 API 라이브러리 등 필수 클래스들을 포함하여 애플리케이션 실행에 필요한 기능을 제공한다.
  • 네이티브 라이브러리 및 내부 구성요소: JVM의 원활한 실행을 위해 운영체제와 연동되는 필수 라이브러리들을 포함한다.

3. JVM

JVM은 자바 애플리케이션의 실행을 담당하며, 여러 내부 구성 요소로 이루어진다.

  • 클래스 로더
    • Loading: 클래스 정보를 메모리에 로드
    • Linking: 클래스 파일을 검사하고 정적 변수의 기본값을 설정
    • Initialization: 정적 변수에 초기값을 할당하고 static block을 실행
  • .class 파일을 메모리에 로드하고, 검증 및 연결(resolution) 과정을 수행한다. 동적 클래스 로딩이 가능하며, 다음 단계로 구성된다.
  • 런타임 데이터 영역
    • 메소드 영역: 클래스 정보, 상수, 정적 변수 저장
    • : 객체와 배열이 생성되는 공간으로, 가비지 컬렉터가 관리한다.
    • 자바 스택: 각 스레드의 메소드 호출 및 지역 변수를 저장
    • PC 레지스터: 현재 실행 중인 명령의 위치를 추적
    • 네이티브 메소드 스택: 네이티브 메소드 호출 시 사용
  • 애플리케이션 실행 중 필요한 데이터를 저장하는 메모리 영역으로 다음과 같이 구분된다.
  • 실행 엔진
    • JIT 컴파일러: 자주 실행되는 바이트 코드를 네이티브 코드로 동적 컴파일하여 성능을 최적화한다.
    • 인터프리터: 바이트코드를 한 줄씩 해석하여 실행한다.
    • 가비지 컬렉터: 실행 중 사용되지 않는 객체를 회수하여 메모리 누수를 방지한다.
  • 바이트코드를 실제 머신 코드로 실행하는 역할을 담당하며, 다음 구성 요소를 포함한다.
  • 네이티브 인터페이스(JNI)
  • C/C++ 등 네이티브 라이브러리와의 상호작용을 지원하여, 자바 코드와 네이티브 코드 간의 통신을 가능하게 한다.

JVM 아키텍처

Hotspot JVM 아키텍처


자바의 빌드 과정

자바 애플리케이션이 실행되기까지의 빌드 과정은 컴파일과 링크 단계를 거친다.

1. 컴파일 단계

  • 정의: 자바 소스 코드(.java)를 바이트코드(.class)로 변환하는 과정이다.
  • 과정:
    • 구문 분석: 소스 코드의 문법을 검사하여 오류를 검출한다.
    • 최적화: 불필요한 코드를 제거하거나 효율적인 코드로 변환하여 성능을 개선한다.
    • 객체 코드 생성: 각 소스 파일을 개별적으로 기계어 수준의 객체 코드로 변환한다.

컴파일 과정에서는 주로 문법 오류나 타입 오류 등이 발견된다.

2. 링크 단계

  • 정의: 여러 객체 파일과 라이브러리를 하나의 실행 환경으로 결합하는 과정이다. 단, 자바는 전체 프로그램을 하나의 실행 파일로 결합하지 않고, 런타임에 필요한 클래스와 라이브러리를 동적으로 로딩한다.
  • 과정:
    • 검증(Verification): 로드된 바이트코드가 JVM의 규칙에 부합하는지 검사하여 보안과 안정성을 확보한다.
    • 준비(Preparation): 클래스 변수(정적 변수)의 메모리를 할당하고 기본값을 설정한다.
    • 해결(Resolution): 클래스 내부 및 외부의 심볼릭 참조를 실제 메모리 주소에 연결한다.

이 과정은 주로 동적 링크 방식으로 진행되어, 실행 중에도 필요한 클래스를 동적으로 로드하거나 갱신할 수 있다.


가비지 컬렉션(GC)

가비지 컬렉션은 힙 영역에서 참조되지 않는 객체를 자동으로 제거하는 기능이다. 이 과정에서 모든 스레드가 일시 중단되는 "Stop-the-world" 이벤트가 발생할 수 있으므로, 불필요한 중단 시간을 최소화하는 것이 중요하다.


Gradle

Gradle은 자바를 비롯한 여러 언어의 빌드 자동화 도구로, 다음과 같은 작업을 지원한다.

  • 전처리
  • 컴파일
  • 패키징
  • 테스팅
  • 배포

이를 통해 복잡한 빌드 과정을 자동화하고 효율성을 높일 수 있다.


자바 버전 종류

자바는 용도에 따라 다음과 같은 버전으로 구분된다.

  • Java SE (Standard Edition): 일반 데스크탑 및 서버 애플리케이션 개발에 사용된다.
  • Java EE (Enterprise Edition): 대규모 기업용 애플리케이션 개발을 위해 확장된 API와 기능을 제공한다.
  • Java ME (Micro Edition): 제한된 자원 환경(모바일, 임베디드 디바이스 등)에서 사용된다.
  • JavaFX: 그래픽 사용자 인터페이스 및 고성능 그래픽 가속을 위한 플랫폼이다.

기본 데이터 타입과 참조 타입의 차이

자바는 기본 데이터 타입과 참조 타입을 구분하여 관리한다.

  • 저장 방식:
    • 기본 타입은 실제 값을 직접 저장한다.
    • 참조 타입은 객체의 메모리 주소를 저장한다.
  • 메모리 위치:
    • 기본 타입은 주로 스택 영역에 저장된다.
    • 참조 타입은 힙 영역에 객체가 생성되고, 해당 객체의 주소가 스택에 저장된다.
  • 연산 방식:
    • 기본 타입은 산술 연산 등 직접적인 계산이 가능하다.
    • 참조 타입은 객체 내부의 데이터나 메서드를 통해 간접적으로 다루어진다.

오버로딩과 오버라이딩

자바에서 메서드 다형성을 구현하는 두 가지 주요 방식은 오버로딩과 오버라이딩이다.

  • 오버로딩 (Overloading):
    • 같은 이름의 메서드를 매개변수의 타입이나 개수를 다르게 정의한다.
    • 반환 타입은 관계없으며, 컴파일 타임에 어떤 메서드를 호출할지 결정된다.
  • 오버라이딩 (Overriding):
    • 부모 클래스에서 상속받은 메서드를 자식 클래스에서 재정의한다.
    • 메서드명, 매개변수, 반환 타입이 모두 동일해야 하며, 런타임 다형성을 구현하는 핵심 메커니즘이다.
    • 인터페이스를 통한 간접 구현 방식도 자주 활용된다.

제네릭

제네릭은 클래스나 메서드에서 사용할 타입을 외부에서 지정할 수 있도록 하는 기능이다. 이를 통해 컴파일 타임에 타입 안전성을 확보할 수 있으며, 재사용성이 높은 코드를 작성할 수 있다.

  • 특징:
    • 클래스나 메서드 선언 시, 타입 매개변수를 지정할 수 있다.
    • <> 내부에는 오직 참조 자료형(클래스, 인터페이스, 배열)만 올 수 있다.
    • 기본 자료형을 사용하려면 해당 자료형의 래퍼 클래스(Integer, Double 등)를 사용해야 한다.