질문 모음
- 자바의 특징
- 객체 지향 프로그래밍 언어 (추상화, 상속, 다형성, 캡슐화)
- 기본 자료형을 제외한 모든 요소들이 객체로 표현됨
- 장점
- JVM 위에서 동작 → 운영체제에 독립적
- GarbageCollector를 통한 자동 메모리 관리
- 단점
- JVM 위에서 동작 → 실행 속도가 상대적으로 느리다
- 다중 상속이나 타입에 엄격하며, 제약이 많다
- 객체 지향 프로그래밍(OOP)의 특징
- 객체 : OOP의 기본 단위, 모든 실재 대상을 지칭함
- OOP : 명령어의 목록이 아닌, 객체들의 상호작용으로 컴퓨터 프로그래밍 로직을 구성하는 프로그래밍 패러다임
- 특징
- 추상화 : 객체의 공통적인 속성과 기능을 추출하여 정의
- 상속 : 기존 클래스를 재활용하여 새로운 클래스를 작성
- 다형성 : 어떤 객체의 속성이나 기능이 상황에 따라 여러 형태를 갖는 성질
- 캡슐화 : 서로 연관 있는 속성과 기능들을 하나로 묶어, 데이터를 외부로부터 보호
- 모듈 재사용 → 확장, 유지보수 수월
- 상속, 컴포지션(합성)
- 상속 : is-a 관계, 클래스를 확장해 부모 클래스에서 속상 및 동작을 상속하는 기능
- 컴포지션 : has-a 관계, 클래스가 구성원 데이터로 다른 클래스의 객체를 포함하는 능력
- JVM (Java Virtual Machine)
- 자바 가상 머신, 자바 프로그램 실행 환경을 만들어 주는 소프트웨어
- JVM은 자바 실행 환경 JRE(Java Runtime Environment)에 포함
- JVM을 사용하면 하나의 바이트 코드(
.class)로 모든 플랫폼에서 동작 가능하다
- 바이트 코드는 각자 플랫폼에 설치되어있는 JVM이 OS에 맞는 실행파일로 바꿔줌
⇒ Java는 운영체제에 독립적이다, 플랫폼의 영향을 받지 않는다
비교 (C, Java)


- Java는 플랫폼에 종속적이지 않지만, JVM은 플랫폼에 종속적이다
- 자바는 컴파일된 바이트코드로 어떤 JVM에서도 동작 가능
- 리눅스의 JVM과 윈도우의 JVM은 서로 다름
- 작동/역할
- 스택 기반으로 동작
- Java Byte Code를 OS에 맞게 해석
- GarbageCollector을 통해 자동으로 메모리 관리 수행
- 자바의 메모리 영역 (JVM 메모리 구조)
- 메서드 영역 : static 변수, 전역 변수, 코드에서 사용하는 클래스 저장. 프로그램의 시작부터 종료까지 남아 있다
- 스택 영역 : 지역 변수, 메서드 등을 LIFO 방식으로 저장. 메모리가 호출될 때 메모리에 할당되고 종료되면 메모리 해제
- 힙 영역 : new 연산자를 통해 동적 할당된 객체 등 참조 데이터 저장. Gc 의해 관리
- 상수 풀
- Constant pool, 상수나 필드/메소드 등의 reference 값을 저장하는 공간
- 힙 영역의 permanent area(고정 영역)에 생성되어 Java 프로세스의 종료까지 계속 유지되는 메모리 영역
- 각 데이터의 reference를 갖고 있어서 실제 물리적 메모리 위치 참조에 사용

- 자바의 컴파일 과정
- 개발자가 Java 파일을 생성
- build
- Java compiler의 javac의 명령어를 통해 바이트 코드(
.class)를 생성
- Class Loader를 통해 JVM 메모리 내로 로드
- 실행엔진을 통해 컴퓨터가 읽을 수 있는 기계어로 해석 (각 OS에 맞는 기계어)

- Java에서 제공하는 원시 타입들 (단위: byte)
- 정수형 byte(1), short(2), int(4), long(8)
- 실수형 float(4), double(8)
- 문자형 char(2)
- 논리형 boolean (1)
- 오버라이딩, 오버로딩
- 오버라이딩 Overriding : 상위 클래스에 있는 메소드를 하위 클래스에서 재정의
- 오버로딩 : Overloading : 매개변수의 개수나 타입을 다르게 하여 같은 이름의 메소드를 여러 개 정의
- 불변 객체
- 객체 생성 이후 내부의 상태가 변하지 않는 객체
- Java 기준
- 원시 타입 필드 :
final 키워드 사용
- 참조 타입 필드 (객체, 배열, 리스트 등을 참조)
- 참조 변수가
- 일반 객체인 경우, 객체를 사용하는 필드의 참조 변수도 불변 객체로 변경
- 배열인 경우, 배열을 copy해서 저장하고 getter를 clone으로 반환
- 리스트인 경우, 배열처럼 새로운 List를 만들어 값을 복사
- 장점
- Thread-safe → 병렬 프로그래밍에 유용, 동기화를 고려하지 않아도 됨
(공유 자원이 불변이기 때문에 항상 동일한 값을 반환하기 때문)
- 실패 원자적인 메소드를 만들 수 있음
텍스트(어떠한 예외가 발생하더라도 메소드 호출 전의 상태 유지 가능
→ 예외 발생 전과 똑같은 상태로 다음 로직 처리 가능)
- 부수효과를 피해 오류 최소화 가능
(부수효과: 변수의 값이 바뀌거나 객체의 필드 값을 설정하거나 예외/오류가 발생하여 실행이 중단되는 현상)
- 메소드 호출 시 파라미터 값이 변하지 않는다는 것을 보장
- 가비지 컬렉션 성능 향상 (Gc가 스캔하는 객체의 수 감소 → 수행 시 지연시간 감소)
- 추상 클래스, 인터페이스
- 추상 클래스
- 클래스 내 추상 메소드가 하나 이상 포함되거나, abstract로 정의된 클래스
- 사용 목적: 추상 클래스는 상속 받는 클래스들의 공통적인 로직을 추상화 시키고, 기능 확장을 위해 사용
- 다중 상속 불가
- 인터페이스
- 모든 메소드가 추상 메소드로만 이루어진 것
- 사용 목적: 그 인터페이스를 구현하는 모든 클래스에 대해 특정한 메소드가 반드시 존재하도록 강제함
- 다중 상속 가능
- 공통점
- new 연산자로 인스턴스 생성 불가능
- 사용하기 위해서는 하위 클래스에서 확장/구현 필요
- 팀 작업에 있어서 인터페이스의 장점
- 팀 작업 시 개발코드와 객체가 서로 통신하는 접점 역할
- 객체 내부 구조를 모르더라도, 인터페이스 메소드 명만 알면 다른 팀의 작업을 기다리지 않아도 됨
- 해당 객체가 수정되더라도, 개발 코드 부분은 수정하지 않아도 된다
- 가비지 컬렉션 Garbage Collection
- JVM의 메모리 관리 기법 중 하나
- 시스템에서 동적으로 할당됐던 메모리 영역 중, 필요 없어진 메모리 영역을 회수
- 과정
1. JVM이 어플리케이션의 실행을 잠시 멈춤
2. GC를 실행하는 스레드를 제외한 모든 스레드 작업 중단 (Stop the World)
3. 사용하지 않는 메모리를 제거 (Mark and Sweep)
4. 작업 재개
- 클래스와 객채
- 클래스 : 객체를 만들어내기 위한 설계도, 툴. 객체 생성에 사용한다
- 객체 : 설계도(클래스)를 기반으로 생성되며, 고유의 이름/상태(필드)/행동(메소드)을 갖는다
→ 객체에 메모리가 할당되어 실제로 활용되는 실체는 ‘인스턴스’라 부름
- 생성자 Constructor
- 클래스와 같은 이름의 메소드로, 객체가 생성될 때 호출되는 메소드
- 명시적으로 생성자를 만들지 않아도 default로 만들어짐
- 파라미터를 다르게 하여 오버로딩 가능
- Wrapper Class, Boxing, UnBoxing
- Wrapper class : 기본(원시) 자료형에 대한 객체 표현
- Boxing : 기본 자료형 → wrapper class 변환
- Unboxing : wrapper class → 기본 자료형 변환
public class Wrapper_Ex {
public static void main(String[] args) {
Integer num = new Integer(17);
int n = num.intValue();
System.out.println(n);
}
}
- 제네릭 Generic
- 클래스 선언 시 타입을 결정하지 않고, 객체 생성 시 유동적으로 재사용하기 위한 것
- 장점
- 형변환을 따로 할 필요가 없음
- 타입 에러가 발생하지 않음
- 컬렉션 클래스에서 제너릭을 사용하면, 컴파일러는 특정 타입만 포함되도록 컬렉션을 제한 → 런타임에 발생할 수 있는 모든 잠재적 예외를 컴파일 시 방지한다
public class ClassName <T, K> { ... }
public class Main {
public static void main(String[] args) {
ClassName<String, Integer> a = new ClassName<String, Integer>();
}
}
- new String(), 리터럴(””)의 차이
new String() : new 키워드로 새로운 객체를 생성 → Heap 영역에 저장
- 리터럴
" " : Heap 안에 있는 String Constant Pool 영역에 저장
- 접근 제한자
- 변수 또는 메소드의 접근 범위를 설정해주기 위해 사용하는 예약어
public : 같은 프로젝트 내 어디서든 사용 가능
protec : 같은 패키지, 다른 패키지의 자손 클래스에서 접근 가능
default : 같은 패키지 내에서만 접근 가능
private : 같은 클래스에서만 접근 가능
- 클래스 멤버 변수 초기화 순서
- static 변수 선언부 : 클래스가 로드될 때(method 메모리 영역에 올라갈 때)
- 필드 변수 선언부 : 객체가 생성될 때(heap area) 생성자 block보다 앞서 초기화
- 생성자 block : 객체가 생성될 때 JVM이 내부적으로 locking (thread-safe 영역)
- 필드 변수 중 final 변수의 가시화(다른 스레드에 공개)는 생성자 block이 끝난 다음임
(필드 변수 선언부에서 이미 초기화 되었다면 덮어씀)
- Static 키워드를 사용한 변수/메소드
- 클래스가 메모리에 올라갈 때 자동 생성
- 클래스 로딩이 끝나면 바로 사용 가능
- 모든 객체가 메모리를 공유
- GC 관리 영역 밖이기에 프로그램 종료까지 메모리 값 유지
- static을 사용하는 이유
- 자주 변하지 않거나 공통으로 사용하는 값 등의 공용 자원에 적용
- 매번 메모리에 로딩 하거나 값을 읽어주는 것보다 일종의 ‘전역변수’와 같은 개념을 통해 접근 → 비용 감소, 효율적
- 인스턴스 생성 없이 바로 생성 가능 → 프로그램 내에서 공통으로 사용되는 데이터 관리할 때 이용
자바 코드 실행 과정
1. JVM
자바 가상 머신, JVM, Java Virtual Machine
자바 프로그램 실행환경을 만들어 주는 소프트웨어
자바 코드를 컴파일하여 .class 바이트 코드로 만들면, 이 코드가 JVM에서 실행된다
JVM은 자바 실행 환경(JRE, Java Runtime Environment)에 포함된다
(현재 사용하는 컴퓨터의 운영체제에 맞는 JRE가 설치되어 있다면 → JVM도 설치되어 있음)
Java는 플랫폼 독립적이다
JVM을 사용하면 하나의 바이트 코드(.class)로 모든 플랫폼에서 동작하도록 할 수 있다.
JVM은 플랫폼에 종속적이다
자바는 컴파일된 바이트코드로 어떤 JVM에서도 동작 가능하지만, 리눅스의 JVM과 윈도우의 JVM은 서로 다르다.
2. 자바 컴파일 과정
컴파일 Compile
고급언어로 작성된 .java 파일을 기계어인 byte code, 즉 .class 파일로 변환하는 과정

- 자바 클래스 파일(
.java)에 소스코드 작성
[Java Compiler, Javac]가 자바 소스 파일을 컴파일
⇒ 자바 바이트 코드(.class) 생성
- 아직 컴퓨터가 읽을 수 없는, JVM만 이해할 수 있는 코드
- 1 byte 크기의 Opcode와 추가 피연산자로 이루어짐
- 컴파일된 바이트 코드를 JVM의
[Class Loader]에게 전달
[Class Loader]는 동적 로딩을 통해 필요한 클래스를 로딩 & 링크 → JVM 메모리에 올림
- 세부 동작
1. 로드 : 클래스 파일을 가져와 [런타임 데이터 영역](JVM의 메모리)에 로드
2. 검증 : 자바 언어 명세 및 JVM 명세대로 구성되었는지 검사
3. 준비 : 클래스가 필요로 하는 메모리 할당 (필드, 메서드, 인터페이스 등)
4. 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경
5. 초기화 : 클래스 변수들을 적절한 값으로 초기화 (static 필드)
[실행 엔진]은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와 실행
- 실행 방식
- 인터프리터 방식
- 바이트 코드를 하나씩 읽고 → 해석하고 → 실행
- 하나하나의 실행은 빠르나, 전체적인 실행 속도는 느리다
- JIT 컴파일러 방식
- Just-In-Time Compiler
- 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경
→ 이후, 메서드를 더이상 인터프리팅 하지 않고 바이너리 코드로 직접 실행
- 인터프리터의 단점을 보완하기 위해 도입
- 하나씩 인터프리팅하여 실행 X
- 바이트 코드 전체가 컴파일된 바이너리 코드를 실행 O
- 실행 속도는 인터프리터 방식보다 빠르다
클래스 로더 Class Loader

자바는 동적으로 클래스를 읽어오므로, 프로그램이 실행 중인 런타임에서야 모든 코드가 자바 가상 머신과 연결된다. 이때 동적으로 클래스를 로딩해주는 역할을 하는 것이 클래스 로더이다.
자바에서 소스를 생성하면 .java 파일이 생성되고, 이걸 컴파일하면 .class 파일이 생성되는데, 클래스 로더는 .class 파일을 묶어서 JVM이 운영체제로부터 할당받은 메모리 영역인 Runtime Data Area로 적재한다.
런타임 데이터 영역 Runtime Data Area


JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터를 적재하는 곳이다.
- 모든 스레드가 공유 → GC의 대상
- 스레드가 하나씩 생성
- Stack, PC 레지스터, 네이티브 메서드 스택