2022.03.14 - [IT 책 독서록] - [스프링 입문을 위한 자바 객체지향의 원리와 이해] 1 ~ 2장 정리
[스프링 입문을 위한 자바 객체지향의 원리와 이해] 1 ~ 2장 정리
1장 : 온고지신. 청출어람 1장에서 얘기하고자 하는 말은 다음 두 문장으로 정리된다. "스프링같은 신기술은 하늘에서 뚝 하고 떨어진 것이 아니라 이전 기술의 어깨를 디딤돌삼아 그 위에 이전
blog.robinjoon.space
객체지향은 인간지향이다.
인간이 세상을 바라보는 시각을 프로그래밍에 접목시킨 것이 객체지향 프로그래밍이다.
객체지향의 4대 특성
캡슐화, 상속, 추상화, 다형성 ▷ 캡! 상추다
캡슐화 : 정보은닉
상속 : 재사용
추상화 : 모델링
다형성 : 사용 편의
클래스와 객체 ▷ 클래스 : 객체 = 붕어빵틀 : 붕어빵 ?
클래스와 객체의 관계룰 비유할 떄 많이 쓰는 붕어빵틀과 붕어빵 비유가 올바른 비유일까?
클래스와 객체를 붕어빵틀과 붕어빵으로 비유하면 아래와 같은 이상한 코드가 나온다.
붕어빵틀 붕어빵 = new 붕어빵틀();
이걸 인간의 입장에서 해석하면, 새로운 붕어빵틀을 만들었더니 붕어빵이 되었다. 정도로 해석할 수 있다. 뭔가 많이 이상하다.
붕어방틀과 붕어빵의 관계는 팩토리다. 즉, 붕어빵틀은 붕어빵을 만드는 팩토리인 것이다. 붕어빵틀과 붕어빵으로 클래스와 객체를 비유한 것은, "코드에서 객체가 어떤 구조로 이루어져 있는지 표현하는 것이 클래스" 라는 관점에서 나온 비유다.
클래스는 분류에 대한 개념이고, 객체는 실체다. 따라서 이런 관계를 나타내는 올바른 비유는 다음과 같다.
클래스 : 객체 = 사람 : 김연아
추상화 : 모델링
추상의 사전적 정의는 아래와 같다.
추상(象) [명사][심리] 여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용
여기서 "공통 특성 / 공통 속성 추출" 이라는 부분에 주목하면 결국 추상화는 모델링이다.
추상화 : 구체적인 것을 분해해서 관심영역에 대한 특성만을 가지고 재조합 하는 것.
▷ 구체적인 것을 분해해서 관심영역(애플리케이션 경계, Context)에 대한 특성만을 가지고 재조합 하는 것. = 모델링
모델은 실제 사물을 정확히 복제하는 것이 아닌, 목적에 맞게 관심 있는 ㅌ특성만을 추출해서 표현하는 것.
객체와 메모리
객체, 즉 클래스의 인스턴스는 힙 영역에 생성된다. 스택영역에 있는 변수는 참조변수로서 힙영역의 메모리 주소를 참조한다. 흔히 가리킨다 라고 표현한다. 만약, 힙영역에 존재하는 객체를 참조하는 변수가 없다면 갈비지 컬렉터(GC)가 청소한다.
클래스 멤버와 객체 멤버
미키마우스의 꼬리는 몇개인가요?
제리의 꼬리는 몇개인가요?
쥐의 꼬리는 몇개인가요?
이 질문들의 답은 하나다. 미키마우스와 제리는 객체고, 쥐는 클래스다. 만일 어떤 클래스의 인스턴스가 모두 공통으로 가지는 속성이 있다면, 그걸 각 인스턴스마다 별도로 가지고있게 하지 말고, 클래스에 속성을 주는게 합리적이다. 이럴 때 정적 멤버 속성, 즉 클래스 멤버 속성을 사용한다. 정적 멤버 속성은 기본적으로 해당 클래스의 모든 객체들이 같은 값을 가질 때 사용하는 것이 정석이다.
정적 메서드는 언제 쓰나? 일단, 가장 먼저 main 메서드는 정적 메서드여야만 한다. 이 메서드는 최초로 실행되는 메서드고, 이 메서드가 실행될 시점에는 아직 아무 객체도 메모리에 존재하지 않으므로 클래스 멤버여야 한다.
그 외로 실무에선, 클래스의 인스턴스로 사용하지 않게되는 유틸리티성 메서드를 주로 정적 메서드로 구성한다.
상속 : 재사용 + 확장
현실에서 상속이라는 말의 의미를 그대로 객체지향에서의 상속으로 받아들이면 문제가 생긴다. 객체지향에서 상속은 계층도/조직도 가 아닌 분류도 개념으로 일종의 재사용과 확장으로 받아들여야 한다. 그래서 자바에서 상속을 나타내는 예약어가 extends 인 것이다. 그런 관점에서 부모클래스 - 자식클래스 라는 말보단, 상위 클래스 -하위클래스 나 슈퍼 클래스 - 서브 클래스 라고 부르는 것이 합당하다.
객체지향에서 상속관계는 다음 문장을 만족해야 한다.
하위 클래스는 상위 클래스다.
상속을 조직도로 이해하는 경우 아래와 같은 모순 점이 생긴다.
아버지는 할아버지다.
아들은 아버지다.
딸은 아버지다.
반면 분류도의 경우는 문제가 없다.
포유류는 동물이다.
고래는 포유류다.
고래는 동물이다.
상속은 특성을 물려받는다 라는 의미에서 이름붙여진 것이다.
상속을 통해, 상위 클래스에서 작성한 메서드를 하위 클래스에서 그대로 사용할 수 있다.
상속과 is a 규칙
영문법에 관한 이야기라 생략하고 is a 규칙은 is a kind of 라고 바꿔야 더 자연스럽고 오해의 소지가 없어진다.
즉, 하위 클래스는 상위 클래스의 한 종류인 것이다.
다중 상속과 인터페이스
자바는 다중 상속을 지원하지 않는다. 두 상위 클래스가 같은 이름의 속성이나 메서드를 가질 때 어떻게 처리할지를 결정하는 과정에서 발생하는 실이 다중상속을 통해 가져올 득 보다 적기 때문이다. 대신 자바는 인터페이스를 도입함으로써 다중상속의 실을 버리고 득만 취했다.
인터페이스는 is a kind of 관계보다는 be able to 즉, "무었을 할 수 있는" 이라는 의미를 가진다.
상속은 상위 클래스가 하위 클래스에게 특성을 물려주는 것이고, 인터페이스는 클래스가 무었을 할 수 있다를 구현하도록 강제한다. 따라서 다음 문장이 성립한다.
상위 클래스는 하위 클래스에게 물려줄 특성이 많을 수록 좋고, 인터페이스는 구현을 강제할 메서드가 적을 수록 좋다.
상속과 메모리
Animal 클래스를 상속한 Penguin 클래스가 있다고 하자. 그럼, Penguin 클래스의 인스턴스를 사용하는 방법은 다음 두가지가 있을 것이다.
Penguin pororo = new Penguin();
Animal pingu = new Penguin();
전자의 경우 참조변수 pororo 는 힙영역에 생성된 Penguin 객체를 참조하게 되고 후자는 힙 영역의 Animal 객체를 참조하게 된다(어떤 클래스의 인스턴스를 생성하면 그 클래스가 상속하고있는 클래스의 인스턴스도 생성된다). 따라서, 전자의 경우 Penguin 클래스에서 따로 정의한 메서드를 사용할 수 있지만, 후자에선 불가능하다.
다형성 : 사용편의성
객체지향에서 다형성이라 하면 오버라이딩(Overriding) 과 오버로딩(Overloading)이라고 할 수 있다.
- 오버라이딩(Overriding) : 같은 메서드이름, 같은 인자 목록으로 상위 클래스의 메서드를 재정의
- 오버로딩(Overloading) : 같은 메서드 이름, 다른 인자목록으로 다수의 메서드를 중복 정의.
다형성과 메모리
하위 클래스에서 오버라이딩한 메서드는 힙영역에 생성된 상위클래스의 메서드를 덮어쓴다.(실제 메모리에서 덮어쓰는건지는 모르겠지만, 비유적으로..)따라서, 하위클래스에서 어떤 메서드를 오버라이딩을 한 경우, 참조변수를 상위클래스로 하든, 하위클래스로 하든 상관없이 재정의된 메서드가 호출된다.
다형성이 사용편의성을 의미하는 이유
다형성을 지원하지 않는 언어에서는 두 수를 더해서 반환하는 함수가 있을 때, 가능한 타입의 조합에 따른 모든 함수를 작성해야 한다. 예를 들어 addInt(int a, int b), addIntandDouble(int a, double b) 처럼 말이다. 게다가, 메서드 이름들도 모두 달라야 한다. 아주 골치아픈 상황이 된다. 자바의 경우 제네릭까지 이용한다면, 메서드 하나로 모든 경우를 대응할 수 있게 된다.
오버라이딩의 경우도 마찬가지로, 하위 클래스가 재정의한 메서드를 알아서 호출해 줌으로써 형변환이나 instanceof 연산자를 써서 하위 클래스가 무엇인지 신경쓰지 않아도 된다. 따라서 코드가 깔끔해진다.
이런 이유로 다형성이 사용 편의성을 준다는 것이다.
캡슐화 : 정보은닉
자바에서 캡슐화와 관련해 기억해야할 두가지 사항이 있다.
- 상속을 받지 않았다면 다른 객체의 객체 멤버에 접근하기 위해선, 그 객체의 참조변수를 이용해 접근하야 한다.
- 정적 멤버는 클래스명.정적멤버명 으로 접근하는게 원칙이다.
특히, 두번째 사항을 기억해야 하는 이유는 일관성 때문이다. 어떤 객체에서 자기 클래스에 정의된 public 정적 속성에 접근하는 방법은 클래스이름.정적속성, 정적속성, this.정적속성 의 3가지나 았다. 이것들이 코드에서 뒤섞여 나타난다면 모두 같은 것을 의미하지만 다르게 작성되어있으므로 헷갈리게 된다. 따라서 의미상으로 정적 속성은 클래스에 부여된 것이므로 클래스.정적속성 으로 사용하는게 합리적이다.
객체의 복사
일반 변수를 복사하는 경우 값을 그대로 복사해 다른 메모리에 직접 집어넣는 방법(call by value)를 사용하지만, 객체를 복사하게 될 경우 참조변수가 가지고 있는 값은 "힙영역에 위치한 객체의 메모리 주소" 이므로, 이를 복사하게 되고, 결국 이는 같은 객체를 두 참조변수가 가리키고있는 상태가 된다. 따라서, 한 참조변수를통해 객체를 수정하면, 같은 객체를 가리키고있는 다른 변수로 접근해도 당연히 객체가 수정되어있다. 이런 방식을 call by reference 라고 한다.
두 방식은 본질적으로 같다. 한 변수가 가지고있는 값을 다른 변수에 집어넣는건데, 일반 변수의 경우 변수에 저장된 값을 그 값 자체로 판단하고, 참조 변수인 경우 값을 주소로 판단하기 때문에 다른 결과를 보이는 것이다.
'IT 책 독서록' 카테고리의 다른 글
[스프링 입문을 위한 자바 객체지향의 원리와 이해] 5장 내용정리 (0) | 2022.04.01 |
---|---|
[스프링 입문을 위한 자바 객체지향의 원리와 이해] 4장 정리 (0) | 2022.03.31 |
[객체지향의 사실과 오해] 부록 A 내용정리 (0) | 2022.03.18 |
[객체지향의 사실과 오해] 7장 내용정리 (0) | 2022.03.18 |
[스프링 입문을 위한 자바 객체지향의 원리와 이해] 1 ~ 2장 정리 (0) | 2022.03.14 |