본문 바로가기

프로그래밍 기초

Java 기초 개념 요약 정리(1)

※ 틀린 부분이 있을 수 있으며, 피드백은 언제나 환영합니다.

서술형(답이 비어 있는 버전) 링크

https://docs.google.com/document/d/1uXxIevQh4zZXClbluEd5H5de6FDvw8Fe0ot9_yMjqAM/edit?usp=sharing

 

Java 기초 개념 요약 정리 1(서술형)

각종 용어 JLS(Java Language Specification) ㄴ 의미: JSR(Java Specification Request) ㄴ 의미: JEP(JDK Enhancement Proposal) ㄴ 의미: JRE(Java Runtime Environment) ㄴ 의미: Java SE(Java Standard Edition) ㄴ 의미: ㄴ 핵심 구성 요소:

docs.google.com


각종 용어

JLS(Java Language Specification)

ㄴ 의미: Java 프로그래밍 언어를 위한 공식 명세서.

 

JSR(Java Specification Request)

ㄴ 의미: 새로운 명세서를 발달시키거나 기존의 명세서를 수정하기 위해 JCP(Java Community Process)에 제출된 제안.

 

JEP(JDK Enhancement Proposal)

ㄴ 의미: Java 핵심 기술에 대한 향상을 제안하는 문서.

 

JRE(Java Runtime Environment)

ㄴ 의미: Java 프로그램이 올바르게 실행되기 위해 필요한 SW. Java 프로그램과 OS 간 통신을 위한 기본 기술이다.

 

Java SE(Java Standard Edition)

ㄴ 의미: 다목적 컴퓨팅을 위한 핵심 Java 플랫폼.

ㄴ 핵심 구성 요소: 

    ㅡ JVM: Java 바이트 코드를 실행하기 위해 필요한 가상 머신.

    ㅡ Java API: 표준 라이브러리와 패키지를 포함하는 풍부한 집합.

    ㅡ JDK: Java App을 개발하기 위해 필요한 도구 모음. 컴파일러, 디버깅 도구, JVM을 포함한다.


가비지 컬렉션

가비지 컬렉션(Garbage Collection)

ㄴ 의미: Java의 자동적인 메모리 관리 시스템.

ㄴ 목적: App에서 더 이상 사용되지 않는 객체에 의해 점유된 메모리를 환원하는 것.

ㄴ 종류:

Parallel GC: 다중 CPU 시스템에서 더욱 좋은 처리량을 위해 멀티스레드를 사용하는 GC. Java 1.8까지 디폴트였다.
G1 GC: 리전과 일시 정지 시간 목표를 도입하여 처리량과 지연 간 균형을 잡는 GC. Java 9부터 디폴트이다.
ZGC: 컬러드 포인터와 로드 배리어를 사용해서 힙 크기에 상관 없이 초저지연 목표를 달성하는 GC. Java 15에 추가되었다.
Generational ZGC: ZGC에 세대별 디자인을 더하여, 초저지연을 유지하면서도 처리량을 상당히 개선한 GC. Java 21에 추가되었다.

ㄴ 동작 방식:

1. 표시(Mark, 필수적): GC는 루트에서부터 객체 그래프를 횡단하면서, 도달할 수 있는 모든 객체를 "살아있는 것"으로 표시한다.
2. 제거(Sweep, 필수적): GC가 다시 힙을 선형적으로 통과하면서 도달할 수 없는 모든 객체를 식별하고, 이 객체가 차지하는 공간을 새로운 객체 할당에 재사용할 수 있도록 한다.
3. 압축(Compact, 선택적): 살아있는 객체를 인접한 메모리 블록으로 모이도록 재배치하여 단편화를 막는다.

 

STW(Stop-The-World)

ㄴ 의미: GC가 특정한 작업을 안전하게 수행하도록 하기 위해 모든 App 스레드를 일시 정지하는 단계.
ㄴ 일어나는 이유: GC가 라이브 객체를 정확하게 식별하기 위해서는 객체 참조에 대한 안정된 스냅샷이 필요하기 때문이다.


객체

객체(Object)

ㄴ 의미: 클래스를 바탕으로 생성하여 메모리상에 할당함으로써 가용 상태가 된 것.

ㄴ 목적에 따른 종류:

DAO(Data Access Object): DB의 데이터에 접근하기 위한 객체.
DTO(Data Transfer Object): 계층 간 데이터 교환을 위한 데이터 컨테이너.
VO(Value Object): 단순히 값 자체를 표현하기 위해 사용되는 불변 클래스.

ㄴ 가변성에 따른 종류:

가변 객체(Mutable Object):
ㄴ 의미: 생성 후에도 상태를 자유롭게 수정할 수 있는 객체.
ㄴ 장점: 기존 객체의 상태 값을 바꿔서 재사용할 수 있으므로 메모리 효율과 성능 면에서 유리하다.
ㄴ 단점: 스레드 안전하지 않을 수 있다.

불변 객체(Immutable Object):
ㄴ 의미: 한 번 생성되면 상태를 절대 변경할 수 없는 객체.
ㄴ 장점: 본질적으로 스레드 안전하다.
ㄴ 단점: 값이 바뀔 때마다 새로운 객체를 만들어야 하기 때문에, 수정이 빈번하면 GC 부하가 커질 수 있다.

 

인스턴스(Instance)

ㄴ 의미:
    ㅡ Java에서 객체와 상호 교환적으로 사용할 수 있는 용어이다.
    ㅡ 다만 이 용어는 독립적인 개체로서의 의미를 강조하는 객체와 달리 클래스와의 관계를 강조한다.
    ㅡ 이는 "객체 A는 클래스 B의 인스턴스다"와 같이 표현할 수 있다.

 

클래스(Class)

ㄴ 의미:
    ㅡ 객체를 생성하는 데 필요한 상태와 행동을 캡슐화한 청사진이며, 객체의 타입을 정의한다.
    ㅡ 상태는 필드로 대표되고, 행동은 메소드로 대표된다.

 

추상 클래스(Abstract Class)

ㄴ 의미: 추상 메소드를 포함할 수 있는 클래스.

 

인터페이스(Interface)

ㄴ 의미: 구현하는 클래스가 반드시 제공해야 하는 기능을 정의하는 명세이자 계약.

 

추상 클래스와 인터페이스 비교

추상 클래스: 상속을 통한 상태와 행위 구조의 공유에 집중한다.
인터페이스: 구현을 통한 기능의 의무적인 실체화에 집중한다.

 

자료구조(Data Structure)

ㄴ 의미: 효율적인 접근과 조정을 위해서 데이터를 컴퓨터에 조직하고 저장하는 방법.

 

자료형(Data Type)

ㄴ 종류:

원시 타입(Primitive Type)
ㄴ 의미:
ㅡ 개발자가 원시 타입을 쓸 때는, 원시 타입의 데이터 그 자체를 직접 다루는 것이다.

ㅡ 이를 새로운 변수에 할당하거나 함수에 건네주면 데이터의 완전한 독립적인 복사본을 생성한다.
ㅡ 스택에서 변수를 저장하는 메모리 주소는 실제 데이터를 포함한다.
ㄴ 종류:
ㅡ byte (1 Byte)
ㅡ short (2 Bytes)
ㅡ int (4 Bytes)
ㅡ long (8 Bytes)
ㅡ float (4 Bytes)
ㅡ double (8 Bytes)
ㅡ char (2 Bytes)
ㅡ boolean (1 Byte)


참조 타입(Reference Type)
ㄴ 의미:
ㅡ 
개발자가 참조 타입을 쓸 때는, 참조 타입의 데이터 그 자체가 아니라 데이터가 저장된 곳으로의 참조를 다루는 것이다.

ㅡ 이를 새로운 변수에 할당하거나 함수에 건네주는 것 또한 데이터가 아닌 참조를 복사한다.
실제 데이터는 힙에 저장되며, 스택에서 변수를 저장하는 메모리 주소는 힙에 있는 메모리 주소로의 참조를 포함한다.

 

가상 메소드(Virtual Method)

ㄴ 의미:

    ㅡ 동적 바인딩으로 처리되는 멤버 메소드로서, 다형성의 원리가 적용된다.
    ㅡ Java에서는 모든 인스턴스 메소드가 가상 메소드이다.

 

메인 메소드(main Method)

ㄴ 의미:
    ㅡ 모든 Java App에서의 진입점.
    ㅡ JVM은 반드시 하나의 진입점을 찾아야만 프로그램을 실행할 수 있도록 설계되어 있다.
ㄴ 주요 구성 요소: public static void main(String[] args)
ㄴ static 구성 요소가 주는 이점:
    ㅡ 프로그램의 실행을 메인 클래스라는 개별적인 객체의 상태로부터 분리한다.
    ㅡ 객체를 생성하는 복잡한 과정을 건너뛰고 가장 깔끔한 방식으로 프로그램을 실행할 수 있도록 한다.
ㄴ void 구성 요소가 주는 이점:
    ㅡ 모호하게 해석될 수 있는 값을 반환하는 문제를 회피한다.
    ㅡ OS에 특정한 종료 코드 관례에서 벗어나도록 하여 일관된 행동을 제공한다.


구문

람다 표현식(Lambda Expression)

ㄴ 의미: 메소드를 함수형 스타일로 표현한 것으로, Java 8에 도입되었다.
ㄴ 요점: 오직 실행될 로직만 남겨서 복잡한 식을 단순하게 표현할 수 있으며, 가독성을 크게 향상시킨다.

어노테이션(Annotation)

ㄴ 의미: 컴파일러 및 런타임 환경에 메타데이터를 제공하기 위한 Java의 문법적 요소.

 

접근 제어자(Access Modifier)

ㄴ 의미: 클래스, 메소드, 변수 등의 접근 범위를 지정하여 캡슐화와 추상화를 구현하는 핵심 기능.
ㄴ 종류:

public: 어디서나 자유롭게 접근할 수 있다.
protected: 같은 패키지 내 클래스 또는 상속받은 자식 클래스에서만 접근할 수 있다.
default: 기본값으로, 같은 패키지 내 클래스에서만 접근할 수 있다.
private: 해당 멤버를 선언한 클래스에서만 접근할 수 있다.

 

제네릭(Generic)

ㄴ 의미:
    ㅡ 제네릭 타입 및 메소드를 정의하고 사용할 수 있는 언어적 특성.
    ㅡ 런타임 환경에 아무런 영향을 미치지 않는 컴파일 타임의 전처리 기술.
ㄴ 사용 이유:
    ㅡ 잘못된 타입 사용으로 인해 발생할 수 있는 런타임 에러를 컴파일 타임에 검출하여 타입 안전성을 확보할 수 있음.
    ㅡ 제네릭을 사용하면 타입을 국한할 수 있으므로 요소를 찾아올 때 타입 변환이 필요하지 않아 성능이 향상됨.


시성 제어

모니터 락(Monitor Lock)
ㄴ 의미: 모든 객체의 동기화 매커니즘의 기반을 형성하는 모니터를 사용하는 배타 락.

임계 영역(Critical Section)
ㄴ 의미: 공유되는 데이터가 사용되어 동기화가 필요한 코드 블록.

생산자 - 소비자 문제(Producer - Consumer Problem)
ㄴ 의미: 공유되는 리소스를 저장하는 원형 버퍼를 가정할 때 발생할 수 있는 다음의 세 가지 문제의 집합:

1. 오버플로우 문제(Overflowing): 생산자가 기존의 데이터를 덮어쓰는 문제.
2. 언더플로우 문제(Underflowing): 소비자가 올바르지 않은 데이터를 읽는 문제.
3. 경쟁 상태(Race Condition): 생산자와 소비자 간 경쟁이 발생하는 문제.

ㄴ 해결 방법: 
    ㅡ 상호 배제: 이진 세마포어, 뮤텍스
    ㅡ 실행 순서 제어: 카운팅 세마포어, 조건 변수
    ㅡ 상태 관리: 모니터 객체, 원자적 변수

스레드 동기화(Thread Synchronization)
ㄴ 의미: 멀티스레드 환경에서 상호 배제를 통해 데이터의 가시성과 원자성을 보장함으로써 최종적으로 일관성을 유지하는 것.
    ㅡ 상호 배제: 여러 스레드가 하나의 공유되는 리소스에 동시에 접근하지 못하도록 막는 것.
    ㅡ 가시성: 한 스레드가 수정한 결과가 다른 스레드에게 즉시 보이게 하는 것.
    ㅡ 원자성: 변경 사항이 모두 적용되거나 아예 적용되지 않는 것.
    ㅡ 일관성: 어느 시점에서도 데이터에 모순이 없는 상태가 유지되는 것.

synchronized
ㄴ 의미: 모니터 객체를 사용하여 스레드를 동기화한다.
ㄴ 기능: 임계 영역에 대한 상호 배제를 지원하고, 이 영역 안에서 wait(), notify()와 notifyAll() 메소드를 사용하여 실행 순서 제어와 상태 관리를 지원한다.
ㄴ 문제점:

1. Spurious Wakeup: notify()는 대기 중인 임의의 스레드를 깨우기 때문에 현 상태에 알맞지 않은 스레드를 깨울 수 있다.
2. Lost Wakeup: notify()가 현 상태에 알맞지 않은 스레드를 깨운다면 무한 대기에 빠질 수도 있다.
3. Thundering Herd Problem: notifyAll()을 사용하면 조건에 맞지 않는 스레드가 경쟁하면서 대기 상태로 전환되기까지 불필요한 컨텍스트 스위칭 비용이 발생할 수 있다.

ㄴ 대안책: java.utils.concurrent 패키지에 포함된 고수준의 싱크로나이저, 그리고 내부적으로 이들을 다루는 동시적 컬렉션.

 

블로킹(Blocking)
ㄴ 의미:

    ㅡ 특정 스레드가 리소스를 사용 중이면, 다른 스레드는 그 리소스가 해제될 때까지 대기한다.
ㄴ 구현 방식
    ㅡ 주로 락을 사용하여 리소스를 제어한다.
ㄴ 장점:
    ㅡ 구현이 비교적 쉽고 논리적 흐름이 직관적이다.
ㄴ 단점:
    ㅡ 데드락이 발생할 수 있다.
    ㅡ 우선순위 역전 현상이 발생할 수 있다.
    ㅡ 스레드의 블로킹 및 언블로킹 중 컨텍스트 스위칭이 발생한다.

논블로킹(Non-Blocking)
ㄴ 의미:
    ㅡ 어떤 스레드의 실패나 지연은 다른 스레드의 실행에 영향을 미치지 않는다.
ㄴ 구현 방식:
    ㅡ 주로 CAS 같은 원자적 연산을 활용한다.
ㄴ 장점:
    ㅡ 데드락이 발생하지 않는다.
    ㅡ 컨텍스트 스위칭 비용을 줄인다.
ㄴ 단점:
    ㅡ 알고리즘 설계가 복잡하다.
    ㅡ 웨이트 프리 알고리즘이 아니라면 기아가 발생할 수 있다.

동기(Synchronous)
ㄴ 의미:
    ㅡ 코드가 위에서부터 아래로 순차적으로 실행된다.
    ㅡ 선행 작업이 완료되어야만 후행 작업으로 넘어갈 수 있다.
ㄴ 장점:
    ㅡ 구현이 비교적 쉽고 논리적 흐름이 직관적이다.
ㄴ 단점
    ㅡ 중간에 오래 걸리는 작업으로 인해 블로킹이 발생할 수 있다.

비동기(Asynchronous)
ㄴ 의미:
    ㅡ 오래 걸리는 작업이 완료될 때까지 기다리지 않고 즉시 다음 작업을 수행한다.
    ㅡ 나중에 콜백 함수가 실행되거나 또는 결과로서 상태가 갱신되는 것을 통해 작업이 완료되었는지 알 수 있다.
ㄴ 장점
    ㅡ 컨텍스트 스위칭 비용을 줄인다.
ㄴ 단점
    ㅡ 코드 구현이 복잡해진다.
    ㅡ 작업의 실행 순서가 보장되지 않아 결과 예측이 어려울 수 있다.


동일성 및 동등성

동일성 및 동등성 비교

ㄴ 동일성(참조 동등성): 객체가 참조하는 메모리 주소가 동등한 것.
ㄴ 동등성(값 동등성): 객체의 논리적인 상태가 동등한 것. 의미론적으로 동등한 것을 의미하기도 한다.

동등성의 5가지 원칙

ㄴ 의미: 동등성의 5가지 원칙은 단순히 수학적인 개념으로서가 아니라, equals() 메소드를 오버라이딩할 때 반드시 지켜야 하는 기술적 가이드라인으로서 의미가 있다.
ㄴ 항목:

반사성: null이 아닌 모든 x에 대하여 x.equals(x)는 true이다.
대칭성: null이 아닌 모든 x, y에 대하여 x.equals(y)가 true면 y.equals(x)도 true이다.
추이성: null이 아닌 모든 x, y, z에 대하여 x.equals(y)가 true고 y.equals(z)가 true면 x.equals(z)도 true이다.
일관성: null이 아닌 모든 x, y에 대하여 각각의 객체의 상태가 변하지 않을 때 x.equals(y)가 true면 x.equals(y)는 언제나 true이다.
null에 대한 비항등성: null이 아닌 모든 x에 대하여 x.equals(null)은 false이다.

 

equals()

ㄴ 의미: 
    ㅡ 동등성 비교를 위해 사용되는 메소드.
    ㅡ Object Class에 의해 정의된다.

hashCode()

ㄴ 의미:
    ㅡ 객체를 식별할 수 있는 하나의 정수 값을 만들어내는 메소드.
    ㅡ 마찬가지로 Object Class에 의해 정의된다.

equals()와 hashCode() 간 관계

ㄴ 결론: equals()를 오버라이딩할 때는 hashCode()를 함께 오버라이딩해야 한다.

ㄴ 이유:

논리적 이유:
Object 클래스 명세에는 두 가지 규칙이 정의되어 있다.
- 동등성 원칙: equals()를 통해 동등하다고 판단된 두 객체의 hashCode() 값은 반드시 일치해야 한다.
- 역은 성립하지 않는다: hashCode()가 같다고 해서 반드시 equals()가 true일 필요는 없다.
리스코프 치환 원칙에 따라, 이러한 동작 방식은 Object를 참조하는 모든 참조형 타입 객체에 예외 없이 적용되어야 한다.
Object에서 equals()는 동일성 비교를 수행하며, hashCode() 또한 객체의 메모리 주소를 기반으로 생성된다.
equals()만 오버라이딩하고 hashCode()는 그대로 사용한다면, hashCode()가 여전히 메모리 주소를 기반으로 동작하기 때문에 equals()를 통해 동등한 것으로 판명된 객체의 해시 값이 다를 수 있고, 이는 위의 조건에 어긋난다.
따라서 hashCode() 메소드는 equals() 메소드와 함께 오버라이딩되어야 한다.

기술적 이유:

해시 기반 컬렉션은 객체의 hashCode()를 사용하여 내부 버킷의 위치를 판단하기 때문에, equals()는 같지만 hashCode()는 다른 경우 동등한 객체를 찾지 못하거나 객체를 중복 저장하는 등 심각한 논리적 문제가 발생한다.

'프로그래밍 기초' 카테고리의 다른 글

Java 기초 개념 요약 정리(2)  (0) 2026.02.05
아키텍처 기초 개념 요약 정리  (0) 2025.12.09
JVM 기초 개념 요약 정리  (1) 2025.12.08