담비의 개발블로그

자바(Java)란 무엇인가? 본문

CS(컴퓨터과학)

자바(Java)란 무엇인가?

담비12 2025. 11. 27. 21:36

자바는 객체지향프로그래밍 언어이다.

자바의 핵심 슬로건은 "한 번 작성하면, 어디서든 실행된다"(Write Once, Rnu Anywhere)이다.

 

1. 운영 체제에 독립적(플랫폼 독립성)

자바는 컴파일러가 소스코드(.java 확장자 파일)를 특정 운영체제나 하드웨어의 기계어가 아닌, 바이트 코드(.class 확장자 파일)라는 중간 언어로 변환한다. 이 바이트 코드는 각 운영체제에(OS) 맞게 설치된 JVM에 의해 해석되고 실행된다. JVM은 하드웨어와 운영체제에 맞는 가상의 컴퓨터 역할을 한다. 개발자는 코드를 한번만 작성하면 Windows, Linux, macOS 등 어떤 환경에서도 동일하게 실행할 수 있다. 

 

※ JVM(Java Virtual Machine) :  JVM은 자바 바이트 코드를 해당 운영 체제(OS)가 이해할 수 있는 기계어로 변환하고 실행하는 소프트웨어 기반의 가상 컴퓨터

 

2. 객체 지향 언어

자바는 순수한 객체 지향 언어로 설계되었으며 객체 지향 프로그래밍의 핵심 개념인 상속, 캡슐화, 다형성, 추상화를 완벽하게 지원한다.

 

①  상속은 이미 정의된 클래스의 속성(변수)과 기능(메서드)을 새로운 클래스가 물려받아 재사용할 수 있도록 하는 개념이다.

// 부모 클래스 (Superclass)
class Animal {
    String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + "가 먹이를 먹습니다.");
    }
}

// 자식 클래스 (Subclass) - Animal 클래스를 상속받음
class Dog extends Animal {
    public Dog(String name) {
        // 부모 클래스의 생성자 호출
        super(name); 
    }
    
    // Dog만의 고유한 기능
    public void bark() {
        System.out.println(name + "가 멍멍 짖습니다.");
    }
}

public class InheritanceExample {
    public static void main(String[] args) {
        Dog myDog = new Dog("바둑이");
        
        // Dog 클래스에는 eat() 메서드가 정의되어 있지 않지만, Animal로부터 상속받아 사용 가능
        myDog.eat();  // 출력: 바둑이가 먹이를 먹습니다. 
        myDog.bark(); // 출력: 바둑이가 멍멍 짖습니다.
    }
}

② 캡슐화는 데이터(변수)와 그 데이터를 처리하는 함수(메서드)를 하나의 단위(클래스로 묶고, 외부에서의 접근으로부터 데이터를 보호하는 개념이다.

class Account {
    // 1. 데이터를 private으로 보호 (정보 은닉)
    private double balance; 

    // 생성자
    public Account(double initialBalance) {
        // 내부 메서드를 통해 초기화 (유효성 검사 적용 가능)
        setBalance(initialBalance); 
    }

    // 2. Getter (데이터 읽기 전용 메서드)
    public double getBalance() {
        return balance;
    }

    // 3. Setter (데이터 쓰기/변경용 메서드)
    public void setBalance(double newBalance) {
        // Setter 내부에서 유효성 검사 로직 추가 가능
        if (newBalance >= 0) {
            this.balance = newBalance;
        } else {
            System.out.println("잔액은 음수가 될 수 없습니다.");
        }
    }
}

public class EncapsulationExample {
    public static void main(String[] args) {
        Account myAccount = new Account(10000.0);
        
        // 직접 접근 불가능 (컴파일 에러 발생: myAccount.balance = -5000.0;)
        
        // Getter를 통한 안전한 값 확인
        System.out.println("현재 잔액: " + myAccount.getBalance()); // 출력: 현재 잔액: 10000.0
        
        // Setter를 통한 안전한 값 변경 (유효성 검사 통과)
        myAccount.setBalance(15000.0);
        System.out.println("변경 후 잔액: " + myAccount.getBalance()); // 출력: 변경 후 잔액: 15000.0
        
        // Setter를 통한 잘못된 값 변경 시도 (유효성 검사 실패)
        myAccount.setBalance(-500.0); // 출력: 잔액은 음수가 될 수 없습니다.
    }
}

③ 다형성은 여러 가지 형태를 가질 수 있는 성질'이라는 의미로, 하나의 메서드나 객체가 상황에 따라 다르게 동작하는 것을 말한다.

// 부모 클래스
class Vehicle {
    public void run() {
        System.out.println("탈것이 달립니다.");
    }
}

// 자식 클래스 1: run() 메서드를 오버라이딩(재정의)
class Car extends Vehicle {
    @Override
    public void run() {
        System.out.println("자동차가 쌩쌩 달립니다.");
    }
}

// 자식 클래스 2: run() 메서드를 오버라이딩(재정의)
class Bicycle extends Vehicle {
    @Override
    public void run() {
        System.out.println("자전거가 천천히 달립니다.");
    }
}

public class PolymorphismExample {
    public static void main(String[] args) {
        // 부모 타입(Vehicle)의 참조 변수가 
        // 자식 타입(Car, Bicycle)의 객체를 참조합니다.
        
        Vehicle v1 = new Car();
        Vehicle v2 = new Bicycle();
        
        // run()을 호출하지만, 실제 객체의 타입에 따라 다른 결과가 나옴 (다형성)
        v1.run(); // 출력: 자동차가 쌩쌩 달립니다.
        v2.run(); // 출력: 자전거가 천천히 달립니다.
        
        Vehicle[] vehicles = {new Car(), new Bicycle()};
        for (Vehicle v : vehicles) {
            v.run(); // 동일한 코드가 다른 동작을 수행
        }
    }
}

④ 추상화는 객체들의 공통적인 특징을 파악하여 하나의 개념으로 묶는 과정이며, 사용자가 복잡한 내부 구현은 숨기고 필요한 핵심 기능(인터페이스)만 제공하는 개념이다.

// 인터페이스를 이용한 추상화
interface RemoteControl {
    // 규격만 정의 (public abstract 메서드)
    void turnOn();
    void turnOff();
}

// 실제 구현 클래스 (TV)
class Television implements RemoteControl {
    @Override
    public void turnOn() {
        System.out.println("TV가 켜집니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("TV가 꺼집니다.");
    }
}

public class AbstractionExample {
    public static void main(String[] args) {
        // RemoteControl 타입으로만 객체를 다룸 (구현 세부 정보 숨김)
        RemoteControl tvRemote = new Television(); 
        
        // 사용자는 turnOn(), turnOff() 인터페이스만 알면 됨
        tvRemote.turnOn();  // 출력: TV가 켜집니다.
        tvRemote.turnOff(); // 출력: TV가 꺼집니다.
        
        // 나중에 Radio 클래스가 추가되어도 RemoteControl 타입으로 처리 가능
    }
}

 

3. 자동 메모리 관리 (Garbage Collection, GC)
C나 C++과 같은 언어에서는 프로그래머가 사용하지 않는 메모리를 직접 해제해야 하지만, 자바에서는 가비지 컬렉터(Garbage Collector)가 이 역할을 자동으로 수행한다.

 

Garbage Collector : JVM의 기능중 하나이다. 가비지 컬렉터가 힙 영역을 주기적으로 검사하여, 더 이상 프로그램에서 접근할 수 없는 "쓰레기(Garbage)" 객체들을 자동으로 찾아내어 메모리를 해제한다.

 


4. 멀티스레드 지원
자바는 하나의 프로그램이 여러 작업을 동시에 처리할 수 있도록 멀티스레드 기능을 지원한다.
운영 체제와 독립적으로 멀티스레드 구현이 가능하며, 이를 통해 대규모 서버 애플리케이션이나 고성능 환경에서 효율적으로 자원을 활용할 수 있다.

5. 강력한 생태계와 안정성
자바는 오랜 기간 동안 광범위하게 사용되어 왔기 때문에 방대한 양의 API 라이브러리와 개발 도구, 그리고 활발한 개발자 커뮤니티를 갖추고 있다. 이는 개발 과정에서 발생하는 문제 해결이 용이하며, 안정적이고 효율적인 개발 환경을 제공한다.