개발 공부/자바

스프링 부트 개발자를 위한 Java 핵심 정리

baby-t 2025. 9. 24. 08:36

스프링 부트(Spring Boot)는 Java 언어를 기반으로 하는 강력한 웹 프레임워크입니다. 따라서 스프링 부트를 효과적으로 사용하려면 Java의 핵심 원리와 특징에 대한 견고한 이해가 필수적입니다. ☕️

이번 포스팅에서는 Java가 어떤 언어인지, 가장 중요한 특징인 객체 지향 프로그래밍(OOP)은 무엇인지, 그리고 스프링 개발에서 자주 마주하게 될 주요 문법들을 다시 한번 짚어보겠습니다.


## 1. Java의 가장 큰 특징: JVM과 WORA

  • ## 1. JVM (Java Virtual Machine): Java의 심장, 번역가
    • 역할: 자바 바이트코드(.class 파일)를 실제로 실행하는 가상 컴퓨터입니다.
    • 상세 설명: Java 코드는 컴파일되면 CPU가 직접 읽을 수 있는 기계어가 아닌, JVM만이 이해할 수 있는 중간 언어인 '바이트코드'가 됩니다. JVM은 이 바이트코드를 한 줄씩 읽어들여, 현재 프로그램이 실행되고 있는 운영체제(Windows, Mac 등)에 맞는 기계어로 실시간으로 번역하고 실행합니다.
    • 핵심 특징: 운영체제별로 각각 다른 버전의 JVM이 존재하기 때문에, 개발자는 운영체제를 신경 쓸 필요 없이 바이트코드 하나만 만들면 됩니다. 이것이 바로 **"Write Once, Run Anywhere"**를 가능하게 하는 핵심 엔진입니다.

    ## 2. JRE (Java Runtime Environment): 실행에 필요한 모든 것
    • 역할: 컴파일된 자바 프로그램을 실행하는 데 필요한 환경을 제공합니다.
    • 상세 설명: 프로그램이 실행되려면 JVM만으로는 부족합니다. 화면에 글자를 출력하거나, 파일을 읽는 등 기본적인 기능들을 수행하려면 **핵심 라이브러리(Java Class Libraries)**가 반드시 필요합니다. JRE는 이 JVM과 핵심 라이브러리들을 모두 합쳐놓은 패키지입니다.
    • 핵심 특징: 개발자가 아닌 일반 사용자가 자바로 만들어진 프로그램(예: Minecraft Java Edition)을 실행하고 싶다면, JRE만 설치하면 됩니다.

    ## 3. JDK (Java Development Kit): 개발에 필요한 모든 것
    • 역할: 자바 프로그램을 개발하는 데 필요한 모든 도구를 제공합니다.
    • 상세 설명: 개발자는 프로그램을 실행만 하는 것이 아니라, .java 소스 코드를 .class 바이트코드로 컴파일도 해야 하고, 코드의 문제를 찾아내는 디버깅도 해야 합니다. JDK는 이러한 개발 활동에 필요한 모든 도구를 포함하는 가장 큰 범위의 패키지입니다. 당연히, 개발한 프로그램을 실행도 해봐야 하므로 JDK는 JRE를 완전히 포함하고 있습니다.
    • 핵심 특징: 자바 개발을 하려면 반드시 JDK를 설치해야 합니다.

    ## 한눈에 비교하기
  • 구분 핵심 역할 포함하는 것 주요 사용자
    JDK 자바 프로그램 개발 JRE + 컴파일러 등 개발 도구 개발자
    JRE 자바 프로그램 실행 JVM + 핵심 라이브러리 일반 사용자
    JVM 바이트코드 번역 및 실행 (실행 엔진) (JRE에 포함)

### 자바 프로그램의 컴파일 및 실행 과정

 

  • 개발자가 .java 파일을 작성합니다. (소스 코드)
  • **자바 컴파일러(javac)**가 .java 파일을 읽어들여, JVM이 이해할 수 있는 .class 파일을 생성합니다. (바이트코드)
  • **JVM(자바 가상 머신)**이 이 .class 파일을 실행하여, 운영체제(Windows, Mac 등)가 이해할 수 있는 기계어로 번역하고 프로그램을 구동합니다.

 


## 2. Java의 심장: 객체 지향 프로그래밍 (OOP)

Java는 대표적인 객체 지향 프로그래밍(Object-Oriented Programming) 언어입니다. 이는 세상을 **객체(Object)**들의 상호작용으로 바라보고, 프로그램을 객체들의 집합으로 설계하는 방식입니다. 스프링 프레임워크는 이 OOP 원칙을 극대화하여 설계되었습니다.

### 클래스와 객체

  • 클래스(Class): 객체를 만들기 위한 '설계도' 또는 '틀'입니다. (예: 자동차 설계도)
  • 객체(Object): 클래스라는 설계도를 바탕으로 메모리에 실체화된 **'인스턴스(instance)'**입니다. (예: 설계도로 만든 내 파란색 아반떼)

### OOP의 4대 원칙

  1. 캡슐화 (Encapsulation)
    • 데이터(필드)와 그 데이터를 처리하는 메소드를 하나의 클래스로 묶고, 외부의 직접적인 접근을 제한하는 것입니다. private으로 선언된 필드를 public 메소드(Getter/Setter)를 통해서만 제어하도록 하여 데이터의 무결성을 지킵니다.
  2. 상속 (Inheritance)
    • 부모 클래스의 필드와 메소드를 자식 클래스가 물려받는 것입니다 (extends 키워드). 코드의 재사용성을 높이고 계층 구조를 만들 수 있습니다. (예: class Cat extends Animal)
  3. 다형성 (Polymorphism)
    • 하나의 인터페이스나 부모 클래스를 사용하여, 여러 다른 구현체의 객체를 다룰 수 있는 능력입니다.
    • 예를 들어, Animal이라는 부모 클래스 변수에 Dog 객체도, Cat 객체도 담을 수 있습니다. 같은 makeSound() 메소드를 호출하더라도, 실제 담겨있는 객체가 무엇이냐에 따라 다른 소리를 내는 것이 바로 다형성입니다.
    Java
    Animal myDog = new Dog();
    Animal myCat = new Cat();
    myDog.makeSound(); // "멍멍!" 출력
    myCat.makeSound(); // "야옹" 출력
    
    이 원리는 스프링의 DI(의존성 주입)가 가능한 근본적인 기반이 됩니다.
  4. 추상화 (Abstraction)
    • 복잡한 내부 구현을 숨기고, 사용자에게는 필요한 핵심 기능(인터페이스)만 노출하는 것입니다.
    • 예를 들어, 우리는 List라는 인터페이스를 사용하여 add, get 등의 기능을 호출할 뿐, 그 내부에서 ArrayList가 배열 크기를 어떻게 조절하는지, LinkedList가 노드를 어떻게 연결하는지는 알 필요가 없습니다.

## 3. Spring 개발에 필수적인 Java 문법

  • 기본 타입(Primitive Type) vs. 참조 타입(Reference Type)
    • 기본 타입: int, long, double, boolean 등. 변수에 실제 값을 직접 저장하며, 주로 스택 메모리에 생성됩니다.
    • 참조 타입: String, List 등 클래스의 모든 객체. 변수에는 객체가 있는 힙 메모리의 주소 값을 저장합니다.
  • 인터페이스 (Interface)
    • 객체의 **'역할' 또는 '기능 명세'**를 정의하는 껍데기입니다. 다형성을 통해 객체 간의 결합도를 낮추는(느슨한 결합) 데 결정적인 역할을 하며, 스프링 DI의 핵심 기반입니다.
  • 예외 처리 (Exception Handling)
    • try-catch-finally 구문을 사용하여 프로그램 실행 중 발생할 수 있는 예외(오류)를 처리합니다. 안정적인 백엔드 서비스를 위해 필수적입니다.
  • 제네릭 (Generics)
    • 클래스나 메소드에서 사용할 데이터 타입을 미리 지정하지 않고, 사용 시점에 지정할 수 있게 하는 기능입니다. List<String>이나 Optional<Integer>의 <> 부분이 제네릭입니다. 컴파일 시점에 타입 체크를 할 수 있어 코드의 안정성을 높여줍니다.
  • 어노테이션 (Annotation)
    • @Controller, @Autowired, @Override처럼 @ 기호로 시작하는 코드입니다. 코드 자체의 로직에는 영향을 주지 않지만, 컴파일러나 프레임워크에게 특별한 **메타데이터(부가 정보)**를 제공하여 특정 기능을 수행하도록 지시합니다. 스프링은 어노테이션을 매우 적극적으로 사용합니다.
  • 람다와 스트림 (Lambda & Stream, Java 8+)
    • 람다(Lambda): (parameter) -> { body } 형태로, 익명 함수를 간결하게 표현하는 방식입니다.
    • 스트림(Stream): 컬렉션(리스트 등)의 요소들을 하나씩 순회하며 필터링, 매핑 등 다양한 처리를 할 수 있는 매우 강력하고 현대적인 데이터 처리 기능입니다. (예: list.stream().filter(...).collect(...))