객체 지향 프로그래밍 언어를 사용해 본 적이 없다면 코드 작성을 시작하기 전에 몇 가지 기본 개념을 익혀야 합니다. 이 섹션에서는 객체, 클래스, 상속, 인터페이스 및 패키지에 대해 소개합니다. 각 논의는 이러한 개념이 실제 세계와 어떻게 관련되는지에 초점을 맞추는 동시에 Java 프로그래밍 언어의 구문에 대한 소개를 제공합니다.

객체란 무엇인가요?

객체는 관련 상태 및 동작의 소프트웨어 번들입니다. 이 섹션에서는 객체 내에서 상태와 동작이 어떻게 표현되는지 설명하고 데이터 캡슐화의 개념을 소개하며 이러한 방식으로 소프트웨어를 설계할 때의 이점에 대해 설명합니다.

객체는 모두 상태와 동작을 가지고 있다는 두 가지 특징을 공유합니다. 개는 상태(이름, 색깔, 품종, 배고픔)와 행동(짖기, 물 가져오기, 꼬리 흔들기)을 가지고 있습니다. 자전거에도 상태(현재 기어, 현재 페달 케이던스, 현재 속도)와 행동(기어 변경, 페달 케이던스 변경, 브레이크 밟기)이 있습니다. 실제 사물의 상태와 동작을 파악하는 것은 객체 지향 프로그래밍의 관점에서 사고를 시작하는 좋은 방법입니다.

지금 잠시 시간을 내어 주변에 있는 실제 사물을 관찰해 보세요. 보이는 각 사물에 대해 두 가지 질문을 해보세요: “이 물체가 어떤 상태에 있을 수 있을까?” 그리고 “이 물체가 어떤 동작을 수행할 수 있을까?“. 관찰한 내용을 반드시 기록하세요. 이렇게 하다 보면 실제 사물의 복잡성이 다양하다는 것을 알 수 있습니다. 데스크톱 램프는 두 가지 상태(켜기, 끄기)와 두 가지 동작(켜기, 끄기)만 있을 수 있지만 데스크톱 라디오는 추가적인 상태(켜기, 끄기, 현재 볼륨, 현재 방송국)와 동작(켜기, 끄기, 볼륨 높이기, 볼륨 줄이기, 찾기, 스캔, 튜닝)을 가질 수도 있습니다. 또한 일부 객체에는 다른 객체도 포함될 수 있습니다. 이러한 현실 세계의 관찰은 다음을 위한 출발점입니다. 소프트웨어 객체

소프트웨어 객체는 상태와 관련 동작으로 구성됩니다. 객체는 필드(일부 프로그래밍 언어의 변수)에 상태를 저장하고 메서드(일부 프로그래밍 언어의 함수)를 통해 동작을 노출합니다. 메서드는 객체의 내부 상태에서 작동하며 객체 간 통신을 위한 주요 메커니즘 역할을 합니다. 내부 상태를 숨기고 모든 상호작용을 객체의 메서드를 통해 수행하도록 하는 것을 데이터 캡슐화라고 하며, 이는 객체 지향 프로그래밍의 기본 원칙입니다.

예를 들어 자전거를 생각해 보세요: 소프트웨어 객체로 모델링된 자전거

상태(현재 속도, 현재 페달 케이던스, 현재 기어)를 속성으로 지정하고 해당 상태를 변경하는 방법을 제공함으로써 객체는 외부 세계가 어떻게 사용하도록 허용되는지 제어할 수 있습니다. 예를 들어 자전거에 기어가 6개만 있는 경우 기어를 변경하는 메서드는 1보다 작거나 6보다 큰 값은 모두 거부할 수 있습니다.

코드를 개별 소프트웨어 객체에 번들링하면 다음과 같은 여러 가지 이점이 있습니다:

  1. 모듈화: 한 개체의 소스 코드는 다른 개체의 소스 코드와 독립적으로 작성 및 유지 관리할 수 있습니다. 한 번 생성된 개체는 시스템 내에서 쉽게 전달할 수 있습니다.
  2. 정보 숨김: 객체의 메서드와만 상호 작용하기 때문에 내부 구현의 세부 사항은 외부에 노출되지 않습니다.
  3. 코드 재사용: 이미 존재하는 객체(다른 소프트웨어 개발자가 작성한 것일 수도 있음)가 있다면 프로그램에서 해당 객체를 사용할 수 있습니다. 이를 통해 전문가가 복잡한 작업별 객체를 구현/테스트/디버깅할 수 있으며, 사용자는 이를 자신의 코드에서 실행할 수 있습니다.
  4. 연결성 및 디버깅 용이성: 특정 객체에 문제가 있는 것으로 판명되면 애플리케이션에서 해당 객체를 제거하고 다른 객체를 대체할 수 있는 플러그인만 연결하면 됩니다. 이는 실제 세계에서 기계적인 문제를 해결하는 것과 유사합니다. 볼트가 부러지면 기계 전체를 교체하는 것이 아니라 볼트 하나만 교체하면 됩니다.

클래스란 무엇인가요?

애플리케이션에서는 종종 같은 종류의 개별 개체를 많이 찾을 수 있습니다. 동일한 제조사와 모델을 가진 수천 대의 자전거가 존재할 수 있습니다. 각 자전거는 동일한 청사진 세트로 제작되었으므로 동일한 구성 요소를 포함합니다. 객체 지향 용어로는 자전거를 자전거라는 객체 클래스의 인스턴스라고 합니다. 클래스는 개별 객체가 생성되는 청사진입니다.

다음 Bicycle 클래스는 자전거의 가능한 구현 중 하나입니다:

class Bicycle {
 
    int cadence = 0;
    int speed = 0;
    int gear = 1;
 
    void changeCadence(int newValue) {
         cadence = newValue;
    }
 
    void changeGear(int newValue) {
         gear = newValue;
    }
 
    void speedUp(int increment) {
         speed = speed + increment;   
    }
 
    void applyBrakes(int decrement) {
         speed = speed - decrement;
    }
 
    void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

Java 프로그래밍 언어의 구문이 생소할 수 있지만, 이 클래스의 디자인은 앞서 설명한 자전거 객체에 대한 내용을 기반으로 합니다. cadence, speed, gear 필드는 객체의 상태를 나타내며, changeCadence(), changeGear(), speedUp() 등의 메서드는 외부 세계와의 상호 작용을 정의합니다.

Bicycle 클래스에는 main() 메서드가 포함되어 있지 않다는 것을 눈치챘을 것입니다. 이는 완전한 애플리케이션이 아니라 애플리케이션에서 사용될 수 있는 자전거에 대한 청사진일 뿐이기 때문입니다. 새로운 Bicycle 객체를 생성하고 사용하는 책임은 애플리케이션의 다른 클래스에 있습니다.

다음은 두 개의 개별 Bicycle 객체를 생성하고 해당 메서드를 호출하는 BicycleDemo 클래스입니다:

class BicycleDemo {
    public static void main(String[] args) {
 
        // Create two different 
        // Bicycle objects
        Bicycle bike1 = new Bicycle();
        Bicycle bike2 = new Bicycle();
 
        // Invoke methods on 
        // those objects
        bike1.changeCadence(50);
        bike1.speedUp(10);
        bike1.changeGear(2);
        bike1.printStates();
 
        bike2.changeCadence(50);
        bike2.speedUp(10);
        bike2.changeGear(2);
        bike2.changeCadence(40);
        bike2.speedUp(10);
        bike2.changeGear(3);
        bike2.printStates();
    }
}

이 테스트의 출력에는 두 자전거의 최종 페달 cadence, speed 및 gear가 출력됩니다:

cadence:50 speed:10 gear:2
cadence:40 speed:20 gear:3

상속이란 무엇인가요?

서로 다른 종류의 물체는 서로 어느 정도 공통점이 있는 경우가 많습니다. 예를 들어 산악 자전거, 로드 자전거, 탠덤 자전거는 모두 자전거의 특성(현재 속도, 현재 페달 케이던스, 현재 기어)을 공유합니다. 그러나 탠덤 자전거에는 두 개의 시트와 두 세트의 핸들바, 로드 자전거에는 드롭 핸들바, 일부 산악 자전거에는 추가 체인 링이 있어 낮은 기어비를 제공하는 등 각각 다른 특징도 정의되어 있습니다.

객체 지향 프로그래밍을 사용하면 클래스가 다른 클래스에서 일반적으로 사용되는 상태와 동작을 상속할 수 있습니다. 이 예제에서 Bicycle은 이제 MountainBike, RoadBike, TandemBike의 슈퍼클래스가 됩니다. Java 프로그래밍 언어에서 각 클래스는 하나의 직접적인 수퍼클래스를 가질 수 있으며, 각 수퍼클래스는 무제한의 하위 클래스를 생성할 수 있습니다: 자전거 클래스 계층 구조

서브클래스를 만드는 구문은 간단합니다. 클래스 선언의 시작 부분에 extends 키워드를 사용하고 그 뒤에 상속할 클래스 이름을 입력하면 됩니다:

class MountainBike extends Bicycle {
 
    // new fields and methods defining 
    // a mountain bike would go here
 
}

이를 통해 MountainBikeBicycle과 동일한 필드와 메서드를 모두 사용하면서도 고유한 기능에만 코드가 집중할 수 있습니다. 이렇게 하면 서브클래스의 코드를 읽기 쉽게 만들 수 있습니다. 하지만 각 수퍼클래스가 정의하는 상태와 동작은 각 서브클래스의 소스 파일에 나타나지 않으므로 해당 코드를 적절히 문서화해야 합니다.

인터페이스란 무엇인가요?

이미 학습했듯이 객체는 노출되는 메서드를 통해 외부 세계와의 상호 작용을 정의합니다. 예를 들어 텔레비전 전면에 있는 버튼은 사용자와 플라스틱 케이스 반대편에 있는 전기 배선 사이의 인터페이스로, 메서드는 외부 세계와 물체의 인터페이스를 형성합니다. “전원” 버튼을 누르면 TV를 켜고 끌 수 있습니다.

가장 일반적인 형태에서 인터페이스는 빈 몸체를 가진 관련 메서드 그룹입니다. 인터페이스로 지정된 자전거의 동작은 다음과 같이 나타날 수 있습니다:

interface Bicycle {
 
    //  wheel revolutions per minute
    void changeCadence(int newValue);
 
    void changeGear(int newValue);
 
    void speedUp(int increment);
 
    void applyBrakes(int decrement);
}

이 인터페이스를 구현하려면 클래스 이름을 특정 자전거 브랜드(예: ACMEBicycle)로 변경하고 클래스 선언에 implements 키워드를 사용해야 합니다:

class ACMEBicycle implements Bicycle {
 
    int cadence = 0;
    int speed = 0;
    int gear = 1;
 
   // The compiler will now require that methods
   // changeCadence, changeGear, speedUp, and applyBrakes
   // all be implemented. Compilation will fail if those
   // methods are missing from this class.
 
    void changeCadence(int newValue) {
         cadence = newValue;
    }
 
    void changeGear(int newValue) {
         gear = newValue;
    }
 
    void speedUp(int increment) {
         speed = speed + increment;   
    }
 
    void applyBrakes(int decrement) {
         speed = speed - decrement;
    }
 
    void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

인터페이스를 구현하면 클래스가 제공하기로 약속한 동작을 보다 공식화할 수 있습니다. 인터페이스는 클래스와 외부 세계 간의 계약을 형성하며, 이 계약은 컴파일러에 의해 빌드 시점에 시행됩니다. 클래스가 인터페이스를 구현한다고 주장하는 경우 해당 인터페이스에서 정의한 모든 메서드가 소스 코드에 나타나야 클래스가 성공적으로 컴파일됩니다.

참고: 실제로 ACMEBicycle 클래스를 컴파일하려면 구현된 인터페이스 메서드의 시작 부분에 public 키워드를 추가해야 합니다. 그 이유는 나중에 클래스와 객체, 인터페이스상속 섹션에서 배우게 될 것입니다.

패키지란 무엇인가요?

패키지는 관련 클래스 및 인터페이스 집합을 구성하는 네임스페이스입니다.개념적으로 패키지는 컴퓨터의 여러 폴더와 비슷하다고 생각할 수 있습니다.HTML 페이지는 한 폴더에, 이미지는 다른 폴더에, 스크립트나 애플리케이션은 또 다른 폴더에 보관할 수 있습니다. Java 프로그래밍 언어로 작성된 소프트웨어는 수백, 수천 개의 개별 클래스로 구성될 수 있으므로 관련 클래스와 인터페이스를 패키지로 묶어 정리하는 것이 좋습니다.

Java 플랫폼은 자체 애플리케이션에서 사용하기에 적합한 방대한 클래스 라이브러리(패키지 세트)를 제공합니다. 이 라이브러리를 “애플리케이션 프로그래밍 인터페이스” 또는 줄여서 “API”라고 합니다. 이 라이브러리의 패키지는 범용 프로그래밍과 가장 일반적으로 연관된 작업을 나타냅니다. 예를 들어 문자열 객체에는 문자 문자열의 상태와 동작이 포함되어 있고, 파일 객체에는 프로그래머가 파일 시스템에서 파일을 쉽게 생성, 삭제, 검사, 비교 또는 수정할 수 있으며, 소켓 객체에는 네트워크 소켓을 생성하고 사용할 수 있고, 다양한 GUI 객체는 버튼과 체크박스 및 기타 그래픽 사용자 인터페이스와 관련된 모든 것을 제어할 수 있습니다. 말 그대로 수천 개의 클래스 중에서 선택할 수 있습니다. 따라서 프로그래머는 애플리케이션을 작동시키는 데 필요한 인프라가 아닌 특정 애플리케이션의 디자인에 집중할 수 있습니다.

Java 플랫폼 API 사양에는 Java SE 플랫폼에서 제공하는 모든 패키지, 인터페이스, 클래스, 필드 및 메서드에 대한 전체 목록이 포함되어 있습니다. 브라우저에서 페이지를 로드하고 북마크에 추가하세요. 프로그래머로서 이 문서는 가장 중요한 참고 문서가 될 것입니다.