객체란?
객체는 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 객체는 차, 탁자, 고양이와 같은 실세계의 개체와 같습니다.
수명주기 life cycle 동안 객체는 상태와 동작을 가집니다. 예를 들어 고양이의 '상태'는 색, 이름, 품종이 될 수 있고 고양이의 '동작'은 놀고, 먹고, 자고, 야옹 소리를 내는 것일 수 있습니다.
자바에서 객체는 new 키워드를 통해 만들어진 클래스의 인스턴스로 필드에 상태를 저장하고 메서드로 동작을 표현합니다.
각 인스턴스는 메모리 공간을 차지하며 다른 객체와 소통할 수 있습니다. 예를 들어 다른 객체에 해당하는 '소년'은 역시 객체에 해당하는 고양이를 어루만지거나 잠을 재울 수 있습니다."
객체는 클래스의 인스턴스입니다. 클래스는 객체의 설계도이며, 객체는 이 클래스에 정의된 특성(속성)과 행동(메소드)를 메모리 상에 실체화 합니다. 인스턴스는 메모리 공간을 차지함으로써, 고유한 속성 값을 유지할 수 있고 동일한 클래스로부터 생성된 다른 객체와 독립적으로 작동할 수 있습니다.
객체가 메모리 공간을 차지한다는 것
객체가 메모리 공간을 차지한다는 것은 객체가 자신만의 상태를 가지고 이를 유지할 수 있다는 의미입니다. 프로그램 실행 중에 객체가 가지는 필드=속성=데이터는 객체에 의해 읽고 수정될 수 있습니다.
클래스
클래스는 객체지향 프로그래밍의 핵심 개념 증 하나입니다. 클래스는 특정 타입의 객체를 만드는 데 필요한 지침의 집합입니다. 클래스는 템플릿, 청사진 또는 객체를 반드는 방법을 알려주는 레시피라고 할 수 있습니다.
객체를 만드는 과정을 '인스턴스화한다’고 하며 new 키워드로 수행할 수 있습니다. 클래스는 여러 번 인스턴스화하여 원하는 만큼 많은 객체를 만들수 있습니다.
클래스의 정의는 파일 형태로 하드 드라이브에 저장될 뿐 메모리의 힙 영역을소모하지 않습니다. 클래스를 인스턴스화 하면 생성된 객체는 메모리 힙 영역에 할당됩니다. 클래스가 따라야 하는 중요한 원칙 중 하나는 단일 책임 원칙입니다. 클래스는 이 원칙을 따르면서 단 하나의 일을 할 수 있도록 설계 및 작성되어야 합니다.
구성이란?
구성은 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 기본적으로 구성은 좀 더 제한적인 집약 관계입니다. 집약이 자체 수명 주기를 가지는 두 객체 간의 HAS-A 관계를 의미한다면, 구성은 단독으로 존재할 수 없는 객체를 포함하는 HAS-A 관계를 의미합니다.
이러한 연결고리를 강조하기 위해서 HAS-A 관계는 PART-OF 관계라고도 합니다. 예를 들어 Car(자동차)는 Engine(엔진)을 가집니다. 즉, Engine은 Car와 PART-OF 관계입니다. 차가 파괴되면 엔진도 파괴됩니다. 구성은 객체의 가시성을 제어하고 코드를 재사용하므로 상속보다 더 낫다고 말합니다.”
캡슐화란?
캡슐화는 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 캡슐화는 주로 코드와 데이터를 하나의 작업 단위인 클래스로 결합하고 외부 코드가 이 데이터에 직접 접근하지 못하게 하는 방어막 역할을 합니다.
또한 객체 상태를 외부로부터 숨기고 이 상태에 접근하기 위한 일련의 public 메서드를 노출하는 기법입니다. 각 객체가 클래스 안에서 상태를 private으로 유지할 때 캡슐화가 성립되었다고 말할 수 있습니다. 따라서 캡슐화는 정보 은닉 메커니즘이라고 불리기도 합니다.
캡슐화를 이용하는 코드는 몇 가지 장점이 있습니다. 먼저 코드의 느슨한 결합이 가능합니다. 예를 들어 클라이언트 코드와 어긋나지 않는 상태에서 클래스 변수의 이름을 변경할 수 있습니다.
또한 재사용할 수 있으며 클래스 내에서 데이터가 어떻게 조작되는지 클라이언트가 인식하지 못하므로 안전합니다.
마지막으로 필드를 테스트하는 것보다 메서드를 테스트하는 편이 더 쉽기 때문에 캡슐화를 이용한 코드는 테스트하기 쉽다는 장점이 있습니다. 자바에서 캡슐화는 public, private, protected와 같은 접근 제어자로 구현할 수 있습니다.
일반적으로 객체가 자체 상태를 관리할 때 상태는 private 변수로 선언되고 public 메서드로 접근 및 수정됩니다. 예를 살펴볼까요? Cat 클래스는 mood(기분), hungry(배고픔), energy(에너지)와 같은 필드로 구성할 수 있습니다. Cat 클래스의 외부 코드는 이러한 필드를 직접 수정할 수는 없지만 play, feed, sleep과 같이 클래스 상태를 내부적으로 수정하는 public 메서드를 호출할 수 있습니다. Cat 클래스는 meow와 같이 클래스 외부에서 접근할 수 없는 private 메서드도 가질 수 있습니다. 이것이 캡슐화입니다.
다형성
다형성은 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 다형성을 뜻하는 'polymorphism'은 많다'를 의미하는 'poly'와 '형태'를 의미하는 'morph'라는 2개의 그리스어로 구성된 단어입니다. 즉, 다형성은 많은 형태를 의미합니다.
좀 더 정확하게 말해, 객체지향 프로그래밍에서 다형성은 객체가 때에 따라 다르게 동작할 수 있게 해주거나 어떤 동작이 다른 방법으로 동작할 수 있도록 하는 역할을 합니다.
다형성을 구현하는 방법 중 하나는 메서드 오버로딩입니다. 여러 개의 메서드가 동일한 이름을 가지고 있지만 매개변수가 다른 경우 컴파일러가 오버로드된 메서드 가운데 어떤 형식을 호출할 것인지 컴파일 시간에 식별할 수 있으므로 컴파일 타임 다형성이라고도 합니다.
이때 오버로드된 메서드의 형태에 따라 객체는 다르게 동작합니다. 예를 들어 Triangle(삼각형)이라는 클래스에는 서로 다른 매개변수를 가진 여러 개의 draw 메서드를 정의할 수 있습니다.
집약
집약은 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 집약은 단방향 연관 관계의 특별한 경우입니다. 연관이 서로 독립적인 두 클래스 간의 관계를 의미한다면 집약은 두 객체 간의 HAS-A 관계를 의미합니다.
여기서 집약 관계의 두 객체는 자체 수명 주기를 가지며 객체 중 하나는 HAS-A 관계의 소유자입니다. 자체 수명 주기를 갖는다는 것은 한 객체가 종료되어도 다른 객체에 영향을 미치지 않는다는 의미입니다.
예를 들어 TennisPlayer(테니스 선수)는 Racket(라켓)을 가집니다. Racket은 TennisPlayer를 사용할 수 없으므로 이것은 단방향 연관 관계입니다. TennisPlayer가 죽더라도 Racket은 영향을 받지 않습니다.
추상화
아인슈타인은 '모든 것은 더 단순하게 만드는 것이 아니라 가능한 한 단순하게 만들어야 한다'고 말했습니다. 추상화는 사용자를 위해 무언가를 최대한 간단하게 만들고자 하는 객체지향프로그래밍의 핵심 개념 중 하나입니다.
객체지향 프로그래밍의 객체는 사용자에게 높은 수준의 작업 집합만 노출하고 작업의 내부 구현 내용은 숨겨야 한다는 말이 있습니다. 이 개념을 구현하는 추상화를 통해 사용자는 애플리케이션이 일을 수행하는 방법이 아니라 수행하는 일 자체에 집중할 수 있습니다.
즉, 내용을 노출하는 복잡성을 줄이고 코드의 재사용성을 높이며 코드 중복을 방지하고 낮은 결합도와 높은 응집도를 유지합니다. 또한 중요한 내용만 공개하여 애플리케이선의 보안과 재량권을 유지합니다.
실생활의 예를 들어보겠습니다. 차를 운전하는 남자가 있다고 가정하겠습니다. 이때 남자는 각각의 페달이 무슨 원을 하는지. 핸들이 무슨 일을 하는지 알고 있지만 페달과 핸들에 힘을 실어주는 차 내부의 메키니즘은 전혀 알지 못하는 경우가 많습니다. 이것이 추상화입니다.
상속
상속은 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 상속을 통해 다른 객체를 기반으로 객체를 만들 수 있습니다. 상속은 서로 다른 객체가 상당히 유사하고 몇 가지 공통된 로직을 공유하지만 완전히 동일하지는 않을 때 유용합니다.
상속은 객체가 다른 객체의 코드를 재사용할 수 있도록 허용하여 코드의 재사용성을 유지하고 각 객체만의 로직도 추가할 수 있습니다. 따라서 상속을 구현하려면 공통된 로직을 재사용하고 다른 클래스의 고유 로직을 추출해야합니다. 이를 IS-A 관계라고 하며 부모-자녀 관계라고도 합니다.
상속 관계는 Foo가 Buzz를상속할 때 'Foo IS-A Buzz'와 같이 표현할 수 있습니다. 예를 들어 '고양이 IS-A 고양이과의 동물' 또는 '기차 IS-A 교통 수단'과 같이 상속 관계를 표현할 수 있습니다. IS-A관계는 클래스의 계층 정의에 사용하는 작업 단위입니다. 자바에서 상속은 extends 키워드로 부모 클래스로부터 자식 클래스를 파생시켜 구현합니다.
자식 클래스는 부모의 필드와 메서드를 재사용할 수 있으며 자신만의 필드와 메서드를 추가할 수 있습니다. 상속된 객체는슈퍼클래스 또는 부모 클래스라고 하고 슈퍼클래스를 상속받은 객체는 서브클래스 또는 자식 클래스라고 합니다.
자바에서는 여러 개의 클래스를 상속할 수 없습니다. 따라서 서브클래스 또는 자식 클래스는 2개 이상의 슈퍼클래스 또는 부모 클래스로부터 필드와 메서드를 상속받을수 없습니다. 예를 들어 Employee(직원) 클래스는 부모 클래스로서 소프트웨어 회사의모든 직원의 공통 로직을 정의할 수 있고, Programmer(개발자) 클래스는 자식 클래스로서 Employee 클래스를 상속받아 정의된 공통 로직을 사용하고 개발자에게 특화된 로지을추가할 수 있습니다. 다른 클래스도 Programmer나 Employee 클래스를 상속할 수 있습니다.
연관
연관 객체지향 프로그래밍의 핵심 개념 중 하나입니다. 연관은 서로 독립적인 두 클래스 간의 관계를 의미하며 객체 간의 다중 관계라고도 합니다. 연관에서는 소유자가 없습니다. 연관 관계에 있는 객체들은 서로 사용 가능한 양방향 연관 관계를 가지거나 한 객체만 다른 객체를 사용할 수 있는 단방향 연관 관계를 가지며 자체 수명을 가집니다.
연관에는 단방향이나 역방향, 일대일, 일대다, 다대일, 다대다 관계가 있습니다. 예를 들어 Person(사람)과 Address(주소) 객체에는 양방향 다대다 관계가 있을 수 있습니다. 즉, 한 명의 사람은 여러개의 주소와 연관될 수 있으며 하나의 주소는 여러 사람에게 속할 수 있습니다. 그러나 사람은 주소 없이 존재할 수 있고 주소도 사람 없이 존재할 수 있습니다.”
참고 자료
- 「 자바 코딩 인터뷰 완벽 가이드 」2022, 안겔 레오나르드