📢 백엔드 관련 자료는 Backend Wiki에서 PR을 통해 검증과 내용 보완을 거친 후 블로그로 이관되고 있습니다 :)
객체 지향 이론 기본 개념
- 객체 지향 프로그래밍 = 실제 세계를 컴퓨터 속에 옮겨 놓기
- 실제 사물의 속성과 기능을 분석
- 데이터(변수)와 함수로 정의
- 필요한 사물끼리 연결
- 실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물 간의 상호작용입니다
- OOP (캡슐화, 상속, 추상화, 다형성) 개념을 중심으로 점차 구체적으로 발전되었습니다
객체 지향 언어란?
- 기존의 프로그래밍 언어(절차적 언어)에서 몇 가지 새로운 규칙을 추가한 언어입니다
- 코드의 재사용성이 높고 유지보수가 용이하며, 중복 코드 제거할 수 있는 특징이 있습니다
객체 지향 언어 주요 특징
- 코드의 재사용성이 높습니다
- 새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있습니다
- 코드의 관리가 용이합니다
- 코드 간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있습니다
- 신뢰성이 높은 프로그래밍을 가능하게 합니다
- 제어자, 메서드를 이용하여 데이터를 보호하고 올바른 값을 유지하도록 합니다
- 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지합니다
객체 지향 프로그래밍 특징 - OOP
객체 지향 프로그래밍의 4대 특징을 간단하게 알아보겠습니다
캡슐화 (Encapsulation)
- 공통된 데이터와 데이터를 활용하는 함수끼리 캡슐(Class) 안에 두는 것
- 즉 개념 혹은 논리적으로 연관된 데이터(변수)와 함수를 하나의 클래스에 캡슐화하는 것을 의미합니다
- 클래스 안에서는 표시할 속성(public 변수)와 숨길 속성(private 변수)을 선택할 수 있습니다
특징 | 설명 |
데이터 캡슐화 | 필드와 메서드를 하나로 묶는 것 |
은닉화 | 외부에 드러나게 하지 않기를 원하는 데이터를 감추어(private) 외부에서 데이터를 직접 접근하는 것을 방지 |
class TV {
int channel;
// 가격은 getPrice()를 통해서만 가져갈 수 있다 -> 직접 접근 불가
private int price;
String color;
void channelUp() {
this.channel++;
}
public int getPrice() {
return price;
}
public void setColor(String color) {
this.color = color;
}
}
상속 (Inheritance)
- 부모 클래스의 특징과 기능을 자식 클래스에게 물려주는 것
- 코드를 더 작은 단위로 Class를 쪼개면서 재사용을 할 수 있습니다
- 공통적인 요소를 합쳐 중복 코드를 제거할 수 있습니다
- 부모 클래스 수정 시 모든 자식 클래스도 일괄 수정되는 특징이 있습니다
class Entrepreneur {
String firstName;
String lastName;
private int shares;
private String company;
}
class Actor {
String firstName;
String lastName;
private int oscars;
private int age;
}
// firstName과 lastName이 공통적으로 사용되는 멤버이다 -> 상속
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
class Person {
String firstName;
String lastName;
}
class Entrepreneur extends Person {
private int shares;
private String company;
}
class Actor extends Person {
private int oscars;
private int age;
}
추상화 (Abstraction)
- 구현 세부 정보를 숨기고 일반 인터페이스를 지정하는 행위
- 세부 사항(구현부)의 수정이 일어난다 하더라도 해당 메서드를 사용하는 다른 어느 곳에서도 수정을 할 필요가 없습니다
💡 예시를 들어보자
자동차에는 엑셀, 브레이크, 핸들, 버튼 등 다양한 인터페이스가 존재한다
우리는 아래와 같이 알 수 있다
엑셀: 차가 움직인다
브레이크: 차가 멈춘다
핸들: 차의 방향을 조절한다
버튼: 각각의 기능이 있다
하지만 구현 세부정보는 각 제조사마다 다르지만 우리는 몰라도 차를 운전하는데 전혀 지장이 없다.
따라서 인터페이스는 구현체 내부에서 어떻게 돌아가는지 몰라도 원하는 기능을 사용하는데 문제가 없다는 특징이 있다
다형성 (Polymorphism)
- 여러 개의 형태를 갖고 있는 것
- 즉 변수 혹은 메서드가 상황에 따라 다른 결과가 나옵니다
- 오버로딩과 오버라이딩을 통해 해당 내용이 가능합니다
- 메서드가 어떻게 작동해야 되는지에 대한 최소한의 규칙이 정해져 있습니다 (return 타입 등)
- 메서드의 핵심은 보존하면서 구현 방식의 모양과 모습만 다르게 구현할 수 있는 방법입니다
class Person {
public String sayHi() {
return "ㅎㅇ";
}
public String sayBye() {
return "ㅂㅂ";
}
}
class 한국인 extends Person {
}
class Italian extends Person {
@Override
public String sayHi() { // 오버라이딩
return "Hi!";
}
}
public static void main(String[] args) {
한국인 한국인1 = new 한국인();
한국인1.sayHi(); // 출력값: ㅎㅇ
Italian italian1 = new Italian();
italian1.sayHi(); // 출력값: Hi!
}
이처럼 한국인 객체의 sayHi()와 Italian 객체의 sayHi()의 결과가 다른 것을 볼 수 있습니다
객체란?
- 객체는 ‘실제로 존재하는 것’ 으로써 우리 주변에서 볼 수 있는 모든 사물들이 곧 객체라고 볼 수 있습니다
- 개념이나 논리 같은 무형적인 것들도 포함됩니다
- 프로그래밍 관점 → 클래스에 정의된 내용대로 메모리에 객체가 생성됨
- 객체 = 속성(변수) + 기능(메서드)
객체 | 설명 |
객체의 정의 | 실제로 존재하는 것, 사물 또는 개념 |
객체의 용도 | 객체가 가지고 있는 기능과 속성에 따라 다름 |
유형의 객체 | 책상, 의자, 모니터 등과 같은 사물 |
무형의 객체 | 수학공식, 프로그램 에러와 같은 논리나 개념 |
클래스란?
- 객체를 정의해놓은 것 → 객체의 설계도 또는 틀이라고 정의
객체 | 클래스 |
제품 | 제품 설계도 |
TV | TV 설계도 |
붕어빵 | 붕어빵 기계 |
- 클래스는 객체를 생성하는 데 사용됩니다
- 자동차라는 객체가 필요하다고 가정해봅시다
- 프로그래밍에서는 클래스를 먼저 작성한 후, 클래스로부터 객체를 생성하여 사용해야 합니다!
1. 자동차라는 클래스를 작성합니다 (설계도)
class Car {
....
}
2. 자동차라는 클래스를 통해 객체를 생성합니다 (인스턴스화)
Car car= new Car();
클래스는 서로 관련된 변수들을 정의하고 이들에 대한 작업을 수행하는 함수들을 함께 정의한 것입니다
클래스가 곧 사용자 정의 타입입니다 (기본 자료형 외) - (ex. VO, DTO)
객체와 인스턴스
- 객체와 인스턴스는 같은 의미이다! -> 따라서 문맥에 따라 구별하여 사용하면 됩니다
💡 예시를 들어보자
차 인스턴스다 x -> 차 객체다 o
차는 차 클래스의 객체이다 x -> 차는 차 클래스의 인스턴스이다 O
- 클래스 —— (인스턴스화) ——> 인스턴스(객체)
- 클래스로부터 객체를 만드는 과정 → 클래스의 인스턴스화
- A 클래스로부터 만들어진 객체 → A 클래스의 인스턴스
// 클래스의 객체를 생성 -> 객체의 주소를 참조변수에 저장 클래스명 변수명 = new 클래스명(); Class Human { ... } // new를 통해 Human 인스턴스 생성 -> gibeom이라는 참조변수에 Human 인스턴스의 주소 저장 Human gibeom = new Human();
참조 변수 vs 인스턴스
- 인스턴스는 오직 참조 변수를 통해서만 다룰 수 있고, 참조 변수의 타입과 인스턴스의 타입은 당연히 일치해야 합니다
- 하나의 인스턴스를 여러 개의 참조 변수가 가리키는 경우가 가능합니다
- 아래 예시에서 gibeom2에 생성된 인스턴스는 gibeom1과 gibeom2이 동시에 가리키고 있습니다
Human gibeom1 = new Human();
Human gibeom2 = new Human();
gibeom1 = gibeom2 // 참조변수 gibeom1한테 gibeom2의 주소값을 부여
// gibeom1의 본래 주소값은 garbage collector에 의해 메모리 반환
- 여러 인스턴스를 하나의 참조 변수가 가리키는 경우는 불가능합니다
- 위 예시의 gibeom1처럼 덮어씌워집니다
객체의 구성 요소
- 객체는 속성과 기능의 집합입니다
- 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(구성원, member)라고 합니다
구성 요소 | 명칭 |
속성 (property) | 멤버 변수, 특성(attribute), 필드(field), 상태(state) |
기능 (function) | 메서드, 함수, 행위(behavior) |
속성과 기능에 대한 예시 (TV)
속성 | 기능 |
크기, 길이, 높이, 무게, 색상, 볼륨, 채널 등 | 켜기, 끄기, 볼륨 높이기 낮추기, 채널 변경하기 등 |
채널 → int channel; | 채널 변경하기 → channelUp() { … } |
- 같은 클래스 안의 멤버일지라도, 각 인스턴스의 속성(멤버변수)은 독립적으로 서로 다른 값을 유지합니다 → 서로 다른 객체 주소 값을 참조
- 메서드의 행위는 모든 인스턴스에 대해 동일하게 동작합니다 (오버라이딩한 경우 제외)
Class Human {
String gender;
int age;
void increaseAge() { ++age; }
}
Class HumanTest {
Human gibeom = new Human();
Human beom = new Human();
gibeom.increaseAge()
// 속성중에 하나인 멤버변수 age는 각 인스턴스마다 서로 다른 값을 유지
// 하지만 increaseAge 같은 메서드 동작 자체는 모든 인스턴스에서 동일하게 작동
System.out.println(gibeom.age); // 1
System.out.println(beom.age); // 0
}
객체 배열
- 객체의 주소를 배열에 저장 → 즉 참조 변수들을 하나로 묵은 참조 변수의 배열
Human[] humanArr = {new Human(), new Human(), new Human()}
마무리
자바를 다시 공부하면서 객체, 클래스, 인스턴스, 참조 변수 등의 용어가 헷갈렸었던 것들이 재정비가 되는 느낌입니다
객체지향의 뿌리는 절차적 언어에서 시작됐다는 내용은 흥미로운 것 같네요
OOP의 캡!상추다 에 대해서도 다시 한번 상기시키며 개발을 할 때 참고해서 코드를 구성해야 될 것 같습니다
감사합니다 :)
📢 자료가 도움이 되셨다면 Backend Wiki로 놀러 오세요!
Reference
💡 잘못된 내용이나, 보충할 내용이 있다면 언제든지 편하게 연락 주시면 감사하겠습니다 :)
🙋🏻♂️ Call me
Email : dev.gibeom@gmail.com
KakaoTalk : https://open.kakao.com/me/beomdrive
'Programming > Java' 카테고리의 다른 글
변수와 메서드, 그 속으로 (0) | 2022.09.06 |
---|