01. JAVA? 객체지향?
1. 자바(JAVA)의 필수 특징 - OOP
- OOP는 자바의 특성 중에 한가지 특성이다.
- OOP의 구성은 다음과 같이 정리할 수 있다.
- 추상화(Abstraction)
- 상속
- 다형성(polymorphism)
- 캡슐화(encapsulation)
1-1. 추상화(Abstraction)
추상화에 대해 생각을 해보면 피카소의 그림과 같은 기괴한 그림이 생각이 난다. JAVA에서의 추상화 또한 이런 기괴한 뜻일까?
추상화라는 본 뜻은 다음과 같다.
추상화는 필요한 부분, 중요한 부분을 통합하여 하나로 만드는 것을 말합니다. (네이버 사전)
위의 뜻을 정리해보는 예를 들어보자, 이 글을 읽는 사람이 하나의 어플리케이션을 만든다고 가정을 하자. 만약 병원에 대한 어플리케이션이라고 가정을 했을때, 필요한 것을 하나씩 추출해보면 다음과 같을 것이다.
환자/의사/간호사 등에 대한 내용으로 중요한 내용을 추릴 수 있는 것처럼 하나의 주제(병원 어플)로 통합 및 관련된 것을 정리하여 만드는 과정이 추상화라고 한다.
한마디로, 필요한 것을 만들기 위해 공통된 특성을 추출하는 과정이 모델링이라고 볼 수 있다.
ex) 동물에 대한 모델링(추상화) 진행
- 무게
- 우는 소리
- 꼬리
- 보행방법(4족보행, 2족보행)
- 날개 유무
- 사는 곳(수상? 육지?)
1-2. 상속
보통 책을 보면 상속을 Inheritance로 표현을 많이 한다. 보통의 책에선 상속을 설명할때 붕어빵틀과 붕어빵, 아버지클래스와 할아버지클래스등으로 나누게 되는데 한번 보면 이해하기가 어렵다.
할아버지 아버지 = new 할아버지 // ?
붕어빵틀 붕어빵 = new 붕어빵틀 // ?
필자가 본 책에서 해당 내용에 대해 자세히 설명이 되어있어 필자가 이해한 내용을 기준으로 작성을 해보면 다음과 같이 정리 할 수 있을것 같다. 보통의 책에서는 상속관계를 계층도의 관계로 구성을 많이 해놓는다.
해당 그림으로 Child는 Parant와의 관계를 설명할 수 있을까? 상속에 대해 더 자세한 그림은 다음과 같이 설명 가능할 것 같다.
굳이 억지로 설명 불가능한 가족관계에 상속을 설명않고 다른 예로 상속관계를 설명하는 그림은 다음과 같을 것이다.
해당 그림이 프로그래밍적으로 설명은 부족하지만 좀더 이해적인 측면에서는 설명이 더 용이할 것 같다.
해당 벤다이어그램으로 설명을 하자면 Animal라는 하나의 클래스를 세분화하면 Birds가 있고 Birds를 더 세분화 하면 Penguin가 나올 수 있다. Penguin클래스는 조류(Birds)의 특성과 동물(Animal)이라는 클래스를 상속 받는다. Animal의 클래스를 세분화하고 확장하면 한 예로 Birds라는 클래스로 확장이 가능하고 Birds를 세분화하고 확장해보면 Penguin이라는 클래스가 나올 수 있다.
Penguin은 조류의 특성도 가지고 있으면서 동물의 특성도 가지고 있다. 어떻게 보면 상위클래스를 포함한 더 구체적인 클래스라고 볼 수 있다.
상속은 상위 클래스를 좀더 확장(세분화)하는 개념이고, Animal의 클래스를 재사용 하는 과정이라고 보는것이다.
근데 문제가 발생한다. 원래 조류는 헤엄을 치는 경우가 거의 없다. 조류 중에 펭귄이나 오리처럼 몇몇 존재만 있다. 그러면 각자 수영의 특성을 같는 어류의 클래스를 상속할 것인가? 다음 그림처럼?
해당 경우에는 Penguin클래스는 Birds클래스와 Fish클래스를 모두 상속하면서 수영하는 특성을 가져와야 할까? 그렇게 되면 다중상속으로 볼 수 있는데 가능할 것인가? 아쉽게도 JAVA는 다중상속을 지양한다. 결론은 해당 벤다이어그램은 너무 세분화된 나머지 잘못 그려진 벤다이어 그램이라고 볼 수 있다. 그렇다면 좀 더 정확한 벤다이어 그램으로 표현하면 어떻게 될까?
필자가 표현력이 부족해서 다음과 같은 그림밖에 표현을 못할 것 같다.
상위 그림처럼 하나의 특별한 예외 케이스를 분류하는 것은 클래스가 아닌 인터페이스라고 불린다.
인터페이스는 'be able to'로 사용하여 번역이 되면 이해가 쉬울 것이다. (ex. 펭귄은 수영 할 수있다.)
만약 어류만 수영할 수 있다고 하면 조류인 펭귄, 포유류인 고래는 어류에 대한 클래스와 각각 조류, 포유류에 대해 상속을 받아야 하는데, 그렇지 않고 Swim이라는 하나의 인터페이스를 분류하여 표현한다는 것이다. 그러므로 다중상속을 피하고 포유류의 성격을 가지면서 헤엄칠 수 있는 특성만 사용이 가능하다는 것이다.
자바가 이처럼 다중상속을 피하고 인터페이스를 사용하는 이유는 다이아몬드 문제를 해결하기 위한 방법 중 하나이다.
다이아몬드 문제?
- Class A에 A라는 메소드가 있다.
- Class B와 Class C는 각각 A를 상속받아 A',A''로 사용가능하다.
- Class D가 다중상속이 가능하여 B,C를 상속받는다.
- Class D가 A메소드 호출시 A',A''중 어떤것을 상속받나에 대한 문제
1-3. 다형성(polymorphism)
JAVA, 객체 지향에서 말하는 다형성은 한마디로 정리하면 오버로딩과 오버라이딩이 있다.
- 오버라이딩은 메소드를 재정의 하는 기능을 말한다.
- 오버로딩은 메소드를 중복정의하는 기능을 말한다.
오버라이딩과 오버로딩의 단어 자체의 의미는 각각 '최우선시 되는', '과적하다'으로 표현된다. 다시말하면 다음과 같은 구조를 예로 들자.
ClassB는 ClassA를 상속받을때 Q1, Q2는 각각 같은 메소드명으로 되어 있는데 뭐라고 정의할 수 있나? Q1의 경우 ClassA의 print()라는 중복된 메소드명으로 사용을 하였고 print(String)의 경우 인자를 받는 새로운 메소드를 사용한다. ClassB에서 print()라는 메소드를 호출하면 ClassA보다 ClassB의 print()가 '최우선시' 사용된다. print(String)의 경우 같은 역할을 하는 print메소드라고 하더라도 인자를 필요로 하는 다른 메소드 형태를 보인다. 해당 결과물은 필요로하는 인자도 차이가 있을 뿐더러 안에서 구현하는 메소드의 형태에 따라 차이가 있을 수 있다. Q1은 peintp()를 오버라이딩, Q2는 print()를 오버로딩한 print(String) 메소드이다.
1-4.캡슐화
캡슐화란 접근 제어자를 통해 정보를 은닉할 수 있는 늑징을 말한다. JAVA에서는 크게 다음과 같은 접근 제어자가 있다.
- public / protected / (default) / private
- public은 패키지 구분 없이 모두 사용이 가능한 영역
- protected 는 상속받은 클래스 혹은 같은 패키지 내의 클래스가 사용가능한 영역
- default는 같은 패키지 내에서만 사용이 가능 default는 말그대로 따로 지정을 안하면 default로 지정된다.
- private 다른 클래스는 절대 사용이 불가능한 구조이다.
해당 영역까지의 내용은 GitHub에 저장해 놓았습니다.
자세한 참고는 소스에 주석까지 같이 참고하시면 좋을거 같네요
https://github.com/Chaeson/studyJava_FROG
Chapter3-> abstraction01~02 : 추상화 설명 및 소스
Chapter3-> encapsulation01: 캡슐화
Chapter3-> inheritance01~03: 상속
Chapter3-> polymotphism01: 다형성
추가로 값에 의한 참조(Call By Value), 주소에 의한 참조(Call By reference)도 소스에 정리가 되어있다.
해당 내용을 요약하면 두개의 개념 자체도 값을 복사하는 개념인데 값 자체를 복사하느냐, 값을 가지고 있는 주소값을 복사하느냐의 차이이다. 주소에 의한 참조는 Heap영역의 객체 자료형을 복사하는 경우가 많고, 값에 의한 참조는 자료형의 값을 저장하는 경우가 많다.
Chapter3->reference: 참조형
참고자료: 스프링 입문을 위한 자바 객체지향의 원리와 이해